From ba28971a18339a4ee45e7a8f581ebbf80b2b4260 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 15 Jun 2023 14:29:15 +0200 Subject: [PATCH] vulkan: Allow mapping images as "read" and/or "write" This way, we unify the code paths for memory access to textures. We also technically gain the ability to modify images, though I have no use case for this. --- gsk/vulkan/gskvulkanbuffer.c | 16 +- gsk/vulkan/gskvulkanbufferprivate.h | 14 +- gsk/vulkan/gskvulkanimage.c | 220 ++++++++++++++++------------ gsk/vulkan/gskvulkanimageprivate.h | 7 +- gsk/vulkan/gskvulkanrenderpass.c | 4 +- 5 files changed, 148 insertions(+), 113 deletions(-) diff --git a/gsk/vulkan/gskvulkanbuffer.c b/gsk/vulkan/gskvulkanbuffer.c index 4b8e6b8cc7..90bdf8b753 100644 --- a/gsk/vulkan/gskvulkanbuffer.c +++ b/gsk/vulkan/gskvulkanbuffer.c @@ -72,18 +72,16 @@ gsk_vulkan_buffer_new_storage (GdkVulkanContext *context, } GskVulkanBuffer * -gsk_vulkan_buffer_new_staging (GdkVulkanContext *context, - gsize size) +gsk_vulkan_buffer_new_map (GdkVulkanContext *context, + gsize size, + GskVulkanMapMode mode) { - return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + return gsk_vulkan_buffer_new_internal (context, + size, + (mode & GSK_VULKAN_READ ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT : 0) | + (mode & GSK_VULKAN_WRITE ? VK_BUFFER_USAGE_TRANSFER_DST_BIT : 0)); } -GskVulkanBuffer * -gsk_vulkan_buffer_new_download (GdkVulkanContext *context, - gsize size) -{ - return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT); -} void gsk_vulkan_buffer_free (GskVulkanBuffer *self) { diff --git a/gsk/vulkan/gskvulkanbufferprivate.h b/gsk/vulkan/gskvulkanbufferprivate.h index bba3f2c227..9c51586216 100644 --- a/gsk/vulkan/gskvulkanbufferprivate.h +++ b/gsk/vulkan/gskvulkanbufferprivate.h @@ -6,14 +6,20 @@ G_BEGIN_DECLS typedef struct _GskVulkanBuffer GskVulkanBuffer; +typedef enum +{ + GSK_VULKAN_READ = (1 << 0), + GSK_VULKAN_WRITE = (1 << 1), + GSK_VULKAN_READWRITE = GSK_VULKAN_READ | GSK_VULKAN_WRITE +} GskVulkanMapMode; + GskVulkanBuffer * gsk_vulkan_buffer_new (GdkVulkanContext *context, gsize size); GskVulkanBuffer * gsk_vulkan_buffer_new_storage (GdkVulkanContext *context, gsize size); -GskVulkanBuffer * gsk_vulkan_buffer_new_staging (GdkVulkanContext *context, - gsize size); -GskVulkanBuffer * gsk_vulkan_buffer_new_download (GdkVulkanContext *context, - gsize size); +GskVulkanBuffer * gsk_vulkan_buffer_new_map (GdkVulkanContext *context, + gsize size, + GskVulkanMapMode mode); void gsk_vulkan_buffer_free (GskVulkanBuffer *buffer); VkBuffer gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self); diff --git a/gsk/vulkan/gskvulkanimage.c b/gsk/vulkan/gskvulkanimage.c index a209f16a52..a7ac3450c2 100644 --- a/gsk/vulkan/gskvulkanimage.c +++ b/gsk/vulkan/gskvulkanimage.c @@ -6,6 +6,8 @@ #include "gskvulkanmemoryprivate.h" #include "gskvulkanpipelineprivate.h" +#include "gdk/gdkmemoryformatprivate.h" + #include struct _GskVulkanUploader @@ -556,7 +558,7 @@ gsk_vulkan_image_new_from_texture (GskVulkanUploader *uploader, gdk_texture_get_width (texture), gdk_texture_get_height (texture)); gdk_texture_downloader_set_format (downloader, result->format); - gsk_vulkan_image_map_memory (result, uploader, &map); + gsk_vulkan_image_map_memory (result, uploader, GSK_VULKAN_WRITE, &map); gdk_texture_downloader_download_into (downloader, map.data, map.stride); gsk_vulkan_image_unmap_memory (result, uploader, &map); gdk_texture_downloader_free (downloader); @@ -588,11 +590,28 @@ gsk_vulkan_image_new_for_upload (GskVulkanUploader *uploader, static void gsk_vulkan_image_map_memory_direct (GskVulkanImage *self, GskVulkanUploader *uploader, + GskVulkanMapMode mode, GskVulkanImageMap *map) { VkImageSubresource image_res; VkSubresourceLayout image_layout; + if (self->vk_image_layout != VK_IMAGE_LAYOUT_PREINITIALIZED) + { + gsk_vulkan_uploader_add_image_barrier (uploader, + FALSE, + self, + VK_IMAGE_LAYOUT_GENERAL, + (mode & GSK_VULKAN_READ ? VK_ACCESS_MEMORY_READ_BIT : 0) | + (mode & GSK_VULKAN_WRITE ? VK_ACCESS_MEMORY_WRITE_BIT : 0)); + + if (mode & GSK_VULKAN_READ) + { + gsk_vulkan_uploader_upload (uploader); + GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan)); + } + } + image_res.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_res.mipLevel = 0; image_res.arrayLayer = 0; @@ -600,6 +619,7 @@ gsk_vulkan_image_map_memory_direct (GskVulkanImage *self, vkGetImageSubresourceLayout (gdk_vulkan_context_get_device (self->vulkan), self->vk_image, &image_res, &image_layout); + map->mode = mode; map->staging_buffer = NULL; map->data = gsk_vulkan_memory_map (self->memory) + image_layout.offset; map->stride = image_layout.rowPitch; @@ -622,13 +642,52 @@ gsk_vulkan_image_unmap_memory_direct (GskVulkanImage *self, static void gsk_vulkan_image_map_memory_indirect (GskVulkanImage *self, GskVulkanUploader *uploader, + GskVulkanMapMode mode, GskVulkanImageMap *map) { - gsize buffer_size = self->width * self->height * 4; + map->mode = mode; + map->stride = self->width * gdk_memory_format_bytes_per_pixel (self->format); + map->staging_buffer = gsk_vulkan_buffer_new_map (uploader->vulkan, self->height * map->stride, mode); + + if (self->vk_image_layout != VK_IMAGE_LAYOUT_PREINITIALIZED) + { + if (mode & GSK_VULKAN_READ) + { + gsk_vulkan_uploader_add_image_barrier (uploader, + FALSE, + self, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT); + + vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader), + self->vk_image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + gsk_vulkan_buffer_get_buffer (map->staging_buffer), + 1, + (VkBufferImageCopy[1]) { + { + .bufferOffset = 0, + .imageSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1 + }, + .imageOffset = { 0, 0, 0 }, + .imageExtent = { + .width = self->width, + .height = self->height, + .depth = 1 + } + } + }); + + gsk_vulkan_uploader_upload (uploader); + GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan)); + } + } - map->staging_buffer = gsk_vulkan_buffer_new_staging (uploader->vulkan, buffer_size); map->data = gsk_vulkan_buffer_map (map->staging_buffer); - map->stride = self->width * 4; } static void @@ -638,70 +697,75 @@ gsk_vulkan_image_unmap_memory_indirect (GskVulkanImage *self, { gsk_vulkan_buffer_unmap (map->staging_buffer); - gsk_vulkan_uploader_add_buffer_barrier (uploader, - FALSE, - &(VkBufferMemoryBarrier) { - .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_HOST_WRITE_BIT, - .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .buffer = gsk_vulkan_buffer_get_buffer (map->staging_buffer), - .offset = 0, - .size = VK_WHOLE_SIZE, - }); - - gsk_vulkan_uploader_add_image_barrier (uploader, - FALSE, - self, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_ACCESS_TRANSFER_WRITE_BIT); - - vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader), - gsk_vulkan_buffer_get_buffer (map->staging_buffer), - self->vk_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - (VkBufferImageCopy[1]) { - { - .bufferOffset = 0, - .imageSubresource = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1 - }, - .imageOffset = { 0, 0, 0 }, - .imageExtent = { - .width = self->width, - .height = self->height, - .depth = 1 + if (map->mode & GSK_VULKAN_WRITE) + { + gsk_vulkan_uploader_add_buffer_barrier (uploader, + FALSE, + &(VkBufferMemoryBarrier) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_HOST_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = gsk_vulkan_buffer_get_buffer (map->staging_buffer), + .offset = 0, + .size = VK_WHOLE_SIZE, + }); + + gsk_vulkan_uploader_add_image_barrier (uploader, + FALSE, + self, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT); + + vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader), + gsk_vulkan_buffer_get_buffer (map->staging_buffer), + self->vk_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + (VkBufferImageCopy[1]) { + { + .bufferOffset = 0, + .imageSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1 + }, + .imageOffset = { 0, 0, 0 }, + .imageExtent = { + .width = self->width, + .height = self->height, + .depth = 1 + } } - } - }); + }); + + uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, + map->staging_buffer); + } + else + { + gsk_vulkan_buffer_free (map->staging_buffer); + } gsk_vulkan_uploader_add_image_barrier (uploader, TRUE, self, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT); - - uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, - map->staging_buffer); } void gsk_vulkan_image_map_memory (GskVulkanImage *self, GskVulkanUploader *uploader, + GskVulkanMapMode mode, GskVulkanImageMap *map) { - g_assert (self->vk_image_layout == VK_IMAGE_LAYOUT_UNDEFINED || - self->vk_image_layout == VK_IMAGE_LAYOUT_PREINITIALIZED); - if (!GSK_DEBUG_CHECK (STAGING) && gsk_vulkan_memory_can_map (self->memory, TRUE)) - gsk_vulkan_image_map_memory_direct (self, uploader, map); + gsk_vulkan_image_map_memory_direct (self, uploader, mode, map); else - gsk_vulkan_image_map_memory_indirect (self, uploader, map); + gsk_vulkan_image_map_memory_indirect (self, uploader, mode, map); } void @@ -776,7 +840,7 @@ gsk_vulkan_image_new_for_offscreen (GdkVulkanContext *context, preferred_format, width, height, - VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, @@ -791,54 +855,18 @@ GdkTexture * gsk_vulkan_image_download (GskVulkanImage *self, GskVulkanUploader *uploader) { - GskVulkanBuffer *buffer; + GskVulkanImageMap map; GdkTexture *texture; GBytes *bytes; - guchar *mem; - - gsk_vulkan_uploader_add_image_barrier (uploader, - FALSE, - self, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_ACCESS_TRANSFER_READ_BIT); - - buffer = gsk_vulkan_buffer_new_download (self->vulkan, self->width * self->height * 4); - - vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader), - self->vk_image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - gsk_vulkan_buffer_get_buffer (buffer), - 1, - (VkBufferImageCopy[1]) { - { - .bufferOffset = 0, - .imageSubresource = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1 - }, - .imageOffset = { 0, 0, 0 }, - .imageExtent = { - .width = self->width, - .height = self->height, - .depth = 1 - } - } - }); - - gsk_vulkan_uploader_upload (uploader); - - GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan)); - mem = gsk_vulkan_buffer_map (buffer); - bytes = g_bytes_new (mem, self->width * self->height * 4); + gsk_vulkan_image_map_memory (self, uploader, GSK_VULKAN_READ, &map); + bytes = g_bytes_new (map.data, map.stride * self->height); texture = gdk_memory_texture_new (self->width, self->height, self->format, bytes, - self->width * 4); - gsk_vulkan_buffer_unmap (buffer); - gsk_vulkan_buffer_free (buffer); + map.stride); + g_bytes_unref (bytes); + gsk_vulkan_image_unmap_memory (self, uploader, &map); return texture; } @@ -860,7 +888,7 @@ gsk_vulkan_image_upload_regions (GskVulkanImage *self, for (int i = 0; i < num_regions; i++) size += regions[i].width * regions[i].height * 4; - staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, size); + staging = gsk_vulkan_buffer_new_map (uploader->vulkan, size, GSK_VULKAN_WRITE); mem = gsk_vulkan_buffer_map (staging); bufferImageCopy = alloca (sizeof (VkBufferImageCopy) * num_regions); diff --git a/gsk/vulkan/gskvulkanimageprivate.h b/gsk/vulkan/gskvulkanimageprivate.h index c7e66ccd3d..471163d101 100644 --- a/gsk/vulkan/gskvulkanimageprivate.h +++ b/gsk/vulkan/gskvulkanimageprivate.h @@ -2,6 +2,7 @@ #include +#include "gskvulkanbufferprivate.h" #include "gskvulkancommandpoolprivate.h" G_BEGIN_DECLS @@ -56,10 +57,11 @@ typedef struct _GskVulkanImageMap GskVulkanImageMap; struct _GskVulkanImageMap { guchar *data; - gsize stride; + gsize stride; + GskVulkanMapMode mode; /* private */ - gpointer staging_buffer; + GskVulkanBuffer *staging_buffer; }; GskVulkanImage * gsk_vulkan_image_new_for_upload (GskVulkanUploader *uploader, @@ -68,6 +70,7 @@ GskVulkanImage * gsk_vulkan_image_new_for_upload (GskVulk gsize height); void gsk_vulkan_image_map_memory (GskVulkanImage *self, GskVulkanUploader *uploader, + GskVulkanMapMode mode, GskVulkanImageMap *map); void gsk_vulkan_image_unmap_memory (GskVulkanImage *self, GskVulkanUploader *uploader, diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 9b9054f88b..59f429aa89 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -1370,7 +1370,7 @@ gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self, height = ceil (node->bounds.size.height * graphene_vec2_get_y (scale)); result = gsk_vulkan_image_new_for_upload (uploader, GDK_MEMORY_DEFAULT, width, height); - gsk_vulkan_image_map_memory (result, uploader, &map); + gsk_vulkan_image_map_memory (result, uploader, GSK_VULKAN_WRITE, &map); surface = cairo_image_surface_create_for_data (map.data, CAIRO_FORMAT_ARGB32, width, height, @@ -1431,7 +1431,7 @@ gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self, height = ceil (node->bounds.size.height * graphene_vec2_get_y (&self->scale)); op->source = gsk_vulkan_image_new_for_upload (uploader, GDK_MEMORY_DEFAULT, width, height); - gsk_vulkan_image_map_memory (op->source, uploader, &map); + gsk_vulkan_image_map_memory (op->source, uploader, GSK_VULKAN_WRITE, &map); surface = cairo_image_surface_create_for_data (map.data, CAIRO_FORMAT_ARGB32, width, height, -- 2.30.2