--- /dev/null
+#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,
+ VkPipelineLayout pipeline_layout,
+ VkCommandBuffer command_buffer,
+ GskVulkanImage *image,
+ const cairo_rectangle_int_t *area,
+ GskVulkanBuffer **buffer)
+{
+ VkImageLayout image_layout;
+ VkAccessFlags access;
+ gsize stride;
+
+ 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,
+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+ 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_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,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ 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, 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,
+ VkPipelineLayout pipeline_layout,
+ VkCommandBuffer command_buffer)
+{
+ GskVulkanDownloadOp *self = (GskVulkanDownloadOp *) op;
+
+ return gsk_vulkan_download_op_command_with_area (op,
+ render,
+ pipeline_layout,
+ 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,
+ NULL,
+ NULL,
+ 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);
+}
#include "gskrendererprivate.h"
#include "gskvulkanbufferprivate.h"
#include "gskvulkancommandpoolprivate.h"
+#include "gskvulkandownloadopprivate.h"
#include "gskvulkanglyphcacheprivate.h"
#include "gskvulkanprivate.h"
#include "gskvulkanpushconstantsopprivate.h"
}
static void
-gsk_vulkan_render_add_node (GskVulkanRender *self,
- GskRenderNode *node)
+gsk_vulkan_render_add_node (GskVulkanRender *self,
+ GskRenderNode *node,
+ GskVulkanDownloadFunc download_func,
+ gpointer download_data)
{
graphene_vec2_t scale;
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+ if (download_func)
+ gsk_vulkan_download_op (self, self->target, download_func, download_data);
+
gsk_vulkan_render_seal_ops (self);
gsk_vulkan_render_verbose_print (self, "start of frame");
gsk_vulkan_render_sort_ops (self);
GskVulkanImage *target,
const graphene_rect_t *rect,
const cairo_region_t *clip,
- GskRenderNode *node)
+ GskRenderNode *node,
+ GskVulkanDownloadFunc download_func,
+ gpointer download_data)
{
gsk_vulkan_render_cleanup (self);
gsk_vulkan_render_setup (self, target, rect, clip);
- gsk_vulkan_render_add_node (self, node);
+ gsk_vulkan_render_add_node (self, node, download_func, download_data);
gsk_vulkan_render_submit (self);
}
g_clear_object (&self->vulkan);
}
+static void
+gsk_vulkan_renderer_download_texture_cb (gpointer user_data,
+ GdkMemoryFormat format,
+ const guchar *data,
+ int width,
+ int height,
+ gsize stride)
+{
+ GdkTexture **texture = (GdkTexture **) user_data;
+ GBytes *bytes;
+
+ bytes = g_bytes_new (data, stride * height);
+ *texture = gdk_memory_texture_new (width, height,
+ format,
+ bytes,
+ stride);
+ g_bytes_unref (bytes);
+}
+
static GdkTexture *
gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
GskRenderNode *root,
rounded_viewport.size.width,
rounded_viewport.size.height);
- gsk_vulkan_render_render (render, image, &rounded_viewport, NULL, root);
+ texture = NULL;
+ gsk_vulkan_render_render (render,
+ image,
+ &rounded_viewport,
+ NULL,
+ root,
+ gsk_vulkan_renderer_download_texture_cb,
+ &texture);
- texture = gsk_vulkan_render_download_target (render);
-
- g_object_unref (image);
gsk_vulkan_render_free (render);
+ g_object_unref (image);
+
+ /* check that callback setting texture was actually called, as its technically async */
+ g_assert (texture);
#ifdef G_ENABLE_DEBUG
start_time = gsk_profiler_timer_get_start (profiler, self->profile_timers.cpu_time);
render_region = get_render_region (self);
draw_index = gdk_vulkan_context_get_draw_index (self->vulkan);
- gsk_vulkan_render_render (render, self->targets[draw_index], NULL, render_region, root);
+ gsk_vulkan_render_render (render,
+ self->targets[draw_index],
+ NULL,
+ render_region,
+ root,
+ NULL, NULL);
#ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (profiler, self->profile_counters.frames);