vulkan: Add a Cairo upload node
authorBenjamin Otte <otte@redhat.com>
Sun, 25 Jun 2023 23:38:50 +0000 (01:38 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 16 Jul 2023 10:12:36 +0000 (12:12 +0200)
... and use it for cairo nodes.

gsk/meson.build
gsk/vulkan/gskvulkanrenderpass.c
gsk/vulkan/gskvulkanuploadcairoop.c [new file with mode: 0644]
gsk/vulkan/gskvulkanuploadcairoopprivate.h [new file with mode: 0644]

index fd201a583f446ce6abd691a3d026e69ad01dc285..df886cb4c9968e4978f2756947939829f800d44f 100644 (file)
@@ -135,6 +135,7 @@ if have_vulkan
     'vulkan/gskvulkantextpipeline.c',
     'vulkan/gskvulkantexturepipeline.c',
     'vulkan/gskvulkantextureop.c',
+    'vulkan/gskvulkanuploadcairoop.c',
     'vulkan/gskvulkanuploadop.c',
   ])
 
index 5f9d5c9f01ad54339252d20915f2cfcbb96ea249..cf430d053762ed95543f1422de1a3cace0045284 100644 (file)
@@ -28,6 +28,7 @@
 #include "gskvulkanpushconstantsprivate.h"
 #include "gskvulkanscissoropprivate.h"
 #include "gskvulkantextureopprivate.h"
+#include "gskvulkanuploadcairoopprivate.h"
 #include "gskvulkanuploadopprivate.h"
 #include "gskprivate.h"
 
@@ -393,6 +394,26 @@ gsk_vulkan_render_pass_get_node_as_image (GskVulkanRenderPass       *self,
         return result;
       }
 
