Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 121 additions & 1 deletion 3rdparty/wlroots/include/render/vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <wayland-util.h>
#include <vulkan/vulkan.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/render/wlr_texture.h>
Expand Down Expand Up @@ -44,6 +45,7 @@ struct wlr_vk_device {
bool sync_file_import_export;
bool implicit_sync_interop;
bool sampler_ycbcr_conversion;
bool separate_depth_stencil_layouts;

// we only ever need one queue for rendering and transfer commands
uint32_t queue_family;
Expand Down Expand Up @@ -98,6 +100,7 @@ const struct wlr_vk_format *vulkan_get_format_from_drm(uint32_t drm_format);
struct wlr_vk_format_modifier_props {
VkDrmFormatModifierPropertiesEXT props;
VkExtent2D max_extent;
VkExtent2D transfer_src_max_extent;
bool has_mutable_srgb;
};

Expand Down Expand Up @@ -234,6 +237,7 @@ struct wlr_vk_render_buffer {
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
uint32_t mem_count;
VkImage image;
VkImageUsageFlags image_usage;

// Framebuffer and image view for rendering directly onto the buffer image,
// without any color transform.
Expand Down Expand Up @@ -290,6 +294,44 @@ struct wlr_vk_command_buffer {

#define VULKAN_COMMAND_BUFFERS_CAP 64

// Binary semaphore holding an imported foreign-texture DMA-BUF sync_file.
// Reusable once the texture_sync timeline semaphore reaches release_point.
struct wlr_vk_texture_sync_sem {
VkSemaphore semaphore;
uint64_t release_point;
};

// Append a wlr_buffer pointer to an append-only alias tracking list (dedup).
// Stale entries after buffer destruction may alias recycled pointers, which
// only ever adds a conservative extra memory dependency. Returns false when
// the allocation failed (the entry was then not added).
static inline bool vulkan_alias_list_add(struct wl_array *list,
struct wlr_buffer *buffer) {
struct wlr_buffer **entry;
wl_array_for_each(entry, list) {
if (*entry == buffer) {
return true;
}
}
struct wlr_buffer **slot = wl_array_add(list, sizeof(*slot));
if (slot == NULL) {
return false;
}
*slot = buffer;
return true;
}

static inline bool vulkan_alias_list_contains(const struct wl_array *list,
struct wlr_buffer *buffer) {
const struct wlr_buffer **entry;
wl_array_for_each(entry, list) {
if (*entry == buffer) {
return true;
}
}
return false;
}

// Vulkan wlr_renderer implementation on top of a wlr_vk_device.
struct wlr_vk_renderer {
struct wlr_renderer wlr_renderer;
Expand Down Expand Up @@ -326,6 +368,72 @@ struct wlr_vk_renderer {
VkSemaphore timeline_semaphore;
uint64_t timeline_point;

// Frame-batched waiting on foreign texture DMA-BUF sync_files (Qt/QRhi
// path). Unsignaled sync_files are imported into binary semaphores and
// waited on by a bridge command buffer. Its pipeline barrier extends the
// wait dependency to the later Qt submission on the same queue.
VkSemaphore texture_sync_timeline_semaphore;
uint64_t texture_sync_timeline_point;
struct wl_array texture_sync_semaphores; // struct wlr_vk_texture_sync_sem
struct wl_array texture_sync_pending; // private texture sync wait entries
struct wl_array texture_sync_wait_infos; // VkSemaphoreSubmitInfoKHR scratch
bool texture_sync_batch_active;
bool texture_sync_force_poll; // env WLR_VK_FORCE_SYNC_POLL

// Per-pass batching of foreign-texture acquire/release barriers (Qt/QRhi
// path). Instead of emitting one vkCmdPipelineBarrier per texture, the
// barriers are accumulated while a batch is active and recorded as a
// single call before (acquire phase) or after (release phase) the Qt draw.
struct wl_array texture_acquire_barriers; // VkImageMemoryBarrier
struct wl_array texture_release_barriers; // VkImageMemoryBarrier
// struct wlr_vk_texture * parallel to the barrier arrays above. A deferred
// barrier that is discarded without being recorded (batch abort, or a
// flush without a command buffer) must roll the per-texture ownership
// bookkeeping back, otherwise qt_sampling_acquired would claim a transfer
// that never happened.
struct wl_array texture_acquire_textures; // struct wlr_vk_texture *
struct wl_array texture_release_textures; // struct wlr_vk_texture *
// Set while a batch is active when a texture about to be sampled aliases
// (second import of the same DMA-BUF) a buffer that was rendered as a
// color attachment and is recorded in frame_render_buffers. The producer's
// writes happened through the other logical VkImage, so neither an
// ownership-transfer acquire (its source access mask is ignored) nor an
// image barrier naming the sampled image covers them in its memory scope:
// §Memory Aliasing requires a memory dependency, and only a global
// (resource-free) memory barrier can span the two aliases. One such
// barrier is recorded when the batch flushes.
bool frame_producer_alias_dep;
bool texture_barrier_batch_active;
bool texture_barrier_batch_release; // current batch is the release phase

// wlr_buffer * rendered as a color attachment by the current frame's
// command buffer (output, layer, and cursor render buffers). Append-only
// with dedup, cleared by waylib_vk_renderer_reset_frame_alias_lists() at
// the compositor frame boundary: same-queue submission order already
// covers next-frame dependencies, so the lists only need to span one
// frame's recording. Stale entries would only ever add a conservative
// extra dependency, never remove one.
struct wl_array frame_render_buffers;
// wlr_buffer * sampled as a texture by the (Qt/QRhi) frame's command
// buffer. Same lifecycle and conservative policy as
// frame_render_buffers: a render-buffer acquire for one of these buffers
// records a global read-before-write (WAR) alias dependency, because the
// sampling may have read the aliased memory through another logical
// image whose barriers are out of this image's access scope.
struct wl_array frame_sampled_buffers;

// Force the legacy blocking staging-upload path instead of the
// GPU-side asynchronous one (env WLR_VK_FORCE_STAGE_BLOCK).
bool stage_force_block;
// Enable the GPU-side asynchronous staging-upload path. Must only be set
// once the consumer (Qt/QRhi) is confirmed to submit to the same VkQueue,
// since the path relies on the same-queue texture-sync bridge to order the
// upload before the uploaded texture is sampled.
bool stage_async_enabled;
// A stage upload was submitted asynchronously and needs the texture-sync
// bridge barrier before the consumer submits its command buffer.
bool stage_async_needs_bridge;

size_t last_pool_size;
struct wl_list descriptor_pools; // wlr_vk_descriptor_pool.link
struct wl_list render_format_setups; // wlr_vk_render_format_setup.link
Expand Down Expand Up @@ -408,6 +516,13 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer);
// finished execution.
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);

// Submits the current stage command buffer without blocking the CPU. The
// staging buffers it used are hidden in the command buffer's stage_buffers
// list and reclaimed once its timeline point is reached. Callers that sample
// the uploaded content must flush the texture-sync bridge and then submit
// their own command buffer to the same queue.
bool vulkan_submit_stage_async(struct wlr_vk_renderer *renderer);

struct wlr_vk_render_pass_texture {
struct wlr_vk_texture *texture;

Expand Down Expand Up @@ -497,6 +612,11 @@ struct wlr_vk_texture {
struct wlr_vk_command_buffer *last_used_cb; // to track when it can be destroyed
bool dmabuf_imported;
bool owned; // if dmabuf_imported: whether we have ownership of the image
bool qt_sampling_acquired; // waylib/Qt-only bookkeeping: the Qt Quick RHI
// path (waylib_vk_renderer_prepare_texture_for_sampling() /
// waylib_vk_renderer_begin_readback()) currently holds a foreign->own
// acquire. Decoupled from 'owned', which is reserved for wlroots' own render-pass bookkeeping.
bool readback_acquired; // waylib/Qt-only: a readback acquire is in flight
bool transitioned; // if dma_imported: whether we transitioned it away from preinit
bool has_alpha; // whether the image is has alpha channel
bool using_mutable_srgb; // can be accessed through _SRGB format view
Expand All @@ -515,7 +635,7 @@ struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);
VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
const struct wlr_dmabuf_attributes *attribs,
VkDeviceMemory mems[static WLR_DMABUF_MAX_PLANES], uint32_t *n_mems,
bool for_render, bool *using_mutable_srgb);
bool for_render, bool *using_mutable_srgb, VkImageUsageFlags *image_usage);
struct wlr_texture *vulkan_texture_from_buffer(
struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer);
void vulkan_texture_destroy(struct wlr_vk_texture *texture);
Expand Down
91 changes: 91 additions & 0 deletions 3rdparty/wlroots/include/wlr/render/vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct wlr_vk_image_attribs {
VkImage image;
VkImageLayout layout;
VkFormat format;
VkImageUsageFlags usage;
};

struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd);
Expand Down Expand Up @@ -49,4 +50,94 @@ bool waylib_vk_renderer_record_render_buffer_release(struct wlr_renderer *render
struct wlr_buffer *buffer, VkCommandBuffer cb, VkImageLayout old_layout);
bool waylib_vk_renderer_flush_stage(struct wlr_renderer *renderer);

/* waylib extensions (not upstream): Qt Quick RHI texture-sampling helpers. */
VkQueue waylib_vk_renderer_get_queue(struct wlr_renderer *renderer);
bool waylib_vk_renderer_has_separate_depth_stencil_layouts(
struct wlr_renderer *renderer);

// Prepare a wlroots-owned Vulkan texture for sampling on the given command
// buffer, transitioning it to SHADER_READ_ONLY_OPTIMAL and transferring queue
// ownership to the graphics queue if it is not already owned. The optional
// attribs out-parameter receives the texture's image attributes.
bool waylib_vk_renderer_prepare_texture_for_sampling(struct wlr_renderer *renderer,
struct wlr_texture *texture, VkCommandBuffer cb,
struct wlr_vk_image_attribs *attribs);
bool waylib_vk_renderer_finish_texture_sampling(struct wlr_renderer *renderer,
struct wlr_texture *texture, VkCommandBuffer cb);

// Collect foreign-texture sync_files while a compositor frame is recorded,
// then submit one semaphore wait with a bridge barrier before the compositor
// command buffer is submitted to the same queue. The barrier extends the wait
// dependency to that later submission. The abort function is idempotent.
bool waylib_vk_renderer_begin_texture_sync_batch(struct wlr_renderer *renderer);
bool waylib_vk_renderer_flush_texture_sync_batch(struct wlr_renderer *renderer);
void waylib_vk_renderer_abort_texture_sync_batch(struct wlr_renderer *renderer);

// Batch the per-texture queue-family-ownership/layout barriers that
// waylib_vk_renderer_prepare_texture_for_sampling() and
// waylib_vk_renderer_finish_texture_sampling() would otherwise emit one at a
// time. Begin a batch (release=false for the pre-draw acquire phase,
// release=true for the post-draw release phase), call prepare/finish for each
// texture, then flush once to record a single vkCmdPipelineBarrier covering
// every accumulated texture. While a batch is active, prepare defers acquire
// barriers and finish defers release barriers; a call belonging to the other
// phase still records immediately so the two phases never mix in one flush.
// abort discards any pending barriers and is idempotent.
bool waylib_vk_renderer_begin_texture_barrier_batch(struct wlr_renderer *renderer,
bool release);
bool waylib_vk_renderer_flush_texture_barrier_batch(struct wlr_renderer *renderer,
VkCommandBuffer cb);
void waylib_vk_renderer_abort_texture_barrier_batch(struct wlr_renderer *renderer);

// Clear the frame's color-attachment-producer and sampled-texture alias
// lists. Call from the compositor frame boundary once the frame's GPU work
// has completed (e.g. after a synchronous Qt Offscreen endFrame on the same
// queue): every submission of the finished frame is ordered implicit with the
// next one on the same queue, and the in-frame alias barriers are recorded
// from the lists during the next frame, so keeping stale entries only adds
// permanent global barriers and unbounded CPU scans.
void waylib_vk_renderer_reset_frame_alias_lists(struct wlr_renderer *renderer);

// Readback ownership gate for DMA-BUF-imported wlroots textures read through
// wlr_texture_read_pixels()/vulkan_read_pixels() from outside the Qt frame.
// The import lacks a known Vulkan-side layout and may carry an unsignaled
// producer fence, so reading it without this gate uses FOREIGN-owned memory.
// Call begin_readback() before the read: for a dmabuf texture it waits the
// buffer's DMA-BUF fences (sync_file poll) and records/submit a FOREIGN->own
// acquire barrier leaving the image in VK_IMAGE_LAYOUT_GENERAL; the follow-up
// read_pixels() staging command buffer is submitted later on the same queue,
// which gives the required execution dependency. ACQUIRED means end_readback()
// MUST be called after the read (recorded on its own command buffer); NOOP is
// returned for textures that are not DMA-BUF imports (SHM upload textures);
// ERROR fails closed for multi-plane/disjoint/YCbCr textures or a texture
// whose foreign ownership is already held. begin_readback() never waits the
// read itself; the read_pixels() staging submit CPU-waits as usual.
enum wlr_vk_texture_readback_state {
WLR_VK_TEXTURE_READBACK_ERROR = 0,
WLR_VK_TEXTURE_READBACK_ACQUIRED,
WLR_VK_TEXTURE_READBACK_NOOP,
};
enum wlr_vk_texture_readback_state waylib_vk_texture_begin_readback(
struct wlr_renderer *renderer, struct wlr_texture *texture);
void waylib_vk_texture_end_readback(struct wlr_renderer *renderer,
struct wlr_texture *texture);

// Enable the GPU-side asynchronous staging-upload path used for shared-memory
// (CPU-rendered) client buffers. It submits the staging copy without blocking
// the caller and chains the upload through the texture-sync bridge before the
// texture is sampled, so it must only be enabled when the consumer (e.g.
// Qt/QRhi) submits its command buffers to the same VkQueue as the renderer and
// flushes that bridge before submission. When disabled (the default), staging
// uploads use a blocking wait.
void waylib_vk_renderer_set_stage_async_enabled(struct wlr_renderer *renderer,
bool enabled);

// Restrict the renderer's advertised dmabuf and shm texture format sets to
// the given DRM format whitelist, dropping every other format so clients
// cannot allocate buffers the compositor is unable to display. Call once
// after renderer creation and before any client connects. Passing an empty
// whitelist fails without touching the sets.
bool waylib_vk_renderer_restrict_texture_formats(struct wlr_renderer *renderer,
const uint32_t *drm_formats, size_t count);

#endif
17 changes: 17 additions & 0 deletions 3rdparty/wlroots/render/vulkan/pixel_format.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,23 @@ static bool query_modifier_support(struct wlr_vk_device *dev,
}

if (supported) {
// Transfer-source support is optional and must not remove an
// otherwise valid render modifier. Users can inspect the actual
// image usage and fall back when this stricter query fails.
const VkImageUsageFlags transfer_src_usage =
vulkan_render_usage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
const VkFormat variant = p.has_mutable_srgb ?
props->format.vk_srgb : VK_FORMAT_UNDEFINED;
struct wlr_vk_format_modifier_props transfer_src = {0};
const char *transfer_src_errmsg = NULL;
if ((m.drmFormatModifierTilingFeatures &
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) &&
query_modifier_usage_support(dev, props->format.vk,
variant, transfer_src_usage, &m, &transfer_src,
&transfer_src_errmsg)) {
p.transfer_src_max_extent = transfer_src.max_extent;
}

props->dmabuf.render_mods[props->dmabuf.render_mod_count++] = p;
wlr_drm_format_set_add(&dev->dmabuf_render_formats,
props->format.drm, m.drmFormatModifier);
Expand Down
Loading
Loading