gtk/gsk/gskvulkanimage.c
Georges Basile Stavracas Neto 147a455171 vulkan: Destroy image before releasing associate memory
VkImage contains a reference to the VkDeviceMemory and, because
the current code frees the VkDeviceMemory before destroying the
VkImage that references it, a warning is triggered by the validation
layers.

This is not critical, since we release both resources at the same
place. But the warning triggered by the validation layers sums up
adding 1 MB per second of extra debug logging, making the debugging
process much more painful.

This commit simply swaps the destruction order, and destroys the
VkImage first, then the now unused VkDeviceMemory.
2017-12-13 22:49:16 -02:00

821 lines
30 KiB
C

#include "config.h"
#include "gskvulkanimageprivate.h"
#include "gskvulkanbufferprivate.h"
#include "gskvulkanmemoryprivate.h"
#include "gskvulkanpipelineprivate.h"
#include <string.h>
struct _GskVulkanUploader
{
GdkVulkanContext *vulkan;
GskVulkanCommandPool *command_pool;
GArray *before_buffer_barriers;
GArray *before_image_barriers;
VkCommandBuffer copy_buffer;
GArray *after_buffer_barriers;
GArray *after_image_barriers;
GSList *staging_image_free_list;
GSList *staging_buffer_free_list;
};
struct _GskVulkanImage
{
GObject parent_instance;
GdkVulkanContext *vulkan;
gsize width;
gsize height;
VkImageUsageFlags vk_usage;
VkImage vk_image;
VkImageView vk_image_view;
VkImageLayout vk_image_layout;
VkAccessFlags vk_access;
GskVulkanMemory *memory;
};
G_DEFINE_TYPE (GskVulkanImage, gsk_vulkan_image, G_TYPE_OBJECT)
GskVulkanUploader *
gsk_vulkan_uploader_new (GdkVulkanContext *context,
GskVulkanCommandPool *command_pool)
{
GskVulkanUploader *self;
self = g_slice_new0 (GskVulkanUploader);
self->vulkan = g_object_ref (context);
self->command_pool = command_pool;
self->before_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
self->after_buffer_barriers = g_array_new (FALSE, FALSE, sizeof (VkBufferMemoryBarrier));
self->before_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
self->after_image_barriers = g_array_new (FALSE, FALSE, sizeof (VkImageMemoryBarrier));
return self;
}
void
gsk_vulkan_uploader_free (GskVulkanUploader *self)
{
gsk_vulkan_uploader_reset (self);
g_array_unref (self->after_buffer_barriers);
g_array_unref (self->before_buffer_barriers);
g_array_unref (self->after_image_barriers);
g_array_unref (self->before_image_barriers);
g_object_unref (self->vulkan);
g_slice_free (GskVulkanUploader, self);
}
static void
gsk_vulkan_uploader_add_image_barrier (GskVulkanUploader *self,
gboolean after,
GskVulkanImage *image,
VkImageLayout new_layout,
VkAccessFlags new_access)
{
GArray *array;
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = image->vk_access,
.dstAccessMask = new_access,
.oldLayout = image->vk_image_layout,
.newLayout = new_layout,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image->vk_image,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1
}
};
if (after)
array = self->after_image_barriers;
else
array = self->before_image_barriers;
g_array_append_val (array, barrier);
image->vk_image_layout = new_layout;
image->vk_access = new_access;
}
static void
gsk_vulkan_uploader_add_buffer_barrier (GskVulkanUploader *self,
gboolean after,
const VkBufferMemoryBarrier *barrier)
{
GArray *array;
if (after)
array = self->after_buffer_barriers;
else
array = self->before_buffer_barriers;
g_array_append_val (array, *barrier);
}
static VkCommandBuffer
gsk_vulkan_uploader_get_copy_buffer (GskVulkanUploader *self)
{
if (self->copy_buffer == VK_NULL_HANDLE)
self->copy_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
return self->copy_buffer;
}
void
gsk_vulkan_uploader_upload (GskVulkanUploader *self)
{
if (self->before_buffer_barriers->len > 0 || self->before_image_barriers->len > 0)
{
VkCommandBuffer command_buffer;
command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
vkCmdPipelineBarrier (command_buffer,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
self->before_buffer_barriers->len, (VkBufferMemoryBarrier *) self->before_buffer_barriers->data,
self->before_image_barriers->len, (VkImageMemoryBarrier *) self->before_image_barriers->data);
gsk_vulkan_command_pool_submit_buffer (self->command_pool, command_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
g_array_set_size (self->before_buffer_barriers, 0);
g_array_set_size (self->before_image_barriers, 0);
}
/* append these to existing buffer */
if (self->after_buffer_barriers->len > 0 || self->after_image_barriers->len > 0)
{
VkCommandBuffer command_buffer = gsk_vulkan_uploader_get_copy_buffer (self);
vkCmdPipelineBarrier (command_buffer,
VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, NULL,
self->after_buffer_barriers->len, (VkBufferMemoryBarrier *) self->after_buffer_barriers->data,
self->after_image_barriers->len, (VkImageMemoryBarrier *) self->after_image_barriers->data);
g_array_set_size (self->after_buffer_barriers, 0);
g_array_set_size (self->after_image_barriers, 0);
}
if (self->copy_buffer != VK_NULL_HANDLE)
{
gsk_vulkan_command_pool_submit_buffer (self->command_pool, self->copy_buffer, 0, NULL, 0, NULL, VK_NULL_HANDLE);
self->copy_buffer = VK_NULL_HANDLE;
}
}
void
gsk_vulkan_uploader_reset (GskVulkanUploader *self)
{
g_array_set_size (self->before_image_barriers, 0);
self->copy_buffer = VK_NULL_HANDLE;
g_array_set_size (self->after_image_barriers, 0);
g_slist_free_full (self->staging_image_free_list, g_object_unref);
self->staging_image_free_list = NULL;
g_slist_free_full (self->staging_buffer_free_list, (GDestroyNotify) gsk_vulkan_buffer_free);
self->staging_buffer_free_list = NULL;
}
static GskVulkanImage *
gsk_vulkan_image_new (GdkVulkanContext *context,
gsize width,
gsize height,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageLayout layout,
VkAccessFlags access,
VkMemoryPropertyFlags memory)
{
VkMemoryRequirements requirements;
GskVulkanImage *self;
self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
self->vulkan = g_object_ref (context);
self->width = width;
self->height = height;
self->vk_usage = usage;
self->vk_image_layout = layout;
self->vk_access = access;
GSK_VK_CHECK (vkCreateImage, gdk_vulkan_context_get_device (context),
&(VkImageCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.flags = 0,
.imageType = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_B8G8R8A8_UNORM,
.extent = { width, height, 1 },
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = tiling,
.usage = usage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.initialLayout = self->vk_image_layout,
},
NULL,
&self->vk_image);
vkGetImageMemoryRequirements (gdk_vulkan_context_get_device (context),
self->vk_image,
&requirements);
self->memory = gsk_vulkan_memory_new (context,
requirements.memoryTypeBits,
memory,
requirements.size);
GSK_VK_CHECK (vkBindImageMemory, gdk_vulkan_context_get_device (context),
self->vk_image,
gsk_vulkan_memory_get_device_memory (self->memory),
0);
return self;
}
static void
gsk_vulkan_image_upload_data (GskVulkanImage *self,
guchar *data,
gsize width,
gsize height,
gsize data_stride)
{
VkImageSubresource image_res;
VkSubresourceLayout image_layout;
gsize mem_stride;
guchar *mem;
image_res.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_res.mipLevel = 0;
image_res.arrayLayer = 0;
mem_stride = width * 4;
vkGetImageSubresourceLayout (gdk_vulkan_context_get_device (self->vulkan),
self->vk_image, &image_res, &image_layout);
mem = gsk_vulkan_memory_map (self->memory) + image_layout.offset;
if (image_layout.rowPitch == width * 4 && data_stride == mem_stride)
{
memcpy (mem, data, data_stride * height);
}
else
{
for (gsize i = 0; i < height; i++)
{
memcpy (mem + i * image_layout.rowPitch, data + i * data_stride, width * 4);
}
}
gsk_vulkan_memory_unmap (self->memory);
}
static void
gsk_vulkan_image_ensure_view (GskVulkanImage *self,
VkFormat format)
{
if (self->vk_image_view == VK_NULL_HANDLE)
GSK_VK_CHECK (vkCreateImageView, gdk_vulkan_context_get_device (self->vulkan),
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = self->vk_image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = format,
.components = {
.r = VK_COMPONENT_SWIZZLE_R,
.g = VK_COMPONENT_SWIZZLE_G,
.b = VK_COMPONENT_SWIZZLE_B,
.a = VK_COMPONENT_SWIZZLE_A,
},
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
NULL,
&self->vk_image_view);
}
static GskVulkanImage *
gsk_vulkan_image_new_from_data_via_staging_buffer (GskVulkanUploader *uploader,
guchar *data,
gsize width,
gsize height,
gsize stride)
{
GskVulkanImage *self;
GskVulkanBuffer *staging;
gsize buffer_size = width * height * 4;
guchar *mem;
staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, buffer_size);
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);
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(staging),
.offset = 0,
.size = buffer_size,
});
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_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 (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
}
}
});
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, staging);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
static GskVulkanImage *
gsk_vulkan_image_new_from_data_via_staging_image (GskVulkanUploader *uploader,
guchar *data,
gsize width,
gsize height,
gsize stride)
{
GskVulkanImage *self, *staging;
staging = gsk_vulkan_image_new (uploader->vulkan,
width,
height,
VK_IMAGE_TILING_LINEAR,
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
gsk_vulkan_image_upload_data (staging, data, width, height, stride);
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_uploader_add_image_barrier (uploader,
FALSE,
staging,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT);
gsk_vulkan_uploader_add_image_barrier (uploader,
FALSE,
self,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT);
vkCmdCopyImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
staging->vk_image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
self->vk_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&(VkImageCopy) {
.srcSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.srcOffset = { 0, 0, 0 },
.dstSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.dstOffset = { 0, 0, 0 },
.extent = {
.width = width,
.height = 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_image_free_list = g_slist_prepend (uploader->staging_image_free_list, staging);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
static GskVulkanImage *
gsk_vulkan_image_new_from_data_directly (GskVulkanUploader *uploader,
guchar *data,
gsize width,
gsize height,
gsize stride)
{
GskVulkanImage *self;
self = gsk_vulkan_image_new (uploader->vulkan,
width,
height,
VK_IMAGE_TILING_LINEAR,
VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_ACCESS_HOST_WRITE_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
gsk_vulkan_image_upload_data (self, data, width, height, stride);
gsk_vulkan_uploader_add_image_barrier (uploader,
TRUE,
self,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_ACCESS_SHADER_READ_BIT);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
GskVulkanImage *
gsk_vulkan_image_new_from_data (GskVulkanUploader *uploader,
guchar *data,
gsize width,
gsize height,
gsize stride)
{
if (GSK_RENDER_MODE_CHECK (STAGING_BUFFER))
return gsk_vulkan_image_new_from_data_via_staging_buffer (uploader, data, width, height, stride);
if (GSK_RENDER_MODE_CHECK (STAGING_IMAGE))
return gsk_vulkan_image_new_from_data_via_staging_image (uploader, data, width, height, stride);
else
return gsk_vulkan_image_new_from_data_directly (uploader, data, width, height, stride);
}
GskVulkanImage *
gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
VkImage image,
VkFormat format,
gsize width,
gsize height)
{
GskVulkanImage *self;
self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
self->vulkan = g_object_ref (context);
self->width = width;
self->height = height;
self->vk_image = image;
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
GskVulkanImage *
gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
gsize width,
gsize height)
{
GskVulkanImage *self;
self = gsk_vulkan_image_new (context,
width,
height,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
GskVulkanImage *
gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
gsize width,
gsize height)
{
GskVulkanImage *self;
self = gsk_vulkan_image_new (context,
width,
height,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
0,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
GskVulkanImage *
gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
gsize width,
gsize height)
{
GskVulkanImage *self;
self = gsk_vulkan_image_new (context,
width,
height,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
0,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
GdkTexture *
gsk_vulkan_image_download (GskVulkanImage *self,
GskVulkanUploader *uploader)
{
GskVulkanBuffer *buffer;
GdkTexture *texture;
guchar *mem;
gsk_vulkan_uploader_add_image_barrier (uploader,
FALSE,
self,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT);
buffer = gsk_vulkan_buffer_new_download (self->vulkan, self->width * self->height * 4);
vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader),
self->vk_image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
gsk_vulkan_buffer_get_buffer (buffer),
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_upload (uploader);
GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
mem = gsk_vulkan_buffer_map (buffer);
texture = gdk_texture_new_for_data (mem, self->width, self->height, self->width * 4);
gsk_vulkan_buffer_unmap (buffer);
gsk_vulkan_buffer_free (buffer);
return texture;
}
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;
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);
bufferImageCopy = alloca (sizeof (VkBufferImageCopy) * num_regions);
memset (bufferImageCopy, 0, sizeof (VkBufferImageCopy) * num_regions);
offset = 0;
for (int i = 0; i < num_regions; i++)
{
m = mem + offset;
if (regions[i].stride == regions[i].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);
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 (staging),
self->vk_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
num_regions,
bufferImageCopy);
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, staging);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
}
static void
gsk_vulkan_image_finalize (GObject *object)
{
GskVulkanImage *self = GSK_VULKAN_IMAGE (object);
if (self->vk_image_view != VK_NULL_HANDLE)
{
vkDestroyImageView (gdk_vulkan_context_get_device (self->vulkan),
self->vk_image_view,
NULL);
}
/* memory is NULL for for_swapchain() images, where we don't own
* the VkImage */
if (self->memory)
{
vkDestroyImage (gdk_vulkan_context_get_device (self->vulkan),
self->vk_image,
NULL);
gsk_vulkan_memory_free (self->memory);
}
g_object_unref (self->vulkan);
G_OBJECT_CLASS (gsk_vulkan_image_parent_class)->finalize (object);
}
static void
gsk_vulkan_image_class_init (GskVulkanImageClass *klass)
{
G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_image_finalize;
}
static void
gsk_vulkan_image_init (GskVulkanImage *self)
{
}
gsize
gsk_vulkan_image_get_width (GskVulkanImage *self)
{
return self->width;
}
gsize
gsk_vulkan_image_get_height (GskVulkanImage *self)
{
return self->height;
}
VkImage
gsk_vulkan_image_get_image (GskVulkanImage *self)
{
return self->vk_image;
}
VkImageView
gsk_vulkan_image_get_image_view (GskVulkanImage *self)
{
return self->vk_image_view;
}