add first part of xcb swapchain creation; memory bug somewhere
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 4 Oct 2018 04:43:29 +0000 (21:43 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 4 Oct 2018 04:43:29 +0000 (21:43 -0700)
vulkan-driver/Cargo.toml
vulkan-driver/src/api_impl.rs
vulkan-driver/src/handle.rs
vulkan-driver/src/image.rs [new file with mode: 0644]
vulkan-driver/src/lib.rs
vulkan-driver/src/shm.rs [new file with mode: 0644]
vulkan-driver/src/swapchain.rs [new file with mode: 0644]
vulkan-driver/src/xcb_swapchain.rs [new file with mode: 0644]
vulkan-driver/vulkan-wrapper.h

index 8fc0efa5b6c8a97c394176ad1103002333a8ed7d..5bd3d44a1c1a829a0c19431fbe4f927b2e0a07e7 100644 (file)
@@ -16,7 +16,9 @@ uuid = {version = "0.7", features = ["v5"]}
 sys-info = "0.5"
 
 [target.'cfg(unix)'.dependencies]
-xcb = "0.8"
+xcb = {version = "0.8", features = ["shm"]}
+libc = "0.2"
+errno = "0.2"
 
 [build-dependencies]
 bindgen = "0.40"
index f71d19124ad8fa4d2f43231e35a41dbe09bb0778..aedd75411a125b120a6c6323bc1e83daac4d646a 100644 (file)
@@ -13,8 +13,10 @@ use std::ops::*;
 use std::os::raw::c_char;
 use std::ptr::null;
 use std::ptr::null_mut;
+use std::ptr::NonNull;
 use std::slice;
 use std::str::FromStr;
+use swapchain::{SurfaceImplementation, SurfacePlatform, Swapchain};
 use sys_info;
 use uuid;
 #[cfg(unix)]
@@ -117,6 +119,7 @@ fn is_supported_structure_type(v: api::VkStructureType) -> bool {
         | api::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES
         | api::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2
         | api::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES
+        | api::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR
         | api::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES
         | api::VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO
         | api::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO
@@ -148,6 +151,7 @@ fn is_supported_structure_type(v: api::VkStructureType) -> bool {
         | api::VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2
         | api::VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2
         | api::VK_STRUCTURE_TYPE_SUBMIT_INFO
+        | api::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR
         | api::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
         | api::VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET => true,
         _ => false,
@@ -3365,7 +3369,9 @@ pub unsafe extern "system" fn vkDestroyInstance(
     instance: api::VkInstance,
     _allocator: *const api::VkAllocationCallbacks,
 ) {
-    OwnedHandle::from(instance);
+    if !instance.is_null() {
+        OwnedHandle::from(instance);
+    }
 }
 
 #[allow(non_snake_case)]
@@ -3531,7 +3537,9 @@ pub unsafe extern "system" fn vkDestroyDevice(
     device: api::VkDevice,
     _allocator: *const api::VkAllocationCallbacks,
 ) {
-    OwnedHandle::from(device);
+    if !device.is_null() {
+        OwnedHandle::from(device);
+    }
 }
 
 unsafe fn enumerate_extension_properties(
@@ -5142,10 +5150,42 @@ pub unsafe extern "system" fn vkGetDescriptorSetLayoutSupport(
 #[allow(non_snake_case)]
 pub unsafe extern "system" fn vkDestroySurfaceKHR(
     _instance: api::VkInstance,
-    _surface: api::VkSurfaceKHR,
-    _pAllocator: *const api::VkAllocationCallbacks,
+    surface: api::VkSurfaceKHR,
+    _allocator: *const api::VkAllocationCallbacks,
 ) {
-    unimplemented!()
+    if !surface.is_null() {
+        let surface = SharedHandle::from(surface);
+        match surface.platform {
+            api::VK_ICD_WSI_PLATFORM_MIR => {
+                panic!("unimplemented platform: VK_ICD_WSI_PLATFORM_MIR")
+            }
+            api::VK_ICD_WSI_PLATFORM_WAYLAND => {
+                panic!("unimplemented platform: VK_ICD_WSI_PLATFORM_WAYLAND")
+            }
+            api::VK_ICD_WSI_PLATFORM_WIN32 => {
+                panic!("unimplemented platform: VK_ICD_WSI_PLATFORM_WIN32")
+            }
+            api::VK_ICD_WSI_PLATFORM_XCB => {
+                Box::from_raw(surface.take().get().unwrap().as_ptr() as *mut api::VkIcdSurfaceXcb);
+            }
+            api::VK_ICD_WSI_PLATFORM_XLIB => {
+                panic!("unimplemented platform: VK_ICD_WSI_PLATFORM_XLIB")
+            }
+            api::VK_ICD_WSI_PLATFORM_ANDROID => {
+                panic!("unimplemented platform: VK_ICD_WSI_PLATFORM_ANDROID")
+            }
+            api::VK_ICD_WSI_PLATFORM_MACOS => {
+                panic!("unimplemented platform: VK_ICD_WSI_PLATFORM_MACOS")
+            }
+            api::VK_ICD_WSI_PLATFORM_IOS => {
+                panic!("unimplemented platform: VK_ICD_WSI_PLATFORM_IOS")
+            }
+            api::VK_ICD_WSI_PLATFORM_DISPLAY => {
+                panic!("unimplemented platform: VK_ICD_WSI_PLATFORM_DISPLAY")
+            }
+            platform => panic!("unknown VkSurfaceKHR platform: {:?}", platform),
+        }
+    }
 }
 
 #[allow(non_snake_case)]
@@ -5160,50 +5200,117 @@ pub unsafe extern "system" fn vkGetPhysicalDeviceSurfaceSupportKHR(
 
 #[allow(non_snake_case)]
 pub unsafe extern "system" fn vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
-    _physicalDevice: api::VkPhysicalDevice,
-    _surface: api::VkSurfaceKHR,
-    _pSurfaceCapabilities: *mut api::VkSurfaceCapabilitiesKHR,
+    physical_device: api::VkPhysicalDevice,
+    surface: api::VkSurfaceKHR,
+    surface_capabilities: *mut api::VkSurfaceCapabilitiesKHR,
 ) -> api::VkResult {
-    unimplemented!()
+    let mut surface_capabilities_2 = api::VkSurfaceCapabilities2KHR {
+        sType: api::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
+        pNext: null_mut(),
+        surfaceCapabilities: mem::zeroed(),
+    };
+    match vkGetPhysicalDeviceSurfaceCapabilities2KHR(
+        physical_device,
+        &api::VkPhysicalDeviceSurfaceInfo2KHR {
+            sType: api::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
+            pNext: null(),
+            surface: surface,
+        },
+        &mut surface_capabilities_2,
+    ) {
+        api::VK_SUCCESS => {
+            *surface_capabilities = surface_capabilities_2.surfaceCapabilities;
+            api::VK_SUCCESS
+        }
+        error => error,
+    }
 }
 
 #[allow(non_snake_case)]
 pub unsafe extern "system" fn vkGetPhysicalDeviceSurfaceFormatsKHR(
-    _physicalDevice: api::VkPhysicalDevice,
-    _surface: api::VkSurfaceKHR,
-    _pSurfaceFormatCount: *mut u32,
-    _pSurfaceFormats: *mut api::VkSurfaceFormatKHR,
+    _physical_device: api::VkPhysicalDevice,
+    surface: api::VkSurfaceKHR,
+    surface_format_count: *mut u32,
+    surface_formats: *mut api::VkSurfaceFormatKHR,
 ) -> api::VkResult {
-    unimplemented!()
+    let surface_implementation = SurfacePlatform::from(SharedHandle::from(surface).platform)
+        .unwrap()
+        .get_surface_implementation();
+    let returned_surface_formats = match surface_implementation.get_surface_formats(surface) {
+        Ok(returned_surface_formats) => returned_surface_formats,
+        Err(result) => return result,
+    };
+    enumerate_helper(
+        surface_format_count,
+        surface_formats,
+        returned_surface_formats.iter(),
+        |a, b| *a = *b,
+    )
 }
 
 #[allow(non_snake_case)]
 pub unsafe extern "system" fn vkGetPhysicalDeviceSurfacePresentModesKHR(
-    _physicalDevice: api::VkPhysicalDevice,
-    _surface: api::VkSurfaceKHR,
-    _pPresentModeCount: *mut u32,
-    _pPresentModes: *mut api::VkPresentModeKHR,
+    _physical_device: api::VkPhysicalDevice,
+    surface: api::VkSurfaceKHR,
+    present_mode_count: *mut u32,
+    present_modes: *mut api::VkPresentModeKHR,
 ) -> api::VkResult {
-    unimplemented!()
+    let surface_implementation = SurfacePlatform::from(SharedHandle::from(surface).platform)
+        .unwrap()
+        .get_surface_implementation();
+    let returned_present_modes = match surface_implementation.get_present_modes(surface) {
+        Ok(returned_present_modes) => returned_present_modes,
+        Err(result) => return result,
+    };
+    enumerate_helper(
+        present_mode_count,
+        present_modes,
+        returned_present_modes.iter(),
+        |a, b| *a = *b,
+    )
 }
 
 #[allow(non_snake_case)]
 pub unsafe extern "system" fn vkCreateSwapchainKHR(
-    _device: api::VkDevice,
-    _pCreateInfo: *const api::VkSwapchainCreateInfoKHR,
-    _pAllocator: *const api::VkAllocationCallbacks,
-    _pSwapchain: *mut api::VkSwapchainKHR,
+    device: api::VkDevice,
+    create_info: *const api::VkSwapchainCreateInfoKHR,
+    _allocator: *const api::VkAllocationCallbacks,
+    swapchain: *mut api::VkSwapchainKHR,
 ) -> api::VkResult {
-    unimplemented!()
+    parse_next_chain_const!{
+        create_info,
+        root = api::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+        device_group_swapchain_create_info: api::VkDeviceGroupSwapchainCreateInfoKHR = api::VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR,
+    }
+    let ref create_info = *create_info;
+    let device_group_swapchain_create_info = if device_group_swapchain_create_info.is_null() {
+        None
+    } else {
+        Some(&*device_group_swapchain_create_info)
+    };
+    *swapchain = Handle::null();
+    let platform = SurfacePlatform::from(SharedHandle::from(create_info.surface).platform).unwrap();
+    match platform
+        .get_surface_implementation()
+        .build(create_info, device_group_swapchain_create_info)
+    {
+        Ok(new_swapchain) => {
+            *swapchain = OwnedHandle::<api::VkSwapchainKHR>::new(new_swapchain).take();
+            api::VK_SUCCESS
+        }
+        Err(error) => error,
+    }
 }
 
 #[allow(non_snake_case)]
 pub unsafe extern "system" fn vkDestroySwapchainKHR(
     _device: api::VkDevice,
-    _swapchain: api::VkSwapchainKHR,
-    _pAllocator: *const api::VkAllocationCallbacks,
+    swapchain: api::VkSwapchainKHR,
+    _allocator: *const api::VkAllocationCallbacks,
 ) {
-    unimplemented!()
+    if !swapchain.is_null() {
+        OwnedHandle::from(swapchain);
+    }
 }
 
 #[allow(non_snake_case)]
@@ -5474,11 +5581,31 @@ pub unsafe extern "system" fn vkGetFenceFdKHR(
 
 #[allow(non_snake_case)]
 pub unsafe extern "system" fn vkGetPhysicalDeviceSurfaceCapabilities2KHR(
-    _physicalDevice: api::VkPhysicalDevice,
-    _pSurfaceInfo: *const api::VkPhysicalDeviceSurfaceInfo2KHR,
-    _pSurfaceCapabilities: *mut api::VkSurfaceCapabilities2KHR,
+    _physical_device: api::VkPhysicalDevice,
+    surface_info: *const api::VkPhysicalDeviceSurfaceInfo2KHR,
+    surface_capabilities: *mut api::VkSurfaceCapabilities2KHR,
 ) -> api::VkResult {
-    unimplemented!()
+    parse_next_chain_const!{
+        surface_info,
+        root = api::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
+    }
+    let ref surface_info = *surface_info;
+    parse_next_chain_mut!{
+        surface_capabilities,
+        root = api::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
+    }
+    let ref mut surface_capabilities = *surface_capabilities;
+    let surface_implementation =
+        SurfacePlatform::from(SharedHandle::from(surface_info.surface).platform)
+            .unwrap()
+            .get_surface_implementation();
+    match surface_implementation.get_capabilities(surface_info.surface) {
+        Ok(capabilities) => {
+            surface_capabilities.surfaceCapabilities = capabilities;
+            api::VK_SUCCESS
+        }
+        Err(result) => result,
+    }
 }
 
 #[allow(non_snake_case)]
@@ -6054,11 +6181,26 @@ pub unsafe extern "system" fn vkGetQueueCheckpointDataNV(
 #[allow(non_snake_case)]
 pub unsafe extern "system" fn vkCreateXcbSurfaceKHR(
     _instance: api::VkInstance,
-    _pCreateInfo: *const api::VkXcbSurfaceCreateInfoKHR,
-    _pAllocator: *const api::VkAllocationCallbacks,
-    _pSurface: *mut api::VkSurfaceKHR,
+    create_info: *const api::VkXcbSurfaceCreateInfoKHR,
+    _allocator: *const api::VkAllocationCallbacks,
+    surface: *mut api::VkSurfaceKHR,
 ) -> api::VkResult {
-    unimplemented!()
+    parse_next_chain_const!{
+        create_info,
+        root = api::VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
+    }
+    let ref create_info = *create_info;
+    let new_surface = Box::new(api::VkIcdSurfaceXcb {
+        base: api::VkIcdSurfaceBase {
+            platform: api::VK_ICD_WSI_PLATFORM_XCB,
+        },
+        connection: create_info.connection,
+        window: create_info.window,
+    });
+    *surface = api::VkSurfaceKHR::new(NonNull::new(
+        Box::into_raw(new_surface) as *mut api::VkIcdSurfaceBase
+    ));
+    api::VK_SUCCESS
 }
 
 #[cfg(unix)]
index 559aa58a2a31a9286530f3a4922b86efd26d978d..9db1077bd1db7068cc323800f1acba9c648abcec 100644 (file)
@@ -9,6 +9,7 @@ use std::ops::Deref;
 use std::ops::DerefMut;
 use std::ptr::null_mut;
 use std::ptr::NonNull;
+use swapchain::Swapchain;
 
 #[repr(C)]
 pub struct DispatchableType<T> {
@@ -16,8 +17,6 @@ pub struct DispatchableType<T> {
     value: T,
 }
 
-impl<T> DispatchableType<T> {}
-
 impl<T> From<T> for DispatchableType<T> {
     fn from(v: T) -> Self {
         Self {
@@ -40,10 +39,7 @@ impl<T> DerefMut for DispatchableType<T> {
     }
 }
 
-pub trait Handle: Copy + Eq + fmt::Debug {
-    type Value;
-    fn get(&self) -> Option<NonNull<Self::Value>>;
-    fn new(v: Option<NonNull<Self::Value>>) -> Self;
+pub trait HandleAllocFree: Handle {
     unsafe fn allocate<T: Into<Self::Value>>(v: T) -> Self {
         Self::new(Some(NonNull::new_unchecked(Box::into_raw(Box::new(
             v.into(),
@@ -52,6 +48,12 @@ pub trait Handle: Copy + Eq + fmt::Debug {
     unsafe fn free(self) {
         Box::from_raw(self.get().unwrap().as_ptr());
     }
+}
+
+pub trait Handle: Copy + Eq + fmt::Debug {
+    type Value;
+    fn get(&self) -> Option<NonNull<Self::Value>>;
+    fn new(v: Option<NonNull<Self::Value>>) -> Self;
     fn null() -> Self {
         Self::new(None)
     }
@@ -87,7 +89,12 @@ impl<T> PartialEq for DispatchableHandle<T> {
 impl<T> fmt::Debug for DispatchableHandle<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("DispatchableHandle")
-            .field(&self.get().map(|v| v.as_ptr()).unwrap_or(null_mut()))
+            .field(
+                &self
+                    .get()
+                    .map(|v| v.as_ptr())
+                    .unwrap_or(null_mut::<*mut ()>() as *mut _),
+            )
             .finish()
     }
 }
@@ -143,9 +150,9 @@ impl<T> Handle for NondispatchableHandle<T> {
 }
 
 #[repr(transparent)]
-pub struct OwnedHandle<T: Handle>(T);
+pub struct OwnedHandle<T: HandleAllocFree>(T);
 
-impl<T: Handle> OwnedHandle<T> {
+impl<T: HandleAllocFree> OwnedHandle<T> {
     pub fn new<I: Into<T::Value>>(v: I) -> Self {
         unsafe { OwnedHandle(T::allocate(v)) }
     }
@@ -160,20 +167,20 @@ impl<T: Handle> OwnedHandle<T> {
     }
 }
 
-impl<T: Handle> Deref for OwnedHandle<T> {
+impl<T: HandleAllocFree> Deref for OwnedHandle<T> {
     type Target = T::Value;
     fn deref(&self) -> &T::Value {
         unsafe { &*self.0.get().unwrap().as_ptr() }
     }
 }
 
-impl<T: Handle> DerefMut for OwnedHandle<T> {
+impl<T: HandleAllocFree> DerefMut for OwnedHandle<T> {
     fn deref_mut(&mut self) -> &mut T::Value {
         unsafe { &mut *self.0.get().unwrap().as_ptr() }
     }
 }
 
-impl<T: Handle> Drop for OwnedHandle<T> {
+impl<T: HandleAllocFree> Drop for OwnedHandle<T> {
     fn drop(&mut self) {
         if !self.0.is_null() {
             unsafe {
@@ -183,7 +190,7 @@ impl<T: Handle> Drop for OwnedHandle<T> {
     }
 }
 
-impl<T: Handle> fmt::Debug for OwnedHandle<T>
+impl<T: HandleAllocFree> fmt::Debug for OwnedHandle<T>
 where
     T::Value: fmt::Debug,
 {
@@ -227,128 +234,192 @@ where
 
 pub type VkInstance = DispatchableHandle<Instance>;
 
+impl HandleAllocFree for VkInstance {}
+
 pub type VkPhysicalDevice = DispatchableHandle<PhysicalDevice>;
 
+impl HandleAllocFree for VkPhysicalDevice {}
+
 pub type VkDevice = DispatchableHandle<Device>;
 
+impl HandleAllocFree for VkDevice {}
+
 pub type VkQueue = DispatchableHandle<Queue>;
 
+impl HandleAllocFree for VkQueue {}
+
 pub struct CommandBuffer {}
 
 pub type VkCommandBuffer = DispatchableHandle<CommandBuffer>;
 
+impl HandleAllocFree for VkCommandBuffer {}
+
 pub struct Semaphore {}
 
 pub type VkSemaphore = NondispatchableHandle<Semaphore>;
 
+impl HandleAllocFree for VkSemaphore {}
+
 pub struct Fence {}
 
 pub type VkFence = NondispatchableHandle<Fence>;
 
+impl HandleAllocFree for VkFence {}
+
 pub struct DeviceMemory {}
 
 pub type VkDeviceMemory = NondispatchableHandle<DeviceMemory>;
 
+impl HandleAllocFree for VkDeviceMemory {}
+
 pub struct Buffer {}
 
 pub type VkBuffer = NondispatchableHandle<Buffer>;
 
+impl HandleAllocFree for VkBuffer {}
+
 pub struct Image {}
 
 pub type VkImage = NondispatchableHandle<Image>;
 
+impl HandleAllocFree for VkImage {}
+
 pub struct Event {}
 
 pub type VkEvent = NondispatchableHandle<Event>;
 
+impl HandleAllocFree for VkEvent {}
+
 pub struct QueryPool {}
 
 pub type VkQueryPool = NondispatchableHandle<QueryPool>;
 
+impl HandleAllocFree for VkQueryPool {}
+
 pub struct BufferView {}
 
 pub type VkBufferView = NondispatchableHandle<BufferView>;
 
+impl HandleAllocFree for VkBufferView {}
+
 pub struct ImageView {}
 
 pub type VkImageView = NondispatchableHandle<ImageView>;
 
+impl HandleAllocFree for VkImageView {}
+
 pub struct ShaderModule {}
 
 pub type VkShaderModule = NondispatchableHandle<ShaderModule>;
 
+impl HandleAllocFree for VkShaderModule {}
+
 pub struct PipelineCache {}
 
 pub type VkPipelineCache = NondispatchableHandle<PipelineCache>;
 
+impl HandleAllocFree for VkPipelineCache {}
+
 pub struct PipelineLayout {}
 
 pub type VkPipelineLayout = NondispatchableHandle<PipelineLayout>;
 
+impl HandleAllocFree for VkPipelineLayout {}
+
 pub struct RenderPass {}
 
 pub type VkRenderPass = NondispatchableHandle<RenderPass>;
 
+impl HandleAllocFree for VkRenderPass {}
+
 pub struct Pipeline {}
 
 pub type VkPipeline = NondispatchableHandle<Pipeline>;
 
+impl HandleAllocFree for VkPipeline {}
+
 pub struct DescriptorSetLayout {}
 
 pub type VkDescriptorSetLayout = NondispatchableHandle<DescriptorSetLayout>;
 
+impl HandleAllocFree for VkDescriptorSetLayout {}
+
 pub struct Sampler {}
 
 pub type VkSampler = NondispatchableHandle<Sampler>;
 
+impl HandleAllocFree for VkSampler {}
+
 pub struct DescriptorPool {}
 
 pub type VkDescriptorPool = NondispatchableHandle<DescriptorPool>;
 
+impl HandleAllocFree for VkDescriptorPool {}
+
 pub struct DescriptorSet {}
 
 pub type VkDescriptorSet = NondispatchableHandle<DescriptorSet>;
 
+impl HandleAllocFree for VkDescriptorSet {}
+
 pub struct Framebuffer {}
 
 pub type VkFramebuffer = NondispatchableHandle<Framebuffer>;
 
+impl HandleAllocFree for VkFramebuffer {}
+
 pub struct CommandPool {}
 
 pub type VkCommandPool = NondispatchableHandle<CommandPool>;
 
+impl HandleAllocFree for VkCommandPool {}
+
 pub struct SamplerYcbcrConversion {}
 
 pub type VkSamplerYcbcrConversion = NondispatchableHandle<SamplerYcbcrConversion>;
 
+impl HandleAllocFree for VkSamplerYcbcrConversion {}
+
 pub struct DescriptorUpdateTemplate {}
 
 pub type VkDescriptorUpdateTemplate = NondispatchableHandle<DescriptorUpdateTemplate>;
 
-pub struct SurfaceKHR {}
+impl HandleAllocFree for VkDescriptorUpdateTemplate {}
+
+pub type VkSurfaceKHR = NondispatchableHandle<api::VkIcdSurfaceBase>;
 
-pub type VkSurfaceKHR = NondispatchableHandle<SurfaceKHR>;
+// HandleAllocFree specifically not implemented for VkSurfaceKHR
 
-pub struct SwapchainKHR {}
+pub type VkSwapchainKHR = NondispatchableHandle<Box<Swapchain>>;
 
-pub type VkSwapchainKHR = NondispatchableHandle<SwapchainKHR>;
+impl HandleAllocFree for VkSwapchainKHR {}
 
 pub struct DisplayKHR {}
 
 pub type VkDisplayKHR = NondispatchableHandle<DisplayKHR>;
 
+impl HandleAllocFree for VkDisplayKHR {}
+
 pub struct DisplayModeKHR {}
 
 pub type VkDisplayModeKHR = NondispatchableHandle<DisplayModeKHR>;
 
+impl HandleAllocFree for VkDisplayModeKHR {}
+
 pub struct DebugReportCallbackEXT {}
 
 pub type VkDebugReportCallbackEXT = NondispatchableHandle<DebugReportCallbackEXT>;
 
+impl HandleAllocFree for VkDebugReportCallbackEXT {}
+
 pub struct DebugUtilsMessengerEXT {}
 
 pub type VkDebugUtilsMessengerEXT = NondispatchableHandle<DebugUtilsMessengerEXT>;
 
+impl HandleAllocFree for VkDebugUtilsMessengerEXT {}
+
 pub struct ValidationCacheEXT {}
 
 pub type VkValidationCacheEXT = NondispatchableHandle<ValidationCacheEXT>;
+
+impl HandleAllocFree for VkValidationCacheEXT {}
diff --git a/vulkan-driver/src/image.rs b/vulkan-driver/src/image.rs
new file mode 100644 (file)
index 0000000..21c31ae
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// Copyright 2018 Jacob Lifshay
+use api;
+
+pub enum SupportedTilings {
+    Any,
+    LinearOnly,
+}
+
+pub struct ImageDescriptor {
+    pub supported_tilings: SupportedTilings,
+    pub format: api::VkFormat,
+    pub extents: api::VkExtent3D,
+    pub mip_levels: u32,
+}
index fa00c49dc77ad9377340d7a88e2cd368c9b8db8e..91068b6803389ee2825b4e21e97220286c978f3d 100644 (file)
@@ -2,6 +2,10 @@
 // Copyright 2018 Jacob Lifshay
 #[macro_use]
 extern crate enum_map;
+#[cfg(unix)]
+extern crate errno;
+#[cfg(unix)]
+extern crate libc;
 extern crate sys_info;
 extern crate uuid;
 #[cfg(unix)]
@@ -9,6 +13,12 @@ extern crate xcb;
 mod api;
 mod api_impl;
 mod handle;
+mod image;
+#[cfg(unix)]
+mod shm;
+mod swapchain;
+#[cfg(unix)]
+mod xcb_swapchain;
 use std::ffi::CStr;
 use std::os::raw::c_char;
 
diff --git a/vulkan-driver/src/shm.rs b/vulkan-driver/src/shm.rs
new file mode 100644 (file)
index 0000000..3aeb070
--- /dev/null
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// Copyright 2018 Jacob Lifshay
+use errno;
+use libc;
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::ops::DerefMut;
+use std::os::raw::c_int;
+use std::ptr::null_mut;
+use std::slice;
+
+#[derive(Debug)]
+pub struct SharedMemorySegment {
+    id: c_int,
+    size: usize,
+    _phantom_data: PhantomData<*mut u8>,
+}
+
+unsafe impl Send for SharedMemorySegment {}
+unsafe impl Sync for SharedMemorySegment {}
+
+impl SharedMemorySegment {
+    pub unsafe fn new(id: c_int, size: usize) -> Self {
+        assert_ne!(size, 0);
+        assert_ne!(id, -1);
+        SharedMemorySegment {
+            id,
+            size,
+            _phantom_data: PhantomData,
+        }
+    }
+    pub unsafe fn create_with_flags(size: usize, flags: c_int) -> Result<Self, errno::Errno> {
+        match libc::shmget(libc::IPC_PRIVATE, size, flags) {
+            -1 => Err(errno::errno()),
+            id => Ok(Self::new(id, size)),
+        }
+    }
+    pub fn create(size: usize) -> Result<Self, errno::Errno> {
+        unsafe { Self::create_with_flags(size, libc::IPC_CREAT | libc::IPC_EXCL | 0o666) }
+    }
+    pub fn map(&self) -> Result<MappedSharedMemorySegment, errno::Errno> {
+        unsafe {
+            let memory = libc::shmat(self.id, null_mut(), 0);
+            if memory == !0usize as *mut _ {
+                Err(errno::errno())
+            } else {
+                Ok(MappedSharedMemorySegment {
+                    memory: memory as *mut u8,
+                    size: self.size,
+                })
+            }
+        }
+    }
+}
+
+impl Drop for SharedMemorySegment {
+    fn drop(&mut self) {
+        unsafe {
+            libc::shmctl(self.id, libc::IPC_RMID, null_mut());
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct MappedSharedMemorySegment {
+    memory: *mut u8,
+    size: usize,
+}
+
+impl MappedSharedMemorySegment {
+    unsafe fn get(&self) -> *mut [u8] {
+        slice::from_raw_parts_mut(self.memory, self.size)
+    }
+}
+
+unsafe impl Send for MappedSharedMemorySegment {}
+unsafe impl Sync for MappedSharedMemorySegment {}
+
+impl Deref for MappedSharedMemorySegment {
+    type Target = [u8];
+    fn deref(&self) -> &[u8] {
+        unsafe { &*self.get() }
+    }
+}
+
+impl DerefMut for MappedSharedMemorySegment {
+    fn deref_mut(&mut self) -> &mut [u8] {
+        unsafe { &mut *self.get() }
+    }
+}
+
+impl Drop for MappedSharedMemorySegment {
+    fn drop(&mut self) {
+        unsafe {
+            libc::shmdt(self.memory as *const _);
+        }
+    }
+}
diff --git a/vulkan-driver/src/swapchain.rs b/vulkan-driver/src/swapchain.rs
new file mode 100644 (file)
index 0000000..c86647b
--- /dev/null
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// Copyright 2018 Jacob Lifshay
+use api;
+use std::any::Any;
+use std::borrow::Cow;
+use std::error::Error;
+use std::fmt::{self, Debug};
+#[cfg(unix)]
+use xcb_swapchain::XcbSurfaceImplementation;
+
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Enum)]
+#[allow(non_camel_case_types)]
+pub enum SurfacePlatform {
+    VK_ICD_WSI_PLATFORM_MIR,
+    VK_ICD_WSI_PLATFORM_WAYLAND,
+    VK_ICD_WSI_PLATFORM_WIN32,
+    VK_ICD_WSI_PLATFORM_XCB,
+    VK_ICD_WSI_PLATFORM_XLIB,
+    VK_ICD_WSI_PLATFORM_ANDROID,
+    VK_ICD_WSI_PLATFORM_MACOS,
+    VK_ICD_WSI_PLATFORM_IOS,
+    VK_ICD_WSI_PLATFORM_DISPLAY,
+}
+
+#[derive(Debug)]
+pub struct UnknownSurfacePlatform(pub api::VkIcdWsiPlatform);
+
+impl fmt::Display for UnknownSurfacePlatform {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "unknown surface platform {:?}", self.0)
+    }
+}
+
+impl Error for UnknownSurfacePlatform {}
+
+impl SurfacePlatform {
+    pub fn from(platform: api::VkIcdWsiPlatform) -> Result<Self, UnknownSurfacePlatform> {
+        match platform {
+            api::VK_ICD_WSI_PLATFORM_MIR => Ok(SurfacePlatform::VK_ICD_WSI_PLATFORM_MIR),
+            api::VK_ICD_WSI_PLATFORM_WAYLAND => Ok(SurfacePlatform::VK_ICD_WSI_PLATFORM_WAYLAND),
+            api::VK_ICD_WSI_PLATFORM_WIN32 => Ok(SurfacePlatform::VK_ICD_WSI_PLATFORM_WIN32),
+            api::VK_ICD_WSI_PLATFORM_XCB => Ok(SurfacePlatform::VK_ICD_WSI_PLATFORM_XCB),
+            api::VK_ICD_WSI_PLATFORM_XLIB => Ok(SurfacePlatform::VK_ICD_WSI_PLATFORM_XLIB),
+            api::VK_ICD_WSI_PLATFORM_ANDROID => Ok(SurfacePlatform::VK_ICD_WSI_PLATFORM_ANDROID),
+            api::VK_ICD_WSI_PLATFORM_MACOS => Ok(SurfacePlatform::VK_ICD_WSI_PLATFORM_MACOS),
+            api::VK_ICD_WSI_PLATFORM_IOS => Ok(SurfacePlatform::VK_ICD_WSI_PLATFORM_IOS),
+            api::VK_ICD_WSI_PLATFORM_DISPLAY => Ok(SurfacePlatform::VK_ICD_WSI_PLATFORM_DISPLAY),
+            platform => Err(UnknownSurfacePlatform(platform)),
+        }
+    }
+    pub fn get_surface_implementation(self) -> Cow<'static, dyn SurfaceImplementation> {
+        #[cfg(unix)]
+        const XCB_SURFACE_IMPLEMENTATION: XcbSurfaceImplementation = XcbSurfaceImplementation;
+        match self {
+            #[cfg(unix)]
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_XCB => Cow::Borrowed(&XCB_SURFACE_IMPLEMENTATION),
+            _ => Cow::Owned(FallbackSurfaceImplementation(self).duplicate()),
+        }
+    }
+}
+
+impl From<SurfacePlatform> for api::VkIcdWsiPlatform {
+    fn from(platform: SurfacePlatform) -> api::VkIcdWsiPlatform {
+        match platform {
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_MIR => api::VK_ICD_WSI_PLATFORM_MIR,
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_WAYLAND => api::VK_ICD_WSI_PLATFORM_WAYLAND,
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_WIN32 => api::VK_ICD_WSI_PLATFORM_WIN32,
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_XCB => api::VK_ICD_WSI_PLATFORM_XCB,
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_XLIB => api::VK_ICD_WSI_PLATFORM_XLIB,
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_ANDROID => api::VK_ICD_WSI_PLATFORM_ANDROID,
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_MACOS => api::VK_ICD_WSI_PLATFORM_MACOS,
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_IOS => api::VK_ICD_WSI_PLATFORM_IOS,
+            SurfacePlatform::VK_ICD_WSI_PLATFORM_DISPLAY => api::VK_ICD_WSI_PLATFORM_DISPLAY,
+        }
+    }
+}
+
+pub trait Swapchain: Any + Sync + Send + Debug {}
+
+pub trait SurfaceImplementation: Any + Sync + Send + Debug {
+    fn get_platform(&self) -> SurfacePlatform;
+    unsafe fn get_surface_formats(
+        &self,
+        surface: api::VkSurfaceKHR,
+    ) -> Result<Cow<'static, [api::VkSurfaceFormatKHR]>, api::VkResult>;
+    unsafe fn get_present_modes(
+        &self,
+        surface: api::VkSurfaceKHR,
+    ) -> Result<Cow<'static, [api::VkPresentModeKHR]>, api::VkResult>;
+    unsafe fn get_capabilities(
+        &self,
+        surface: api::VkSurfaceKHR,
+    ) -> Result<api::VkSurfaceCapabilitiesKHR, api::VkResult>;
+    unsafe fn build(
+        &self,
+        create_info: &api::VkSwapchainCreateInfoKHR,
+        device_group_create_info: Option<&api::VkDeviceGroupSwapchainCreateInfoKHR>,
+    ) -> Result<Box<Swapchain>, api::VkResult>;
+    fn duplicate(&self) -> Box<dyn SurfaceImplementation>;
+}
+
+impl ToOwned for dyn SurfaceImplementation {
+    type Owned = Box<dyn SurfaceImplementation>;
+    fn to_owned(&self) -> Box<dyn SurfaceImplementation> {
+        self.duplicate()
+    }
+}
+
+#[derive(Debug)]
+pub struct FallbackSurfaceImplementation(SurfacePlatform);
+
+impl FallbackSurfaceImplementation {
+    pub fn report_error(&self) -> ! {
+        panic!(
+            "there is no surface implementation for {:?}",
+            self.get_platform()
+        )
+    }
+}
+
+impl SurfaceImplementation for FallbackSurfaceImplementation {
+    fn get_platform(&self) -> SurfacePlatform {
+        self.0
+    }
+    unsafe fn get_surface_formats(
+        &self,
+        _surface: api::VkSurfaceKHR,
+    ) -> Result<Cow<'static, [api::VkSurfaceFormatKHR]>, api::VkResult> {
+        self.report_error()
+    }
+    unsafe fn get_present_modes(
+        &self,
+        surface: api::VkSurfaceKHR,
+    ) -> Result<Cow<'static, [api::VkPresentModeKHR]>, api::VkResult> {
+        self.report_error()
+    }
+    unsafe fn get_capabilities(
+        &self,
+        surface: api::VkSurfaceKHR,
+    ) -> Result<api::VkSurfaceCapabilitiesKHR, api::VkResult> {
+        self.report_error()
+    }
+    unsafe fn build(
+        &self,
+        _create_info: &api::VkSwapchainCreateInfoKHR,
+        _device_group_create_info: Option<&api::VkDeviceGroupSwapchainCreateInfoKHR>,
+    ) -> Result<Box<Swapchain>, api::VkResult> {
+        self.report_error()
+    }
+    fn duplicate(&self) -> Box<dyn SurfaceImplementation> {
+        Box::new(FallbackSurfaceImplementation(self.0))
+    }
+}
diff --git a/vulkan-driver/src/xcb_swapchain.rs b/vulkan-driver/src/xcb_swapchain.rs
new file mode 100644 (file)
index 0000000..8fdff80
--- /dev/null
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// Copyright 2018 Jacob Lifshay
+use api;
+use handle::Handle;
+use image::{ImageDescriptor, SupportedTilings};
+use libc;
+use std::borrow::Cow;
+use std::mem;
+use std::ops::{Deref, DerefMut};
+use std::os::raw::c_char;
+use std::ptr::null_mut;
+use std::ptr::NonNull;
+use swapchain::{SurfaceImplementation, SurfacePlatform, Swapchain};
+use xcb;
+
+#[derive(Debug)]
+pub struct XcbSwapchain {}
+
+impl Swapchain for XcbSwapchain {}
+
+struct ReplyObject<T>(NonNull<T>);
+
+impl<T> ReplyObject<T> {
+    unsafe fn from(v: *mut T) -> Option<Self> {
+        NonNull::new(v).map(ReplyObject)
+    }
+}
+
+impl<T> Deref for ReplyObject<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        unsafe { self.0.as_ref() }
+    }
+}
+
+impl<T> DerefMut for ReplyObject<T> {
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe { self.0.as_mut() }
+    }
+}
+
+impl<T> Drop for ReplyObject<T> {
+    fn drop(&mut self) {
+        unsafe {
+            libc::free(self.0.as_ptr() as *mut libc::c_void);
+        }
+    }
+}
+
+struct ServerObject<Id: 'static + Copy> {
+    id: Id,
+    connection: *mut xcb::ffi::xcb_connection_t,
+    free_fn: unsafe extern "C" fn(connection: *mut xcb::ffi::xcb_connection_t, id: Id)
+        -> xcb::ffi::xcb_void_cookie_t,
+}
+
+impl<Id: 'static + Copy> ServerObject<Id> {
+    fn get(&self) -> Id {
+        self.id
+    }
+}
+
+impl<Id: 'static + Copy> Drop for ServerObject<Id> {
+    fn drop(&mut self) {
+        unsafe {
+            (self.free_fn)(self.connection, self.id);
+        }
+    }
+}
+
+type Gc = ServerObject<xcb::ffi::xcb_gcontext_t>;
+
+unsafe fn create_gc(
+    id: xcb::ffi::xcb_gcontext_t,
+    connection: *mut xcb::ffi::xcb_connection_t,
+) -> Gc {
+    ServerObject {
+        id,
+        connection,
+        free_fn: xcb::ffi::xcb_free_gc,
+    }
+}
+
+type Pixmap = ServerObject<xcb::ffi::xcb_pixmap_t>;
+
+unsafe fn create_pixmap(
+    id: xcb::ffi::xcb_pixmap_t,
+    connection: *mut xcb::ffi::xcb_connection_t,
+) -> Pixmap {
+    ServerObject {
+        id,
+        connection,
+        free_fn: xcb::ffi::xcb_free_pixmap,
+    }
+}
+
+type ShmSeg = ServerObject<xcb::ffi::shm::xcb_shm_seg_t>;
+
+unsafe fn create_shm_seg(
+    id: xcb::ffi::shm::xcb_shm_seg_t,
+    connection: *mut xcb::ffi::xcb_connection_t,
+) -> ShmSeg {
+    ServerObject {
+        id,
+        connection,
+        free_fn: xcb::ffi::shm::xcb_shm_detach,
+    }
+}
+
+enum SurfaceFormatGroup {
+    B8G8R8A8,
+}
+
+enum SwapchainSetupError {
+    BadSurface,
+    NoSupport,
+}
+
+unsafe fn query_extension(
+    connection: *mut xcb::ffi::xcb_connection_t,
+    extension_name: &str,
+) -> xcb::ffi::xcb_query_extension_cookie_t {
+    let len = extension_name.len() as u16;
+    assert_eq!(len as usize, extension_name.len());
+    xcb::ffi::xcb_query_extension(connection, len, extension_name.as_ptr() as *const c_char)
+}
+
+pub const MAX_SWAPCHAIN_IMAGE_COUNT: u32 = 16;
+
+struct SwapchainSetupFirstStage {
+    gc: Gc,
+    shm_supported: bool,
+    window_depth: u8,
+    surface_format_group: SurfaceFormatGroup,
+    present_modes: &'static [api::VkPresentModeKHR],
+    capabilities: api::VkSurfaceCapabilitiesKHR,
+    shared_present_capabilities: Option<api::VkSharedPresentSurfaceCapabilitiesKHR>,
+    image_pixel_size: usize,
+    scanline_alignment: usize,
+    shm_version: Option<xcb::ffi::shm::xcb_shm_query_version_cookie_t>,
+    image_descriptor: ImageDescriptor,
+}
+
+impl SwapchainSetupFirstStage {
+    unsafe fn new(
+        connection: *mut xcb::ffi::xcb_connection_t,
+        window: xcb::ffi::xcb_window_t,
+        is_full_setup: bool,
+    ) -> Result<Self, SwapchainSetupError> {
+        let has_mit_shm = query_extension(connection, "MIT-SHM");
+        let geometry = xcb::ffi::xcb_get_geometry(connection, window);
+        let window_attributes = xcb::ffi::xcb_get_window_attributes(connection, window);
+        let tree = xcb::ffi::xcb_query_tree(connection, window);
+        let gc = xcb::ffi::xcb_generate_id(connection);
+        xcb::ffi::xcb_create_gc(
+            connection,
+            gc,
+            window,
+            xcb::ffi::XCB_GC_GRAPHICS_EXPOSURES,
+            [0].as_ptr(),
+        );
+        let gc = create_gc(gc, connection);
+        let has_mit_shm = ReplyObject::from(xcb::ffi::xcb_query_extension_reply(
+            connection,
+            has_mit_shm,
+            null_mut(),
+        ));
+        let shm_supported = has_mit_shm.map(|v| v.present != 0).unwrap_or(false);
+        let shm_version = if is_full_setup && shm_supported {
+            Some(xcb::ffi::shm::xcb_shm_query_version(connection))
+        } else {
+            None
+        };
+        let geometry = ReplyObject::from(xcb::ffi::xcb_get_geometry_reply(
+            connection,
+            geometry,
+            null_mut(),
+        ))
+        .ok_or(SwapchainSetupError::BadSurface)?;
+        let image_extent = api::VkExtent2D {
+            width: geometry.width as u32,
+            height: geometry.height as u32,
+        };
+        mem::drop(geometry);
+        let window_attributes = ReplyObject::from(xcb::ffi::xcb_get_window_attributes_reply(
+            connection,
+            window_attributes,
+            null_mut(),
+        ))
+        .ok_or(SwapchainSetupError::BadSurface)?;
+        let window_visual_id = window_attributes.visual;
+        mem::drop(window_attributes);
+        let tree = ReplyObject::from(xcb::ffi::xcb_query_tree_reply(connection, tree, null_mut()))
+            .ok_or(SwapchainSetupError::BadSurface)?;
+        let root_window = tree.root;
+        mem::drop(tree);
+        let mut screen = None;
+        let mut roots_iter =
+            xcb::ffi::xcb_setup_roots_iterator(xcb::ffi::xcb_get_setup(connection));
+        while roots_iter.rem != 0 {
+            if (*roots_iter.data).root == root_window {
+                screen = Some(roots_iter.data);
+                break;
+            }
+            xcb::ffi::xcb_screen_next(&mut roots_iter);
+        }
+        let screen = screen.ok_or(SwapchainSetupError::BadSurface)?;
+        let mut window_visual_type_and_depth = None;
+        let mut depth_iter = xcb::ffi::xcb_screen_allowed_depths_iterator(screen);
+        while depth_iter.rem != 0 {
+            let mut visual_iter = xcb::ffi::xcb_depth_visuals_iterator(depth_iter.data);
+            while visual_iter.rem != 0 {
+                if (*visual_iter.data).visual_id == window_visual_id {
+                    window_visual_type_and_depth =
+                        Some((visual_iter.data, (*depth_iter.data).depth));
+                    break;
+                }
+                xcb::ffi::xcb_visualtype_next(&mut visual_iter);
+            }
+            if window_visual_type_and_depth.is_some() {
+                break;
+            }
+            xcb::ffi::xcb_depth_next(&mut depth_iter);
+        }
+        let (window_visual_type, window_depth) =
+            window_visual_type_and_depth.ok_or(SwapchainSetupError::BadSurface)?;
+        let ref window_visual_type = *window_visual_type;
+        let red_mask = window_visual_type.red_mask;
+        let green_mask = window_visual_type.green_mask;
+        let blue_mask = window_visual_type.blue_mask;
+        let alpha_mask = match window_depth {
+            24 => 0,
+            32 => !(red_mask | green_mask | blue_mask),
+            _ => return Err(SwapchainSetupError::NoSupport),
+        };
+        let mut window_pixmap_format = None;
+        let mut formats_iter =
+            xcb::ffi::xcb_setup_pixmap_formats_iterator(xcb::ffi::xcb_get_setup(connection));
+        while formats_iter.rem != 0 {
+            if (*formats_iter.data).depth == window_depth {
+                window_pixmap_format = Some(formats_iter.data);
+                break;
+            }
+            xcb::ffi::xcb_format_next(&mut formats_iter);
+        }
+        let ref window_pixmap_format =
+            *(window_pixmap_format.ok_or(SwapchainSetupError::BadSurface)?);
+        let image_pixel_size = match window_pixmap_format.bits_per_pixel {
+            24 => 3,
+            32 => 4,
+            _ => return Err(SwapchainSetupError::NoSupport),
+        };
+        fn u32_from_bytes(v: [u8; 4]) -> u32 {
+            unsafe { mem::transmute(v) }
+        }
+        let surface_format_group = match (
+            u32_from_bytes([0xFF, 0, 0, 0]),
+            u32_from_bytes([0, 0xFF, 0, 0]),
+            u32_from_bytes([0, 0, 0xFF, 0]),
+            u32_from_bytes([0, 0, 0, 0xFF]),
+        ) {
+            (r, g, b, a)
+                if r == red_mask
+                    && g == green_mask
+                    && b == blue_mask
+                    && (alpha_mask == 0 || a == alpha_mask) =>
+            {
+                SurfaceFormatGroup::B8G8R8A8
+            }
+            _ => return Err(SwapchainSetupError::NoSupport),
+        };
+        let scanline_alignment = match window_pixmap_format.scanline_pad {
+            8 => 1,
+            16 => 2,
+            32 => 4,
+            _ => unreachable!("invalid pixmap format scanline_pad"),
+        };
+        const PRESENT_MODES: &'static [api::VkPresentModeKHR] = &[
+            api::VK_PRESENT_MODE_FIFO_KHR, // FIXME: properly implement FIFO present mode using X11 Present extension
+            api::VK_PRESENT_MODE_IMMEDIATE_KHR,
+        ];
+        Ok(Self {
+            gc,
+            shm_supported,
+            window_depth,
+            surface_format_group,
+            present_modes: PRESENT_MODES,
+            capabilities: api::VkSurfaceCapabilitiesKHR {
+                minImageCount: 2,
+                maxImageCount: MAX_SWAPCHAIN_IMAGE_COUNT,
+                currentExtent: image_extent,
+                minImageExtent: image_extent,
+                maxImageExtent: image_extent,
+                maxImageArrayLayers: 1,
+                supportedTransforms: api::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
+                currentTransform: api::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
+                supportedCompositeAlpha: api::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+                supportedUsageFlags: api::VK_IMAGE_USAGE_TRANSFER_SRC_BIT
+                    | api::VK_IMAGE_USAGE_TRANSFER_DST_BIT
+                    | api::VK_IMAGE_USAGE_SAMPLED_BIT
+                    | api::VK_IMAGE_USAGE_STORAGE_BIT
+                    | api::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+                    | api::VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
+            },
+            shared_present_capabilities: None,
+            image_pixel_size,
+            scanline_alignment,
+            shm_version,
+            image_descriptor: ImageDescriptor {
+                supported_tilings: SupportedTilings::Any,
+                format: api::VK_FORMAT_UNDEFINED,
+                extents: api::VkExtent3D {
+                    width: image_extent.width,
+                    height: image_extent.height,
+                    depth: 1,
+                },
+                mip_levels: 1,
+            },
+        })
+    }
+}
+
+impl XcbSwapchain {
+    unsafe fn new(
+        create_info: &api::VkSwapchainCreateInfoKHR,
+        device_group_create_info: Option<&api::VkDeviceGroupSwapchainCreateInfoKHR>,
+    ) -> Result<Self, api::VkResult> {
+        unimplemented!()
+    }
+}
+
+#[derive(Debug)]
+pub struct XcbSurfaceImplementation;
+
+impl XcbSurfaceImplementation {
+    unsafe fn get_surface(&self, surface: api::VkSurfaceKHR) -> &api::VkIcdSurfaceXcb {
+        let surface = surface.get().unwrap().as_ptr();
+        assert_eq!((*surface).platform, api::VK_ICD_WSI_PLATFORM_XCB);
+        &*(surface as *const api::VkIcdSurfaceXcb)
+    }
+}
+
+impl SurfaceImplementation for XcbSurfaceImplementation {
+    fn get_platform(&self) -> SurfacePlatform {
+        SurfacePlatform::VK_ICD_WSI_PLATFORM_XCB
+    }
+    unsafe fn get_surface_formats(
+        &self,
+        surface: api::VkSurfaceKHR,
+    ) -> Result<Cow<'static, [api::VkSurfaceFormatKHR]>, api::VkResult> {
+        let surface = &self.get_surface(surface);
+        let first_stage = SwapchainSetupFirstStage::new(surface.connection, surface.window, false)
+            .map_err(|v| match v {
+                SwapchainSetupError::BadSurface | SwapchainSetupError::NoSupport => {
+                    api::VK_ERROR_SURFACE_LOST_KHR
+                }
+            })?;
+        match first_stage.surface_format_group {
+            SurfaceFormatGroup::B8G8R8A8 => {
+                const SURFACE_FORMATS: &'static [api::VkSurfaceFormatKHR] = &[
+                    api::VkSurfaceFormatKHR {
+                        format: api::VK_FORMAT_B8G8R8A8_SRGB,
+                        colorSpace: api::VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+                    },
+                    api::VkSurfaceFormatKHR {
+                        format: api::VK_FORMAT_B8G8R8A8_UNORM,
+                        colorSpace: api::VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+                    },
+                ];
+                Ok(Cow::Borrowed(SURFACE_FORMATS))
+            }
+        }
+    }
+    unsafe fn get_present_modes(
+        &self,
+        surface: api::VkSurfaceKHR,
+    ) -> Result<Cow<'static, [api::VkPresentModeKHR]>, api::VkResult> {
+        let surface = &self.get_surface(surface);
+        let first_stage = SwapchainSetupFirstStage::new(surface.connection, surface.window, false)
+            .map_err(|v| match v {
+                SwapchainSetupError::BadSurface | SwapchainSetupError::NoSupport => {
+                    api::VK_ERROR_SURFACE_LOST_KHR
+                }
+            })?;
+        Ok(Cow::Borrowed(first_stage.present_modes))
+    }
+    unsafe fn get_capabilities(
+        &self,
+        surface: api::VkSurfaceKHR,
+    ) -> Result<api::VkSurfaceCapabilitiesKHR, api::VkResult> {
+        let surface = &self.get_surface(surface);
+        let first_stage = SwapchainSetupFirstStage::new(surface.connection, surface.window, false)
+            .map_err(|v| match v {
+                SwapchainSetupError::BadSurface | SwapchainSetupError::NoSupport => {
+                    api::VK_ERROR_SURFACE_LOST_KHR
+                }
+            })?;
+        Ok(first_stage.capabilities)
+    }
+    unsafe fn build(
+        &self,
+        create_info: &api::VkSwapchainCreateInfoKHR,
+        device_group_create_info: Option<&api::VkDeviceGroupSwapchainCreateInfoKHR>,
+    ) -> Result<Box<Swapchain>, api::VkResult> {
+        Ok(Box::new(XcbSwapchain::new(
+            create_info,
+            device_group_create_info,
+        )?))
+    }
+    fn duplicate(&self) -> Box<dyn SurfaceImplementation> {
+        Box::new(Self {})
+    }
+}
index 956139e8baff0bc2de138b819c5f84fb310c8a4d..ddc15bfd18d43fce8dbd94328b7c77f30aab0e56 100644 (file)
@@ -4,13 +4,13 @@
 #ifdef __ANDROID__
 #error not supported on Android; need to fix ABI
 #endif
+#ifdef __unix
+#define VK_USE_PLATFORM_XCB_KHR
+#endif
 #define VK_NO_PROTOTYPES
 #include <vulkan/vulkan.h>
 #include <vulkan/vk_icd.h>
-#ifdef __unix
-typedef struct xcb_connection_t xcb_connection_t;
-typedef uint32_t xcb_visualid_t;
-typedef uint32_t xcb_window_t;
-#include <vulkan/vulkan_xcb.h>
-#endif
 #undef VK_NO_PROTOTYPES
+#ifdef VK_USE_PLATFORM_XCB_KHR
+#undef VK_USE_PLATFORM_XCB_KHR
+#endif