vulkan: Add a glyph shader
authorBenjamin Otte <otte@redhat.com>
Mon, 3 Jul 2023 05:53:22 +0000 (07:53 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 16 Jul 2023 10:12:59 +0000 (12:12 +0200)
This shader is an updated version of the mask shader, but I want to use
the mask name for the mask node and that's a different functionality.

Also, add an operation for it and partially implement the mask node
using it, so we can test that this shader works.

Replacing the shader used for text rendering is the next step.

13 files changed:
gsk/meson.build
gsk/vulkan/gskvulkanglyphop.c [new file with mode: 0644]
gsk/vulkan/gskvulkanglyphopprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanrenderpass.c
gsk/vulkan/resources/glyph-clip-rounded.frag.spv [new file with mode: 0644]
gsk/vulkan/resources/glyph-clip-rounded.vert.spv [new file with mode: 0644]
gsk/vulkan/resources/glyph-clip.frag.spv [new file with mode: 0644]
gsk/vulkan/resources/glyph-clip.vert.spv [new file with mode: 0644]
gsk/vulkan/resources/glyph.frag [new file with mode: 0644]
gsk/vulkan/resources/glyph.frag.spv [new file with mode: 0644]
gsk/vulkan/resources/glyph.vert [new file with mode: 0644]
gsk/vulkan/resources/glyph.vert.spv [new file with mode: 0644]
gsk/vulkan/resources/meson.build

index e1c06513f19c859e89361274d84acb7c6380a8d8..bfb09d7d0b5ff99aaa97f8b9418b9f3a9b6ac368 100644 (file)
@@ -118,6 +118,7 @@ if have_vulkan
     'vulkan/gskvulkancommandpool.c',
     'vulkan/gskvulkancrossfadeop.c',
     'vulkan/gskvulkanglyphcache.c',
+    'vulkan/gskvulkanglyphop.c',
     'vulkan/gskvulkanimage.c',
     'vulkan/gskvulkaninsetshadowop.c',
     'vulkan/gskvulkanlineargradientop.c',
diff --git a/gsk/vulkan/gskvulkanglyphop.c b/gsk/vulkan/gskvulkanglyphop.c
new file mode 100644 (file)
index 0000000..4617806
--- /dev/null
@@ -0,0 +1,132 @@
+#include "config.h"
+
+#include "gskvulkanglyphopprivate.h"
+
+#include "vulkan/resources/glyph.vert.h"
+
+typedef struct _GskVulkanGlyphOp GskVulkanGlyphOp;
+
+struct _GskVulkanGlyphOp
+{
+  GskVulkanOp op;
+
+  GskVulkanImage *image;
+  graphene_rect_t rect;
+  graphene_rect_t tex_rect;
+  GdkRGBA color;
+
+  guint32 image_descriptor;
+  gsize vertex_offset;
+};
+
+static void
+gsk_vulkan_glyph_op_finish (GskVulkanOp *op)
+{
+  GskVulkanGlyphOp *self = (GskVulkanGlyphOp *) op;
+
+  g_object_unref (self->image);
+}
+
+static void
+gsk_vulkan_glyph_op_upload (GskVulkanOp         *op,
+                            GskVulkanRenderPass *pass,
+                            GskVulkanRender     *render,
+                            GskVulkanUploader   *uploader)
+{
+}
+
+static inline gsize
+round_up (gsize number, gsize divisor)
+{
+  return (number + divisor - 1) / divisor * divisor;
+}
+
+static gsize
+gsk_vulkan_glyph_op_count_vertex_data (GskVulkanOp *op,
+                                       gsize        n_bytes)
+{
+  GskVulkanGlyphOp *self = (GskVulkanGlyphOp *) op;
+  gsize vertex_stride;
+
+  vertex_stride = gsk_vulkan_glyph_info.pVertexBindingDescriptions[0].stride;
+  n_bytes = round_up (n_bytes, vertex_stride);
+  self->vertex_offset = n_bytes;
+  n_bytes += vertex_stride;
+  return n_bytes;
+}
+
+static void
+gsk_vulkan_glyph_op_collect_vertex_data (GskVulkanOp         *op,
+                                         GskVulkanRenderPass *pass,
+                                         GskVulkanRender     *render,
+                                         guchar              *data)
+{
+  GskVulkanGlyphOp *self = (GskVulkanGlyphOp *) op;
+  GskVulkanGlyphInstance *instance = (GskVulkanGlyphInstance *) (data + self->vertex_offset);
+
+  gsk_vulkan_rect_to_float (&self->rect, instance->rect);
+  gsk_vulkan_rect_to_float (&self->tex_rect, instance->tex_rect);
+  instance->tex_id = self->image_descriptor;
+  gsk_vulkan_rgba_to_float (&self->color, instance->color);
+}
+
+static void
+gsk_vulkan_glyph_op_reserve_descriptor_sets (GskVulkanOp     *op,
+                                             GskVulkanRender *render)
+{
+  GskVulkanGlyphOp *self = (GskVulkanGlyphOp *) op;
+
+  self->image_descriptor = gsk_vulkan_render_get_image_descriptor (render, self->image, GSK_VULKAN_SAMPLER_DEFAULT);
+}
+
+static VkPipeline
+gsk_vulkan_glyph_op_get_pipeline (GskVulkanOp *op)
+{
+  return VK_NULL_HANDLE;
+}
+
+static void
+gsk_vulkan_glyph_op_command (GskVulkanOp      *op,
+                             GskVulkanRender  *render,
+                             VkPipelineLayout  pipeline_layout,
+                             VkCommandBuffer   command_buffer)
+{
+  GskVulkanGlyphOp *self = (GskVulkanGlyphOp *) op;
+
+  vkCmdDraw (command_buffer,
+             6, 1,
+             0, self->vertex_offset / gsk_vulkan_glyph_info.pVertexBindingDescriptions[0].stride);
+}
+
+static const GskVulkanOpClass GSK_VULKAN_GLYPH_OP_CLASS = {
+  GSK_VULKAN_OP_SIZE (GskVulkanGlyphOp),
+  "glyph",
+  &gsk_vulkan_glyph_info,
+  gsk_vulkan_glyph_op_finish,
+  gsk_vulkan_glyph_op_upload,
+  gsk_vulkan_glyph_op_count_vertex_data,
+  gsk_vulkan_glyph_op_collect_vertex_data,
+  gsk_vulkan_glyph_op_reserve_descriptor_sets,
+  gsk_vulkan_glyph_op_get_pipeline,
+  gsk_vulkan_glyph_op_command
+};
+
+void
+gsk_vulkan_glyph_op (GskVulkanRenderPass    *render_pass,
+                     const char             *clip_type,
+                     GskVulkanImage         *image,
+                     const graphene_rect_t  *rect,
+                     const graphene_point_t *offset,
+                     const graphene_rect_t  *tex_rect,
+                     const GdkRGBA          *color)
+{
+  GskVulkanGlyphOp *self;
+
+  self = (GskVulkanGlyphOp *) gsk_vulkan_op_alloc (render_pass, &GSK_VULKAN_GLYPH_OP_CLASS);
+
+  ((GskVulkanOp *) self)->clip_type = g_intern_string (clip_type);
+  self->image = g_object_ref (image);
+  graphene_rect_offset_r (rect, offset->x, offset->y, &self->rect);
+  gsk_vulkan_normalize_tex_coords (&self->tex_rect, rect, tex_rect);
+  self->color = *color;
+}
diff --git a/gsk/vulkan/gskvulkanglyphopprivate.h b/gsk/vulkan/gskvulkanglyphopprivate.h
new file mode 100644 (file)
index 0000000..deb64b9
--- /dev/null
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "gskvulkanopprivate.h"
+
+G_BEGIN_DECLS
+
+void                    gsk_vulkan_glyph_op                             (GskVulkanRenderPass            *render_pass,
+                                                                         const char                     *clip_type,
+                                                                         GskVulkanImage                 *image,
+                                                                         const graphene_rect_t          *rect,
+                                                                         const graphene_point_t         *offset,
+                                                                         const graphene_rect_t          *tex_rect,
+                                                                         const GdkRGBA                  *color);
+
+
+G_END_DECLS
+
index b4989ec6a0bc46829894a0ea6ec0c7d55a57b397..4a33d21fd25ce454701695725d45145696f52dcb 100644 (file)
@@ -17,6 +17,7 @@
 #include "gskvulkancoloropprivate.h"
 #include "gskvulkancolortextpipelineprivate.h"
 #include "gskvulkancrossfadeopprivate.h"
+#include "gskvulkanglyphopprivate.h"
 #include "gskvulkaninsetshadowopprivate.h"
 #include "gskvulkanlineargradientopprivate.h"
 #include "gskvulkanopprivate.h"
@@ -1297,6 +1298,52 @@ gsk_vulkan_render_pass_add_blur_node (GskVulkanRenderPass       *self,
   return TRUE;
 }
 
+static inline gboolean
+gsk_vulkan_render_pass_add_mask_node (GskVulkanRenderPass       *self,
+                                      GskVulkanRender           *render,
+                                      const GskVulkanParseState *state,
+                                      GskRenderNode             *node)
+{
+  GskVulkanImage *mask_image;
+  graphene_rect_t mask_tex_rect;
+  GskRenderNode *source, *mask;
+  GskMaskMode mode;
+
+  mode = gsk_mask_node_get_mask_mode (node);
+  source = gsk_mask_node_get_source (node);
+  mask = gsk_mask_node_get_mask (node);
+  mask_image = gsk_vulkan_render_pass_get_node_as_image (self,
+                                                         render,
+                                                         state,
+                                                         mask,
+                                                         &mask_tex_rect);
+  if (mask_image == NULL)
+    {
+      if (mode == GSK_MASK_MODE_INVERTED_ALPHA)
+        gsk_vulkan_render_pass_add_node (self, render, state, source);
+
+      return TRUE;
+    }
+
+  /* Use the glyph shader as an optimization */
+  if (mode == GSK_MASK_MODE_ALPHA &&
+      gsk_render_node_get_node_type (source) == GSK_COLOR_NODE)
+    {
+      graphene_rect_t bounds;
+      if (graphene_rect_intersection (&source->bounds, &mask->bounds, &bounds))
+        gsk_vulkan_glyph_op (self,
+                             gsk_vulkan_clip_get_clip_type (&state->clip, &state->offset, &bounds),
+                             mask_image,
+                             &bounds,
+                             &state->offset,
+                             &mask_tex_rect,
+                             gsk_color_node_get_color (source));
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 static inline gboolean
 gsk_vulkan_render_pass_add_debug_node (GskVulkanRenderPass       *self,
                                        GskVulkanRender           *render,
@@ -1343,7 +1390,7 @@ static const GskVulkanRenderPassNodeFunc nodes_vtable[] = {
   [GSK_DEBUG_NODE] = gsk_vulkan_render_pass_add_debug_node,
   [GSK_GL_SHADER_NODE] = NULL,
   [GSK_TEXTURE_SCALE_NODE] = gsk_vulkan_render_pass_add_texture_scale_node,
-  [GSK_MASK_NODE] = NULL,
+  [GSK_MASK_NODE] = gsk_vulkan_render_pass_add_mask_node,
 };
 
 static void
diff --git a/gsk/vulkan/resources/glyph-clip-rounded.frag.spv b/gsk/vulkan/resources/glyph-clip-rounded.frag.spv
new file mode 100644 (file)
index 0000000..ff2212a
Binary files /dev/null and b/gsk/vulkan/resources/glyph-clip-rounded.frag.spv differ
diff --git a/gsk/vulkan/resources/glyph-clip-rounded.vert.spv b/gsk/vulkan/resources/glyph-clip-rounded.vert.spv
new file mode 100644 (file)
index 0000000..d177868
Binary files /dev/null and b/gsk/vulkan/resources/glyph-clip-rounded.vert.spv differ
diff --git a/gsk/vulkan/resources/glyph-clip.frag.spv b/gsk/vulkan/resources/glyph-clip.frag.spv
new file mode 100644 (file)
index 0000000..bfd95cd
Binary files /dev/null and b/gsk/vulkan/resources/glyph-clip.frag.spv differ
diff --git a/gsk/vulkan/resources/glyph-clip.vert.spv b/gsk/vulkan/resources/glyph-clip.vert.spv
new file mode 100644 (file)
index 0000000..d177868
Binary files /dev/null and b/gsk/vulkan/resources/glyph-clip.vert.spv differ
diff --git a/gsk/vulkan/resources/glyph.frag b/gsk/vulkan/resources/glyph.frag
new file mode 100644 (file)
index 0000000..0f87adc
--- /dev/null
@@ -0,0 +1,20 @@
+#version 450
+
+#include "common.frag.glsl"
+#include "clip.frag.glsl"
+#include "rect.frag.glsl"
+
+layout(location = 0) in vec2 inPos;
+layout(location = 1) in flat Rect inRect;
+layout(location = 2) in vec2 inTexCoord;
+layout(location = 3) in flat uint inTexId;
+layout(location = 4) in flat vec4 inColor;
+
+layout(location = 0) out vec4 color;
+
+void main()
+{
+  float alpha = inColor.a * rect_coverage (inRect, inPos);
+  alpha *= texture(get_sampler (inTexId), inTexCoord).a;
+  color = clip_scaled (inPos, vec4(inColor.rgb, 1) * alpha);
+}
diff --git a/gsk/vulkan/resources/glyph.frag.spv b/gsk/vulkan/resources/glyph.frag.spv
new file mode 100644 (file)
index 0000000..bfd95cd
Binary files /dev/null and b/gsk/vulkan/resources/glyph.frag.spv differ
diff --git a/gsk/vulkan/resources/glyph.vert b/gsk/vulkan/resources/glyph.vert
new file mode 100644 (file)
index 0000000..0f9b647
--- /dev/null
@@ -0,0 +1,26 @@
+#version 450
+
+#include "common.vert.glsl"
+#include "rect.vert.glsl"
+
+layout(location = 0) in vec4 inRect;
+layout(location = 1) in vec4 inTexRect;
+layout(location = 2) in vec4 inColor;
+layout(location = 3) in uint inTexId;
+
+layout(location = 0) out vec2 outPos;
+layout(location = 1) out flat Rect outRect;
+layout(location = 2) out vec2 outTexCoord;
+layout(location = 3) out flat uint outTexId;
+layout(location = 4) out flat vec4 outColor;
+
+void main() {
+  Rect r = rect_from_gsk (inRect);
+  vec2 pos = set_position_from_rect (r);
+
+  outPos = pos;
+  outRect = r;
+  outTexCoord = scale_tex_coord (pos, r, inTexRect);
+  outTexId = inTexId;
+  outColor = inColor;
+}
diff --git a/gsk/vulkan/resources/glyph.vert.spv b/gsk/vulkan/resources/glyph.vert.spv
new file mode 100644 (file)
index 0000000..e92bf92
Binary files /dev/null and b/gsk/vulkan/resources/glyph.vert.spv differ
index 5075f97b8323608fb6c56258877c867ffd1ce4a8..8881eb1b6bf4cb9d02d433bc2331b0c046dc5ac2 100644 (file)
@@ -18,6 +18,7 @@ gsk_private_vulkan_fragment_shaders = [
   'color.frag',
   'color-matrix.frag',
   'cross-fade.frag',
+  'glyph.frag',
   'inset-shadow.frag',
   'linear.frag',
   'mask.frag',
@@ -32,6 +33,7 @@ gsk_private_vulkan_vertex_shaders = [
   'color.vert',
   'color-matrix.vert',
   'cross-fade.vert',
+  'glyph.vert',
   'inset-shadow.vert',
   'linear.vert',
   'mask.vert',