working on adding KHR_swapchain extension
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 15 Sep 2017 13:25:27 +0000 (06:25 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 15 Sep 2017 13:25:27 +0000 (06:25 -0700)
src/vulkan/api_objects.cpp
src/vulkan/api_objects.h
src/vulkan_icd/vulkan_icd.cpp
src/vulkan_icd/wsi.h
src/vulkan_icd/x11_wsi.cpp

index 55e7d12ee16e67f3df19df58b3b35f36e2ff1e2f..199f7daffee19d6a4dd2ee505b8f3cd0d039e93c 100644 (file)
@@ -357,5 +357,19 @@ util::variant<std::unique_ptr<Vulkan_device>, VkResult> Vulkan_device::create(
     assert(create_info.pQueueCreateInfos[0].queueCount == 1);
     return std::make_unique<Vulkan_device>(physical_device, enabled_features, extensions);
 }
+
+std::unique_ptr<Vulkan_semaphore> 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<Vulkan_semaphore>();
+}
+
+std::unique_ptr<Vulkan_image> Vulkan_image::create(Vulkan_device &device, const VkImageCreateInfo &create_info)
+{
+#warning finish implementing Vulkan_image::create
+    return std::make_unique<Vulkan_image>();
+}
 }
 }
index 8c2b1d39650b7c07c5f258b9d5965681a04ff7a1..2e8adb47af03c26bb75ab2cef466a51373e3f4c9 100644 (file)
@@ -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_extension> 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 <typename Object_type, typename Vulkan_handle_type>
+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<Object_type *>(reinterpret_cast<Vulkan_nondispatchable_object *>(v));
+    }
+    static std::unique_ptr<Object_type> move_from_handle(Vulkan_handle_type v) noexcept
+    {
+        return std::unique_ptr<Object_type>(from_handle(v));
+    }
+};
+
 template <typename Object_type>
 typename std::
     enable_if<std::is_base_of<Vulkan_dispatchable_object<Object_type,
@@ -1155,6 +1181,19 @@ decltype(to_handle(static_cast<Object_type *>(nullptr))) move_to_handle(
     return to_handle(v.release());
 }
 
+template <typename Object_type, typename = void>
+typename std::
+    enable_if<std::is_base_of<Vulkan_nondispatchable_object<Object_type,
+                                                            typename Object_type::Vulkan_handle>,
+                              Object_type>::value,
+              typename Object_type::Vulkan_handle>::type
+    to_handle(Object_type *object) noexcept
+{
+    return reinterpret_cast<typename Object_type::Vulkan_handle>(
+        static_cast<Vulkan_nondispatchable_object<Object_type, typename Object_type::Vulkan_handle>
+                        *>(object));
+}
+
 struct Vulkan_instance;
 
 struct Vulkan_physical_device
@@ -1488,8 +1527,16 @@ struct Vulkan_instance : public Vulkan_dispatchable_object<Vulkan_instance, VkIn
 
 struct Vulkan_device : public Vulkan_dispatchable_object<Vulkan_device, VkDevice>
 {
-    struct Queue
+    struct Queue : public Vulkan_dispatchable_object<Queue, VkQueue>
     {
+        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<Vulkan_device, VkDevice
         : instance(physical_device.instance),
           physical_device(physical_device),
           enabled_features(enabled_features),
+          queues{Queue(*this)},
           extensions(extensions)
     {
     }
@@ -1513,6 +1561,20 @@ struct Vulkan_device : public Vulkan_dispatchable_object<Vulkan_device, VkDevice
     static util::variant<std::unique_ptr<Vulkan_device>, VkResult> create(
         Vulkan_physical_device &physical_device, const VkDeviceCreateInfo &create_info);
 };
+
+struct Vulkan_semaphore : public Vulkan_nondispatchable_object<Vulkan_semaphore, VkSemaphore>
+{
+    static std::unique_ptr<Vulkan_semaphore> create(Vulkan_device &device,
+                                                    const VkSemaphoreCreateInfo &create_info);
+};
+
+struct Vulkan_image : public Vulkan_nondispatchable_object<Vulkan_image, VkImage>
+{
+    virtual ~Vulkan_image() = default;
+#warning finish implementing Vulkan_image
+    static std::unique_ptr<Vulkan_image> create(Vulkan_device &device,
+                                                const VkImageCreateInfo &create_info);
+};
 }
 }
 
