From f5e574f0fad08ec3ef80dbb7d997b03a6dd94fbf Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Fri, 15 Sep 2017 06:25:27 -0700 Subject: [PATCH] working on adding KHR_swapchain extension --- src/vulkan/api_objects.cpp | 14 ++ src/vulkan/api_objects.h | 66 +++++++++- src/vulkan_icd/vulkan_icd.cpp | 165 +++++++++++++++++++++--- src/vulkan_icd/wsi.h | 83 +++++++++--- src/vulkan_icd/x11_wsi.cpp | 234 +++++++++++++++++++++++++++++++--- 5 files changed, 504 insertions(+), 58 deletions(-) diff --git a/src/vulkan/api_objects.cpp b/src/vulkan/api_objects.cpp index 55e7d12..199f7da 100644 --- a/src/vulkan/api_objects.cpp +++ b/src/vulkan/api_objects.cpp @@ -357,5 +357,19 @@ util::variant, VkResult> Vulkan_device::create( assert(create_info.pQueueCreateInfos[0].queueCount == 1); return std::make_unique(physical_device, enabled_features, extensions); } + +std::unique_ptr Vulkan_semaphore::create(Vulkan_device &device, + const VkSemaphoreCreateInfo &create_info) +{ + assert(create_info.sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO); + assert(create_info.flags == 0); + return std::make_unique(); +} + +std::unique_ptr Vulkan_image::create(Vulkan_device &device, const VkImageCreateInfo &create_info) +{ +#warning finish implementing Vulkan_image::create + return std::make_unique(); +} } } diff --git a/src/vulkan/api_objects.h b/src/vulkan/api_objects.h index 8c2b1d3..2e8adb4 100644 --- a/src/vulkan/api_objects.h +++ b/src/vulkan/api_objects.h @@ -46,13 +46,15 @@ enum class Supported_extension KHR_surface, KHR_xcb_surface, KHR_xlib_surface, + KHR_swapchain, }; kazan_util_generate_enum_traits(Supported_extension, Supported_extension::Not_supported, Supported_extension::KHR_surface, Supported_extension::KHR_xcb_surface, - Supported_extension::KHR_xlib_surface); + Supported_extension::KHR_xlib_surface, + Supported_extension::KHR_swapchain); typedef util::Enum_set Supported_extensions; @@ -83,6 +85,8 @@ constexpr Extension_scope get_extension_scope(Supported_extension extension) noe #else return Extension_scope::Not_supported; #endif + case Supported_extension::KHR_swapchain: + return Extension_scope::Device; } assert(!"unknown extension"); return Extension_scope::Not_supported; @@ -117,6 +121,11 @@ constexpr VkExtensionProperties get_extension_properties(Supported_extension ext #else return {}; #endif + case Supported_extension::KHR_swapchain: + return { + .extensionName = VK_KHR_SWAPCHAIN_EXTENSION_NAME, + .specVersion = VK_KHR_SWAPCHAIN_SPEC_VERSION, + }; } assert(!"unknown extension"); return {}; @@ -156,6 +165,8 @@ constexpr Supported_extensions get_extension_dependencies(Supported_extension ex return {Supported_extension::KHR_surface}; case Supported_extension::KHR_xlib_surface: return {Supported_extension::KHR_surface}; + case Supported_extension::KHR_swapchain: + return {Supported_extension::KHR_surface}; } assert(!"unknown extension"); return {}; @@ -1135,6 +1146,21 @@ struct Vulkan_dispatchable_object } }; +template +struct Vulkan_nondispatchable_object +{ + typedef Vulkan_handle_type Vulkan_handle; + typedef Object_type Object; + static Object_type *from_handle(Vulkan_handle_type v) noexcept + { + return static_cast(reinterpret_cast(v)); + } + static std::unique_ptr move_from_handle(Vulkan_handle_type v) noexcept + { + return std::unique_ptr(from_handle(v)); + } +}; + template typename std:: enable_if(nullptr))) move_to_handle( return to_handle(v.release()); } +template +typename std:: + enable_if, + Object_type>::value, + typename Object_type::Vulkan_handle>::type + to_handle(Object_type *object) noexcept +{ + return reinterpret_cast( + static_cast + *>(object)); +} + struct Vulkan_instance; struct Vulkan_physical_device @@ -1488,8 +1527,16 @@ struct Vulkan_instance : public Vulkan_dispatchable_object { - struct Queue + struct Queue : public Vulkan_dispatchable_object { + Vulkan_instance &instance; + Vulkan_physical_device &physical_device; + Vulkan_device &device; + explicit Queue(Vulkan_device &device) noexcept : instance(device.instance), + physical_device(device.physical_device), + device(device) + { + } }; Vulkan_instance &instance; Vulkan_physical_device &physical_device; @@ -1503,6 +1550,7 @@ struct Vulkan_device : public Vulkan_dispatchable_object, VkResult> create( Vulkan_physical_device &physical_device, const VkDeviceCreateInfo &create_info); }; + +struct Vulkan_semaphore : public Vulkan_nondispatchable_object +{ + static std::unique_ptr create(Vulkan_device &device, + const VkSemaphoreCreateInfo &create_info); +}; + +struct Vulkan_image : public Vulkan_nondispatchable_object +{ + virtual ~Vulkan_image() = default; +#warning finish implementing Vulkan_image + static std::unique_ptr create(Vulkan_device &device, + const VkImageCreateInfo &create_info); +}; } } diff --git a/src/vulkan_icd/vulkan_icd.cpp b/src/vulkan_icd/vulkan_icd.cpp index 1a117d2..66ccca7 100644 --- a/src/vulkan_icd/vulkan_icd.cpp +++ b/src/vulkan_icd/vulkan_icd.cpp @@ -233,12 +233,17 @@ extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( } extern "C" VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(VkDevice device, - uint32_t queueFamilyIndex, - uint32_t queueIndex, - VkQueue *pQueue) + uint32_t queue_family_index, + uint32_t queue_index, + VkQueue *queue) { -#warning finish implementing vkGetDeviceQueue - assert(!"vkGetDeviceQueue is not implemented"); + assert(device); + assert(queue_family_index < vulkan::Vulkan_physical_device::queue_family_property_count); + assert(queue_index < vulkan::Vulkan_device::queue_count); + assert(queue); + auto *device_pointer = vulkan::Vulkan_device::from_handle(device); + static_assert(vulkan::Vulkan_device::queue_count == 1, ""); + *queue = to_handle(&device_pointer->queues[0]); } extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(VkQueue queue, @@ -435,13 +440,22 @@ extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences(VkDevice device, extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, - const VkSemaphoreCreateInfo *pCreateInfo, + const VkSemaphoreCreateInfo *create_info, const VkAllocationCallbacks *allocator, - VkSemaphore *pSemaphore) + VkSemaphore *semaphore) { validate_allocator(allocator); -#warning finish implementing vkCreateSemaphore - assert(!"vkCreateSemaphore is not implemented"); + assert(device); + assert(create_info); + assert(semaphore); + return vulkan_icd::catch_exceptions_and_return_result( + [&]() + { + auto create_result = vulkan::Vulkan_semaphore::create( + *vulkan::Vulkan_device::from_handle(device), *create_info); + *semaphore = move_to_handle(std::move(create_result)); + return VK_SUCCESS; + }); } extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore(VkDevice device, @@ -449,8 +463,8 @@ extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore(VkDevice device, const VkAllocationCallbacks *allocator) { validate_allocator(allocator); -#warning finish implementing vkDestroySemaphore - assert(!"vkDestroySemaphore is not implemented"); + assert(device); + vulkan::Vulkan_semaphore::move_from_handle(semaphore).reset(); } extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent(VkDevice device, @@ -1375,13 +1389,28 @@ extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR(VkInstance instance, } extern "C" VKAPI_ATTR VkResult VKAPI_CALL - vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, + vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physical_device, + uint32_t queue_family_index, VkSurfaceKHR surface, - VkBool32 *pSupported) + VkBool32 *supported) { -#warning finish implementing vkGetPhysicalDeviceSurfaceSupportKHR - assert(!"vkGetPhysicalDeviceSurfaceSupportKHR is not implemented"); + assert(physical_device); + assert(queue_family_index < vulkan::Vulkan_physical_device::queue_family_property_count); + assert(surface); + assert(supported); + return vulkan_icd::catch_exceptions_and_return_result( + [&]() + { + auto *surface_base = reinterpret_cast(surface); + auto *wsi = vulkan_icd::Wsi::find(surface_base->platform); + assert(wsi); + bool is_supported{}; + auto result = wsi->get_surface_support(surface_base, is_supported); + if(result != VK_SUCCESS) + return result; + *supported = is_supported; + return VK_SUCCESS; + }); } extern "C" VKAPI_ATTR VkResult VKAPI_CALL @@ -1478,6 +1507,100 @@ extern "C" VKAPI_ATTR VkBool32 VKAPI_CALL } #endif +#ifdef VK_USE_PLATFORM_XLIB_KHR +extern "C" VKAPI_ATTR VkResult VKAPI_CALL + vkCreateXlibSurfaceKHR(VkInstance instance, + const VkXlibSurfaceCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) +{ +#warning finish implementing vkCreateXlibSurfaceKHR + assert(!"vkCreateXlibSurfaceKHR is not implemented"); +} + +extern "C" VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( + VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display *dpy, VisualID visualID) +{ +#warning finish implementing vkGetPhysicalDeviceXlibPresentationSupportKHR + assert(!"vkGetPhysicalDeviceXlibPresentationSupportKHR is not implemented"); +} +#endif + +extern "C" VKAPI_ATTR VkResult VKAPI_CALL + vkCreateSwapchainKHR(VkDevice device, + const VkSwapchainCreateInfoKHR *create_info, + const VkAllocationCallbacks *allocator, + VkSwapchainKHR *swapchain) +{ + validate_allocator(allocator); + assert(device); + assert(create_info); + assert(swapchain); + return vulkan_icd::catch_exceptions_and_return_result( + [&]() + { + assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); + auto *surface_base = reinterpret_cast(create_info->surface); + auto *wsi = vulkan_icd::Wsi::find(surface_base->platform); + assert(wsi); + auto create_result = + wsi->create_swapchain(*vulkan::Vulkan_device::from_handle(device), *create_info); + if(util::holds_alternative(create_result)) + return util::get(create_result); + *swapchain = move_to_handle( + util::get>(std::move(create_result))); + return VK_SUCCESS; + }); +} + +extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR(VkDevice device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks *allocator) +{ + validate_allocator(allocator); + assert(device); + assert(swapchain); + vulkan_icd::Vulkan_swapchain::move_from_handle(swapchain).reset(); +} + +extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR(VkDevice device, + VkSwapchainKHR swapchain, + uint32_t *swapchain_image_count, + VkImage *swapchain_images) +{ + assert(device); + assert(swapchain); + return vulkan_icd::catch_exceptions_and_return_result( + [&]() + { + auto *swapchain_pointer = vulkan_icd::Vulkan_swapchain::from_handle(swapchain); + std::vector images; + images.reserve(swapchain_pointer->images.size()); + for(auto &image : swapchain_pointer->images) + images.push_back(to_handle(image.get())); + return vulkan_icd::vulkan_enumerate_list_helper( + swapchain_image_count, swapchain_images, images.data(), images.size()); + }); +} + +extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device, + VkSwapchainKHR swapchain, + uint64_t timeout, + VkSemaphore semaphore, + VkFence fence, + uint32_t *pImageIndex) +{ +#warning finish implementing vkAcquireNextImageKHR + assert(!"vkAcquireNextImageKHR is not implemented"); +} + +extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, + const VkPresentInfoKHR *pPresentInfo) +{ +#warning finish implementing vkQueuePresentKHR + assert(!"vkQueuePresentKHR is not implemented"); +} + namespace kazan { namespace vulkan_icd @@ -1717,6 +1840,16 @@ PFN_vkVoidFunction Vulkan_loader_interface::get_procedure_address( INSTANCE_SCOPE_EXTENSION_FUNCTION(vkGetPhysicalDeviceXcbPresentationSupportKHR, KHR_xcb_surface); #endif +#ifdef VK_USE_PLATFORM_XLIB_KHR + INSTANCE_SCOPE_EXTENSION_FUNCTION(vkCreateXlibSurfaceKHR, KHR_xlib_surface); + INSTANCE_SCOPE_EXTENSION_FUNCTION(vkGetPhysicalDeviceXlibPresentationSupportKHR, + KHR_xlib_surface); +#endif + INSTANCE_SCOPE_EXTENSION_FUNCTION(vkCreateSwapchainKHR, KHR_swapchain); + INSTANCE_SCOPE_EXTENSION_FUNCTION(vkDestroySwapchainKHR, KHR_swapchain); + INSTANCE_SCOPE_EXTENSION_FUNCTION(vkGetSwapchainImagesKHR, KHR_swapchain); + INSTANCE_SCOPE_EXTENSION_FUNCTION(vkAcquireNextImageKHR, KHR_swapchain); + INSTANCE_SCOPE_EXTENSION_FUNCTION(vkQueuePresentKHR, KHR_swapchain); #undef LIBRARY_SCOPE_FUNCTION #undef INSTANCE_SCOPE_FUNCTION diff --git a/src/vulkan_icd/wsi.h b/src/vulkan_icd/wsi.h index c7fab09..75645a2 100644 --- a/src/vulkan_icd/wsi.h +++ b/src/vulkan_icd/wsi.h @@ -26,6 +26,8 @@ #include "vulkan/vulkan.h" #include "vulkan/vk_icd.h" #include "vulkan/remove_xlib_macros.h" +#include "vulkan/api_objects.h" +#include "util/variant.h" #include #include #include @@ -34,6 +36,22 @@ namespace kazan { namespace vulkan_icd { +struct Wsi; + +class Vulkan_swapchain + : public vulkan::Vulkan_nondispatchable_object +{ +public: + std::vector> images; + +public: + explicit Vulkan_swapchain(std::vector> images) noexcept + : images(std::move(images)) + { + } + virtual ~Vulkan_swapchain() = default; +}; + struct Wsi { class Wsi_list @@ -87,10 +105,15 @@ struct Wsi { } virtual void destroy_surface(VkIcdSurfaceBase *surface) const noexcept = 0; - virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, VkBool32 &supported) const = 0; - virtual VkResult get_surface_formats(VkIcdSurfaceBase *surface, std::vector &surface_formats) const = 0; - virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector &present_modes) const = 0; - virtual VkResult get_surface_capabilities(VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const = 0; + virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &supported) const = 0; + virtual VkResult get_surface_formats( + VkIcdSurfaceBase *surface, std::vector &surface_formats) const = 0; + virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, + std::vector &present_modes) const = 0; + virtual VkResult get_surface_capabilities(VkIcdSurfaceBase *surface, + VkSurfaceCapabilitiesKHR &capabilities) const = 0; + virtual util::variant> create_swapchain( + vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const = 0; }; static_assert(std::is_trivially_destructible::value, @@ -106,10 +129,15 @@ struct Xcb_wsi final : public Wsi struct Implementation; VkIcdSurfaceBase *create_surface(const VkXcbSurfaceCreateInfoKHR &create_info) const; virtual void destroy_surface(VkIcdSurfaceBase *surface) const noexcept override; - virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, VkBool32 &supported) const override; - virtual VkResult get_surface_formats(VkIcdSurfaceBase *surface, std::vector &surface_formats) const override; - virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector &present_modes) const override; - virtual VkResult get_surface_capabilities(VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const override; + virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &supported) const override; + virtual VkResult get_surface_formats( + VkIcdSurfaceBase *surface, std::vector &surface_formats) const override; + virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, + std::vector &present_modes) const override; + virtual VkResult get_surface_capabilities( + VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const override; + virtual util::variant> create_swapchain( + vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const override; static const Xcb_wsi &get() noexcept; }; #endif @@ -124,10 +152,15 @@ struct Xlib_wsi final : public Wsi struct Implementation; VkIcdSurfaceBase *create_surface(const VkXlibSurfaceCreateInfoKHR &create_info) const; virtual void destroy_surface(VkIcdSurfaceBase *surface) const noexcept override; - virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, VkBool32 &supported) const override; - virtual VkResult get_surface_formats(VkIcdSurfaceBase *surface, std::vector &surface_formats) const override; - virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector &present_modes) const override; - virtual VkResult get_surface_capabilities(VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const override; + virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &supported) const override; + virtual VkResult get_surface_formats( + VkIcdSurfaceBase *surface, std::vector &surface_formats) const override; + virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, + std::vector &present_modes) const override; + virtual VkResult get_surface_capabilities( + VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const override; + virtual util::variant> create_swapchain( + vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const override; static const Xlib_wsi &get() noexcept; }; #endif @@ -143,10 +176,15 @@ struct Wayland_wsi final : public Wsi struct Implementation; VkIcdSurfaceBase *create_surface(const VkWaylandSurfaceCreateInfoKHR &create_info) const; virtual void destroy_surface(VkIcdSurfaceBase *surface) const noexcept override; - virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, VkBool32 &supported) const override; - virtual VkResult get_surface_formats(VkIcdSurfaceBase *surface, std::vector &surface_formats) const override; - virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector &present_modes) const override; - virtual VkResult get_surface_capabilities(VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const override; + virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &supported) const override; + virtual VkResult get_surface_formats( + VkIcdSurfaceBase *surface, std::vector &surface_formats) const override; + virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, + std::vector &present_modes) const override; + virtual VkResult get_surface_capabilities( + VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const override; + virtual util::variant> create_swapchain( + vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const override; static const Wayland_wsi &get() noexcept; }; #endif @@ -170,10 +208,15 @@ struct Win32_wsi final : public Wsi struct Implementation; VkIcdSurfaceBase *create_surface(const VkWin32SurfaceCreateInfoKHR &create_info) const; virtual void destroy_surface(VkIcdSurfaceBase *surface) const noexcept override; - virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, VkBool32 &supported) const override; - virtual VkResult get_surface_formats(VkIcdSurfaceBase *surface, std::vector &surface_formats) const override; - virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector &present_modes) const override; - virtual VkResult get_surface_capabilities(VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const override; + virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &supported) const override; + virtual VkResult get_surface_formats( + VkIcdSurfaceBase *surface, std::vector &surface_formats) const override; + virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, + std::vector &present_modes) const override; + virtual VkResult get_surface_capabilities( + VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const override; + virtual util::variant> create_swapchain( + vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const override; static const Win32_wsi &get() noexcept; }; #endif diff --git a/src/vulkan_icd/x11_wsi.cpp b/src/vulkan_icd/x11_wsi.cpp index 8c7761f..963a7d1 100644 --- a/src/vulkan_icd/x11_wsi.cpp +++ b/src/vulkan_icd/x11_wsi.cpp @@ -33,6 +33,10 @@ #include #include #include +#include +#include +#include +#include #include "util/optional.h" namespace kazan @@ -213,8 +217,11 @@ struct Xcb_wsi::Implementation std::uint32_t image_width; std::uint32_t image_height; Surface_format_group surface_format_group; - std::vector present_modes; + util::optional> present_modes; VkSurfaceCapabilitiesKHR capabilities; + std::size_t image_pixel_size; + std::size_t scanline_alignment; + xcb_shm_query_version_cookie_t shm_query_version_cookie; Start_setup_results(Gc gc, bool shm_is_supported, unsigned window_depth, @@ -222,7 +229,10 @@ struct Xcb_wsi::Implementation std::uint32_t image_height, Surface_format_group surface_format_group, std::vector present_modes, - const VkSurfaceCapabilitiesKHR &capabilities) noexcept + const VkSurfaceCapabilitiesKHR &capabilities, + std::size_t image_pixel_size, + std::size_t scanline_alignment, + xcb_shm_query_version_cookie_t shm_query_version_cookie) noexcept : status(Status::Success), gc(std::move(gc)), shm_is_supported(shm_is_supported), @@ -231,21 +241,31 @@ struct Xcb_wsi::Implementation image_height(image_height), surface_format_group(surface_format_group), present_modes(std::move(present_modes)), - capabilities(capabilities) + capabilities(capabilities), + image_pixel_size(image_pixel_size), + scanline_alignment(scanline_alignment), + shm_query_version_cookie(shm_query_version_cookie) { } - Start_setup_results(Status status) noexcept : status(status), - gc(), - shm_is_supported(), - window_depth(), - surface_format_group(), - present_modes(), - capabilities{} + constexpr Start_setup_results(Status status) noexcept : status(status), + gc(), + shm_is_supported(), + window_depth(), + image_width(), + image_height(), + surface_format_group(), + present_modes(), + capabilities{}, + image_pixel_size(), + scanline_alignment(), + shm_query_version_cookie() { assert(status != Status::Success); } }; - static Start_setup_results start_setup(xcb_connection_t *connection, xcb_window_t window) + static Start_setup_results start_setup(xcb_connection_t *connection, + xcb_window_t window, + bool is_full_setup) { auto mit_shm_cookie = query_extension(connection, "MIT-SHM"); auto get_geometry_cookie = xcb_get_geometry(connection, window); @@ -261,7 +281,7 @@ struct Xcb_wsi::Implementation Query_extension_reply(xcb_query_extension_reply(connection, mit_shm_cookie, nullptr)); bool shm_is_supported = mit_shm_reply && mit_shm_reply->present; xcb_shm_query_version_cookie_t shm_query_version_cookie{}; - if(shm_is_supported) + if(shm_is_supported && is_full_setup) shm_query_version_cookie = xcb_shm_query_version(connection); auto get_geometry_reply = Get_geometry_reply(xcb_get_geometry_reply(connection, get_geometry_cookie, nullptr)); @@ -410,8 +430,156 @@ struct Xcb_wsi::Implementation image_height, surface_format_group, present_modes, - capabilities); + capabilities, + image_pixel_size, + scanline_alignment, + shm_query_version_cookie); } + struct Swapchain final : public Vulkan_swapchain + { + struct Swapchain_image final : public vulkan::Vulkan_image + { + std::shared_ptr pixels; + std::size_t row_pitch; + std::uint32_t width; + std::uint32_t height; + std::size_t pixel_size; + Shared_memory_segment shared_memory_segment; + Server_shm_seg server_shm_seg; + Pixmap pixmap; + std::list::iterator iter; + Swapchain_image(std::shared_ptr pixels, + std::size_t row_pitch, + std::uint32_t width, + std::uint32_t height, + std::size_t pixel_size, + Shared_memory_segment shared_memory_segment, + Server_shm_seg server_shm_seg, + Pixmap pixmap, + std::list::iterator iter) noexcept + : pixels(std::move(pixels)), + row_pitch(row_pitch), + width(width), + height(height), + pixel_size(pixel_size), + shared_memory_segment(std::move(shared_memory_segment)), + server_shm_seg(std::move(server_shm_seg)), + pixmap(std::move(pixmap)), + iter(iter) + { + } + }; + xcb_connection_t *connection; + xcb_window_t window; + bool shm_is_supported; + std::list free_list; + explicit Swapchain(Start_setup_results start_setup_results, + xcb_connection_t *connection, + xcb_window_t window, + const VkSwapchainCreateInfoKHR &create_info) + : Vulkan_swapchain({}), + connection(connection), + window(window), + shm_is_supported(start_setup_results.shm_is_supported) + { + std::size_t unpadded_scanline_size = + start_setup_results.image_pixel_size * start_setup_results.image_width; + std::size_t padded_scanline_size = + (unpadded_scanline_size + start_setup_results.scanline_alignment - 1U) + & ~(start_setup_results.scanline_alignment - 1U); + std::size_t image_size = padded_scanline_size * start_setup_results.image_height; + if(shm_is_supported) + { + auto shm_query_version_reply = Shm_query_version_reply(xcb_shm_query_version_reply( + connection, start_setup_results.shm_query_version_cookie, nullptr)); + if(!shm_query_version_reply || !shm_query_version_reply->shared_pixmaps + || shm_query_version_reply->pixmap_format != XCB_IMAGE_FORMAT_Z_PIXMAP) + { + std::cerr + << "shared memory pixmaps are not supported, falling back to using core " + "X protocol" + << std::endl; + shm_is_supported = false; + } + } + auto image_count = std::max(create_info.minImageCount, 2); + while(true) + { + bool shm_failed = false; + for(std::uint32_t i = 0; i < image_count; i++) + { + Shared_memory_segment shared_memory_segment; + std::shared_ptr pixels; + Server_shm_seg server_shm_seg; + Pixmap pixmap; + if(shm_is_supported) + { + shared_memory_segment = Shared_memory_segment::create(image_size); + pixels = shared_memory_segment.map(); + auto seg_id = xcb_generate_id(connection); + auto shm_attach_cookie = xcb_shm_attach_checked( + connection, seg_id, shared_memory_segment.get(), false); + auto error = + Generic_error(xcb_request_check(connection, shm_attach_cookie)); + if(error) + { + shm_failed = true; + break; + } + server_shm_seg = Server_shm_seg(seg_id, connection); + auto pixmap_id = xcb_generate_id(connection); + error = Generic_error(xcb_request_check( + connection, + xcb_shm_create_pixmap_checked(connection, + pixmap_id, + window, + start_setup_results.image_width, + start_setup_results.image_height, + start_setup_results.window_depth, + server_shm_seg.get(), + 0))); + if(error) + { + shm_failed = true; + break; + } + pixmap = Pixmap(pixmap_id, connection); + } + else + { + pixels = std::shared_ptr(new unsigned char[image_size], + [](unsigned char *p) noexcept + { + delete[] p; + }); + } + auto image_iter = free_list.insert(free_list.end(), nullptr); + auto image = + std::make_unique(std::move(pixels), + padded_scanline_size, + start_setup_results.image_width, + start_setup_results.image_height, + start_setup_results.image_pixel_size, + std::move(shared_memory_segment), + std::move(server_shm_seg), + std::move(pixmap), + image_iter); + *image_iter = image.get(); + images.push_back(std::move(image)); + } + if(shm_failed) + { + std::cerr << "using shared memory failed, falling back to using core X protocol" + << std::endl; + shm_is_supported = false; + free_list.clear(); + images.clear(); + continue; + } + break; + } + } + }; }; VkIcdSurfaceBase *Xcb_wsi::create_surface(const VkXcbSurfaceCreateInfoKHR &create_info) const @@ -433,10 +601,10 @@ void Xcb_wsi::destroy_surface(VkIcdSurfaceBase *surface) const noexcept delete reinterpret_cast(surface); } -VkResult Xcb_wsi::get_surface_support(VkIcdSurfaceBase *surface_, VkBool32 &supported) const +VkResult Xcb_wsi::get_surface_support(VkIcdSurfaceBase *surface_, bool &supported) const { auto &surface = *reinterpret_cast(surface_); - switch(Implementation::start_setup(surface.connection, surface.window).status) + switch(Implementation::start_setup(surface.connection, surface.window, false).status) { case Implementation::Start_setup_results::Status::Bad_surface: return VK_ERROR_SURFACE_LOST_KHR; @@ -455,7 +623,8 @@ VkResult Xcb_wsi::get_surface_formats(VkIcdSurfaceBase *surface_, std::vector &surface_formats) const { auto &surface = *reinterpret_cast(surface_); - auto start_setup_result = Implementation::start_setup(surface.connection, surface.window); + auto start_setup_result = + Implementation::start_setup(surface.connection, surface.window, false); switch(start_setup_result.status) { case Implementation::Start_setup_results::Status::Bad_surface: @@ -490,14 +659,15 @@ VkResult Xcb_wsi::get_present_modes(VkIcdSurfaceBase *surface_, std::vector &present_modes) const { auto &surface = *reinterpret_cast(surface_); - auto start_setup_result = Implementation::start_setup(surface.connection, surface.window); + auto start_setup_result = + Implementation::start_setup(surface.connection, surface.window, false); switch(start_setup_result.status) { case Implementation::Start_setup_results::Status::Bad_surface: case Implementation::Start_setup_results::Status::No_support: return VK_ERROR_SURFACE_LOST_KHR; case Implementation::Start_setup_results::Status::Success: - present_modes = std::move(start_setup_result.present_modes); + present_modes = std::move(start_setup_result.present_modes.value()); return VK_SUCCESS; } assert(!"unreachable"); @@ -508,7 +678,8 @@ VkResult Xcb_wsi::get_surface_capabilities(VkIcdSurfaceBase *surface_, VkSurfaceCapabilitiesKHR &capabilities) const { auto &surface = *reinterpret_cast(surface_); - auto start_setup_result = Implementation::start_setup(surface.connection, surface.window); + auto start_setup_result = + Implementation::start_setup(surface.connection, surface.window, false); switch(start_setup_result.status) { case Implementation::Start_setup_results::Status::Bad_surface: @@ -522,6 +693,18 @@ VkResult Xcb_wsi::get_surface_capabilities(VkIcdSurfaceBase *surface_, return {}; } +util::variant> Xcb_wsi::create_swapchain( + vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const +{ +#warning finish implementing Xcb_wsi::create_swapchain + auto &surface = *reinterpret_cast(create_info.surface); + return std::make_unique( + Implementation::start_setup(surface.connection, surface.window, true), + surface.connection, + surface.window, + create_info); +} + const Xcb_wsi &Xcb_wsi::get() noexcept { static const Xcb_wsi retval{}; @@ -572,7 +755,7 @@ void Xlib_wsi::destroy_surface(VkIcdSurfaceBase *surface) const noexcept delete reinterpret_cast(surface); } -VkResult Xlib_wsi::get_surface_support(VkIcdSurfaceBase *surface_, VkBool32 &supported) const +VkResult Xlib_wsi::get_surface_support(VkIcdSurfaceBase *surface_, bool &supported) const { auto &surface = *reinterpret_cast(surface_); auto xcb_surface = Implementation::get_xcb_surface(surface); @@ -607,6 +790,17 @@ VkResult Xlib_wsi::get_surface_capabilities(VkIcdSurfaceBase *surface_, reinterpret_cast(&xcb_surface), capabilities); } +util::variant> Xlib_wsi::create_swapchain( + vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const +{ + assert(create_info.surface); + auto &surface = *reinterpret_cast(create_info.surface); + auto xcb_surface = Implementation::get_xcb_surface(surface); + VkSwapchainCreateInfoKHR xcb_create_info = create_info; + xcb_create_info.surface = reinterpret_cast(&xcb_surface); + return Xcb_wsi::get().create_swapchain(device, xcb_create_info); +} + const Xlib_wsi &Xlib_wsi::get() noexcept { static const Xlib_wsi retval{}; -- 2.30.2