working on adding x11 wsi
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 14 Sep 2017 15:44:04 +0000 (08:44 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 14 Sep 2017 15:44:04 +0000 (08:44 -0700)
src/vulkan/api_objects.h
src/vulkan_icd/vulkan_icd.cpp
src/vulkan_icd/wsi.h
src/vulkan_icd/x11_wsi.cpp

index 3dd97a6d92abe4e78224ba06ddab7941e43c9133..8c2b1d39650b7c07c5f258b9d5965681a04ff7a1 100644 (file)
@@ -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_extension> 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 {};
index ec2af35a2c8ffce4e56c39eaa3f5bef93b7cb77c..1a117d20e43c81851aa38fddc7ac7bbf96857a55 100644 (file)
@@ -24,6 +24,7 @@
 #include "util/string_view.h"
 #include <initializer_list>
 #include <iostream>
+#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<VkIcdSurfaceBase *>(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<VkIcdSurfaceBase *>(surface);
+            auto *wsi = vulkan_icd::Wsi::find(surface_base->platform);
+            assert(wsi);
+            std::vector<VkSurfaceFormatKHR> 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<VkIcdSurfaceBase *>(surface);
+            auto *wsi = vulkan_icd::Wsi::find(surface_base->platform);
+            assert(wsi);
+            std::vector<VkPresentModeKHR> 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
index 0ffd00714e80d4e8e27df31d501f10c24198b819..c7fab09f1115ebb648e9b7a8f64b071d8a3f83ec 100644 (file)
@@ -28,6 +28,7 @@
 #include "vulkan/remove_xlib_macros.h"
 #include <type_traits>
 #include <cstdint>
+#include <vector>
 
 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<VkSurfaceFormatKHR> &surface_formats) const = 0;
+    virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector<VkPresentModeKHR> &present_modes) const = 0;
+    virtual VkResult get_surface_capabilities(VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const = 0;
 };
 
 static_assert(std::is_trivially_destructible<Wsi>::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<VkSurfaceFormatKHR> &surface_formats) const override;
+    virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector<VkPresentModeKHR> &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<VkSurfaceFormatKHR> &surface_formats) const override;
+    virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector<VkPresentModeKHR> &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<VkSurfaceFormatKHR> &surface_formats) const override;
+    virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector<VkPresentModeKHR> &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<VkSurfaceFormatKHR> &surface_formats) const override;
+    virtual VkResult get_present_modes(VkIcdSurfaceBase *surface, std::vector<VkPresentModeKHR> &present_modes) const override;
+    virtual VkResult get_surface_capabilities(VkIcdSurfaceBase *surface, VkSurfaceCapabilitiesKHR &capabilities) const override;
     static const Win32_wsi &get() noexcept;
 };
 #endif
index 9cdd390a222d9638c7c40eec8942a30f7128f93d..8c7761fd0aeb8731a91e90da28867a6afc7fc22b 100644 (file)
@@ -32,6 +32,7 @@
 #include <cassert>
 #include <cstdlib>
 #include <memory>
+#include <cstring>
 #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 <typename T = void>
     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<VkPresentModeKHR> 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<VkPresentModeKHR> 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<VkPresentModeKHR> 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<VkSurfaceFormatKHR> &surface_formats) const
+{
+    auto &surface = *reinterpret_cast<Surface_type *>(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<VkPresentModeKHR> &present_modes) const
+{
+    auto &surface = *reinterpret_cast<Surface_type *>(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_type *>(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<xcb_window_t>(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_type *>(surface_);
-    switch(Implementation::start_setup(XGetXCBConnection(surface.dpy),
-                                       static_cast<xcb_window_t>(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<VkIcdSurfaceBase *>(&xcb_surface),
+                                              supported);
+}
+
+VkResult Xlib_wsi::get_surface_formats(VkIcdSurfaceBase *surface_,
+                                       std::vector<VkSurfaceFormatKHR> &surface_formats) const
+{
+    auto &surface = *reinterpret_cast<Surface_type *>(surface_);
+    auto xcb_surface = Implementation::get_xcb_surface(surface);
+    return Xcb_wsi::get().get_surface_formats(reinterpret_cast<VkIcdSurfaceBase *>(&xcb_surface),
+                                              surface_formats);
+}
+
+VkResult Xlib_wsi::get_present_modes(VkIcdSurfaceBase *surface_,
+                                     std::vector<VkPresentModeKHR> &present_modes) const
+{
+    auto &surface = *reinterpret_cast<Surface_type *>(surface_);
+    auto xcb_surface = Implementation::get_xcb_surface(surface);
+    return Xcb_wsi::get().get_present_modes(reinterpret_cast<VkIcdSurfaceBase *>(&xcb_surface),
+                                            present_modes);
+}
+
+VkResult Xlib_wsi::get_surface_capabilities(VkIcdSurfaceBase *surface_,
+                                            VkSurfaceCapabilitiesKHR &capabilities) const
+{
+    auto &surface = *reinterpret_cast<Surface_type *>(surface_);
+    auto xcb_surface = Implementation::get_xcb_surface(surface);
+    return Xcb_wsi::get().get_surface_capabilities(
+        reinterpret_cast<VkIcdSurfaceBase *>(&xcb_surface), capabilities);
 }
 
 const Xlib_wsi &Xlib_wsi::get() noexcept