wsi: Move common objects to the wayland wsi::surface
authorRosen Zhelev <rosen.zhelev@arm.com>
Thu, 22 Jul 2021 22:49:15 +0000 (23:49 +0100)
committerRosen Zhelev <rosen.zhelev@arm.com>
Tue, 17 Aug 2021 15:42:21 +0000 (16:42 +0100)
Moves data and Wayland objects such as the registry to the
wsi::wayland::surface implementation. This also fixes a few issues
with queries where the Wayland display's default queue was wrongly
used and minimizes leaking of server memory from registry creation.

Moves the ownership of the zwp_linux_dmabuf_interface object to the
wsi::wayland::surface as it can be shared between swapchains.

Fixes issues with casting VkSurfaces in the Wayland backend that can
fail when using other layers that wrap the object.

Change-Id: Ibacf0d4229b73bd685254507f52e58d6341aa9b6
Signed-off-by: Rosen Zhelev <rosen.zhelev@arm.com>
wsi/wayland/surface.cpp
wsi/wayland/surface.hpp
wsi/wayland/surface_properties.cpp
wsi/wayland/surface_properties.hpp
wsi/wayland/swapchain.cpp
wsi/wayland/swapchain.hpp
wsi/wayland/wl_helpers.cpp
wsi/wayland/wl_helpers.hpp
wsi/wayland/wl_object_owner.hpp

index f70d3d5..a22f6e8 100644 (file)
 #include "surface.hpp"
 #include "swapchain.hpp"
 #include "surface_properties.hpp"
+#include "wl_object_owner.hpp"
+#include "wl_helpers.hpp"
+#include "util/log.hpp"
 
 namespace wsi
 {
 namespace wayland
 {
 
+struct formats_vector
+{
+   util::vector<drm_format_pair> *formats{nullptr};
+   bool is_out_of_memory{false};
+};
+
+namespace
+{
+/* Handler for format event of the zwp_linux_dmabuf_v1 interface. */
+extern "C" void zwp_linux_dmabuf_v1_format_impl(void *data, struct zwp_linux_dmabuf_v1 *dma_buf, uint32_t drm_format)
+{
+}
+
+/* Handler for modifier event of the zwp_linux_dmabuf_v1 interface. */
+extern "C" void zwp_linux_dmabuf_v1_modifier_impl(void *data, struct zwp_linux_dmabuf_v1 *dma_buf, uint32_t drm_format,
+                                                  uint32_t modifier_hi, uint32_t modifier_low)
+{
+   auto *drm_supported_formats = reinterpret_cast<formats_vector *>(data);
+
+   drm_format_pair format = {};
+   format.fourcc = drm_format;
+   format.modifier = (static_cast<uint64_t>(modifier_hi) << 32) | modifier_low;
+
+   if (!drm_supported_formats->is_out_of_memory)
+   {
+      drm_supported_formats->is_out_of_memory = !drm_supported_formats->formats->try_push_back(format);
+   }
+}
+} // namespace
+
+/*
+ * @brief Get supported formats and modifiers using the zwp_linux_dmabuf_v1 interface.
+ *
+ * @param[in]  display               The wl_display that is being used.
+ * @param[in]  queue                 The wl_event_queue set for the @p dmabuf_interface
+ * @param[in]  dmabuf_interface      Object of the zwp_linux_dmabuf_v1 interface.
+ * @param[out] supported_formats     Vector which will contain the supported drm
+ *                                   formats and their modifiers.
+ *
+ * @retval VK_SUCCESS                    Indicates success.
+ * @retval VK_ERROR_UNKNOWN              Indicates one of the Wayland functions failed.
+ * @retval VK_ERROR_OUT_OF_DEVICE_MEMORY Indicates the host went out of memory.
+ */
+static VkResult get_supported_formats_and_modifiers(wl_display *display, wl_event_queue *queue,
+                                                    zwp_linux_dmabuf_v1 *dmabuf_interface,
+                                                    util::vector<drm_format_pair> &supported_formats)
+{
+   formats_vector drm_supported_formats;
+   drm_supported_formats.formats = &supported_formats;
+
+   const zwp_linux_dmabuf_v1_listener dma_buf_listener = {
+      .format = zwp_linux_dmabuf_v1_format_impl,
+      .modifier = zwp_linux_dmabuf_v1_modifier_impl,
+   };
+   int res = zwp_linux_dmabuf_v1_add_listener(dmabuf_interface, &dma_buf_listener, &drm_supported_formats);
+   if (res < 0)
+   {
+      WSI_LOG_ERROR("Failed to add zwp_linux_dmabuf_v1 listener.");
+      return VK_ERROR_UNKNOWN;
+   }
+
+   /* Get all modifier events. */
+   res = wl_display_roundtrip_queue(display, queue);
+   if (res < 0)
+   {
+      WSI_LOG_ERROR("Roundtrip failed.");
+      return VK_ERROR_UNKNOWN;
+   }
+
+   if (drm_supported_formats.is_out_of_memory)
+   {
+      WSI_LOG_ERROR("Host got out of memory.");
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+   }
+
+   return VK_SUCCESS;
+}
+
+struct surface::init_parameters
+{
+   const util::allocator& allocator;
+   wl_display *display;
+   wl_surface *surf;
+};
+
+surface::surface(const init_parameters &params)
+   : wsi::surface()
+   , wayland_display(params.display)
+   , wayland_surface(params.surf)
+   , supported_formats(params.allocator)
+   , properties(*this, params.allocator)
+   , surface_queue(nullptr)
+{
+}
+
+bool surface::init()
+{
+   surface_queue = wl_display_create_queue(wayland_display);
+
+   if (surface_queue == nullptr)
+   {
+      WSI_LOG_ERROR("Failed to create wl surface queue.");
+      return false;
+   }
+
+   auto display_proxy = make_proxy_with_queue(wayland_display, surface_queue);
+   if (display_proxy == nullptr)
+   {
+      WSI_LOG_ERROR("Failed to create wl display proxy.");
+      return false;
+   };
+
+   auto registry = registry_owner{ wl_display_get_registry(display_proxy.get()) };
+   if (registry == nullptr)
+   {
+      WSI_LOG_ERROR("Failed to get wl display registry.");
+      return false;
+   }
+
+   const wl_registry_listener registry_listener = { registry_handler };
+   int res = wl_registry_add_listener(registry.get(), &registry_listener, &dmabuf_interface);
+   if (res < 0)
+   {
+      WSI_LOG_ERROR("Failed to add registry listener.");
+      return false;
+   }
+
+   res = wl_display_roundtrip_queue(wayland_display, surface_queue);
+   if (res < 0)
+   {
+      WSI_LOG_ERROR("Roundtrip failed.");
+      return false;
+   }
+
+   if (dmabuf_interface.get() == nullptr)
+   {
+      WSI_LOG_ERROR("Failed to obtain zwp_linux_dma_buf_v1 interface.");
+      return false;
+   }
+
+   VkResult vk_res =
+      get_supported_formats_and_modifiers(wayland_display, surface_queue, dmabuf_interface.get(), supported_formats);
+   if (vk_res != VK_SUCCESS)
+   {
+      return false;
+   }
+
+   return true;
+}
+
+util::unique_ptr<surface> surface::make_surface(const util::allocator &allocator, wl_display *display,
+                                                wl_surface *surf)
+{
+   init_parameters params {allocator, display, surf};
+   auto wsi_surface = allocator.make_unique<surface>(params);
+   if (wsi_surface != nullptr)
+   {
+      if (wsi_surface->init())
+      {
+         return wsi_surface;
+      }
+   }
+   return nullptr;
+}
+
+surface::~surface()
+{
+   if (surface_queue != nullptr)
+   {
+      wl_event_queue_destroy(surface_queue);
+   }
+}
+
 wsi::surface_properties &surface::get_properties()
 {
-   return surface_properties::get_instance();
+   return properties;
 }
 
 util::unique_ptr<swapchain_base> surface::allocate_swapchain(layer::device_private_data &dev_data,
                                                              const VkAllocationCallbacks *allocator)
 {
    util::allocator alloc{ dev_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, allocator };
-   return util::unique_ptr<swapchain_base>(alloc.make_unique<swapchain>(dev_data, allocator));
+   return util::unique_ptr<swapchain_base>(alloc.make_unique<swapchain>(dev_data, allocator, *this));
 }
 
 } // namespace wayland
index 12c1462..8bc0fdb 100644 (file)
 
 #pragma once
 
+#include <wayland-client.h>
+
 #include "wsi/surface.hpp"
+#include "surface_properties.hpp"
+#include "wl_object_owner.hpp"
 
 namespace wsi
 {
 namespace wayland
 {
 
+struct drm_format_pair
+{
+   uint32_t fourcc;
+   uint64_t modifier;
+};
+
 class surface : public wsi::surface
 {
 public:
-   surface() = default;
+   surface() = delete;
+   struct init_parameters;
+
+   /** Constructor to allow for custom allocation, but require privately defined arguments. */
+   surface(const init_parameters&);
+
+   /**
+    * @brief Allocates and initializes a surface
+    *
+    * @param allocator An allocator to use for host allocations needed for the surface.
+    * @param display   The Wayland display used to create the VkSurface
+    * @param surf      The Wayland surface used to create the VkSurface
+    *
+    * @return A constructed and initalized surface or nullptr on failure
+    */
+   static util::unique_ptr<surface> make_surface(const util::allocator &allocator, wl_display *display,
+                                                 wl_surface *surf);
+
+   /** Destructor */
+   ~surface() override;
 
    wsi::surface_properties &get_properties() override;
    util::unique_ptr<swapchain_base> allocate_swapchain(layer::device_private_data &dev_data,
                                                        const VkAllocationCallbacks *allocator) override;
+
+   /** Returns the Wayland display */
+   wl_display *get_wl_display() const
+   {
+      return wayland_display;
+   }
+
+   /** Returns the Wayland surface */
+   wl_surface *get_wl_surface() const
+   {
+      return wayland_surface;
+   }
+
+   /**
+    * @brief Returns a pointer to the Wayland zwp_linux_dmabuf_v1 interface.
+    *
+    * The raw pointer is valid throughout the lifetime of this surface.
+    */
+   zwp_linux_dmabuf_v1 *get_dmabuf_interface()
+   {
+      return dmabuf_interface.get();
+   }
+
+   /**
+    * @brief Returns a reference to a list of DRM formats supported by the Wayland surface.
+    *
+    * The reference is valid throughout the lifetime of this surface.
+    */
+   const util::vector<drm_format_pair> &get_formats() const
+   {
+      return supported_formats;
+   }
+
+private:
+   /**
+    * @brief Initialize the WSI surface by creating Wayland queues and linking to Wayland protocols.
+    *
+    * @return true on success, false otherwise.
+    */
+   bool init();
+
+   /** The native Wayland display */
+   wl_display *wayland_display;
+   /** The native Wayland surface */
+   wl_surface *wayland_surface;
+   /** A list of DRM formats supported by the Wayland compositor on this surface */
+   util::vector<drm_format_pair> supported_formats;
+   /** Surface properties specific to the Wayland surface. */
+   surface_properties properties;
+
+   /** Container for the zwp_linux_dmabuf_v1 interface binding */
+   zwp_linux_dmabuf_v1_owner dmabuf_interface;
+   /** Private queue for surface events generated by the layer */
+   wl_event_queue *surface_queue;
 };
 
 } // namespace wayland
index 2da5e1d..7622c4a 100644 (file)
@@ -47,15 +47,17 @@ namespace wsi
 namespace wayland
 {
 
-struct vk_format_hasher
+surface_properties::surface_properties(surface &wsi_surface, const util::allocator &allocator)
+   : specific_surface(&wsi_surface)
+   , supported_formats(allocator)
 {
-   size_t operator()(const VkFormat format) const
-   {
-      return std::hash<uint64_t>()(static_cast<uint64_t>(format));
-   }
-};
+}
 
-using vk_format_set = std::unordered_set<VkFormat, vk_format_hasher>;
+surface_properties::surface_properties()
+   : specific_surface(nullptr)
+   , supported_formats(util::allocator::get_generic())
+{
+}
 
 surface_properties &surface_properties::get_instance()
 {
@@ -100,118 +102,64 @@ VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_
    return VK_SUCCESS;
 }
 
-static void get_vk_supported_formats(const util::vector<drm_format_pair> &drm_supported_formats,
-                                     vk_format_set &vk_supported_formats)
+static VkResult get_vk_supported_formats(const util::vector<drm_format_pair> &drm_supported_formats,
+                                         vk_format_set &vk_supported_formats)
 {
    for (const auto &drm_format : drm_supported_formats)
    {
       const VkFormat vk_format = util::drm::drm_to_vk_format(drm_format.fourcc);
       if (vk_format != VK_FORMAT_UNDEFINED)
       {
-         const VkFormat srgb_vk_format = util::drm::drm_to_vk_srgb_format(drm_format.fourcc);
-         if (srgb_vk_format != VK_FORMAT_UNDEFINED)
+         auto it = vk_supported_formats.try_insert(vk_format);
+         if (!it.has_value())
          {
-            vk_supported_formats.insert({srgb_vk_format, vk_format});
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
          }
-         else
+      }
+      const VkFormat srgb_vk_format = util::drm::drm_to_vk_srgb_format(drm_format.fourcc);
+      if (srgb_vk_format != VK_FORMAT_UNDEFINED)
+      {
+         auto it = vk_supported_formats.try_insert(srgb_vk_format);
+         if (!it.has_value())
          {
-            vk_supported_formats.insert(vk_format);
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
          }
       }
    }
-}
-
-/*
- * @brief Query a surface's supported formats from the compositor.
- *
- * @details A wl_registry is created in order to get a zwp_linux_dmabuf_v1 object.
- * Then a listener is attached to that object in order to get the supported formats
- * from the server. The supported formats are stored in @p vk_supported_formats.
- *
- * @param[in]  surface                  The surface, which the supported formats
- *                                      are for.
- * @param[out] vk_supported_formats     unordered_set which will store the supported
- *                                      formats.
- *
- * @retval VK_SUCCESS                    Indicates success.
- * @retval VK_ERROR_SURFACE_LOST_KHR     Indicates one of the Wayland functions failed.
- * @retval VK_ERROR_OUT_OF_DEVICE_MEMORY Indicates the host went out of memory.
- */
-static VkResult query_supported_formats(
-   const VkSurfaceKHR surface, vk_format_set &vk_supported_formats, const util::allocator& allocator)
-{
-   const VkIcdSurfaceWayland *vk_surf = reinterpret_cast<VkIcdSurfaceWayland *>(surface);
-   wl_display *display = vk_surf->display;
-
-   auto registry = registry_owner{wl_display_get_registry(display)};
-   if (registry.get() == nullptr)
-   {
-      WSI_LOG_ERROR("Failed to get wl display registry.");
-      return VK_ERROR_SURFACE_LOST_KHR;
-   }
-
-   auto dmabuf_interface = zwp_linux_dmabuf_v1_owner{nullptr};
-   const wl_registry_listener registry_listener = { registry_handler };
-   int res = wl_registry_add_listener(registry.get(), &registry_listener, &dmabuf_interface);
-   if (res < 0)
-   {
-      WSI_LOG_ERROR("Failed to add registry listener.");
-      return VK_ERROR_SURFACE_LOST_KHR;
-   }
-
-   /* Get the dma buf interface. */
-   res = wl_display_roundtrip(display);
-   if (res < 0)
-   {
-      WSI_LOG_ERROR("Roundtrip failed.");
-      return VK_ERROR_SURFACE_LOST_KHR;
-   }
-
-   if (dmabuf_interface.get() == nullptr)
-   {
-      return VK_ERROR_SURFACE_LOST_KHR;
-   }
-
-   util::vector<drm_format_pair> drm_supported_formats{allocator};
-   const VkResult ret = get_supported_formats_and_modifiers(display, dmabuf_interface.get(), drm_supported_formats);
-   if (ret != VK_SUCCESS)
-   {
-      return ret == VK_ERROR_UNKNOWN ? VK_ERROR_SURFACE_LOST_KHR : ret;
-   }
-
-   get_vk_supported_formats(drm_supported_formats, vk_supported_formats);
-
-   return ret;
+   return VK_SUCCESS;
 }
 
 VkResult surface_properties::get_surface_formats(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
                                                  uint32_t *surfaceFormatCount, VkSurfaceFormatKHR *surfaceFormats)
 {
-   vk_format_set formats;
-
    auto &instance = layer::instance_private_data::get(physical_device);
-   const auto query_res = query_supported_formats(surface, formats, instance.get_allocator());
-   if (query_res != VK_SUCCESS)
+
+   assert(specific_surface);
+   if (!supported_formats.size())
    {
-      return query_res;
+      VkResult res = get_vk_supported_formats(specific_surface->get_formats(), supported_formats);
+      if (res != VK_SUCCESS)
+      {
+         return res;
+      }
    }
 
    assert(surfaceFormatCount != nullptr);
    if (nullptr == surfaceFormats)
    {
-      *surfaceFormatCount = formats.size();
+      *surfaceFormatCount = supported_formats.size();
       return VK_SUCCESS;
    }
 
    VkResult res = VK_SUCCESS;
 
-   if (formats.size() > *surfaceFormatCount)
+   if (supported_formats.size() > *surfaceFormatCount)
    {
       res = VK_INCOMPLETE;
    }
 
    uint32_t format_count = 0;
-   for (const auto &format : formats)
+   for (const auto &format : supported_formats)
    {
       if (format_count >= *surfaceFormatCount)
       {
@@ -287,15 +235,17 @@ extern "C" VkResult CreateWaylandSurfaceKHR(VkInstance instance, const VkWayland
 {
    auto &instance_data = layer::instance_private_data::get(instance);
    util::allocator allocator{ instance_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, pAllocator };
-   auto wsi_surface = util::unique_ptr<wsi::surface>(allocator.make_unique<surface>());
+   auto wsi_surface = surface::make_surface(allocator, pCreateInfo->display, pCreateInfo->surface);
    if (wsi_surface == nullptr)
    {
       return VK_ERROR_OUT_OF_HOST_MEMORY;
    }
+
    VkResult res = instance_data.disp.CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
    if (res == VK_SUCCESS)
    {
-      res = instance_data.add_surface(*pSurface, wsi_surface);
+      auto surface_base = util::unique_ptr<wsi::surface>(std::move(wsi_surface));
+      res = instance_data.add_surface(*pSurface, surface_base);
       if (res != VK_SUCCESS)
       {
          instance_data.disp.DestroySurfaceKHR(instance, *pSurface, pAllocator);
index 755c9c4..75e4491 100644 (file)
 #pragma once
 
 #include "wsi/surface_properties.hpp"
+#include "util/unordered_set.hpp"
 
 namespace wsi
 {
 namespace wayland
 {
 
+struct vk_format_hasher
+{
+   size_t operator()(const VkFormat format) const
+   {
+      return std::hash<uint64_t>()(static_cast<uint64_t>(format));
+   }
+};
+
+using vk_format_set = util::unordered_set<VkFormat, vk_format_hasher>;
+
+class surface;
+
 class surface_properties : public wsi::surface_properties
 {
 public:
+   surface_properties(surface &wsi_surface, const util::allocator &alloc);
+
    static surface_properties &get_instance();
 
    VkResult get_surface_capabilities(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
@@ -46,6 +61,16 @@ public:
    VkResult get_required_device_extensions(util::extension_list &extension_list) override;
 
    PFN_vkVoidFunction get_proc_addr(const char *name) override;
+
+private:
+   surface_properties();
+
+   /** If the properties are specific to a @ref wsi::wayland::surface this is a pointer to it. Can be nullptr for
+    * generic Wayland surface properties.
+    */
+   surface *specific_surface;
+   /** Set of supported Vulkan formats by the @ref specific_surface. */
+   vk_format_set supported_formats;
 };
 
 } // namespace wayland
index d7a00f7..5ea2e48 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "swapchain.hpp"
 #include "wl_helpers.hpp"
+#include "surface_properties.hpp"
 
 #include <stdint.h>
 #include <cstring>
@@ -47,24 +48,6 @@ namespace wsi
 namespace wayland
 {
 
-template <typename T>
-static std::unique_ptr<T, std::function<void(T *)>>
-make_proxy_with_queue(T *object, wl_event_queue *queue)
-{
-   auto proxy = reinterpret_cast<T *>(wl_proxy_create_wrapper(object));
-   if (proxy != nullptr)
-   {
-      wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(proxy), queue);
-   }
-
-   auto delete_proxy = [](T *proxy)
-   {
-      wl_proxy_wrapper_destroy(reinterpret_cast<wl_proxy *>(proxy));
-   };
-
-   return std::unique_ptr<T, std::function<void(T *)>>(proxy, delete_proxy);
-}
-
 const VkImageAspectFlagBits plane_flag_bits[MAX_PLANES] = {
    VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
    VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
@@ -84,12 +67,13 @@ struct swapchain::wayland_image_data
    uint32_t num_planes;
 };
 
-swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator)
+swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator,
+                     surface &wsi_surface)
    : swapchain_base(dev_data, pAllocator)
-   , m_display(nullptr)
-   , m_surface(nullptr)
-   , m_dmabuf_interface(nullptr)
-   , m_surface_queue(nullptr)
+   , m_display(wsi_surface.get_wl_display())
+   , m_surface(wsi_surface.get_wl_surface())
+   , m_dmabuf_interface(wsi_surface.get_dmabuf_interface())
+   , m_swapchain_queue(nullptr)
    , m_buffer_queue(nullptr)
    , m_wsi_allocator(nullptr)
    , m_present_pending(false)
@@ -102,9 +86,9 @@ swapchain::~swapchain()
 
    wsialloc_delete(m_wsi_allocator);
    m_wsi_allocator = nullptr;
-   if (m_surface_queue != nullptr)
+   if (m_swapchain_queue != nullptr)
    {
-      wl_event_queue_destroy(m_surface_queue);
+      wl_event_queue_destroy(m_swapchain_queue);
    }
    if (m_buffer_queue != nullptr)
    {
@@ -112,65 +96,25 @@ swapchain::~swapchain()
    }
 }
 
-struct display_queue
-{
-   wl_display *display;
-   wl_event_queue *queue;
-};
-
 VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo)
 {
-   VkIcdSurfaceWayland *vk_surf = reinterpret_cast<VkIcdSurfaceWayland *>(pSwapchainCreateInfo->surface);
-
-   m_display = vk_surf->display;
-   m_surface = vk_surf->surface;
-
-   m_surface_queue = wl_display_create_queue(m_display);
-
-   if (m_surface_queue == nullptr)
+   if ((m_display == nullptr) || (m_surface == nullptr) || (m_dmabuf_interface == nullptr))
    {
-      WSI_LOG_ERROR("Failed to create wl surface display_queue.");
       return VK_ERROR_INITIALIZATION_FAILED;
    }
 
-   m_buffer_queue = wl_display_create_queue(m_display);
-   if (m_buffer_queue == nullptr)
-   {
-      WSI_LOG_ERROR("Failed to create wl buffer display_queue.");
-      return VK_ERROR_INITIALIZATION_FAILED;
-   }
-
-   auto display_proxy = make_proxy_with_queue(m_display, m_surface_queue);
-   if (display_proxy == nullptr)
-   {
-      WSI_LOG_ERROR("Failed to create wl display proxy.");
-      return VK_ERROR_INITIALIZATION_FAILED;
-   }
+   m_swapchain_queue = wl_display_create_queue(m_display);
 
-   auto registry = registry_owner{ wl_display_get_registry(display_proxy.get()) };
-   if (registry == nullptr)
+   if (m_swapchain_queue == nullptr)
    {
-      WSI_LOG_ERROR("Failed to get wl display registry.");
+      WSI_LOG_ERROR("Failed to create swapchain wl queue.");
       return VK_ERROR_INITIALIZATION_FAILED;
    }
 
-   const wl_registry_listener registry_listener = { registry_handler };
-   int res = wl_registry_add_listener(registry.get(), &registry_listener, &m_dmabuf_interface);
-   if (res < 0)
-   {
-      WSI_LOG_ERROR("Failed to add registry listener.");
-      return VK_ERROR_INITIALIZATION_FAILED;
-   }
-
-   res = wl_display_roundtrip_queue(m_display, m_surface_queue);
-   if (res < 0)
-   {
-      WSI_LOG_ERROR("Roundtrip failed.");
-      return VK_ERROR_INITIALIZATION_FAILED;
-   }
-
-   if (m_dmabuf_interface.get() == nullptr)
+   m_buffer_queue = wl_display_create_queue(m_display);
+   if (m_buffer_queue == nullptr)
    {
+      WSI_LOG_ERROR("Failed to create buffer wl queue.");
       return VK_ERROR_INITIALIZATION_FAILED;
    }
 
@@ -594,7 +538,7 @@ VkResult swapchain::create_image(VkImageCreateInfo image_create_info, swapchain_
    }
 
    /* create a wl_buffer using the dma_buf protocol */
-   auto dmabuf_interface_proxy = make_proxy_with_queue(m_dmabuf_interface.get(), m_surface_queue);
+   auto dmabuf_interface_proxy = make_proxy_with_queue(m_dmabuf_interface, m_swapchain_queue);
    if (dmabuf_interface_proxy == nullptr)
    {
       WSI_LOG_ERROR("Failed to allocate dma-buf interface proxy.");
@@ -622,7 +566,7 @@ VkResult swapchain::create_image(VkImageCreateInfo image_create_info, swapchain_
 
    /* TODO: don't roundtrip - we should be able to send the create request now,
     * and only wait for it on first present. only do this once, not for all buffers created */
-   res = wl_display_roundtrip_queue(m_display, m_surface_queue);
+   res = wl_display_roundtrip_queue(m_display, m_swapchain_queue);
    if (res < 0)
    {
       destroy_image(image);
@@ -679,7 +623,7 @@ void swapchain::present_image(uint32_t pendingIndex)
           * time if the compositor isn't responding (perhaps because the
           * window is hidden).
           */
-         res = dispatch_queue(m_display, m_surface_queue, -1);
+         res = dispatch_queue(m_display, m_swapchain_queue, -1);
       } while (res > 0 && m_present_pending);
 
       if (res <= 0)
@@ -697,7 +641,7 @@ void swapchain::present_image(uint32_t pendingIndex)
    if (m_present_mode == VK_PRESENT_MODE_FIFO_KHR)
    {
       /* request a hint when we can present the _next_ frame */
-      auto surface_proxy = make_proxy_with_queue(m_surface, m_surface_queue);
+      auto surface_proxy = make_proxy_with_queue(m_surface, m_swapchain_queue);
       if (surface_proxy == nullptr)
       {
          WSI_LOG_ERROR("failed to create wl_surface proxy");
index d9941fe..2f99ad3 100644 (file)
@@ -34,6 +34,7 @@ extern "C" {
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include "util/wsialloc/wsialloc.h"
 #include "wl_object_owner.hpp"
+#include "surface.hpp"
 
 namespace wsi
 {
@@ -43,7 +44,8 @@ namespace wayland
 class swapchain : public wsi::swapchain_base
 {
 public:
-   explicit swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *allocator);
+   explicit swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *allocator,
+                      surface &wsi_surface);
 
    ~swapchain();
 
@@ -108,10 +110,9 @@ private:
 
    struct wl_display *m_display;
    struct wl_surface *m_surface;
-   zwp_linux_dmabuf_v1_owner m_dmabuf_interface;
-
+   struct zwp_linux_dmabuf_v1 *m_dmabuf_interface;
    /* The queue on which we dispatch the swapchain related events, mostly frame completion */
-   struct wl_event_queue *m_surface_queue;
+   struct wl_event_queue *m_swapchain_queue;
    /* The queue on which we dispatch buffer related events, mostly buffer_release */
    struct wl_event_queue *m_buffer_queue;
 
index 1d453c2..0d400b4 100644 (file)
 
 #include "util/log.hpp"
 
-struct formats_vector
-{
-   util::vector<drm_format_pair> *formats{nullptr};
-   bool is_out_of_memory{false};
-};
-
-namespace
-{
-   /* Handler for format event of the zwp_linux_dmabuf_v1 interface. */
-   extern "C" void dma_buf_format_handler(void *data,
-                                          struct zwp_linux_dmabuf_v1 *dma_buf,
-                                          uint32_t drm_format) {}
-
-   /* Handler for modifier event of the zwp_linux_dmabuf_v1 interface. */
-   extern "C" void dma_buf_modifier_handler(void *data,
-                                            struct zwp_linux_dmabuf_v1 *dma_buf,
-                                            uint32_t drm_format, uint32_t modifier_hi,
-                                            uint32_t modifier_low)
-   {
-      auto *drm_supported_formats = reinterpret_cast<formats_vector *>(data);
-
-      drm_format_pair format = {};
-      format.fourcc = drm_format;
-      format.modifier = (static_cast<uint64_t>(modifier_hi) << 32) | modifier_low;
-
-      if (!drm_supported_formats->formats->try_push_back(format))
-      {
-         drm_supported_formats->is_out_of_memory = true;
-      }
-   }
-}
-
-VkResult get_supported_formats_and_modifiers(
-   wl_display* display, zwp_linux_dmabuf_v1 *dmabuf_interface,
-   util::vector<drm_format_pair> &supported_formats)
-{
-   formats_vector drm_supported_formats;
-   drm_supported_formats.formats = &supported_formats;
-
-   const zwp_linux_dmabuf_v1_listener dma_buf_listener = {
-      .format = dma_buf_format_handler, .modifier = dma_buf_modifier_handler,
-   };
-   int res = zwp_linux_dmabuf_v1_add_listener(dmabuf_interface, &dma_buf_listener,
-                                              &drm_supported_formats);
-   if (res < 0)
-   {
-      WSI_LOG_ERROR("Failed to add zwp_linux_dmabuf_v1 listener.");
-      return VK_ERROR_UNKNOWN;
-   }
-
-   /* Get all modifier events. */
-   res = wl_display_roundtrip(display);
-   if (res < 0)
-   {
-      WSI_LOG_ERROR("Roundtrip failed.");
-      return VK_ERROR_UNKNOWN;
-   }
-
-   if (drm_supported_formats.is_out_of_memory)
-   {
-      WSI_LOG_ERROR("Host got out of memory.");
-      return VK_ERROR_OUT_OF_HOST_MEMORY;
-   }
-
-   return VK_SUCCESS;
-}
-
 extern "C" {
 
    void registry_handler(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface,
index f1a6369..e19093f 100644 (file)
 #include <wayland-client.h>
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include "util/custom_allocator.hpp"
-struct drm_format_pair
-{
-   uint32_t fourcc;
-   uint64_t modifier;
-};
-
-/*
- * @brief Get supported formats and modifiers using the zwp_linux_dmabuf_v1 interface.
- *
- * @param[in]  display               The wl_display that is being used.
- * @param[in]  dmabuf_interface      Object of the zwp_linux_dmabuf_v1 interface.
- * @param[out] supported_formats     Vector which will contain the supported drm
- *                                   formats and their modifiers.
- *
- * @retval VK_SUCCESS                    Indicates success.
- * @retval VK_ERROR_UNKNOWN              Indicates one of the Wayland functions failed.
- * @retval VK_ERROR_OUT_OF_DEVICE_MEMORY Indicates the host went out of memory.
- */
-VkResult get_supported_formats_and_modifiers(
-   struct wl_display* display, struct zwp_linux_dmabuf_v1 *dmabuf_interface,
-   util::vector<drm_format_pair> &supported_formats);
 
 extern "C" {
    void registry_handler(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface,
index fc5208d..c291c2d 100644 (file)
@@ -57,5 +57,20 @@ struct dmabuf_deleter
 
 using registry_owner = std::unique_ptr<wl_registry, registry_deleter>;
 using zwp_linux_dmabuf_v1_owner = std::unique_ptr<zwp_linux_dmabuf_v1, dmabuf_deleter>;
+
+template <typename T>
+static std::unique_ptr<T, std::function<void(T *)>> make_proxy_with_queue(T *object, wl_event_queue *queue)
+{
+   auto proxy = reinterpret_cast<T *>(wl_proxy_create_wrapper(object));
+   if (proxy != nullptr)
+   {
+      wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(proxy), queue);
+   }
+
+   auto delete_proxy = [](T *proxy) { wl_proxy_wrapper_destroy(reinterpret_cast<wl_proxy *>(proxy)); };
+
+   return std::unique_ptr<T, std::function<void(T *)>>(proxy, delete_proxy);
+}
+
 } // namespace wayland
 } // namespace wsi