forked from 1b-agent/opencadstudio-upstream
Merge PR #1023: preserve minified text strokes
Keep adaptive sampling in both text shaders with compact sampling loops. Validate shader derivatives and existing text rendering, including GPU pipeline creation. Closes #964
This commit is contained in:
commit
bf4614856c
3 files changed
+64
-10
No files matched your search
@@ -49,9 +49,29 @@ fn vs_main(v: VertIn) -> VertOut {
|
|||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VertOut) -> @location(0) vec4<f32> {
|
fn fs_main(in: VertOut) -> @location(0) vec4<f32> {
|
||||||
let sd = textureSample(atlas_tex, atlas_samp, in.uv).r;
|
let uv_dx = dpdx(in.uv);
|
||||||
let aa = max(fwidth(sd), 1e-4);
|
let uv_dy = dpdy(in.uv);
|
||||||
let alpha = smoothstep(0.5 - aa, 0.5 + aa, sd);
|
let dims = vec2<f32>(textureDimensions(atlas_tex));
|
||||||
|
let footprint = max(length(uv_dx * dims), length(uv_dy * dims));
|
||||||
|
let sd_center = textureSampleLevel(atlas_tex, atlas_samp, in.uv, 0.0).r;
|
||||||
|
let aa = max(fwidth(sd_center), 1e-4);
|
||||||
|
var alpha = smoothstep(0.5 - aa, 0.5 + aa, sd_center);
|
||||||
|
|
||||||
|
if footprint > 1.0 {
|
||||||
|
// Average coverage over the pixel footprint so thin strokes survive minification.
|
||||||
|
let samples = select(4, 2, footprint <= 4.0);
|
||||||
|
var sum = 0.0;
|
||||||
|
for (var y = 0; y < samples; y += 1) {
|
||||||
|
for (var x = 0; x < samples; x += 1) {
|
||||||
|
let offset = (vec2<f32>(f32(x), f32(y)) + 0.5) / f32(samples) - 0.5;
|
||||||
|
let sd = textureSampleLevel(
|
||||||
|
atlas_tex, atlas_samp, in.uv + uv_dx * offset.x + uv_dy * offset.y, 0.0
|
||||||
|
).r;
|
||||||
|
sum += smoothstep(0.5 - aa, 0.5 + aa, sd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alpha = sum / f32(samples * samples);
|
||||||
|
}
|
||||||
if alpha <= 0.0 {
|
if alpha <= 0.0 {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-7
@@ -59,13 +59,31 @@ fn vs_main(in: VertIn) -> VertOut {
|
|||||||
// ── Fragment stage ────────────────────────────────────────────────────────────
|
// ── Fragment stage ────────────────────────────────────────────────────────────
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VertOut) -> @location(0) vec4<f32> {
|
fn fs_main(in: VertOut) -> @location(0) vec4<f32> {
|
||||||
// SDF value: 0.5 at the glyph edge, higher inside the ink.
|
let uv_dx = dpdx(in.uv);
|
||||||
let sd = textureSample(atlas_tex, atlas_samp, in.uv).r;
|
let uv_dy = dpdy(in.uv);
|
||||||
// Antialias over one screen-space texel of field change.
|
let dims = vec2<f32>(textureDimensions(atlas_tex));
|
||||||
let aa = max(fwidth(sd), 1e-4);
|
let footprint = max(length(uv_dx * dims), length(uv_dy * dims));
|
||||||
let a = smoothstep(0.5 - aa, 0.5 + aa, sd);
|
let sd_center = textureSampleLevel(atlas_tex, atlas_samp, in.uv, 0.0).r;
|
||||||
if (a <= 0.0) {
|
let aa = max(fwidth(sd_center), 1e-4);
|
||||||
|
var alpha = smoothstep(0.5 - aa, 0.5 + aa, sd_center);
|
||||||
|
|
||||||
|
if footprint > 1.0 {
|
||||||
|
// Average coverage over the pixel footprint so thin strokes survive minification.
|
||||||
|
let samples = select(4, 2, footprint <= 4.0);
|
||||||
|
var sum = 0.0;
|
||||||
|
for (var y = 0; y < samples; y += 1) {
|
||||||
|
for (var x = 0; x < samples; x += 1) {
|
||||||
|
let offset = (vec2<f32>(f32(x), f32(y)) + 0.5) / f32(samples) - 0.5;
|
||||||
|
let sd = textureSampleLevel(
|
||||||
|
atlas_tex, atlas_samp, in.uv + uv_dx * offset.x + uv_dy * offset.y, 0.0
|
||||||
|
).r;
|
||||||
|
sum += smoothstep(0.5 - aa, 0.5 + aa, sd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alpha = sum / f32(samples * samples);
|
||||||
|
}
|
||||||
|
if alpha <= 0.0 {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
return vec4<f32>(in.color.rgb, in.color.a * a);
|
return vec4<f32>(in.color.rgb, in.color.a * alpha);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#[test]
|
||||||
|
fn adaptive_text_sampling_passes_derivative_uniformity_validation() {
|
||||||
|
for (name, source) in [
|
||||||
|
("text", include_str!("../src/shaders/text.wgsl")),
|
||||||
|
("block text", include_str!("../src/shaders/block_text.wgsl")),
|
||||||
|
] {
|
||||||
|
let module = naga::front::wgsl::parse_str(source)
|
||||||
|
.unwrap_or_else(|error| panic!("{name}: {}", error.emit_to_string(source)));
|
||||||
|
naga::valid::Validator::new(
|
||||||
|
naga::valid::ValidationFlags::all(),
|
||||||
|
naga::valid::Capabilities::empty(),
|
||||||
|
)
|
||||||
|
.validate(&module)
|
||||||
|
.unwrap_or_else(|error| panic!("{name}: {error:?}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user