#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 ¶ms)
+ : 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(), ®istry_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
#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
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()
{
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(), ®istry_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)
{
{
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);
#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,
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
#include "swapchain.hpp"
#include "wl_helpers.hpp"
+#include "surface_properties.hpp"
#include <stdint.h>
#include <cstring>
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,
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)
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)
{
}
}
-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(), ®istry_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;
}
}
/* 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.");
/* 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);
* 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)
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");
#include <linux-dmabuf-unstable-v1-client-protocol.h>
#include "util/wsialloc/wsialloc.h"
#include "wl_object_owner.hpp"
+#include "surface.hpp"
namespace wsi
{
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();
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;
#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,
#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,
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