[gtk+/wip/otte/rendernode: 83/110] vulkan: Implement staging-buffer image upload



commit 5f0fdcad2d486b1d994a316c0e45c4da8ae489a1
Author: Benjamin Otte <otte redhat com>
Date:   Fri Dec 16 00:22:23 2016 +0100

    vulkan: Implement staging-buffer image upload
    
    This is not enabled by default. Use GSK_RENDERING_MODE=staging-buffer to
    use the code.

 gsk/gskdebug.c               |    1 +
 gsk/gskdebugprivate.h        |    9 ++--
 gsk/gskvulkanbuffer.c        |   26 +++++++--
 gsk/gskvulkanbufferprivate.h |    2 +
 gsk/gskvulkanimage.c         |  123 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 152 insertions(+), 9 deletions(-)
---
diff --git a/gsk/gskdebug.c b/gsk/gskdebug.c
index 02ed8b8..7ee7a7b 100644
--- a/gsk/gskdebug.c
+++ b/gsk/gskdebug.c
@@ -18,6 +18,7 @@ static const GDebugKey gsk_rendering_keys[] = {
   { "shaders", GSK_RENDERING_MODE_SHADERS },
   { "sync", GSK_RENDERING_MODE_SYNC },
   { "staging-image", GSK_RENDERING_MODE_STAGING_IMAGE },
+  { "staging-buffer", GSK_RENDERING_MODE_STAGING_BUFFER }
 };
 
 gboolean
diff --git a/gsk/gskdebugprivate.h b/gsk/gskdebugprivate.h
index a5d4784..6f5d64e 100644
--- a/gsk/gskdebugprivate.h
+++ b/gsk/gskdebugprivate.h
@@ -17,10 +17,11 @@ typedef enum {
 } GskDebugFlags;
 
 typedef enum {
-  GSK_RENDERING_MODE_GEOMETRY      = 1 << 0,
-  GSK_RENDERING_MODE_SHADERS       = 1 << 1,
-  GSK_RENDERING_MODE_SYNC          = 1 << 2,
-  GSK_RENDERING_MODE_STAGING_IMAGE = 1 << 3
+  GSK_RENDERING_MODE_GEOMETRY       = 1 << 0,
+  GSK_RENDERING_MODE_SHADERS        = 1 << 1,
+  GSK_RENDERING_MODE_SYNC           = 1 << 2,
+  GSK_RENDERING_MODE_STAGING_IMAGE  = 1 << 3,
+  GSK_RENDERING_MODE_STAGING_BUFFER = 1 << 4
 } GskRenderingMode;
 
 gboolean gsk_check_debug_flags (GskDebugFlags flags);
diff --git a/gsk/gskvulkanbuffer.c b/gsk/gskvulkanbuffer.c
index 6694131..3c1d76d 100644
--- a/gsk/gskvulkanbuffer.c
+++ b/gsk/gskvulkanbuffer.c
@@ -15,9 +15,10 @@ struct _GskVulkanBuffer
   GskVulkanMemory *memory;
 };
 
