vulkan: Add a new way to upload data into images
authorBenjamin Otte <otte@redhat.com>
Wed, 14 Jun 2023 00:08:17 +0000 (02:08 +0200)
committerBenjamin Otte <otte@redhat.com>
Wed, 14 Jun 2023 01:34:07 +0000 (03:34 +0200)
As an alternative to gsk_vulkan_image_new_from_data() that
takes a given data and creates an image from it, add a 3 step process:
  gsk_vulkan_image_new_for_upload()
  gsk_vulkan_image_map_memory()
  /* put data into memory */
  gsk_vulkan_image_unmap_memory()

The benefit of this approach is that it potentially avoids a copy;
instead of creating a buffer to pass and writing the data into it before
then memcpy()ing it into the image, the data can be written straight
into image memory.

So far, only the staging buffer upload is implemented.

There are also no users, those come in the next commit(s).

gsk/vulkan/gskvulkanimage.c
gsk/vulkan/gskvulkanimageprivate.h

index f10ad5a1d12cdeda3a61adb5c88b77cc1919a665..4e5ab9fd7c729ae574af8417fb6d825860102c0b 100644 (file)
@@ -565,6 +565,102 @@ gsk_vulkan_image_new_from_data (GskVulkanUploader *uploader,
     return gsk_vulkan_image_new_from_data_directly (uploader, data, width, height, stride);
 }
 
+GskVulkanImage *
+gsk_vulkan_image_new_for_upload (GskVulkanUploader *uploader,
+                                 gsize              width,
+                                 gsize              height)
+{
+  GskVulkanImage *self;
+
+  self = gsk_vulkan_image_new (uploader->vulkan,
+                               width,
+                               height,
+                               VK_IMAGE_TILING_OPTIMAL,
+                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+                               VK_IMAGE_USAGE_SAMPLED_BIT,
+                               VK_IMAGE_LAYOUT_UNDEFINED,
+                               VK_ACCESS_TRANSFER_WRITE_BIT,
+                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
+
+  return self;
+}
+
+void
+gsk_vulkan_image_map_memory (GskVulkanImage    *self,
+                             GskVulkanUploader *uploader,
+                             GskVulkanImageMap *map)
+{
+  gsize buffer_size = self->width * self->height * 4;
+
+  g_assert (self->vk_image_layout == VK_IMAGE_LAYOUT_UNDEFINED ||
+            self->vk_image_layout == VK_IMAGE_LAYOUT_PREINITIALIZED);
+
+  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;
+}
+
+void
+gsk_vulkan_image_unmap_memory (GskVulkanImage    *self,
+                               GskVulkanUploader *uploader,
+                               GskVulkanImageMap *map)
+{
+  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
+                                   }
+                               }
+                          });
+
+  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);
+}
+
 GskVulkanImage *
 gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
                                     VkImage           image,
index 07f988bc66b86781bafd736cea8cb626b89fa2c2..fb311409b2644693536d61d88267ba45bf77d4e0 100644 (file)
@@ -58,6 +58,27 @@ GskVulkanImage *        gsk_vulkan_image_new_for_offscreen              (GdkVulk
 GdkTexture *            gsk_vulkan_image_download                       (GskVulkanImage         *self,
                                                                          GskVulkanUploader      *uploader);
 
+typedef struct _GskVulkanImageMap GskVulkanImageMap;
+
+struct _GskVulkanImageMap
+{
+  guchar *data;
+  gsize   stride;
+
+  /* private */
+  gpointer staging_buffer;
+};
+
+GskVulkanImage *        gsk_vulkan_image_new_for_upload                 (GskVulkanUploader      *uploader,
+                                                                         gsize                   width,
+                                                                         gsize                   height);
+void                    gsk_vulkan_image_map_memory                     (GskVulkanImage         *self,
+                                                                         GskVulkanUploader      *uploader,
+                                                                         GskVulkanImageMap      *map);
+void                    gsk_vulkan_image_unmap_memory                   (GskVulkanImage         *self,
+                                                                         GskVulkanUploader      *uploader,
+                                                                         GskVulkanImageMap      *map);
+
 gsize                   gsk_vulkan_image_get_width                      (GskVulkanImage         *self);
 gsize                   gsk_vulkan_image_get_height                     (GskVulkanImage         *self);
 VkImage                 gsk_vulkan_image_get_image                      (GskVulkanImage         *self);