From: Benjamin Otte Date: Sat, 6 May 2023 23:06:52 +0000 (+0200) Subject: vulkan: Start rework on shaders to allow antialiased drawing X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~1^2~185^2~63 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=64bcdb713c3769e663fb325b429d39a69bf1d0a4;p=gtk4.git vulkan: Start rework on shaders to allow antialiased drawing 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. --- diff --git a/gsk/vulkan/resources/clip.vert.glsl b/gsk/vulkan/resources/clip.vert.glsl index 0dce1a0fb7..ae5c75a39d 100644 --- a/gsk/vulkan/resources/clip.vert.glsl +++ b/gsk/vulkan/resources/clip.vert.glsl @@ -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 diff --git a/gsk/vulkan/resources/color.frag b/gsk/vulkan/resources/color.frag index 6b299dffd0..1f988b6517 100644 --- a/gsk/vulkan/resources/color.frag +++ b/gsk/vulkan/resources/color.frag @@ -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); } diff --git a/gsk/vulkan/resources/color.vert b/gsk/vulkan/resources/color.vert index 1e1618aef9..7601b7d82a 100644 --- a/gsk/vulkan/resources/color.vert +++ b/gsk/vulkan/resources/color.vert @@ -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; } diff --git a/gsk/vulkan/resources/meson.build b/gsk/vulkan/resources/meson.build index 86e98acb9e..802f391b4d 100644 --- a/gsk/vulkan/resources/meson.build +++ b/gsk/vulkan/resources/meson.build @@ -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 index 0000000000..73e9db9fd5 --- /dev/null +++ b/gsk/vulkan/resources/rect.frag.glsl @@ -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 index 0000000000..ba07a05a98 --- /dev/null +++ b/gsk/vulkan/resources/rect.glsl @@ -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 index 0000000000..e6f90b8dd1 --- /dev/null +++ b/gsk/vulkan/resources/rect.vert.glsl @@ -0,0 +1,6 @@ +#ifndef _RECT_VERT_ +#define _RECT_VERT_ + +#include "rect.glsl" + +#endif