-GskVulkanBuffer *
-gsk_vulkan_buffer_new (GdkVulkanContext  *context,
-                       gsize              size)
+static GskVulkanBuffer *
+gsk_vulkan_buffer_new_internal (GdkVulkanContext  *context,
+                                gsize              size,
+                                VkBufferUsageFlags usage)
 {
   VkMemoryRequirements requirements;
   GskVulkanBuffer *self;
@@ -32,8 +33,7 @@ gsk_vulkan_buffer_new (GdkVulkanContext  *context,
                                     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
                                     .size = size,
                                     .flags = 0,
-                                    .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
-                                           | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
+                                    .usage = usage,
                                     .sharingMode = VK_SHARING_MODE_EXCLUSIVE
                                 },
                                 NULL,
@@ -55,6 +55,22 @@ gsk_vulkan_buffer_new (GdkVulkanContext  *context,
   return self;
 }
 
+GskVulkanBuffer *
+gsk_vulkan_buffer_new (GdkVulkanContext  *context,
+                       gsize              size)
+{
+  return gsk_vulkan_buffer_new_internal (context, size,
+                                         VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
+                                         | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+}
+
+GskVulkanBuffer *
+gsk_vulkan_buffer_new_staging (GdkVulkanContext  *context,
+                               gsize              size)
+{
+  return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
+}
+
 void
 gsk_vulkan_buffer_free (GskVulkanBuffer *self)
 {
diff --git a/gsk/gskvulkanbufferprivate.h b/gsk/gskvulkanbufferprivate.h
index e497192..30e327e 100644
--- a/gsk/gskvulkanbufferprivate.h
+++ b/gsk/gskvulkanbufferprivate.h
@@ -9,6 +9,8 @@ typedef struct _GskVulkanBuffer GskVulkanBuffer;
 
 GskVulkanBuffer *       gsk_vulkan_buffer_new                           (GdkVulkanContext       *context,
                                                                          gsize                   size);
+GskVulkanBuffer *       gsk_vulkan_buffer_new_staging                   (GdkVulkanContext       *context,
+                                                                         gsize                   size);
 void                    gsk_vulkan_buffer_free                          (GskVulkanBuffer        *buffer);
 
 VkBuffer                gsk_vulkan_buffer_get_buffer                    (GskVulkanBuffer        *self);
diff --git a/gsk/gskvulkanimage.c b/gsk/gskvulkanimage.c
index b82398d..4b4b381 100644
--- a/gsk/gskvulkanimage.c
+++ b/gsk/gskvulkanimage.c
@@ -1,6 +1,8 @@
 #include "config.h"
 
 #include "gskvulkanimageprivate.h"
+
+#include "gskvulkanbufferprivate.h"
 #include "gskvulkanmemoryprivate.h"
 #include "gskvulkanpipelineprivate.h"
 
@@ -137,6 +139,125 @@ gsk_vulkan_image_ensure_view (GskVulkanImage *self,
 }
 
 GskVulkanImage *
+gsk_vulkan_image_new_from_data_via_staging_buffer (GdkVulkanContext  *context,
+                                                   VkCommandBuffer    command_buffer,
+                                                   guchar            *data,
+                                                   gsize              width,
+                                                   gsize              height,
+                                                   gsize              stride)
+{
+  GskVulkanImage *self;
+  GskVulkanBuffer *staging;
+  guchar *mem;
+
+  staging = gsk_vulkan_buffer_new_staging (context, width * height * 4);
+  mem = gsk_vulkan_buffer_map (staging);
+
+  if (stride == width * 4)
+    {
+      memcpy (mem, data, stride * height);
+    }
+  else
+    {
+      for (gsize i = 0; i < height; i++)
+        {
+          memcpy (mem + i * width * 4, data + i * stride, width * 4);
+        }
+    }
+
+  gsk_vulkan_buffer_unmap (staging);
+
+  self = gsk_vulkan_image_new (context,
+                               width,
+                               height, 
+                               VK_IMAGE_TILING_OPTIMAL,
+                               VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
+                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+  vkCmdPipelineBarrier (command_buffer,
+                        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                        0,
+                        0, NULL,
+                        0, NULL,
+                        1, (VkImageMemoryBarrier[1]) {
+                            {
+                                .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+                                .srcAccessMask = VK_ACCESS_HOST_WRITE_BIT,
+                                .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+                                .oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED,
+                                .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                .image = self->vk_image,
+                                .subresourceRange = {
+                                    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                                    .baseMipLevel = 0,
+                                    .levelCount = 1,
+                                    .baseArrayLayer = 0,
+                                    .layerCount = 1
+                                }
+                            }
+                        });
+
+  vkCmdCopyBufferToImage (command_buffer,
+                          gsk_vulkan_buffer_get_buffer (staging),
+                          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 = width,
+                                       .height = height,
+                                       .depth = 1
+                                   }
+                               }
+                          });
+
+  vkCmdPipelineBarrier (command_buffer,
+                        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                        0,
+                        0, NULL,
+                        0, NULL,
+                        1, (VkImageMemoryBarrier[1]) {
+                            {
+                                .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+                                .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+                                .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
+                                .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                                .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                .image = self->vk_image,
+                                .subresourceRange = {
+                                    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                                    .baseMipLevel = 0,
+                                    .levelCount = 1,
+                                    .baseArrayLayer = 0,
+                                    .layerCount = 1
+                                }
+                            }
+                        });
+
+  /* XXX: Is this okay or do we need to keep the staging image around until the commands execute */
+  gsk_vulkan_buffer_free (staging);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_SRGB);
+
+  return self;
+}
+
+GskVulkanImage *
 gsk_vulkan_image_new_from_data_via_staging_image (GdkVulkanContext  *context,
                                                   VkCommandBuffer    command_buffer,
                                                   guchar            *data,
@@ -325,6 +446,8 @@ gsk_vulkan_image_new_from_data (GdkVulkanContext  *context,
                                 gsize              height,
                                 gsize              stride)
 {
+  if (GSK_RENDER_MODE_CHECK (STAGING_BUFFER))
+    return gsk_vulkan_image_new_from_data_via_staging_buffer (context, command_buffer, data, width, height, 
stride);
   if (GSK_RENDER_MODE_CHECK (STAGING_IMAGE))
     return gsk_vulkan_image_new_from_data_via_staging_image (context, command_buffer, data, width, height, 
stride);
   else


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]