Add swapchain related implementations

This commit is contained in:
msiglreith 2017-12-07 22:29:14 +01:00
parent 936b207418
commit c09387bc4f
9 changed files with 231 additions and 49 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
/build/
/target/ /target/
**/*.rs.bk **/*.rs.bk
Cargo.lock Cargo.lock

14
CMakeLists.txt Normal file
View file

@ -0,0 +1,14 @@
cmake_minimum_required (VERSION 2.6)
project (portability)
include_directories("modules/vulkan-docs/src")
add_executable(native_test native/test.cpp native/window.cpp)
find_library(PORTABILITY_LIB portability "target/debug")
target_link_libraries(native_test ${PORTABILITY_LIB})
if (WIN32)
target_link_libraries(native_test Dwmapi Userenv ws2_32)
else (WIN32)
target_link_libraries(native_test pthread dl m X11 xcb)
endif (WIN32)

View file

@ -2,13 +2,13 @@ VULKAN_DIR=modules/vulkan-docs/src
BINDING=target/vulkan.rs BINDING=target/vulkan.rs
NATIVE_DIR=target/native NATIVE_DIR=target/native
TARGET=$(NATIVE_DIR)/test TARGET=$(NATIVE_DIR)/test
OBJECTS=$(NATIVE_DIR)/test.o OBJECTS=$(NATIVE_DIR)/test.o $(NATIVE_DIR)/window.o
LIBRARY=target/debug/libportability.a LIBRARY=target/debug/libportability.a
CC=g++ CC=g++
CFLAGS=-ggdb -O0 -I$(VULKAN_DIR) CFLAGS=-std=c++11 -ggdb -O0 -I$(VULKAN_DIR)
DEPS= DEPS=
LDFLAGS=-lpthread -ldl -lm -lX11 LDFLAGS=-lpthread -ldl -lm -lX11 -lxcb
.PHONY: all binding run .PHONY: all binding run

View file

