mirror of
https://gitlab.freedesktop.org/mesa/vulkan-wsi-layer.git
synced 2026-05-08 21:58:04 +02:00
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:
parent
c7be05e3ff
commit
24f18c6c44
9 changed files with 367 additions and 261 deletions
|
|
@ -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 ¶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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(), ®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)
|
||||
{
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(), ®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)
|
||||
{
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue