From c02872e033b431d9f02a240abeebdf0aaa043ea6 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Fri, 25 Nov 2022 12:28:43 -0500 Subject: [PATCH] render/vulkan: align staging buffers for texture upload vkCmdCopyBufferToImage requires that the buffer offset be a multiple of the texel block size, which for single plane uncompressed formats is the same as the number of bytes per pixel. This commit adds an alignment parameter to vulkan_get_stage_span which ensures that the provided span (and the sequence of image copy operations derived which use it) have this alignment. --- include/render/vulkan.h | 6 ++++-- render/vulkan/renderer.c | 6 +++++- render/vulkan/texture.c | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/render/vulkan.h b/include/render/vulkan.h index 8063291fc..149161c26 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -231,9 +231,11 @@ bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer); // Suballocates a buffer span with the given size that can be mapped // and used as staging buffer. The allocation is implicitly released when the -// stage cb has finished execution. +// stage cb has finished execution. The start of the span will be a multiple +// of the given alignment. struct wlr_vk_buffer_span vulkan_get_stage_span( - struct wlr_vk_renderer *renderer, VkDeviceSize size); + struct wlr_vk_renderer *renderer, VkDeviceSize size, + VkDeviceSize alignment); // Tries to allocate a texture descriptor set. Will additionally // return the pool it was allocated from when successful (for freeing it later). diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 0ef256c27..4a6f9bdf1 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -200,7 +200,7 @@ static void release_stage_allocations(struct wlr_vk_renderer *renderer) { } struct wlr_vk_buffer_span vulkan_get_stage_span(struct wlr_vk_renderer *r, - VkDeviceSize size) { + VkDeviceSize size, VkDeviceSize alignment) { // try to find free span // simple greedy allocation algorithm - should be enough for this usecase // since all allocations are freed together after the frame @@ -215,6 +215,10 @@ struct wlr_vk_buffer_span vulkan_get_stage_span(struct wlr_vk_renderer *r, } assert(start <= buf->buf_size); + + // ensure the proposed start is a multiple of alignment + start += alignment - 1 - ((start + alignment - 1) % alignment); + if (buf->buf_size - start < size) { continue; } diff --git a/render/vulkan/texture.c b/render/vulkan/texture.c index 45e3fec94..9437cafc3 100644 --- a/render/vulkan/texture.c +++ b/render/vulkan/texture.c @@ -73,7 +73,7 @@ static bool write_pixels(struct wlr_vk_texture *texture, } // get staging buffer - struct wlr_vk_buffer_span span = vulkan_get_stage_span(renderer, bsize); + struct wlr_vk_buffer_span span = vulkan_get_stage_span(renderer, bsize, bytespb); if (!span.buffer || span.alloc.size != bsize) { wlr_log(WLR_ERROR, "Failed to retrieve staging buffer"); free(copies);