diff --git a/gsk/vulkan/gskvulkanimage.c b/gsk/vulkan/gskvulkanimage.c index f10ad5a1d1..4e5ab9fd7c 100644 --- a/gsk/vulkan/gskvulkanimage.c +++ b/gsk/vulkan/gskvulkanimage.c @@ -565,6 +565,102 @@ gsk_vulkan_image_new_from_data (GskVulkanUploader *uploader, return gsk_vulkan_image_new_from_data_directly (uploader, data, width, height, stride); } +GskVulkanImage * +gsk_vulkan_image_new_for_upload (GskVulkanUploader *uploader, + gsize width, + gsize height) +{ + GskVulkanImage *self; + + self = gsk_vulkan_image_new (uploader->vulkan, + width, + height, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM); + + return self; +} + +void +gsk_vulkan_image_map_memory (GskVulkanImage *self, + GskVulkanUploader *uploader, + GskVulkanImageMap *map) +{ + gsize buffer_size = self->width * self->height * 4; + + g_assert (self->vk_image_layout == VK_IMAGE_LAYOUT_UNDEFINED || + self->vk_image_layout == VK_IMAGE_LAYOUT_PREINITIALIZED); + + map->staging_buffer = gsk_vulkan_buffer_new_staging (uploader->vulkan, buffer_size); + map->data = gsk_vulkan_buffer_map (map->staging_buffer); + map->stride = self->width * 4; +} + +void +gsk_vulkan_image_unmap_memory (GskVulkanImage *self, + GskVulkanUploader *uploader, + GskVulkanImageMap *map) +{ + gsk_vulkan_buffer_unmap (map->staging_buffer); + + gsk_vulkan_uploader_add_buffer_barrier (uploader, + FALSE, + &(VkBufferMemoryBarrier) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_HOST_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = gsk_vulkan_buffer_get_buffer (map->staging_buffer), + .offset = 0, + .size = VK_WHOLE_SIZE, + }); + + gsk_vulkan_uploader_add_image_barrier (uploader, + FALSE, + self, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT); + + vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader), + gsk_vulkan_buffer_get_buffer (map->staging_buffer), + 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 = self->width, + .height = self->height, + .depth = 1 + } + } + }); + + gsk_vulkan_uploader_add_image_barrier (uploader, + TRUE, + self, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_SHADER_READ_BIT); + + uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, + map->staging_buffer); +} + GskVulkanImage * gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context, VkImage image, diff --git a/gsk/vulkan/gskvulkanimageprivate.h b/gsk/vulkan/gskvulkanimageprivate.h index 07f988bc66..fb311409b2 100644 --- a/gsk/vulkan/gskvulkanimageprivate.h +++ b/gsk/vulkan/gskvulkanimageprivate.h @@ -58,6 +58,27 @@ GskVulkanImage * gsk_vulkan_image_new_for_offscreen (GdkVulk GdkTexture * gsk_vulkan_image_download (GskVulkanImage *self, GskVulkanUploader *uploader); +typedef struct _GskVulkanImageMap GskVulkanImageMap; + +struct _GskVulkanImageMap +{ + guchar *data; + gsize stride; + + /* private */ + gpointer staging_buffer; +}; + +GskVulkanImage * gsk_vulkan_image_new_for_upload (GskVulkanUploader *uploader, + gsize width, + gsize height); +void gsk_vulkan_image_map_memory (GskVulkanImage *self, + GskVulkanUploader *uploader, + GskVulkanImageMap *map); +void gsk_vulkan_image_unmap_memory (GskVulkanImage *self, + GskVulkanUploader *uploader, + GskVulkanImageMap *map); + gsize gsk_vulkan_image_get_width (GskVulkanImage *self); gsize gsk_vulkan_image_get_height (GskVulkanImage *self); VkImage gsk_vulkan_image_get_image (GskVulkanImage *self);