vulkan: Add a clear op
authorBenjamin Otte <otte@redhat.com>
Wed, 12 Jul 2023 07:26:24 +0000 (09:26 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 16 Jul 2023 11:16:15 +0000 (13:16 +0200)
The op emits a vkCmdClearAttachments() with a given color. That can be
used with color nodes that are pixel-aligned and opaque to significantly
speed up rendering when the window background is a solid color.

However, currently this fails a bit outside of fullscreen when rounded
clip rectangles are in use to draw rounded corners.

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

index 224573db4201a0c76d1eb880263a101d72fbc869..7422b8eac3695d659a8b751eeb498e0a0874e1d9 100644 (file)
@@ -111,6 +111,7 @@ if have_vulkan
     'vulkan/gskvulkanblurop.c',
     'vulkan/gskvulkanborderop.c',
     'vulkan/gskvulkanbuffer.c',
+    'vulkan/gskvulkanclearop.c',
     'vulkan/gskvulkanclip.c',
     'vulkan/gskvulkancolormatrixop.c',
     'vulkan/gskvulkancolorop.c',
diff --git a/gsk/vulkan/gskvulkanclearop.c b/gsk/vulkan/gskvulkanclearop.c
new file mode 100644 (file)
index 0000000..edb1ad3
--- /dev/null
@@ -0,0 +1,124 @@
+#include "config.h"
+
+#include "gskvulkanclearopprivate.h"
+
+#include "gskvulkanprivate.h"
+
+typedef struct _GskVulkanClearOp GskVulkanClearOp;
+
+struct _GskVulkanClearOp
+{
+  GskVulkanOp op;
+
+  cairo_rectangle_int_t rect;
+  GdkRGBA color;
+};
+
+static void
+gsk_vulkan_clear_op_finish (GskVulkanOp *op)
+{
+}
+
+static void
+gsk_vulkan_clear_op_print (GskVulkanOp *op,
+                           GString     *string,
+                           guint        indent)
+{
+  GskVulkanClearOp *self = (GskVulkanClearOp *) op;
+
+  print_indent (string, indent);
+  print_int_rect (string, &self->rect);
+  g_string_append_printf (string, "clear ");
+  print_rgba (string, &self->color);
+  print_newline (string);
+}
+
+static void
+gsk_vulkan_clear_op_upload (GskVulkanOp       *op,
+                            GskVulkanUploader *uploader)
+{
+}
+
+static gsize
+gsk_vulkan_clear_op_count_vertex_data (GskVulkanOp *op,
+                                       gsize        n_bytes)
+{
+  return n_bytes;
+}
+
+static void
+gsk_vulkan_clear_op_collect_vertex_data (GskVulkanOp *op,
+                                         guchar      *data)
+{
+}
+
+static void
+gsk_vulkan_clear_op_reserve_descriptor_sets (GskVulkanOp     *op,
+                                             GskVulkanRender *render)
+{
+}
+
+static void
+gsk_vulkan_init_clear_value (VkClearValue  *value,
+                             const GdkRGBA *rgba)
+{
+  gsk_vulkan_rgba_to_float (rgba, value->color.float32);
+}
+
+static GskVulkanOp *
+gsk_vulkan_clear_op_command (GskVulkanOp      *op,
+                             GskVulkanRender  *render,
+                             VkPipelineLayout  pipeline_layout,
+                             VkCommandBuffer   command_buffer)
+{
+  GskVulkanClearOp *self = (GskVulkanClearOp *) op;
+  VkClearValue clear_value;
+
+  gsk_vulkan_init_clear_value (&clear_value, &self->color);
+
+  vkCmdClearAttachments (command_buffer,
+                         1,
+                         &(VkClearAttachment) {
+                           VK_IMAGE_ASPECT_COLOR_BIT,
+                           0,
+                           clear_value,
+                         },
+                         1,
+                         &(VkClearRect) {
+                           {
+                             { self->rect.x, self->rect.y },
+                             { self->rect.width, self->rect.height },
+                           },
+                           0,
+                           1
+                         });
+
+  return op->next;
+}
+
+static const GskVulkanOpClass GSK_VULKAN_SCISSOR_OP_CLASS = {
+  GSK_VULKAN_OP_SIZE (GskVulkanClearOp),
+  GSK_VULKAN_STAGE_COMMAND,
+  NULL,
+  NULL,
+  gsk_vulkan_clear_op_finish,
+  gsk_vulkan_clear_op_print,
+  gsk_vulkan_clear_op_upload,
+  gsk_vulkan_clear_op_count_vertex_data,
+  gsk_vulkan_clear_op_collect_vertex_data,
+  gsk_vulkan_clear_op_reserve_descriptor_sets,
+  gsk_vulkan_clear_op_command
+};
+
+void
+gsk_vulkan_clear_op (GskVulkanRender             *render,
+                     const cairo_rectangle_int_t *rect,
+                     const GdkRGBA               *color)
+{
+  GskVulkanClearOp *self;
+
+  self = (GskVulkanClearOp *) gsk_vulkan_op_alloc (render, &GSK_VULKAN_SCISSOR_OP_CLASS);
+
+  self->rect = *rect;
+  self->color = *color;
+}
diff --git a/gsk/vulkan/gskvulkanclearopprivate.h b/gsk/vulkan/gskvulkanclearopprivate.h
new file mode 100644 (file)
index 0000000..92f3351
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "gskvulkanopprivate.h"
+
+G_BEGIN_DECLS
+
+void                    gsk_vulkan_clear_op                             (GskVulkanRender                *render,
+                                                                         const cairo_rectangle_int_t    *rect,
+                                                                         const GdkRGBA                  *color);
+
+
+G_END_DECLS
+
index ec3d9878143f50030bf064aff0c6abba61d857e5..4d331ddfc1fea746123abe6ec0638548b2f3731a 100644 (file)
@@ -12,6 +12,7 @@
 #include "gskvulkanblendmodeopprivate.h"
 #include "gskvulkanbluropprivate.h"
 #include "gskvulkanborderopprivate.h"
+#include "gskvulkanclearopprivate.h"
 #include "gskvulkanclipprivate.h"
 #include "gskvulkancolormatrixopprivate.h"
 #include "gskvulkancoloropprivate.h"
@@ -349,11 +350,46 @@ gsk_vulkan_render_pass_add_color_node (GskVulkanRenderPass       *self,
                                        const GskVulkanParseState *state,
                                        GskRenderNode             *node)
 {
+  cairo_rectangle_int_t int_clipped;
+  graphene_rect_t rect, clipped;
+  const GdkRGBA *color;
+
+  color = gsk_color_node_get_color (node);
+  graphene_rect_offset_r (&node->bounds,
+                          state->offset.x, state->offset.y,
+                          &rect);
+  graphene_rect_intersection (&state->clip.rect.bounds, &rect, &clipped);
+
+  if (gdk_rgba_is_opaque (color) &&
+      gsk_vulkan_parse_rect_is_integer (state, &clipped, &int_clipped))
+    {
+      /* now handle all the clip */
+      if (!gdk_rectangle_intersect (&int_clipped, &state->scissor, &int_clipped))
+        return TRUE;
+
+      /* we have handled the bounds, now do the corners */
+      if (state->clip.type != GSK_VULKAN_CLIP_ROUNDED ||
+          gsk_vulkan_clip_contains_rect (&state->clip, 
+                                         graphene_point_zero (),
+                                         &GRAPHENE_RECT_INIT (
+                                           int_clipped.x / graphene_vec2_get_x (&state->scale),
+                                           int_clipped.y / graphene_vec2_get_y (&state->scale),
+                                           int_clipped.width / graphene_vec2_get_x (&state->scale),
+                                           int_clipped.height / graphene_vec2_get_y (&state->scale)
+                                         )))
+        {
+          gsk_vulkan_clear_op (render,
+                               &int_clipped,
+                               color);
+          return TRUE;
+        }
+    }
+
   gsk_vulkan_color_op (render,
                        gsk_vulkan_clip_get_clip_type (&state->clip, &state->offset, &node->bounds),
-                       &node->bounds,
-                       &state->offset,
-                       gsk_color_node_get_color (node));
+                       &rect,
+                       graphene_point_zero (),
+                       color);
 
   return TRUE;
 }