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); command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
vkCmdPipelineBarrier (command_buffer, vkCmdPipelineBarrier (command_buffer,
#if 0
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
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,
0, NULL, 0, NULL,
self->before_buffer_barriers->len, (VkBufferMemoryBarrier *) self->before_buffer_barriers->data, 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); VkCommandBuffer command_buffer = gsk_vulkan_uploader_get_copy_buffer (self);
vkCmdPipelineBarrier (command_buffer, vkCmdPipelineBarrier (command_buffer,
#if 0
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
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,
0, NULL, 0, NULL,
self->after_buffer_barriers->len, (VkBufferMemoryBarrier *) self->after_buffer_barriers->data, 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 stride,
gsize x, gsize x,
gsize y) 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; GskVulkanBuffer *staging;
guchar *mem; 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); 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); m = mem + offset;
if (regions[i].stride == regions[i].width * 4)
{
memcpy (m, regions[i].data, regions[i].stride * regions[i].height);
} }
else else
{ {
for (gsize i = 0; i < height; i++) 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);
memcpy (mem + i * width * 4, data + i * stride, 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); gsk_vulkan_buffer_unmap (staging);
@ -694,24 +747,8 @@ gsk_vulkan_image_upload_region (GskVulkanImage *self,
gsk_vulkan_buffer_get_buffer (staging), gsk_vulkan_buffer_get_buffer (staging),
self->vk_image, self->vk_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, num_regions,
(VkBufferImageCopy[1]) { bufferImageCopy);
{
.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
}
}
});
gsk_vulkan_uploader_add_image_barrier (uploader, gsk_vulkan_uploader_add_image_barrier (uploader,
TRUE, TRUE,

View File

@ -39,6 +39,20 @@ void gsk_vulkan_image_upload_region (GskVulk
gsize stride, gsize stride,
gsize x, gsize x,
gsize y); 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, GskVulkanImage * gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
gsize width, gsize width,
gsize height); gsize height);