wsi: Move common objects to the wayland wsi::surface

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>
This commit is contained in:
Rosen Zhelev 2021-07-22 23:49:15 +01:00
parent c7be05e3ff
commit 24f18c6c44
9 changed files with 367 additions and 261 deletions

View file

@ -29,22 +29,198 @@
#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

View file

@ -28,21 +28,104 @@
#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

View 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);

View file

@ -25,15 +25,30 @@
#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

View 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_swapchain_queue = wl_display_create_queue(m_display);
if (m_swapchain_queue == nullptr)
{
WSI_LOG_ERROR("Failed to create swapchain wl 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;
}
auto registry = registry_owner{ wl_display_get_registry(display_proxy.get()) };
if (registry == nullptr)
{
WSI_LOG_ERROR("Failed to get wl display registry.");
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)
{
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");

View 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;

View file

@ -34,73 +34,6 @@
#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,

View file

@ -28,27 +28,6 @@
#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,

View 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