+    case GSK_CAIRO_NODE:
+      {
+        graphene_rect_t clipped;
+
+        graphene_rect_offset_r (&state->clip.rect.bounds, - state->offset.x, - state->offset.y, &clipped);
+        graphene_rect_intersection (&clipped, &node->bounds, &clipped);
+
+        if (clipped.size.width == 0 || clipped.size.height == 0)
+          return NULL;
+
+        result = gsk_vulkan_upload_cairo_op_init (gsk_vulkan_render_pass_alloc_op (self, gsk_vulkan_upload_cairo_op_size ()),
+                                                  self->vulkan,
+                                                  node,
+                                                  &state->scale,
+                                                  &clipped);
+
+        *tex_bounds = clipped;
+        return result;
+      }
+
     default:
       {
         graphene_rect_t clipped;
diff --git a/gsk/vulkan/gskvulkanuploadcairoop.c b/gsk/vulkan/gskvulkanuploadcairoop.c
new file mode 100644 (file)
index 0000000..c3cbf0e
--- /dev/null
@@ -0,0 +1,134 @@
+#include "config.h"
+
+#include "gskvulkanuploadcairoopprivate.h"
+
+typedef struct _GskVulkanUploadCairoOp GskVulkanUploadCairoOp;
+
+struct _GskVulkanUploadCairoOp
+{
+  GskVulkanOp op;
+
+  GskVulkanImage *image;
+  GskRenderNode *node;
+  graphene_rect_t viewport;
+};
+
+static void
+gsk_vulkan_upload_cairo_op_finish (GskVulkanOp *op)
+{
+  GskVulkanUploadCairoOp *self = (GskVulkanUploadCairoOp *) op;
+
+  g_object_unref (self->image);
+  gsk_render_node_unref (self->node);
+}
+
+static void
+gsk_vulkan_upload_cairo_op_upload (GskVulkanOp           *op,
+                                   GskVulkanRenderPass   *pass,
+                                   GskVulkanRender       *render,
+                                   GskVulkanUploader     *uploader,
+                                   const graphene_rect_t *clip,
+                                   const graphene_vec2_t *scale)
+{
+  GskVulkanUploadCairoOp *self = (GskVulkanUploadCairoOp *) op;
+  GskVulkanImageMap map;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  int width, height;
+
+  width = gsk_vulkan_image_get_width (self->image);
+  height = gsk_vulkan_image_get_height (self->image);
+
+  gsk_vulkan_image_map_memory (self->image, uploader, GSK_VULKAN_WRITE, &map);
+  surface = cairo_image_surface_create_for_data (map.data,
+                                                 CAIRO_FORMAT_ARGB32,
+                                                 width, height,
+                                                 map.stride);
+  cairo_surface_set_device_scale (surface,
+                                  width / self->viewport.size.width,
+                                  height / self->viewport.size.height);
+  cr = cairo_create (surface);
+  cairo_translate (cr, -self->viewport.origin.x, -self->viewport.origin.y);
+
+  gsk_render_node_draw (self->node, cr);
+
+  cairo_destroy (cr);
+
+  cairo_surface_finish (surface);
+  cairo_surface_destroy (surface);
+
+  gsk_vulkan_image_unmap_memory (self->image, uploader, &map);
+}
+
+static gsize
+gsk_vulkan_upload_cairo_op_count_vertex_data (GskVulkanOp *op,
+                                              gsize        n_bytes)
+{
+  return n_bytes;
+}
+
+static void
+gsk_vulkan_upload_cairo_op_collect_vertex_data (GskVulkanOp         *op,
+                                                GskVulkanRenderPass *pass,
+                                                GskVulkanRender     *render,
+                                                guchar              *data)
+{
+}
+
+static void
+gsk_vulkan_upload_cairo_op_reserve_descriptor_sets (GskVulkanOp     *op,
+                                                    GskVulkanRender *render)
+{
+}
+
+static GskVulkanPipeline *
+gsk_vulkan_upload_cairo_op_get_pipeline (GskVulkanOp *op)
+{
+  return NULL;
+}
+
+static void
+gsk_vulkan_upload_cairo_op_command (GskVulkanOp      *op,
+                                    GskVulkanRender  *render,
+                                    VkPipelineLayout  pipeline_layout,
+                                    VkCommandBuffer   command_buffer)
+{
+}
+
+static const GskVulkanOpClass GSK_VULKAN_UPLOAD_CAIRO_OP_CLASS = {
+  GSK_VULKAN_OP_SIZE (GskVulkanUploadCairoOp),
+  gsk_vulkan_upload_cairo_op_finish,
+  gsk_vulkan_upload_cairo_op_upload,
+  gsk_vulkan_upload_cairo_op_count_vertex_data,
+  gsk_vulkan_upload_cairo_op_collect_vertex_data,
+  gsk_vulkan_upload_cairo_op_reserve_descriptor_sets,
+  gsk_vulkan_upload_cairo_op_get_pipeline,
+  gsk_vulkan_upload_cairo_op_command
+};
+
+gsize
+gsk_vulkan_upload_cairo_op_size (void)
+{
+  return GSK_VULKAN_UPLOAD_CAIRO_OP_CLASS.size;
+}
+
+GskVulkanImage *
+gsk_vulkan_upload_cairo_op_init (GskVulkanOp           *op,
+                                 GdkVulkanContext      *context,
+                                 GskRenderNode         *node,
+                                 const graphene_vec2_t *scale,
+                                 const graphene_rect_t *viewport)
+{
+  GskVulkanUploadCairoOp *self = (GskVulkanUploadCairoOp *) op;
+
+  gsk_vulkan_op_init (op, &GSK_VULKAN_UPLOAD_CAIRO_OP_CLASS);
+
+  self->node = gsk_render_node_ref (node);
+  self->image = gsk_vulkan_image_new_for_upload (context,
+                                                 GDK_MEMORY_DEFAULT,
+                                                 ceil (graphene_vec2_get_x (scale) * viewport->size.width),
+                                                 ceil (graphene_vec2_get_y (scale) * viewport->size.height));
+  self->viewport = *viewport;
+
+  return self->image;
+}
diff --git a/gsk/vulkan/gskvulkanuploadcairoopprivate.h b/gsk/vulkan/gskvulkanuploadcairoopprivate.h
new file mode 100644 (file)
index 0000000..398f854
--- /dev/null
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "gskvulkanopprivate.h"
+
+G_BEGIN_DECLS
+
+gsize                   gsk_vulkan_upload_cairo_op_size                 (void) G_GNUC_CONST;
+
+GskVulkanImage *        gsk_vulkan_upload_cairo_op_init                 (GskVulkanOp                    *op,
+                                                                         GdkVulkanContext               *context,
+                                                                         GskRenderNode                  *node,
+                                                                         const graphene_vec2_t          *scale,
+                                                                         const graphene_rect_t          *viewport);
+
+
+
+G_END_DECLS
+