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.
This commit is contained in:
Manuel Stoeckl 2022-11-25 12:28:43 -05:00
parent f0375eed24
commit c02872e033
3 changed files with 10 additions and 4 deletions

View file

@ -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 // Suballocates a buffer span with the given size that can be mapped
// and used as staging buffer. The allocation is implicitly released when the // 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_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 // Tries to allocate a texture descriptor set. Will additionally
// return the pool it was allocated from when successful (for freeing it later). // return the pool it was allocated from when successful (for freeing it later).

View file

@ -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, 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 // try to find free span
// simple greedy allocation algorithm - should be enough for this usecase // simple greedy allocation algorithm - should be enough for this usecase
// since all allocations are freed together after the frame // 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); 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) { if (buf->buf_size - start < size) {
continue; continue;
} }

View file

@ -73,7 +73,7 @@ static bool write_pixels(struct wlr_vk_texture *texture,
} }
// get staging buffer // 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) { if (!span.buffer || span.alloc.size != bsize) {
wlr_log(WLR_ERROR, "Failed to retrieve staging buffer"); wlr_log(WLR_ERROR, "Failed to retrieve staging buffer");
free(copies); free(copies);