From b5c123a8642b635dc74cb02fadc35c87d911a891 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 14 Sep 2017 08:44:04 -0700 Subject: [PATCH] working on adding x11 wsi --- src/vulkan/api_objects.h | 21 +- src/vulkan_icd/vulkan_icd.cpp | 72 +++++-- src/vulkan_icd/wsi.h | 16 ++ src/vulkan_icd/x11_wsi.cpp | 355 ++++++++++++++++++++++++++++++++-- 4 files changed, 430 insertions(+), 34 deletions(-) diff --git a/src/vulkan/api_objects.h b/src/vulkan/api_objects.h index 3dd97a6..8c2b1d3 100644 --- a/src/vulkan/api_objects.h +++ b/src/vulkan/api_objects.h @@ -45,12 +45,14 @@ enum class Supported_extension Not_supported, KHR_surface, KHR_xcb_surface, + KHR_xlib_surface, }; kazan_util_generate_enum_traits(Supported_extension, Supported_extension::Not_supported, Supported_extension::KHR_surface, - Supported_extension::KHR_xcb_surface); + Supported_extension::KHR_xcb_surface, + Supported_extension::KHR_xlib_surface); typedef util::Enum_set Supported_extensions; @@ -74,6 +76,12 @@ constexpr Extension_scope get_extension_scope(Supported_extension extension) noe return Extension_scope::Instance; #else return Extension_scope::Not_supported; +#endif + case Supported_extension::KHR_xlib_surface: +#ifdef VK_USE_PLATFORM_XLIB_KHR + return Extension_scope::Instance; +#else + return Extension_scope::Not_supported; #endif } assert(!"unknown extension"); @@ -99,6 +107,15 @@ constexpr VkExtensionProperties get_extension_properties(Supported_extension ext }; #else return {}; +#endif + case Supported_extension::KHR_xlib_surface: +#ifdef VK_USE_PLATFORM_XLIB_KHR + return { + .extensionName = VK_KHR_XLIB_SURFACE_EXTENSION_NAME, + .specVersion = VK_KHR_XLIB_SURFACE_SPEC_VERSION, + }; +#else + return {}; #endif } assert(!"unknown extension"); @@ -137,6 +154,8 @@ constexpr Supported_extensions get_extension_dependencies(Supported_extension ex return {}; case Supported_extension::KHR_xcb_surface: return {Supported_extension::KHR_surface}; + case Supported_extension::KHR_xlib_surface: + return {Supported_extension::KHR_surface}; } assert(!"unknown extension"); return {}; diff --git a/src/vulkan_icd/vulkan_icd.cpp b/src/vulkan_icd/vulkan_icd.cpp index ec2af35..1a117d2 100644 --- a/src/vulkan_icd/vulkan_icd.cpp +++ b/src/vulkan_icd/vulkan_icd.cpp @@ -24,6 +24,7 @@ #include "util/string_view.h" #include #include +#include "wsi.h" using namespace kazan; @@ -1384,32 +1385,75 @@ extern "C" VKAPI_ATTR VkResult VKAPI_CALL } extern "C" VKAPI_ATTR VkResult VKAPI_CALL - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physical_device, VkSurfaceKHR surface, - VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) + VkSurfaceCapabilitiesKHR *surface_capabilities) { -#warning finish implementing vkGetPhysicalDeviceSurfaceCapabilitiesKHR - assert(!"vkGetPhysicalDeviceSurfaceCapabilitiesKHR is not implemented"); + assert(physical_device); + assert(surface); + 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); + VkSurfaceCapabilitiesKHR capabilities{}; + auto result = wsi->get_surface_capabilities(surface_base, capabilities); + if(result != VK_SUCCESS) + return result; + *surface_capabilities = capabilities; + return VK_SUCCESS; + }); } extern "C" VKAPI_ATTR VkResult VKAPI_CALL - vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, + vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physical_device, VkSurfaceKHR surface, - uint32_t *pSurfaceFormatCount, - VkSurfaceFormatKHR *pSurfaceFormats) + uint32_t *surface_format_count, + VkSurfaceFormatKHR *surface_formats) { -#warning finish implementing vkGetPhysicalDeviceSurfaceFormatsKHR - assert(!"vkGetPhysicalDeviceSurfaceFormatsKHR is not implemented"); + assert(physical_device); + assert(surface); + 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); + std::vector surface_formats_vector; + auto result = wsi->get_surface_formats(surface_base, surface_formats_vector); + if(result != VK_SUCCESS) + return result; + return vulkan_icd::vulkan_enumerate_list_helper(surface_format_count, + surface_formats, + surface_formats_vector.data(), + surface_formats_vector.size()); + }); } extern "C" VKAPI_ATTR VkResult VKAPI_CALL - vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, + vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physical_device, VkSurfaceKHR surface, - uint32_t *pPresentModeCount, - VkPresentModeKHR *pPresentModes) + uint32_t *present_mode_count, + VkPresentModeKHR *present_modes) { -#warning finish implementing vkGetPhysicalDeviceSurfacePresentModesKHR - assert(!"vkGetPhysicalDeviceSurfacePresentModesKHR is not implemented"); + assert(physical_device); + assert(surface); + 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); + std::vector present_modes_vector; + auto result = wsi->get_present_modes(surface_base, present_modes_vector); + if(result != VK_SUCCESS) + return result; + return vulkan_icd::vulkan_enumerate_list_helper(present_mode_count, + present_modes, + present_modes_vector.data(), + present_modes_vector.size()); + }); } #ifdef VK_USE_PLATFORM_XCB_KHR diff --git a/src/vulkan_icd/wsi.h b/src/vulkan_icd/wsi.h index 0ffd007..c7fab09 100644 --- a/src/vulkan_icd/wsi.h +++ b/src/vulkan_icd/wsi.h @@ -28,6 +28,7 @@ #include "vulkan/remove_xlib_macros.h" #include #include +#include namespace kazan { @@ -87,6 +88,9 @@ 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; }; static_assert(std::is_trivially_destructible::value, @@ -103,6 +107,9 @@ struct Xcb_wsi final : public Wsi 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; static const Xcb_wsi &get() noexcept; }; #endif @@ -118,6 +125,9 @@ struct Xlib_wsi final : public Wsi 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; static const Xlib_wsi &get() noexcept; }; #endif @@ -134,6 +144,9 @@ struct Wayland_wsi final : public Wsi 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; static const Wayland_wsi &get() noexcept; }; #endif @@ -158,6 +171,9 @@ struct Win32_wsi final : public Wsi 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; static const Win32_wsi &get() noexcept; }; #endif diff --git a/src/vulkan_icd/x11_wsi.cpp b/src/vulkan_icd/x11_wsi.cpp index 9cdd390..8c7761f 100644 --- a/src/vulkan_icd/x11_wsi.cpp +++ b/src/vulkan_icd/x11_wsi.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "util/optional.h" namespace kazan @@ -40,6 +41,23 @@ namespace vulkan_icd { struct Xcb_wsi::Implementation { + static std::uint32_t u32_from_bytes(std::uint8_t b0, + std::uint8_t b1, + std::uint8_t b2, + std::uint8_t b3) noexcept + { + static_assert(sizeof(std::uint8_t) == 1 && sizeof(std::uint32_t) == 4, ""); + union + { + std::uint8_t bytes[4]; + std::uint32_t u32; + }; + bytes[0] = b0; + bytes[1] = b1; + bytes[2] = b2; + bytes[3] = b3; + return u32; + } template struct Free_functor { @@ -171,6 +189,15 @@ struct Xcb_wsi::Implementation return value; } }; + static xcb_query_extension_cookie_t query_extension(xcb_connection_t *connection, + const char *extension_name) noexcept + { + return xcb_query_extension(connection, std::strlen(extension_name), extension_name); + } + enum class Surface_format_group + { + B8G8R8A8, + }; struct Start_setup_results { enum class Status @@ -180,14 +207,210 @@ struct Xcb_wsi::Implementation Success, }; Status status; + Gc gc; + bool shm_is_supported; + unsigned window_depth; + std::uint32_t image_width; + std::uint32_t image_height; + Surface_format_group surface_format_group; + std::vector present_modes; + VkSurfaceCapabilitiesKHR capabilities; + Start_setup_results(Gc gc, + bool shm_is_supported, + unsigned window_depth, + std::uint32_t image_width, + std::uint32_t image_height, + Surface_format_group surface_format_group, + std::vector present_modes, + const VkSurfaceCapabilitiesKHR &capabilities) noexcept + : status(Status::Success), + gc(std::move(gc)), + shm_is_supported(shm_is_supported), + window_depth(window_depth), + image_width(image_width), + image_height(image_height), + surface_format_group(surface_format_group), + present_modes(std::move(present_modes)), + capabilities(capabilities) + { + } + Start_setup_results(Status status) noexcept : status(status), + gc(), + shm_is_supported(), + window_depth(), + surface_format_group(), + present_modes(), + capabilities{} + { + assert(status != Status::Success); + } }; static Start_setup_results start_setup(xcb_connection_t *connection, xcb_window_t window) { -#warning implement start_setup - assert(!"implement start_setup"); - return { - .status = Start_setup_results::Status::No_support, + auto mit_shm_cookie = query_extension(connection, "MIT-SHM"); + auto get_geometry_cookie = xcb_get_geometry(connection, window); + auto get_window_attributes_cookie = xcb_get_window_attributes(connection, window); + auto query_tree_cookie = xcb_query_tree(connection, window); + auto gc_id = xcb_generate_id(connection); + const std::uint32_t gc_params[1] = { + 0, // value for XCB_GC_GRAPHICS_EXPOSURES + }; + xcb_create_gc(connection, gc_id, window, XCB_GC_GRAPHICS_EXPOSURES, gc_params); + auto gc = Gc(gc_id, connection); + auto mit_shm_reply = + 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) + 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)); + if(!get_geometry_reply) + return Start_setup_results::Status::Bad_surface; + std::uint32_t image_width = get_geometry_reply->width; + std::uint32_t image_height = get_geometry_reply->height; + auto get_window_attributes_reply = Get_window_attributes_reply( + xcb_get_window_attributes_reply(connection, get_window_attributes_cookie, nullptr)); + if(!get_window_attributes_reply) + return Start_setup_results::Status::Bad_surface; + auto window_visual_id = get_window_attributes_reply->visual; + auto query_tree_reply = + Query_tree_reply(xcb_query_tree_reply(connection, query_tree_cookie, nullptr)); + if(!query_tree_reply) + return Start_setup_results::Status::Bad_surface; + auto root_window = query_tree_reply->root; + xcb_screen_t *screen = nullptr; + for(auto iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); iter.rem; + xcb_screen_next(&iter)) + { + if(iter.data->root == root_window) + { + screen = iter.data; + break; + } + } + if(!screen) + return Start_setup_results::Status::Bad_surface; + xcb_visualtype_t *window_visual_type = nullptr; + unsigned window_depth = 0; + for(auto depth_iter = xcb_screen_allowed_depths_iterator(screen); depth_iter.rem; + xcb_depth_next(&depth_iter)) + { + for(auto visual_iter = xcb_depth_visuals_iterator(depth_iter.data); visual_iter.rem; + xcb_visualtype_next(&visual_iter)) + { + if(visual_iter.data->visual_id == window_visual_id) + { + window_visual_type = visual_iter.data; + window_depth = depth_iter.data->depth; + break; + } + } + if(window_visual_type) + break; + } + if(!window_visual_type) + return Start_setup_results::Status::Bad_surface; + std::uint32_t red_mask = window_visual_type->red_mask; + std::uint32_t green_mask = window_visual_type->green_mask; + std::uint32_t blue_mask = window_visual_type->blue_mask; + std::uint32_t alpha_mask; + switch(window_depth) + { + case 24: + alpha_mask = 0; + break; + case 32: + alpha_mask = ~(red_mask | green_mask | blue_mask); + break; + default: + return Start_setup_results::Status::No_support; + } + xcb_format_t *window_pixmap_format = nullptr; + for(auto iter = xcb_setup_pixmap_formats_iterator(xcb_get_setup(connection)); iter.rem; + xcb_format_next(&iter)) + { + if(iter.data->depth == window_depth) + { + window_pixmap_format = iter.data; + break; + } + } + if(!window_pixmap_format) + return Start_setup_results::Status::Bad_surface; + std::size_t image_pixel_size; + switch(window_pixmap_format->bits_per_pixel) + { + case 24: + image_pixel_size = 3; + break; + case 32: + image_pixel_size = 4; + break; + default: + return Start_setup_results::Status::No_support; + } + Surface_format_group surface_format_group; + if(red_mask == u32_from_bytes(0, 0, 0xFF, 0) && green_mask == u32_from_bytes(0, 0xFF, 0, 0) + && blue_mask == u32_from_bytes(0xFF, 0, 0, 0) + && (alpha_mask == 0 || alpha_mask == u32_from_bytes(0, 0, 0, 0xFF)) + && image_pixel_size == 4) + surface_format_group = Surface_format_group::B8G8R8A8; + else + return Start_setup_results::Status::No_support; + std::size_t scanline_alignment = 1; + switch(window_pixmap_format->scanline_pad) + { + case 8: + scanline_alignment = 1; + break; + case 16: + scanline_alignment = 2; + break; + case 32: + scanline_alignment = 4; + break; + default: + assert(!"invalid pixmap format scanline-pad"); + } + std::vector present_modes = { +#warning properly implement fifo present mode using X11 Present extension + VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, + }; + VkSurfaceCapabilitiesKHR capabilities = { + .minImageCount = 1, + .maxImageCount = 0, + .currentExtent = + { + .width = image_width, .height = image_height, + }, + .minImageExtent = + { + .width = image_width, .height = image_height, + }, + .maxImageExtent = + { + .width = image_width, .height = image_height, + }, + .maxImageArrayLayers = 1, + .supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, + .currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, + .supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .supportedUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, }; + return Start_setup_results(std::move(gc), + shm_is_supported, + window_depth, + image_width, + image_height, + surface_format_group, + present_modes, + capabilities); } }; @@ -228,6 +451,77 @@ VkResult Xcb_wsi::get_surface_support(VkIcdSurfaceBase *surface_, VkBool32 &supp return {}; } +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); + 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: + { + surface_formats.clear(); + switch(start_setup_result.surface_format_group) + { + case Implementation::Surface_format_group::B8G8R8A8: + surface_formats = { + { + .format = VK_FORMAT_B8G8R8A8_SRGB, + .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + }, + { + .format = VK_FORMAT_B8G8R8A8_UNORM, + .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + }, + }; + break; + } + return VK_SUCCESS; + } + } + assert(!"unreachable"); + return {}; +} + +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); + 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); + return VK_SUCCESS; + } + assert(!"unreachable"); + return {}; +} + +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); + 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: + capabilities = start_setup_result.capabilities; + return VK_SUCCESS; + } + assert(!"unreachable"); + return {}; +} + const Xcb_wsi &Xcb_wsi::get() noexcept { static const Xcb_wsi retval{}; @@ -249,6 +543,14 @@ namespace vulkan_icd { struct Xlib_wsi::Implementation : public Xcb_wsi::Implementation { + static VkIcdSurfaceXcb get_xcb_surface(const VkIcdSurfaceXlib &surface) noexcept + { + return VkIcdSurfaceXcb{ + .base = {.platform = VK_ICD_WSI_PLATFORM_XCB}, + .connection = XGetXCBConnection(surface.dpy), + .window = static_cast(surface.window), + }; + } }; VkIcdSurfaceBase *Xlib_wsi::create_surface(const VkXlibSurfaceCreateInfoKHR &create_info) const @@ -273,21 +575,36 @@ void Xlib_wsi::destroy_surface(VkIcdSurfaceBase *surface) const noexcept VkResult Xlib_wsi::get_surface_support(VkIcdSurfaceBase *surface_, VkBool32 &supported) const { auto &surface = *reinterpret_cast(surface_); - switch(Implementation::start_setup(XGetXCBConnection(surface.dpy), - static_cast(surface.window)) - .status) - { - case Implementation::Start_setup_results::Status::Bad_surface: - return VK_ERROR_SURFACE_LOST_KHR; - case Implementation::Start_setup_results::Status::No_support: - supported = false; - return VK_SUCCESS; - case Implementation::Start_setup_results::Status::Success: - supported = true; - return VK_SUCCESS; - } - assert(!"unreachable"); - return {}; + auto xcb_surface = Implementation::get_xcb_surface(surface); + return Xcb_wsi::get().get_surface_support(reinterpret_cast(&xcb_surface), + supported); +} + +VkResult Xlib_wsi::get_surface_formats(VkIcdSurfaceBase *surface_, + std::vector &surface_formats) const +{ + auto &surface = *reinterpret_cast(surface_); + auto xcb_surface = Implementation::get_xcb_surface(surface); + return Xcb_wsi::get().get_surface_formats(reinterpret_cast(&xcb_surface), + surface_formats); +} + +VkResult Xlib_wsi::get_present_modes(VkIcdSurfaceBase *surface_, + std::vector &present_modes) const +{ + auto &surface = *reinterpret_cast(surface_); + auto xcb_surface = Implementation::get_xcb_surface(surface); + return Xcb_wsi::get().get_present_modes(reinterpret_cast(&xcb_surface), + present_modes); +} + +VkResult Xlib_wsi::get_surface_capabilities(VkIcdSurfaceBase *surface_, + VkSurfaceCapabilitiesKHR &capabilities) const +{ + auto &surface = *reinterpret_cast(surface_); + auto xcb_surface = Implementation::get_xcb_surface(surface); + return Xcb_wsi::get().get_surface_capabilities( + reinterpret_cast(&xcb_surface), capabilities); } const Xlib_wsi &Xlib_wsi::get() noexcept -- 2.30.2