diff --git a/gsk/gskvulkanimage.c b/gsk/gskvulkanimage.c index c8777f7063..edfb24a678 100644 --- a/gsk/gskvulkanimage.c +++ b/gsk/gskvulkanimage.c @@ -65,27 +65,19 @@ gsk_vulkan_image_new (GdkVulkanContext *context, return self; } -static GskVulkanImage * -gsk_vulkan_image_new_staging (GdkVulkanContext *context, - guchar *data, - gsize width, - gsize height, - gsize stride) +static void +gsk_vulkan_image_upload_data (GskVulkanImage *self, + guchar *data, + gsize width, + gsize height, + gsize data_stride) { VkMemoryRequirements requirements; - GskVulkanImage *self; - guchar *mem; gsize mem_stride; - - self = gsk_vulkan_image_new (context, - width, - height, - VK_IMAGE_TILING_LINEAR, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + guchar *mem; mem_stride = width * 4; - vkGetImageMemoryRequirements (gdk_vulkan_context_get_device (context), + vkGetImageMemoryRequirements (gdk_vulkan_context_get_device (self->vulkan), self->vk_image, &requirements); if (mem_stride % requirements.alignment != 0) @@ -93,21 +85,19 @@ gsk_vulkan_image_new_staging (GdkVulkanContext *context, mem = gsk_vulkan_memory_map (self->memory); - if (stride == width * 4 && stride == mem_stride) + if (data_stride == width * 4 && data_stride == mem_stride) { - memcpy (mem, data, width * height * 4); + memcpy (mem, data, data_stride * height); } else { for (gsize i = 0; i < height; i++) { - memcpy (mem + i * mem_stride, data + i * stride, width * 4); + memcpy (mem + i * mem_stride, data + i * data_stride, width * 4); } } gsk_vulkan_memory_unmap (self->memory); - - return self; } static void @@ -138,16 +128,23 @@ gsk_vulkan_image_ensure_view (GskVulkanImage *self) } GskVulkanImage * -gsk_vulkan_image_new_from_data (GdkVulkanContext *context, - VkCommandBuffer command_buffer, - guchar *data, - gsize width, - gsize height, - gsize stride) +gsk_vulkan_image_new_from_data_via_staging_image (GdkVulkanContext *context, + VkCommandBuffer command_buffer, + guchar *data, + gsize width, + gsize height, + gsize stride) { GskVulkanImage *self, *staging; - staging = gsk_vulkan_image_new_staging (context, data, width, height, stride); + staging = gsk_vulkan_image_new (context, + width, + height, + VK_IMAGE_TILING_LINEAR, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + + gsk_vulkan_image_upload_data (staging, data, width, height, stride); self = gsk_vulkan_image_new (context, width, @@ -253,6 +250,7 @@ gsk_vulkan_image_new_from_data (GdkVulkanContext *context, } }); + /* XXX: Is this okay or do we need to keep the staging image around until the commands execute */ gsk_vulkan_image_free (staging); gsk_vulkan_image_ensure_view (self); @@ -260,6 +258,76 @@ gsk_vulkan_image_new_from_data (GdkVulkanContext *context, return self; } +GskVulkanImage * +gsk_vulkan_image_new_from_data_directly (GdkVulkanContext *context, + VkCommandBuffer command_buffer, + guchar *data, + gsize width, + gsize height, + gsize stride) +{ + GskVulkanImage *self; + + self = gsk_vulkan_image_new (context, + width, + height, + VK_IMAGE_TILING_LINEAR, + VK_IMAGE_USAGE_SAMPLED_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + + gsk_vulkan_image_upload_data (self, data, width, height, stride); + + 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_SHADER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED, + .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 + } + } + }); + + gsk_vulkan_image_ensure_view (self); + + return self; +} + +GskVulkanImage * +gsk_vulkan_image_new_from_data (GdkVulkanContext *context, + VkCommandBuffer command_buffer, + guchar *data, + gsize width, + gsize height, + gsize stride) +{ + switch (GSK_VULKAN_UPLOAD_IMAGE_DEFAULT) + { + default: + g_assert_not_reached (); + /* fall through */ + case GSK_VULKAN_UPLOAD_DIRECTLY: + return gsk_vulkan_image_new_from_data_directly (context, command_buffer, data, width, height, stride); + case GSK_VULKAN_UPLOAD_VIA_STAGING_IMAGE: + return gsk_vulkan_image_new_from_data_via_staging_image (context, command_buffer, data, width, height, stride); + } +} + void gsk_vulkan_image_free (GskVulkanImage *self) { diff --git a/gsk/gskvulkanimageprivate.h b/gsk/gskvulkanimageprivate.h index 57686eac04..7c089c2b7b 100644 --- a/gsk/gskvulkanimageprivate.h +++ b/gsk/gskvulkanimageprivate.h @@ -5,6 +5,14 @@ G_BEGIN_DECLS +/* Modify here for benchmarking */ +#define GSK_VULKAN_UPLOAD_IMAGE_DEFAULT GSK_VULKAN_UPLOAD_DIRECTLY + +typedef enum { + GSK_VULKAN_UPLOAD_DIRECTLY, + GSK_VULKAN_UPLOAD_VIA_STAGING_IMAGE +} GstkVulkanImageUpload; + typedef struct _GskVulkanImage GskVulkanImage; GskVulkanImage * gsk_vulkan_image_new_from_data (GdkVulkanContext *context,