gtk/gsk/vulkan/gskvulkandownloadop.c
Benjamin Otte fee497f9e1 vulkan: Track the current pipeline stage of images
This way, we can in theory properly transition images because we know
which stage to transition from.

IN practice this is happening in future commits.
2023-07-16 13:16:43 +02:00

279 lines
11 KiB
C

#include "config.h"
#include "gskvulkandownloadopprivate.h"
#include "gskvulkanprivate.h"
#include "gdk/gdkmemoryformatprivate.h"
static gsize
gsk_vulkan_download_op_count_vertex_data (GskVulkanOp *op,
gsize n_bytes)
{
return n_bytes;
}
static void
gsk_vulkan_download_op_collect_vertex_data (GskVulkanOp *op,
guchar *data)
{
}
static void
gsk_vulkan_download_op_reserve_descriptor_sets (GskVulkanOp *op,
GskVulkanRender *render)
{
}
static GskVulkanOp *
gsk_vulkan_download_op_command_with_area (GskVulkanOp *op,
GskVulkanRender *render,
VkCommandBuffer command_buffer,
GskVulkanImage *image,
const cairo_rectangle_int_t *area,
GskVulkanBuffer **buffer)
{
VkPipelineStageFlags stage;
VkImageLayout image_layout;
VkAccessFlags access;
gsize stride;
stage = gsk_vulkan_image_get_vk_pipeline_stage (image);
image_layout = gsk_vulkan_image_get_vk_image_layout (image);
access = gsk_vulkan_image_get_vk_access (image);
stride = area->width * gdk_memory_format_bytes_per_pixel (gsk_vulkan_image_get_format (image));
*buffer = gsk_vulkan_buffer_new_map (gsk_vulkan_render_get_context (render),
area->height * stride,
GSK_VULKAN_READ);
vkCmdPipelineBarrier (command_buffer,
stage,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
1, &(VkBufferMemoryBarrier) {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_HOST_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = gsk_vulkan_buffer_get_buffer (*buffer),
.offset = 0,
.size = VK_WHOLE_SIZE,
},
1, &(VkImageMemoryBarrier) {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = access,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.oldLayout = image_layout,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = gsk_vulkan_image_get_vk_image (image),
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1
},
});
gsk_vulkan_image_set_vk_image_layout (image,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT);
vkCmdCopyImageToBuffer (command_buffer,
gsk_vulkan_image_get_vk_image (image),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
gsk_vulkan_buffer_get_buffer (*buffer),
1,
(VkBufferImageCopy[1]) {
{
.bufferOffset = 0,
.bufferRowLength = area->width,
.bufferImageHeight = area->height,
.imageSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.imageOffset = {
.x = area->x,
.y = area->y,
.z = 0
},
.imageExtent = {
.width = area->width,
.height = area->height,
.depth = 1
}
}
});
vkCmdPipelineBarrier (command_buffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
stage,
0,
0, NULL,
0, NULL,
1, &(VkImageMemoryBarrier) {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = gsk_vulkan_image_get_vk_access (image),
.dstAccessMask = access,
.oldLayout = gsk_vulkan_image_get_vk_image_layout (image),
.newLayout = image_layout,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = gsk_vulkan_image_get_vk_image (image),
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1
},
});
gsk_vulkan_image_set_vk_image_layout (image, stage, image_layout, access);
return op->next;
}
typedef struct _GskVulkanDownloadOp GskVulkanDownloadOp;
struct _GskVulkanDownloadOp
{
GskVulkanOp op;
GskVulkanImage *image;
GskVulkanDownloadFunc func;
gpointer user_data;
GskVulkanBuffer *buffer;
};
static void
gsk_vulkan_download_op_finish (GskVulkanOp *op)
{
GskVulkanDownloadOp *self = (GskVulkanDownloadOp *) op;
guchar *data;
gsize stride;
data = gsk_vulkan_buffer_map (self->buffer);
stride = gsk_vulkan_image_get_width (self->image) *
gdk_memory_format_bytes_per_pixel (gsk_vulkan_image_get_format (self->image));
self->func (self->user_data,
gsk_vulkan_image_get_format (self->image),
data,
gsk_vulkan_image_get_width (self->image),
gsk_vulkan_image_get_height (self->image),
stride);
gsk_vulkan_buffer_unmap (self->buffer);
g_object_unref (self->image);
g_clear_pointer (&self->buffer, gsk_vulkan_buffer_free);
}
static void
gsk_vulkan_download_op_print (GskVulkanOp *op,
GString *string,
guint indent)
{
GskVulkanDownloadOp *self = (GskVulkanDownloadOp *) op;
print_indent (string, indent);
g_string_append (string, "download ");
print_image (string, self->image);
print_newline (string);
}
static GskVulkanOp *
gsk_vulkan_download_op_command (GskVulkanOp *op,
GskVulkanRender *render,
VkRenderPass render_pass,
VkCommandBuffer command_buffer)
{
GskVulkanDownloadOp *self = (GskVulkanDownloadOp *) op;
return gsk_vulkan_download_op_command_with_area (op,
render,
command_buffer,
self->image,
&(cairo_rectangle_int_t) {
0, 0,
gsk_vulkan_image_get_width (self->image),
gsk_vulkan_image_get_height (self->image)
},
&self->buffer);
}
static const GskVulkanOpClass GSK_VULKAN_DOWNLOAD_OP_CLASS = {
GSK_VULKAN_OP_SIZE (GskVulkanDownloadOp),
GSK_VULKAN_STAGE_COMMAND,
gsk_vulkan_download_op_finish,
gsk_vulkan_download_op_print,
gsk_vulkan_download_op_count_vertex_data,
gsk_vulkan_download_op_collect_vertex_data,
gsk_vulkan_download_op_reserve_descriptor_sets,
gsk_vulkan_download_op_command
};
void
gsk_vulkan_download_op (GskVulkanRender *render,
GskVulkanImage *image,
GskVulkanDownloadFunc func,
gpointer user_data)
{
GskVulkanDownloadOp *self;
self = (GskVulkanDownloadOp *) gsk_vulkan_op_alloc (render, &GSK_VULKAN_DOWNLOAD_OP_CLASS);
self->image = g_object_ref (image);
self->func = func,
self->user_data = user_data;
}
static void
gsk_vulkan_download_save_png_cb (gpointer filename,
GdkMemoryFormat format,
const guchar *data,
int width,
int height,
gsize stride)
{
GdkTexture *texture;
GBytes *bytes;
bytes = g_bytes_new_static (data, stride * height);
texture = gdk_memory_texture_new (width, height,
format,
bytes,
stride);
gdk_texture_save_to_png (texture, filename);
g_object_unref (texture);
g_bytes_unref (bytes);
g_free (filename);
}
void
gsk_vulkan_download_png_op (GskVulkanRender *render,
GskVulkanImage *image,
const char *filename_format,
...)
{
va_list args;
char *filename;
va_start (args, filename_format);
filename = g_strdup_vprintf (filename_format, args);
va_end (args);
gsk_vulkan_download_op (render,
image,
gsk_vulkan_download_save_png_cb,
filename);
}