Clay custom dispatch improvements & DPI scaling fixes (#26)
Co-authored-by: Zachary Levy <zachary@sunforge.is> Reviewed-on: #26
This commit was merged in pull request #26.
This commit is contained in:
@@ -25,9 +25,9 @@ struct main0_in
|
||||
{
|
||||
float2 p_local [[user(locn0)]];
|
||||
float4 f_color [[user(locn1)]];
|
||||
float2 f_half_size [[user(locn2), flat]];
|
||||
float4 f_radii [[user(locn3), flat]];
|
||||
float f_half_feather [[user(locn4), flat]];
|
||||
float2 f_half_size_ppx [[user(locn2), flat]];
|
||||
float4 f_radii_ppx [[user(locn3), flat]];
|
||||
float f_half_feather_ppx [[user(locn4), flat]];
|
||||
};
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
@@ -96,16 +96,16 @@ fragment main0_out main0(main0_in in [[stage_in]], constant Uniforms& _108 [[buf
|
||||
return out;
|
||||
}
|
||||
float2 param_1 = in.p_local;
|
||||
float2 param_2 = in.f_half_size;
|
||||
float4 param_3 = in.f_radii;
|
||||
float2 param_2 = in.f_half_size_ppx;
|
||||
float4 param_3 = in.f_radii_ppx;
|
||||
float d = sdRoundedBox(param_1, param_2, param_3);
|
||||
if (d > in.f_half_feather)
|
||||
if (d > in.f_half_feather_ppx)
|
||||
{
|
||||
discard_fragment();
|
||||
}
|
||||
float grad_magnitude = fast::max(fwidth(d), 9.9999999747524270787835121154785e-07);
|
||||
float d_n = d / grad_magnitude;
|
||||
float h_n = in.f_half_feather / grad_magnitude;
|
||||
float h_n = in.f_half_feather_ppx / grad_magnitude;
|
||||
float2 uv_1 = (gl_FragCoord.xy * _108.inv_downsample_factor) * _108.inv_working_size;
|
||||
float3 color_1 = blur_input_tex.sample(blur_input_texSmplr, uv_1).xyz;
|
||||
float3 tinted = mix(color_1, color_1 * in.f_color.xyz, float3(in.f_color.w));
|
||||
|
||||
Binary file not shown.
@@ -55,18 +55,18 @@ struct Uniforms
|
||||
struct Gaussian_Blur_Primitive
|
||||
{
|
||||
float4 bounds;
|
||||
float4 radii;
|
||||
float2 half_size;
|
||||
float half_feather;
|
||||
float4 radii_ppx;
|
||||
float2 half_size_ppx;
|
||||
float half_feather_ppx;
|
||||
uint color;
|
||||
};
|
||||
|
||||
struct Gaussian_Blur_Primitive_1
|
||||
{
|
||||
float4 bounds;
|
||||
float4 radii;
|
||||
float2 half_size;
|
||||
float half_feather;
|
||||
float4 radii_ppx;
|
||||
float2 half_size_ppx;
|
||||
float half_feather_ppx;
|
||||
uint color;
|
||||
};
|
||||
|
||||
@@ -81,9 +81,9 @@ struct main0_out
|
||||
{
|
||||
float2 p_local [[user(locn0)]];
|
||||
float4 f_color [[user(locn1)]];
|
||||
float2 f_half_size [[user(locn2)]];
|
||||
float4 f_radii [[user(locn3)]];
|
||||
float f_half_feather [[user(locn4)]];
|
||||
float2 f_half_size_ppx [[user(locn2)]];
|
||||
float4 f_radii_ppx [[user(locn3)]];
|
||||
float f_half_feather_ppx [[user(locn4)]];
|
||||
float4 gl_Position [[position]];
|
||||
};
|
||||
|
||||
@@ -96,26 +96,26 @@ vertex main0_out main0(constant Uniforms& _13 [[buffer(0)]], const device Gaussi
|
||||
out.gl_Position = float4(ndc, 0.0, 1.0);
|
||||
out.p_local = float2(0.0);
|
||||
out.f_color = float4(0.0);
|
||||
out.f_half_size = float2(0.0);
|
||||
out.f_radii = float4(0.0);
|
||||
out.f_half_feather = 0.0;
|
||||
out.f_half_size_ppx = float2(0.0);
|
||||
out.f_radii_ppx = float4(0.0);
|
||||
out.f_half_feather_ppx = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Gaussian_Blur_Primitive p;
|
||||
p.bounds = _69.primitives[int(gl_InstanceIndex)].bounds;
|
||||
p.radii = _69.primitives[int(gl_InstanceIndex)].radii;
|
||||
p.half_size = _69.primitives[int(gl_InstanceIndex)].half_size;
|
||||
p.half_feather = _69.primitives[int(gl_InstanceIndex)].half_feather;
|
||||
p.radii_ppx = _69.primitives[int(gl_InstanceIndex)].radii_ppx;
|
||||
p.half_size_ppx = _69.primitives[int(gl_InstanceIndex)].half_size_ppx;
|
||||
p.half_feather_ppx = _69.primitives[int(gl_InstanceIndex)].half_feather_ppx;
|
||||
p.color = _69.primitives[int(gl_InstanceIndex)].color;
|
||||
float2 corner = _97[int(gl_VertexIndex)];
|
||||
float2 world_pos = mix(p.bounds.xy, p.bounds.zw, corner);
|
||||
float2 center = (p.bounds.xy + p.bounds.zw) * 0.5;
|
||||
out.p_local = (world_pos - center) * _13.dpi_scale;
|
||||
out.f_color = unpack_unorm4x8_to_float(p.color);
|
||||
out.f_half_size = p.half_size;
|
||||
out.f_radii = p.radii;
|
||||
out.f_half_feather = p.half_feather;
|
||||
out.f_half_size_ppx = p.half_size_ppx;
|
||||
out.f_radii_ppx = p.radii_ppx;
|
||||
out.f_half_feather_ppx = p.half_feather_ppx;
|
||||
out.gl_Position = _13.projection * float4(world_pos * _13.dpi_scale, 0.0, 1.0);
|
||||
}
|
||||
return out;
|
||||
|
||||
Binary file not shown.
@@ -107,57 +107,57 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> tex [[textur
|
||||
}
|
||||
float d = 1000000015047466219876688855040.0;
|
||||
float h = 0.5;
|
||||
float2 half_size = in.f_params.xy;
|
||||
float2 p_local = in.f_local_or_uv;
|
||||
float2 half_size_ppx = in.f_params.xy;
|
||||
float2 p_local_ppx = in.f_local_or_uv;
|
||||
if (kind == 1u)
|
||||
{
|
||||
float4 corner_radii = float4(in.f_params.zw, in.f_params2.xy);
|
||||
float4 corner_radii_ppx = float4(in.f_params.zw, in.f_params2.xy);
|
||||
h = in.f_params2.z;
|
||||
float2 param = p_local;
|
||||
float2 param_1 = half_size;
|
||||
float4 param_2 = corner_radii;
|
||||
float2 param = p_local_ppx;
|
||||
float2 param_1 = half_size_ppx;
|
||||
float4 param_2 = corner_radii_ppx;
|
||||
d = sdRoundedBox(param, param_1, param_2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (kind == 2u)
|
||||
{
|
||||
float radius = in.f_params.x;
|
||||
float radius_ppx = in.f_params.x;
|
||||
float sides = in.f_params.y;
|
||||
h = in.f_params.z;
|
||||
float2 param_3 = p_local;
|
||||
float param_4 = radius;
|
||||
float2 param_3 = p_local_ppx;
|
||||
float param_4 = radius_ppx;
|
||||
float param_5 = sides;
|
||||
d = sdRegularPolygon(param_3, param_4, param_5);
|
||||
half_size = float2(radius);
|
||||
half_size_ppx = float2(radius_ppx);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (kind == 3u)
|
||||
{
|
||||
float2 ab = in.f_params.xy;
|
||||
float2 radii_ppx = in.f_params.xy;
|
||||
h = in.f_params.z;
|
||||
float2 param_6 = p_local;
|
||||
float2 param_7 = ab;
|
||||
float2 param_6 = p_local_ppx;
|
||||
float2 param_7 = radii_ppx;
|
||||
d = sdEllipseApprox(param_6, param_7);
|
||||
half_size = ab;
|
||||
half_size_ppx = radii_ppx;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (kind == 4u)
|
||||
{
|
||||
float inner = in.f_params.x;
|
||||
float outer = in.f_params.y;
|
||||
float inner_radius_ppx = in.f_params.x;
|
||||
float outer_radius_ppx = in.f_params.y;
|
||||
float2 n_start = in.f_params.zw;
|
||||
float2 n_end = in.f_params2.xy;
|
||||
uint arc_bits = (flags >> 5u) & 3u;
|
||||
h = in.f_params2.z;
|
||||
float r = length(p_local);
|
||||
d = fast::max(inner - r, r - outer);
|
||||
float r = length(p_local_ppx);
|
||||
d = fast::max(inner_radius_ppx - r, r - outer_radius_ppx);
|
||||
if (arc_bits != 0u)
|
||||
{
|
||||
float d_start = dot(p_local, n_start);
|
||||
float d_end = dot(p_local, n_end);
|
||||
float d_start = dot(p_local_ppx, n_start);
|
||||
float d_end = dot(p_local_ppx, n_end);
|
||||
float _338;
|
||||
if (arc_bits == 1u)
|
||||
{
|
||||
@@ -170,7 +170,7 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> tex [[textur
|
||||
float d_wedge = _338;
|
||||
d = fast::max(d, d_wedge);
|
||||
}
|
||||
half_size = float2(outer);
|
||||
half_size_ppx = float2(outer_radius_ppx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,7 +185,7 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> tex [[textur
|
||||
float4 gradient_end = unpack_unorm4x8_to_float(in.f_effects.x);
|
||||
if ((flags & 4u) != 0u)
|
||||
{
|
||||
float t_1 = length(p_local / half_size);
|
||||
float t_1 = length(p_local_ppx / half_size_ppx);
|
||||
float4 param_8 = gradient_start;
|
||||
float4 param_9 = gradient_end;
|
||||
float param_10 = t_1;
|
||||
@@ -194,7 +194,7 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> tex [[textur
|
||||
else
|
||||
{
|
||||
float2 direction = float2(as_type<half2>(in.f_effects.z));
|
||||
float t_2 = (dot(p_local / half_size, direction) * 0.5) + 0.5;
|
||||
float t_2 = (dot(p_local_ppx / half_size_ppx, direction) * 0.5) + 0.5;
|
||||
float4 param_11 = gradient_start;
|
||||
float4 param_12 = gradient_end;
|
||||
float param_13 = t_2;
|
||||
@@ -206,7 +206,7 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> tex [[textur
|
||||
if ((flags & 1u) != 0u)
|
||||
{
|
||||
float4 uv_rect = in.f_uv_rect;
|
||||
float2 local_uv = ((p_local / half_size) * 0.5) + float2(0.5);
|
||||
float2 local_uv = ((p_local_ppx / half_size_ppx) * 0.5) + float2(0.5);
|
||||
float2 uv = mix(uv_rect.xy, uv_rect.zw, local_uv);
|
||||
shape_color = in.f_color * tex.sample(texSmplr, uv);
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -60,32 +60,21 @@ struct main0_in
|
||||
float4 v_color [[attribute(2)]];
|
||||
};
|
||||
|
||||
vertex main0_out main0(main0_in in [[stage_in]], constant Uniforms& _12 [[buffer(0)]], const device Core_2D_Primitives& _75 [[buffer(1)]], uint gl_InstanceIndex [[instance_id]])
|
||||
vertex main0_out main0(main0_in in [[stage_in]], constant Uniforms& _12 [[buffer(0)]], const device Core_2D_Primitives& _31 [[buffer(1)]], uint gl_InstanceIndex [[instance_id]])
|
||||
{
|
||||
main0_out out = {};
|
||||
if (_12.mode == 0u)
|
||||
{
|
||||
out.f_color = in.v_color;
|
||||
out.f_local_or_uv = in.v_uv;
|
||||
out.f_params = float4(0.0);
|
||||
out.f_params2 = float4(0.0);
|
||||
out.f_flags = 0u;
|
||||
out.f_uv_rect = float4(0.0);
|
||||
out.f_effects = uint4(0u);
|
||||
out.gl_Position = _12.projection * float4(in.v_position * _12.dpi_scale, 0.0, 1.0);
|
||||
}
|
||||
else
|
||||
if (_12.mode == 1u)
|
||||
{
|
||||
Core_2D_Primitive p;
|
||||
p.bounds = _75.primitives[int(gl_InstanceIndex)].bounds;
|
||||
p.color = _75.primitives[int(gl_InstanceIndex)].color;
|
||||
p.flags = _75.primitives[int(gl_InstanceIndex)].flags;
|
||||
p.rotation_sc = _75.primitives[int(gl_InstanceIndex)].rotation_sc;
|
||||
p._pad = _75.primitives[int(gl_InstanceIndex)]._pad;
|
||||
p.params = _75.primitives[int(gl_InstanceIndex)].params;
|
||||
p.params2 = _75.primitives[int(gl_InstanceIndex)].params2;
|
||||
p.uv_rect = _75.primitives[int(gl_InstanceIndex)].uv_rect;
|
||||
p.effects = _75.primitives[int(gl_InstanceIndex)].effects;
|
||||
p.bounds = _31.primitives[int(gl_InstanceIndex)].bounds;
|
||||
p.color = _31.primitives[int(gl_InstanceIndex)].color;
|
||||
p.flags = _31.primitives[int(gl_InstanceIndex)].flags;
|
||||
p.rotation_sc = _31.primitives[int(gl_InstanceIndex)].rotation_sc;
|
||||
p._pad = _31.primitives[int(gl_InstanceIndex)]._pad;
|
||||
p.params = _31.primitives[int(gl_InstanceIndex)].params;
|
||||
p.params2 = _31.primitives[int(gl_InstanceIndex)].params2;
|
||||
p.uv_rect = _31.primitives[int(gl_InstanceIndex)].uv_rect;
|
||||
p.effects = _31.primitives[int(gl_InstanceIndex)].effects;
|
||||
float2 corner = in.v_position;
|
||||
float2 world_pos = mix(p.bounds.xy, p.bounds.zw, corner);
|
||||
float2 center = (p.bounds.xy + p.bounds.zw) * 0.5;
|
||||
@@ -105,6 +94,27 @@ vertex main0_out main0(main0_in in [[stage_in]], constant Uniforms& _12 [[buffer
|
||||
out.f_effects = p.effects;
|
||||
out.gl_Position = _12.projection * float4(world_pos * _12.dpi_scale, 0.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.f_color = in.v_color;
|
||||
out.f_local_or_uv = in.v_uv;
|
||||
out.f_params = float4(0.0);
|
||||
out.f_params2 = float4(0.0);
|
||||
out.f_flags = 0u;
|
||||
out.f_uv_rect = float4(0.0);
|
||||
out.f_effects = uint4(0u);
|
||||
float2 _199;
|
||||
if (_12.mode == 2u)
|
||||
{
|
||||
_199 = in.v_position;
|
||||
}
|
||||
else
|
||||
{
|
||||
_199 = in.v_position * _12.dpi_scale;
|
||||
}
|
||||
float2 pos = _199;
|
||||
out.gl_Position = _12.projection * float4(pos, 0.0, 1.0);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -40,9 +40,9 @@ const uint MAX_KERNEL_PAIRS = 32;
|
||||
// --- Inputs from vertex shader ---
|
||||
layout(location = 0) in vec2 p_local;
|
||||
layout(location = 1) in mediump vec4 f_color;
|
||||
layout(location = 2) flat in vec2 f_half_size;
|
||||
layout(location = 3) flat in vec4 f_radii;
|
||||
layout(location = 4) flat in float f_half_feather;
|
||||
layout(location = 2) flat in vec2 f_half_size_ppx;
|
||||
layout(location = 3) flat in vec4 f_radii_ppx;
|
||||
layout(location = 4) flat in float f_half_feather_ppx;
|
||||
|
||||
// --- Output ---
|
||||
layout(location = 0) out vec4 out_color;
|
||||
@@ -123,15 +123,15 @@ void main() {
|
||||
|
||||
// ---- Mode 1: composite per-primitive.
|
||||
// RRect SDF — early discard for fragments well outside the masked region.
|
||||
float d = sdRoundedBox(p_local, f_half_size, f_radii);
|
||||
if (d > f_half_feather) {
|
||||
float d = sdRoundedBox(p_local, f_half_size_ppx, f_radii_ppx);
|
||||
if (d > f_half_feather_ppx) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// fwidth-based normalization for AA (matches main pipeline approach).
|
||||
float grad_magnitude = max(fwidth(d), 1e-6);
|
||||
float d_n = d / grad_magnitude;
|
||||
float h_n = f_half_feather / grad_magnitude;
|
||||
float h_n = f_half_feather_ppx / grad_magnitude;
|
||||
|
||||
// Sample the fully-blurred working-res texture. gl_FragCoord is full-res; convert to
|
||||
// working-res UV via inv_downsample_factor. No kernel is applied — the H+V blur passes
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
layout(location = 0) out vec2 p_local;
|
||||
// f_color: tint, unpacked from primitive.color. Only meaningful in mode 1.
|
||||
layout(location = 1) out mediump vec4 f_color;
|
||||
// f_half_size: RRect half extents in physical pixels (mode 1 only).
|
||||
layout(location = 2) flat out vec2 f_half_size;
|
||||
// f_radii: per-corner radii in physical pixels (mode 1 only).
|
||||
layout(location = 3) flat out vec4 f_radii;
|
||||
// f_half_feather: SDF anti-aliasing feather (mode 1 only).
|
||||
layout(location = 4) flat out float f_half_feather;
|
||||
// f_half_size_ppx: RRect half extents in physical pixels (mode 1 only).
|
||||
layout(location = 2) flat out vec2 f_half_size_ppx;
|
||||
// f_radii_ppx: per-corner radii in physical pixels (mode 1 only).
|
||||
layout(location = 3) flat out vec4 f_radii_ppx;
|
||||
// f_half_feather_ppx: SDF anti-aliasing feather in physical pixels (mode 1 only).
|
||||
layout(location = 4) flat out float f_half_feather_ppx;
|
||||
|
||||
// --- Uniforms (set 1) ---
|
||||
// Backdrop pipeline's own uniform block — distinct from the main pipeline's
|
||||
@@ -53,10 +53,10 @@ layout(set = 1, binding = 0) uniform Uniforms {
|
||||
// edge effects (e.g. liquid-glass-style refraction outlines) would be a dedicated
|
||||
// primitive type with its own pipeline rather than a flag bit here.
|
||||
struct Gaussian_Blur_Primitive {
|
||||
vec4 bounds; // 0-15: min_xy, max_xy (world-space)
|
||||
vec4 radii; // 16-31: per-corner radii (physical px)
|
||||
vec2 half_size; // 32-39: RRect half extents (physical px)
|
||||
float half_feather; // 40-43: SDF anti-aliasing feather (physical px)
|
||||
vec4 bounds; // 0-15: min_xy, max_xy (world-space, logical px)
|
||||
vec4 radii_ppx; // 16-31: per-corner radii
|
||||
vec2 half_size_ppx; // 32-39: RRect half extents
|
||||
float half_feather_ppx; // 40-43: SDF anti-aliasing feather
|
||||
uint color; // 44-47: tint, packed RGBA u8x4
|
||||
};
|
||||
|
||||
@@ -78,9 +78,9 @@ void main() {
|
||||
// Mode 0 doesn't read the per-primitive varyings; zero-init for safety.
|
||||
p_local = vec2(0.0);
|
||||
f_color = vec4(0.0);
|
||||
f_half_size = vec2(0.0);
|
||||
f_radii = vec4(0.0);
|
||||
f_half_feather = 0.0;
|
||||
f_half_size_ppx = vec2(0.0);
|
||||
f_radii_ppx = vec4(0.0);
|
||||
f_half_feather_ppx = 0.0;
|
||||
} else {
|
||||
// ---- Mode 1: V-composite instanced unit-quad over Gaussian_Blur_Primitive ----
|
||||
Gaussian_Blur_Primitive p = primitives[gl_InstanceIndex];
|
||||
@@ -101,9 +101,9 @@ void main() {
|
||||
p_local = (world_pos - center) * dpi_scale;
|
||||
|
||||
f_color = unpackUnorm4x8(p.color);
|
||||
f_half_size = p.half_size;
|
||||
f_radii = p.radii;
|
||||
f_half_feather = p.half_feather;
|
||||
f_half_size_ppx = p.half_size_ppx;
|
||||
f_radii_ppx = p.radii_ppx;
|
||||
f_half_feather_ppx = p.half_feather_ppx;
|
||||
|
||||
gl_Position = projection * vec4(world_pos * dpi_scale, 0.0, 1.0);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ float sdRegularPolygon(vec2 p, float r, float n) {
|
||||
return length(p) * cos(bn) - r;
|
||||
}
|
||||
|
||||
// Coverage from SDF distance using half-feather width (feather_px * 0.5, pre-computed on CPU).
|
||||
// Coverage from SDF distance using half-feather width (feather_ppx * 0.5, pre-computed on CPU).
|
||||
// Produces a symmetric transition centered on d=0: smoothstep(-h, h, d).
|
||||
float sdf_alpha(float d, float h) {
|
||||
return 1.0 - smoothstep(-h, h, d);
|
||||
@@ -80,56 +80,56 @@ void main() {
|
||||
|
||||
// SDF path — dispatch on kind
|
||||
float d = 1e30;
|
||||
float h = 0.5; // half-feather width; overwritten per shape kind
|
||||
vec2 half_size = f_params.xy; // used by RRect and as reference size for gradients
|
||||
float h = 0.5; // half-feather width (physical px); overwritten per shape kind
|
||||
vec2 half_size_ppx = f_params.xy; // used by RRect and as reference size for gradients
|
||||
|
||||
vec2 p_local = f_local_or_uv; // arrives rotated; vertex shader handled .Rotated
|
||||
vec2 p_local_ppx = f_local_or_uv; // arrives rotated; vertex shader handled .Rotated
|
||||
|
||||
if (kind == 1u) {
|
||||
// RRect — half_feather in params2.z
|
||||
vec4 corner_radii = vec4(f_params.zw, f_params2.xy);
|
||||
// RRect — half_feather_ppx in params2.z
|
||||
vec4 corner_radii_ppx = vec4(f_params.zw, f_params2.xy);
|
||||
h = f_params2.z;
|
||||
d = sdRoundedBox(p_local, half_size, corner_radii);
|
||||
d = sdRoundedBox(p_local_ppx, half_size_ppx, corner_radii_ppx);
|
||||
}
|
||||
else if (kind == 2u) {
|
||||
// NGon — half_feather in params.z
|
||||
float radius = f_params.x;
|
||||
// NGon — half_feather_ppx in params.z
|
||||
float radius_ppx = f_params.x;
|
||||
float sides = f_params.y;
|
||||
h = f_params.z;
|
||||
d = sdRegularPolygon(p_local, radius, sides);
|
||||
half_size = vec2(radius); // for gradient UV computation
|
||||
d = sdRegularPolygon(p_local_ppx, radius_ppx, sides);
|
||||
half_size_ppx = vec2(radius_ppx); // for gradient UV computation
|
||||
}
|
||||
else if (kind == 3u) {
|
||||
// Ellipse — half_feather in params.z
|
||||
vec2 ab = f_params.xy;
|
||||
// Ellipse — half_feather_ppx in params.z
|
||||
vec2 radii_ppx = f_params.xy;
|
||||
h = f_params.z;
|
||||
d = sdEllipseApprox(p_local, ab);
|
||||
half_size = ab; // for gradient UV computation
|
||||
d = sdEllipseApprox(p_local_ppx, radii_ppx);
|
||||
half_size_ppx = radii_ppx; // for gradient UV computation
|
||||
}
|
||||
else if (kind == 4u) {
|
||||
// Ring_Arc — half_feather in params2.z
|
||||
// Ring_Arc — half_feather_ppx in params2.z
|
||||
// Arc mode from flag bits 5-6: 0 = full, 1 = narrow (≤π), 2 = wide (>π)
|
||||
float inner = f_params.x;
|
||||
float outer = f_params.y;
|
||||
float inner_radius_ppx = f_params.x;
|
||||
float outer_radius_ppx = f_params.y;
|
||||
vec2 n_start = f_params.zw;
|
||||
vec2 n_end = f_params2.xy;
|
||||
uint arc_bits = (flags >> 5u) & 3u;
|
||||
|
||||
h = f_params2.z;
|
||||
|
||||
float r = length(p_local);
|
||||
d = max(inner - r, r - outer);
|
||||
float r = length(p_local_ppx);
|
||||
d = max(inner_radius_ppx - r, r - outer_radius_ppx);
|
||||
|
||||
if (arc_bits != 0u) {
|
||||
float d_start = dot(p_local, n_start);
|
||||
float d_end = dot(p_local, n_end);
|
||||
float d_start = dot(p_local_ppx, n_start);
|
||||
float d_end = dot(p_local_ppx, n_end);
|
||||
float d_wedge = (arc_bits == 1u)
|
||||
? max(d_start, d_end) // arc ≤ π: intersect half-planes
|
||||
: min(d_start, d_end); // arc > π: union half-planes
|
||||
d = max(d, d_wedge);
|
||||
}
|
||||
|
||||
half_size = vec2(outer); // for gradient UV computation
|
||||
half_size_ppx = vec2(outer_radius_ppx); // for gradient UV computation
|
||||
}
|
||||
|
||||
// --- fwidth-based normalization for correct AA and stroke width ---
|
||||
@@ -146,18 +146,18 @@ void main() {
|
||||
|
||||
if ((flags & 4u) != 0u) {
|
||||
// Radial gradient (bit 2): t from distance to center
|
||||
mediump float t = length(p_local / half_size);
|
||||
mediump float t = length(p_local_ppx / half_size_ppx);
|
||||
shape_color = gradient_2color(gradient_start, gradient_end, t);
|
||||
} else {
|
||||
// Linear gradient: direction pre-computed on CPU as (cos, sin) f16 pair
|
||||
vec2 direction = unpackHalf2x16(f_effects.z);
|
||||
mediump float t = dot(p_local / half_size, direction) * 0.5 + 0.5;
|
||||
mediump float t = dot(p_local_ppx / half_size_ppx, direction) * 0.5 + 0.5;
|
||||
shape_color = gradient_2color(gradient_start, gradient_end, t);
|
||||
}
|
||||
} else if ((flags & 1u) != 0u) {
|
||||
// Textured (bit 0)
|
||||
vec4 uv_rect = f_uv_rect;
|
||||
vec2 local_uv = p_local / half_size * 0.5 + 0.5;
|
||||
vec2 local_uv = p_local_ppx / half_size_ppx * 0.5 + 0.5;
|
||||
vec2 uv = mix(uv_rect.xy, uv_rect.zw, local_uv);
|
||||
shape_color = f_color * texture(tex, uv);
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#version 450 core
|
||||
|
||||
// ---------- Vertex attributes (used in both modes) ----------
|
||||
// ---------- Vertex attributes (used in all modes) ----------
|
||||
layout(location = 0) in vec2 v_position;
|
||||
layout(location = 1) in vec2 v_uv;
|
||||
layout(location = 2) in vec4 v_color;
|
||||
@@ -16,10 +16,18 @@ layout(location = 6) flat out vec4 f_uv_rect;
|
||||
layout(location = 7) flat out uvec4 f_effects;
|
||||
|
||||
// ---------- Uniforms (single block — avoids spirv-cross reordering on Metal) ----------
|
||||
// Mode values mirror Core_2D_Mode in core_2d.odin:
|
||||
// 0 = Tessellated v_position is in logical pixels; shader scales by dpi_scale.
|
||||
// 1 = SDF v_position is a unit-quad corner; world-space comes from
|
||||
// primitives[gl_InstanceIndex].bounds (logical px). Shader
|
||||
// scales by dpi_scale.
|
||||
// 2 = Text v_position is in *physical* pixels already (the CPU baked
|
||||
// the anchor snap and SDL_ttf glyph offsets, both physical).
|
||||
// Shader must NOT rescale.
|
||||
layout(set = 1, binding = 0) uniform Uniforms {
|
||||
mat4 projection;
|
||||
float dpi_scale;
|
||||
uint mode; // 0 = tessellated, 1 = SDF
|
||||
uint mode;
|
||||
};
|
||||
|
||||
// ---------- SDF primitive storage buffer ----------
|
||||
@@ -44,18 +52,7 @@ layout(std430, set = 0, binding = 0) readonly buffer Core_2D_Primitives {
|
||||
|
||||
// ---------- Entry point ----------
|
||||
void main() {
|
||||
if (mode == 0u) {
|
||||
// ---- Mode 0: Tessellated (used for text and arbitrary user geometry) ----
|
||||
f_color = v_color;
|
||||
f_local_or_uv = v_uv;
|
||||
f_params = vec4(0.0);
|
||||
f_params2 = vec4(0.0);
|
||||
f_flags = 0u;
|
||||
f_uv_rect = vec4(0.0);
|
||||
f_effects = uvec4(0);
|
||||
|
||||
gl_Position = projection * vec4(v_position * dpi_scale, 0.0, 1.0);
|
||||
} else {
|
||||
if (mode == 1u) {
|
||||
// ---- Mode 1: SDF instanced quads ----
|
||||
Core_2D_Primitive p = primitives[gl_InstanceIndex];
|
||||
|
||||
@@ -86,5 +83,25 @@ void main() {
|
||||
f_effects = p.effects;
|
||||
|
||||
gl_Position = projection * vec4(world_pos * dpi_scale, 0.0, 1.0);
|
||||
} else {
|
||||
// ---- Mode 0 (Tessellated) and Mode 2 (Text) ----
|
||||
// Both feed the raw-vertex pipeline (kind 0 in the fragment shader).
|
||||
// They differ only in what coord space `v_position` is in:
|
||||
// Mode 0 — logical pixels, scale here by dpi_scale.
|
||||
// Mode 2 — physical pixels (CPU pre-scaled and snapped to integer
|
||||
// physical pixels for atlas-aligned bilinear sampling).
|
||||
// Do NOT rescale.
|
||||
// `mode` is uniform across the workgroup, so the select compiles to a
|
||||
// uniform-controlled branch with no SIMT divergence cost.
|
||||
f_color = v_color;
|
||||
f_local_or_uv = v_uv;
|
||||
f_params = vec4(0.0);
|
||||
f_params2 = vec4(0.0);
|
||||
f_flags = 0u;
|
||||
f_uv_rect = vec4(0.0);
|
||||
f_effects = uvec4(0);
|
||||
|
||||
vec2 pos = (mode == 2u) ? v_position : (v_position * dpi_scale);
|
||||
gl_Position = projection * vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user