@ -2,3 +2,26 @@
[![Build Status](https://travis-ci.org/kvark/portability.svg?branch=master)](https://travis-ci.org/kvark/portability) [![Build Status](https://travis-ci.org/kvark/portability.svg?branch=master)](https://travis-ci.org/kvark/portability)
This is a prototype static library implementing [Vulkan Portability Initiative](https://www.khronos.org/blog/khronos-announces-the-vulkan-portability-initiative) using gfx-rs [low-level core](http://gfx-rs.github.io/2017/07/24/low-level.html). See gfx-rs [meta issue](https://github.com/gfx-rs/gfx/issues/1354) for backend limitations and further details. This is a prototype static library implementing [Vulkan Portability Initiative](https://www.khronos.org/blog/khronos-announces-the-vulkan-portability-initiative) using gfx-rs [low-level core](http://gfx-rs.github.io/2017/07/24/low-level.html). See gfx-rs [meta issue](https://github.com/gfx-rs/gfx/issues/1354) for backend limitations and further details.
## Build
### Makefile (Unix)
```
make
```
### CMake (Window)
Build the Rust library (portability implementation):
```
cargo build
```
Build the native example:
```
mkdir build
cd build
cmake ..
cmake --build . --target native_test
```

View file

@ -9,8 +9,6 @@
#include <stdio.h> #include <stdio.h>
#include "window.hpp" #include "window.hpp"
extern "C" VkSurfaceKHR vkCreateSurfaceGFX(VkInstance);
int main() { int main() {
printf("starting the portability test\n"); printf("starting the portability test\n");
@ -33,8 +31,9 @@ int main() {
Config config = { 10, 10, 800, 600 }; Config config = { 10, 10, 800, 600 };
Window window = new_window(config); Window window = new_window(config);
#if defined(_WIN32)
VkSurfaceKHR surface; VkSurfaceKHR surface;
#if defined(_WIN32)
VkWin32SurfaceCreateInfoKHR surface_info = {}; VkWin32SurfaceCreateInfoKHR surface_info = {};
surface_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surface_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
surface_info.hinstance = window.instance; surface_info.hinstance = window.instance;
@ -68,6 +67,22 @@ int main() {
printf("\tusing queue family index %d\n", queue_family_index); printf("\tusing queue family index %d\n", queue_family_index);
assert(queue_family_index >= 0); assert(queue_family_index >= 0);
VkDeviceQueueCreateInfo queue_info = {};
float queue_priorities[1] = {0.0};
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info.queueCount = 1;
queue_info.pQueuePriorities = queue_priorities;
VkDeviceCreateInfo device_info = {};
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_info.queueCreateInfoCount = 1;
device_info.pQueueCreateInfos = &queue_info;
VkDevice device = 0;
res = vkCreateDevice(physical_devices[0], &device_info, NULL, &device);
printf("\tvkCreateDevice: res=%d\n", res);
assert(!res);
VkSurfaceFormatKHR surfFormats[20]; VkSurfaceFormatKHR surfFormats[20];
uint32_t formatCount = sizeof(surfFormats) / sizeof(surfFormats[0]); uint32_t formatCount = sizeof(surfFormats) / sizeof(surfFormats[0]);
res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices[0], surface, &formatCount, surfFormats); res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices[0], surface, &formatCount, surfFormats);
@ -103,11 +118,11 @@ int main() {
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
/*VkSwapchainCreateInfoKHR swapchain_ci = {0}; VkSwapchainCreateInfoKHR swapchain_ci = {};
swapchain_ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchain_ci.surface = info.surface; swapchain_ci.surface = surface;
swapchain_ci.minImageCount = desiredNumberOfSwapChainImages; swapchain_ci.minImageCount = desiredNumberOfSwapChainImages;
swapchain_ci.imageFormat = info.format; swapchain_ci.imageFormat = surfFormats[0].format;
swapchain_ci.imageExtent.width = swapchainExtent.width; swapchain_ci.imageExtent.width = swapchainExtent.width;
swapchain_ci.imageExtent.height = swapchainExtent.height; swapchain_ci.imageExtent.height = swapchainExtent.height;
swapchain_ci.preTransform = preTransform; swapchain_ci.preTransform = preTransform;
@ -118,22 +133,23 @@ int main() {
swapchain_ci.clipped = true; swapchain_ci.clipped = true;
swapchain_ci.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; swapchain_ci.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
swapchain_ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchain_ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;*/ swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkDeviceQueueCreateInfo queue_info = {}; VkSwapchainKHR swapchain = 0;
float queue_priorities[1] = {0.0}; res = vkCreateSwapchainKHR(device, &swapchain_ci, NULL, &swapchain);
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; printf("\tvkCreateSwapchainKHR: res=%d\n", res);
queue_info.queueCount = 1;
queue_info.pQueuePriorities = queue_priorities;
VkDeviceCreateInfo device_info = {};
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_info.queueCreateInfoCount = 1;
device_info.pQueueCreateInfos = &queue_info;
VkDevice device = 0; uint32_t image_count = 0;
res = vkCreateDevice(physical_devices[0], &device_info, NULL, &device); res = vkGetSwapchainImagesKHR(device, swapchain, &image_count, NULL);
printf("\tvkCreateDevice: res=%d\n", res); printf("\tvkCreateSwapchainKHR (query): res=%d image_count=%d\n", res, image_count);
assert(!res);
VkImage *swapchain_images = new VkImage[image_count];
assert(swapchain_images);
res = vkGetSwapchainImagesKHR(device, swapchain, &image_count, swapchain_images);
printf("\tvkCreateSwapchainKHR: res=%d\n", res);
assert(!res); assert(!res);
VkCommandPool cmd_pool = 0; VkCommandPool cmd_pool = 0;
@ -164,10 +180,17 @@ int main() {
} }
delete[] swapchain_images;
vkDestroySwapchainKHR(device, swapchain, NULL);
printf("\tvkDestroySwapchainKHR\n");
vkFreeCommandBuffers(device, cmd_pool, 1, &cmd_buffer); vkFreeCommandBuffers(device, cmd_pool, 1, &cmd_buffer);
printf("\tvkFreeCommandBuffers\n");
vkDestroyCommandPool(device, cmd_pool, NULL); vkDestroyCommandPool(device, cmd_pool, NULL);
printf("\tvkDestroyCommandPool\n");
vkDestroySurfaceKHR(instance, surface, NULL); vkDestroySurfaceKHR(instance, surface, NULL);
printf("\tvkDestroySurfaceKHR\n");
vkDestroyDevice(device, NULL); vkDestroyDevice(device, NULL);
printf("\tvkDestroyDevice\n");
vkDestroyInstance(instance, NULL); vkDestroyInstance(instance, NULL);
printf("done.\n"); printf("done.\n");

View file

@ -78,4 +78,39 @@ auto poll_events() -> bool {
return true; return true;
} }
#else
auto new_window(Config config) -> Window {
auto connection = xcb_connect(NULL, NULL);
auto setup = xcb_get_setup(connection);
auto screen_iterator = xcb_setup_roots_iterator(setup);
auto screen = screen_iterator.data;
auto hwnd = xcb_generate_id(connection);
xcb_create_window(
connection,
XCB_COPY_FROM_PARENT,
hwnd,
screen->root,
config.x,
config.y,
config.width,
config.height,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
0,
NULL);
xcb_map_window(connection, hwnd);
xcb_flush(connection);
Window window = Window { connection, hwnd };
return window;
}
auto poll_events() -> bool {
return true;
}
#endif #endif

View file

@ -4,12 +4,17 @@
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h> #include <windows.h>
#else
#include <xcb/xcb.h>
#endif #endif
struct Window { struct Window {
#if defined(_WIN32) #if defined(_WIN32)
HINSTANCE instance; HINSTANCE instance;
HWND window; HWND window;
#else
xcb_connection_t *connection;
xcb_drawable_t window;
#endif #endif
}; };

View file

@ -41,6 +41,21 @@ pub fn format_from_hal(format: format::Format) -> VkFormat {
} }
} }
pub fn hal_from_format(format: VkFormat) -> format::Format {
use VkFormat::*;
use hal::format::ChannelType::*;
use hal::format::SurfaceType::*;
let (sf, cf) = match format {
VK_FORMAT_B8G8R8A8_UNORM => (B8_G8_R8_A8, Unorm),
_ => {
panic!("format {:?}", format);
}
};
format::Format(sf, cf)
}
pub fn extent2d_from_hal(extent: window::Extent2d) -> VkExtent2D { pub fn extent2d_from_hal(extent: window::Extent2d) -> VkExtent2D {
VkExtent2D { VkExtent2D {
width: extent.width, width: extent.width,

View file

@ -498,12 +498,9 @@ pub struct VkBuffer_T {
_unused: [u8; 0], _unused: [u8; 0],
} }
pub type VkBuffer = *mut VkBuffer_T; pub type VkBuffer = *mut VkBuffer_T;
#[repr(C)]
#[derive(Debug, Copy, Clone)] pub type VkImage = Handle<<B as hal::Backend>::Image>;
pub struct VkImage_T {
_unused: [u8; 0],
}
pub type VkImage = *mut VkImage_T;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct VkEvent_T { pub struct VkEvent_T {
@ -5416,12 +5413,11 @@ pub extern fn vkGetPhysicalDeviceSurfacePresentModesKHR(
VkResult::VK_SUCCESS VkResult::VK_SUCCESS
} }
#[repr(C)] pub struct Swapchain {
#[derive(Debug, Copy, Clone)] raw: <B as hal::Backend>::Swapchain,
pub struct VkSwapchainKHR_T { images: Vec<VkImage>,
_unused: [u8; 0],
} }
pub type VkSwapchainKHR = *mut VkSwapchainKHR_T; pub type VkSwapchainKHR = Handle<Swapchain>;
#[repr(u32)] #[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum VkSwapchainCreateFlagBitsKHR { pub enum VkSwapchainCreateFlagBitsKHR {
@ -5502,22 +5498,87 @@ pub type PFN_vkQueuePresentKHR =
pPresentInfo: pPresentInfo:
*const VkPresentInfoKHR) *const VkPresentInfoKHR)
-> VkResult>; -> VkResult>;
extern "C" { #[no_mangle]
pub fn vkCreateSwapchainKHR(device: VkDevice, pub extern fn vkCreateSwapchainKHR(
gpu: VkDevice,
pCreateInfo: *const VkSwapchainCreateInfoKHR, pCreateInfo: *const VkSwapchainCreateInfoKHR,
_pAllocator: *const VkAllocationCallbacks,
pSwapchain: *mut VkSwapchainKHR,
) -> VkResult {
let info = unsafe { &*pCreateInfo };
// TODO: more checks
assert_eq!(info.clipped, VK_TRUE); // TODO
assert_eq!(info.imageSharingMode, VkSharingMode::VK_SHARING_MODE_EXCLUSIVE); // TODO
let config = hal::SwapchainConfig {
color_format: conv::hal_from_format(info.imageFormat),
depth_stencil_format: None,
image_count: info.minImageCount,
};
let (swapchain, backbuffers) = gpu.device.create_swapchain(&mut info.surface.clone(), config);
let images = match backbuffers {
hal::Backbuffer::Images(images) => {
images.into_iter().map(|image| Handle::new(image)).collect()
},
hal::Backbuffer::Framebuffer(_) => {
panic!("Expected backbuffer images. Backends returning only framebuffers are not supported!")
},
};
let swapchain = Swapchain {
raw: swapchain,
images,
};
unsafe { *pSwapchain = Handle::new(swapchain) };
VkResult::VK_SUCCESS
}
#[no_mangle]
pub extern fn vkDestroySwapchainKHR(
device: VkDevice,
mut swapchain: VkSwapchainKHR,
pAllocator: *const VkAllocationCallbacks, pAllocator: *const VkAllocationCallbacks,
pSwapchain: *mut VkSwapchainKHR) -> VkResult; ) {
for image in &mut swapchain.images {
let _ = image.unwrap();
}
let _ = swapchain.unwrap();
} }
extern "C" { #[no_mangle]
pub fn vkDestroySwapchainKHR(device: VkDevice, swapchain: VkSwapchainKHR, pub extern fn vkGetSwapchainImagesKHR(
pAllocator: *const VkAllocationCallbacks); device: VkDevice,
}
extern "C" {
pub fn vkGetSwapchainImagesKHR(device: VkDevice,
swapchain: VkSwapchainKHR, swapchain: VkSwapchainKHR,
pSwapchainImageCount: *mut u32, pSwapchainImageCount: *mut u32,
pSwapchainImages: *mut VkImage) pSwapchainImages: *mut VkImage,
-> VkResult; ) -> VkResult {
debug_assert!(!pSwapchainImageCount.is_null());
let swapchain_image_count = unsafe { *pSwapchainImageCount };
let available_images = swapchain.images.len();
if pSwapchainImages.is_null() {
// If NULL the number of presentable images is returned.
unsafe { *pSwapchainImageCount = swapchain.images.len() as _; }
} else {
let num_images = available_images.min(swapchain_image_count as _);
let swapchain_images = unsafe {
slice::from_raw_parts_mut(pSwapchainImages, num_images)
};
for i in 0..num_images as _ {
swapchain_images[i] = swapchain.images[i];
}
// Overwrite pSwapchainImageCount with actual image count
unsafe { *pSwapchainImageCount = num_images as _; }
if num_images < available_images {
return VkResult::VK_INCOMPLETE;
}
}
VkResult::VK_SUCCESS
} }
extern "C" { extern "C" {
pub fn vkAcquireNextImageKHR(device: VkDevice, swapchain: VkSwapchainKHR, pub fn vkAcquireNextImageKHR(device: VkDevice, swapchain: VkSwapchainKHR,
@ -5797,7 +5858,7 @@ impl Clone for VkWin32SurfaceCreateInfoKHR {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self { *self }
} }
#[no_mangle] #[no_mangle]
pub fn vkCreateWin32SurfaceKHR( pub extern fn vkCreateWin32SurfaceKHR(
instance: VkInstance, instance: VkInstance,
pCreateInfos: *const VkWin32SurfaceCreateInfoKHR, pCreateInfos: *const VkWin32SurfaceCreateInfoKHR,
pAllocator: *const VkAllocationCallbacks, pAllocator: *const VkAllocationCallbacks,
@ -5809,7 +5870,12 @@ pub fn vkCreateWin32SurfaceKHR(
assert_eq!((*pCreateInfos).flags, 0); assert_eq!((*pCreateInfos).flags, 0);
assert!(pAllocator.is_null()); assert!(pAllocator.is_null());
// TODO: handle HINSTANCE // TODO: handle HINSTANCE
*pSurface = Handle::new(instance.create_surface_from_hwnd((*pCreateInfos).hwnd)); *pSurface = Handle::new(
instance.create_surface_from_hwnd(
(*pCreateInfos).hinstance,
(*pCreateInfos).hwnd,
)
);
VkResult::VK_SUCCESS VkResult::VK_SUCCESS
} }
} }