vulkan: Start rework on shaders to allow antialiased drawing
authorBenjamin Otte <otte@redhat.com>
Sat, 6 May 2023 23:06:52 +0000 (01:06 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 4 Jun 2023 17:42:00 +0000 (19:42 +0200)
This introduces the rect object and adds a rect_distance() and
rect_coverage() function.

_distance() returns the signed distance tp the rectangle.
_coverage() returns the coverage of a pixel centered at that position.

Note that the pixel size is computed using dFdx/dFdy.

gsk/vulkan/resources/clip.vert.glsl
gsk/vulkan/resources/color.frag
gsk/vulkan/resources/color.vert
gsk/vulkan/resources/meson.build
gsk/vulkan/resources/rect.frag.glsl [new file with mode: 0644]
gsk/vulkan/resources/rect.glsl [new file with mode: 0644]
gsk/vulkan/resources/rect.vert.glsl [new file with mode: 0644]

index 0dce1a0fb777acfdd43a2565637dbf508d6e60eb..ae5c75a39ddf61439854779980be2827e6391998 100644 (file)
@@ -1,4 +1,5 @@
 #include "constants.glsl"
+#include "rect.vert.glsl"
 
 #ifndef _CLIP_
 #define _CLIP_
@@ -14,21 +15,47 @@ vec4 intersect(vec4 a, vec4 b)
 }
 
 #ifdef CLIP_ROUNDED_RECT
-vec4 clip(vec4 rect)
+
+vec4
+clip(vec4 rect)
 {
   /* rounded corner clipping is done in fragment shader */
   return intersect(rect, push.clip_bounds);
 }
+
+Rect
+clip_rect (vec4 xywh)
+{
+  /* rounded corner clipping is done in fragment shader */
+  return rect_intersect (rect_from_gsk (xywh), rect_to_int (rect_from_gsk (push.clip_bounds)));
+}
+
 #elif defined(CLIP_RECT)
-vec4 clip(vec4 rect)
+
+vec4
+clip(vec4 rect)
 {
   return intersect(rect, push.clip_bounds);
 }
+
+Rect
+clip_rect (vec4 xywh)
+{
+  return rect_intersect (rect_from_gsk (xywh), rect_to_int (rect_from_gsk (push.clip_bounds)));
+}
+
 #elif defined(CLIP_NONE)
 vec4 clip(vec4 rect)
 {
   return rect;
 }
+
+Rect
+clip_rect (vec4 xywh)
+{
+  return rect_from_gsk (xywh);
+}
+
 #else
 #error "No clipping define given. Need CLIP_NONE, CLIP_RECT or CLIP_ROUNDED_RECT"
 #endif
index 6b299dffd076eed99f10b98d03cb160dfc31281e..1f988b651751534f095a532b97004c01485ac402 100644 (file)
@@ -1,13 +1,16 @@
 #version 420 core
 
 #include "clip.frag.glsl"
+#include "rect.frag.glsl"
 
 layout(location = 0) in vec2 inPos;
-layout(location = 1) in vec4 inColor;
+layout(location = 1) in Rect inRect;
+layout(location = 2) in vec4 inColor;
 
 layout(location = 0) out vec4 color;
 
 void main()
 {
-  color = clip (inPos, vec4(inColor.rgb * inColor.a, inColor.a));
+  float alpha = inColor.a * rect_coverage (inRect, inPos);
+  color = clip (inPos, vec4(inColor.rgb, 1) * alpha);
 }
index 1e1618aef9579e5ba61f7440e0b28b911e5382b6..7601b7d82ac94f400ffa2751f0bfec5257a3beb1 100644 (file)
@@ -1,12 +1,14 @@
 #version 420 core
 
 #include "clip.vert.glsl"
+#include "rect.vert.glsl"
 
 layout(location = 0) in vec4 inRect;
 layout(location = 1) in vec4 inColor;
 
 layout(location = 0) out vec2 outPos;
