[gtk+] vulkan: Implement staging-buffer image upload
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] vulkan: Implement staging-buffer image upload
- Date: Tue, 20 Dec 2016 17:13:27 +0000 (UTC)
commit ba7ac637bccb06d356fad7a1c1a23cdec8e5372e
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]