forked from AuroraMiddleware/gtk
147a455171
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.
821 lines
30 KiB
C
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;
|
|
}
|