-layout(location = 1) out flat vec4 outColor;
+layout(location = 1) out flat Rect outRect;
+layout(location = 2) out flat vec4 outColor;
 
 vec2 offsets[6] = { vec2(0.0, 0.0),
                     vec2(1.0, 0.0),
@@ -16,10 +18,11 @@ vec2 offsets[6] = { vec2(0.0, 0.0),
                     vec2(1.0, 1.0) };
 
 void main() {
-  vec4 rect = clip (inRect);
+  Rect rect = rect_to_int (clip_rect (inRect));
 
-  vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
+  vec2 pos = mix (rect.bounds.xy, rect.bounds.zw, offsets[gl_VertexIndex]);
   gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
   outPos = pos;
+  outRect = rect_from_gsk (inRect);
   outColor = inColor;
 }
index 86e98acb9e27398045c0b6ebd1a727b57ea349ec..802f391b4dba0ad29c753bdd0a9c5edcfc70ca78 100644 (file)
@@ -2,6 +2,9 @@ gsk_private_vulkan_include_shaders = [
   'clip.frag.glsl',
   'clip.vert.glsl',
   'constants.glsl',
+  'rect.glsl',
+  'rect.frag.glsl',
+  'rect.vert.glsl',
   'rounded-rect.glsl',
 ]
 
diff --git a/gsk/vulkan/resources/rect.frag.glsl b/gsk/vulkan/resources/rect.frag.glsl
new file mode 100644 (file)
index 0000000..73e9db9
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _RECT_FRAG_
+#define _RECT_FRAG_
+
+#include "rect.glsl"
+
+float
+rect_coverage (Rect r, vec2 p)
+{
+  vec2 dFdp = abs(fwidth (p));
+  Rect prect = Rect(vec4(p - 0.5 * dFdp, p + 0.5 * dFdp));
+  Rect coverect = rect_intersect (r, prect);
+  vec2 coverage = rect_size(coverect) / dFdp;
+  return coverage.x * coverage.y;
+}
+
+#endif
diff --git a/gsk/vulkan/resources/rect.glsl b/gsk/vulkan/resources/rect.glsl
new file mode 100644 (file)
index 0000000..ba07a05
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _RECT_
+#define _RECT_
+
+struct Rect
+{
+  /* x,y and y,w make up the 2 points of this rect,
+     note that this is not containing width or height */
+  vec4 bounds;
+};
+
+Rect
+rect_from_gsk (vec4 xywh)
+{
+  return Rect(xywh.xyxy + vec4(0,0,xywh.zw));
+}
+
+float
+rect_distance (Rect r, vec2 p)
+{
+  vec4 distance = (r.bounds - p.xyxy) * vec4(1.0, 1.0, -1.0, -1.0);
+  vec2 max2 = max (distance.xy, distance.zw);
+  return length (max (max2, 0)) + min (max(max2.x, max2.y), 0);
+}
+
+vec2
+rect_size (Rect r)
+{
+  return r.bounds.zw - r.bounds.xy;
+}
+
+Rect
+rect_to_int (Rect r)
+{
+  return Rect (vec4 (floor(r.bounds.xy), ceil (r.bounds.zw)));
+}
+
+Rect
+rect_intersect (Rect a, Rect b)
+{
+  vec4 result = vec4(max(a.bounds.xy, b.bounds.xy), min(a.bounds.zw, b.bounds.zw));
+  if (any (greaterThanEqual (result.xy, result.zw)))
+    return Rect (vec4(0.0));
+  return Rect(result);
+}
+
+#endif
diff --git a/gsk/vulkan/resources/rect.vert.glsl b/gsk/vulkan/resources/rect.vert.glsl
new file mode 100644 (file)
index 0000000..e6f90b8
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _RECT_VERT_
+#define _RECT_VERT_
+
+#include "rect.glsl"
+
+#endif