vulkan: Add an api to update multiple image regions

Instead of doing multiple copy commands with a tiny buffer
for each glyph, we can just batch them all together. This
also avoids the issue of creating multiple barriers for the
same image.
This commit is contained in:
Matthias Clasen 2017-09-21 13:42:57 -04:00
parent 9a1460218c
commit 64322a2c41
2 changed files with 77 additions and 26 deletions

View File

@ -148,8 +148,12 @@ gsk_vulkan_uploader_upload (GskVulkanUploader *self)
command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
vkCmdPipelineBarrier (command_buffer,
#if 0
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
#endif
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
self->before_buffer_barriers->len, (VkBufferMemoryBarrier *) self->before_buffer_barriers->data,
@ -164,8 +168,12 @@ gsk_vulkan_uploader_upload (GskVulkanUploader *self)
{
VkCommandBuffer command_buffer = gsk_vulkan_uploader_get_copy_buffer (self);
vkCmdPipelineBarrier (command_buffer,
#if 0
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
#endif
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
0,
0, NULL,
self->after_buffer_barriers->len, (VkBufferMemoryBarrier *) self->after_buffer_barriers->data,
@ -663,23 +671,68 @@ gsk_vulkan_image_upload_region (GskVulkanImage *self,
gsize stride,
gsize x,
gsize y)
{
gsk_vulkan_image_upload_regions (self, uploader, 1, (GskImageRegion[1]) {
{
.data = data,
.width = width,
.height = height,
.stride = stride,
.x = x,
.y = y
} });
}
void
gsk_vulkan_image_upload_regions (GskVulkanImage *self,
GskVulkanUploader *uploader,
guint num_regions,
GskImageRegion *regions)
{
GskVulkanBuffer *staging;
guchar *mem;
guchar *m;
gsize size;
gsize offset;
VkBufferImageCopy *bufferImageCopy;
staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, width * height * 4);
size = 0;
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);
mem = gsk_vulkan_buffer_map (staging);
if (stride == width * 4)
bufferImageCopy = alloca (sizeof (VkBufferImageCopy) * num_regions);
memset (bufferImageCopy, 0, sizeof (VkBufferImageCopy) * num_regions);
offset = 0;
for (int i = 0; i < num_regions; i++)
{
memcpy (mem, data, stride * height);
}
else
{
for (gsize i = 0; i < height; i++)
m = mem + offset;
if (regions[i].stride == regions[i].width * 4)
{
memcpy (mem + i * width * 4, data + i * stride, width * 4);
memcpy (m, regions[i].data, regions[i].stride * regions[i].height);
}
else
{
for (gsize r = 0; r < regions[i].height; i++)
memcpy (m + r * regions[i].width * 4, regions[i].data + r * regions[i].stride, regions[i].width * 4);
}
bufferImageCopy[i].bufferOffset = offset;
bufferImageCopy[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferImageCopy[i].imageSubresource.mipLevel = 0;
bufferImageCopy[i].imageSubresource.baseArrayLayer = 0;
bufferImageCopy[i].imageSubresource.layerCount = 1;
bufferImageCopy[i].imageOffset.x = regions[i].x;
bufferImageCopy[i].imageOffset.y = regions[i].y;
bufferImageCopy[i].imageOffset.z = 0;
bufferImageCopy[i].imageExtent.width = regions[i].width;
bufferImageCopy[i].imageExtent.height = regions[i].height;
bufferImageCopy[i].imageExtent.depth = 1;
offset += regions[i].width * regions[i].height * 4;
}
gsk_vulkan_buffer_unmap (staging);
@ -694,24 +747,8 @@ gsk_vulkan_image_upload_region (GskVulkanImage *self,
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 = { x, y, 0 },
.imageExtent = {
.width = width,
.height = height,
.depth = 1
}
}
});
num_regions,
bufferImageCopy);
gsk_vulkan_uploader_add_image_barrier (uploader,
TRUE,

View File

@ -39,6 +39,20 @@ void gsk_vulkan_image_upload_region (GskVulk
gsize stride,
gsize x,
gsize y);
typedef struct {
guchar *data;
gsize width;
gsize height;
gsize stride;
gsize x;
gsize y;
} GskImageRegion;
void gsk_vulkan_image_upload_regions (GskVulkanImage *image,
GskVulkanUploader *uploader,
guint num_regions,
GskImageRegion *regions);
GskVulkanImage * gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
gsize width,
gsize height);