index 1a117d20e43c81851aa38fddc7ac7bbf96857a55..66ccca75debbaa9dab2f8b06bbf99242d7ce96a0 100644 (file)
@@ -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<VkIcdSurfaceBase *>(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<VkIcdSurfaceBase *>(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<VkResult>(create_result))
+                return util::get<VkResult>(create_result);
+            *swapchain = move_to_handle(
+                util::get<std::unique_ptr<vulkan_icd::Vulkan_swapchain>>(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<VkImage> 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
index c7fab09f1115ebb648e9b7a8f64b071d8a3f83ec..75645a207e71b2a1753f74c95003811da57da966 100644 (file)
@@ -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 <type_traits>
 #include <cstdint>
 #include <vector>
@@ -34,6 +36,22 @@ namespace kazan
 {
 namespace vulkan_icd
 {
+struct Wsi;
+
+class Vulkan_swapchain
+    : public vulkan::Vulkan_nondispatchable_object<Vulkan_swapchain, VkSwapchainKHR>
+{
+public:
+    std::vector<std::unique_ptr<vulkan::Vulkan_image>> images;
+
+public:
+    explicit Vulkan_swapchain(std::vector<std::unique_ptr<vulkan::Vulkan_image>> 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<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;
+    virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &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;
+    virtual util::variant<VkResult, std::unique_ptr<Vulkan_swapchain>> create_swapchain(
+        vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const = 0;
 };
 
 static_assert(std::is_trivially_destructible<Wsi>::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<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;
+    virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &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;
+    virtual util::variant<VkResult, std::unique_ptr<Vulkan_swapchain>> 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<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;
+    virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &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;
+    virtual util::variant<VkResult, std::unique_ptr<Vulkan_swapchain>> 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<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;
+    virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &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;
+    virtual util::variant<VkResult, std::unique_ptr<Vulkan_swapchain>> 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<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;
+    virtual VkResult get_surface_support(VkIcdSurfaceBase *surface, bool &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;
+    virtual util::variant<VkResult, std::unique_ptr<Vulkan_swapchain>> create_swapchain(
+        vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const override;
     static const Win32_wsi &get() noexcept;
 };
 #endif
index 8c7761fd0aeb8731a91e90da28867a6afc7fc22b..963a7d15a363c7b3e3ac649b63961fa6c4d9e669 100644 (file)
 #include <cstdlib>
 #include <memory>
 #include <cstring>
+#include <iostream>
+#include <list>
+#include <utility>
+#include <algorithm>
 #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<VkPresentModeKHR> present_modes;
+        util::optional<std::vector<VkPresentModeKHR>> 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<VkPresentModeKHR> 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<void> 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<Swapchain_image *>::iterator iter;
+            Swapchain_image(std::shared_ptr<void> 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<Swapchain_image *>::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<Swapchain_image *> 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<std::uint32_t>(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<void> 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<unsigned char>(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<Swapchain_image>(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_type *>(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_type *>(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<VkSurfaceFormatKHR> &surface_formats) const
 {
     auto &surface = *reinterpret_cast<Surface_type *>(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<VkPresentModeKHR> &present_modes) const
 {
     auto &surface = *reinterpret_cast<Surface_type *>(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_type *>(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<VkResult, std::unique_ptr<Vulkan_swapchain>> Xcb_wsi::create_swapchain(
+    vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const
+{
+#warning finish implementing Xcb_wsi::create_swapchain
+    auto &surface = *reinterpret_cast<Surface_type *>(create_info.surface);
+    return std::make_unique<Implementation::Swapchain>(
+        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_type *>(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_type *>(surface_);
     auto xcb_surface = Implementation::get_xcb_surface(surface);
@@ -607,6 +790,17 @@ VkResult Xlib_wsi::get_surface_capabilities(VkIcdSurfaceBase *surface_,
         reinterpret_cast<VkIcdSurfaceBase *>(&xcb_surface), capabilities);
 }
 
+util::variant<VkResult, std::unique_ptr<Vulkan_swapchain>> Xlib_wsi::create_swapchain(
+    vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const
+{
+    assert(create_info.surface);
+    auto &surface = *reinterpret_cast<Surface_type *>(create_info.surface);
+    auto xcb_surface = Implementation::get_xcb_surface(surface);
+    VkSwapchainCreateInfoKHR xcb_create_info = create_info;
+    xcb_create_info.surface = reinterpret_cast<VkSurfaceKHR>(&xcb_surface);
+    return Xcb_wsi::get().create_swapchain(device, xcb_create_info);
+}
+
 const Xlib_wsi &Xlib_wsi::get() noexcept
 {
     static const Xlib_wsi retval{};