From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- gfx/wr/webrender/res/cs_clip_box_shadow.glsl | 327 +++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 gfx/wr/webrender/res/cs_clip_box_shadow.glsl (limited to 'gfx/wr/webrender/res/cs_clip_box_shadow.glsl') diff --git a/gfx/wr/webrender/res/cs_clip_box_shadow.glsl b/gfx/wr/webrender/res/cs_clip_box_shadow.glsl new file mode 100644 index 0000000000..37a983c759 --- /dev/null +++ b/gfx/wr/webrender/res/cs_clip_box_shadow.glsl @@ -0,0 +1,327 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include shared,clip_shared + +varying highp vec4 vLocalPos; +varying highp vec2 vUv; +flat varying highp vec4 vUvBounds; +flat varying mediump vec4 vEdge; +flat varying highp vec4 vUvBounds_NoClamp; +// Clip mode. Packed in to a vector to avoid bug 1630356. +flat varying mediump vec2 vClipMode; + +#define MODE_STRETCH 0 +#define MODE_SIMPLE 1 + +#ifdef WR_VERTEX_SHADER + +PER_INSTANCE in ivec2 aClipDataResourceAddress; +PER_INSTANCE in vec2 aClipSrcRectSize; +PER_INSTANCE in int aClipMode; +PER_INSTANCE in ivec2 aStretchMode; +PER_INSTANCE in vec4 aClipDestRect; + +struct ClipMaskInstanceBoxShadow { + ClipMaskInstanceCommon base; + ivec2 resource_address; +}; + +ClipMaskInstanceBoxShadow fetch_clip_item() { + ClipMaskInstanceBoxShadow cmi; + + cmi.base = fetch_clip_item_common(); + cmi.resource_address = aClipDataResourceAddress; + + return cmi; +} + +struct BoxShadowData { + vec2 src_rect_size; + int clip_mode; + int stretch_mode_x; + int stretch_mode_y; + RectWithEndpoint dest_rect; +}; + +BoxShadowData fetch_data() { + BoxShadowData bs_data = BoxShadowData( + aClipSrcRectSize, + aClipMode, + aStretchMode.x, + aStretchMode.y, + RectWithEndpoint(aClipDestRect.xy, aClipDestRect.zw) + ); + return bs_data; +} + +void main(void) { + ClipMaskInstanceBoxShadow cmi = fetch_clip_item(); + Transform clip_transform = fetch_transform(cmi.base.clip_transform_id); + Transform prim_transform = fetch_transform(cmi.base.prim_transform_id); + BoxShadowData bs_data = fetch_data(); + ImageSource res = fetch_image_source_direct(cmi.resource_address); + + RectWithEndpoint dest_rect = bs_data.dest_rect; + + ClipVertexInfo vi = write_clip_tile_vertex( + dest_rect, + prim_transform, + clip_transform, + cmi.base.sub_rect, + cmi.base.task_origin, + cmi.base.screen_origin, + cmi.base.device_pixel_scale + ); + vClipMode.x = float(bs_data.clip_mode); + + vec2 texture_size = vec2(TEX_SIZE(sColor0)); + vec2 local_pos = vi.local_pos.xy / vi.local_pos.w; + vLocalPos = vi.local_pos; + vec2 dest_rect_size = rect_size(dest_rect); + + switch (bs_data.stretch_mode_x) { + case MODE_STRETCH: { + vEdge.x = 0.5; + vEdge.z = (dest_rect_size.x / bs_data.src_rect_size.x) - 0.5; + vUv.x = (local_pos.x - dest_rect.p0.x) / bs_data.src_rect_size.x; + break; + } + case MODE_SIMPLE: + default: { + vEdge.xz = vec2(1.0); + vUv.x = (local_pos.x - dest_rect.p0.x) / dest_rect_size.x; + break; + } + } + + switch (bs_data.stretch_mode_y) { + case MODE_STRETCH: { + vEdge.y = 0.5; + vEdge.w = (dest_rect_size.y / bs_data.src_rect_size.y) - 0.5; + vUv.y = (local_pos.y - dest_rect.p0.y) / bs_data.src_rect_size.y; + break; + } + case MODE_SIMPLE: + default: { + vEdge.yw = vec2(1.0); + vUv.y = (local_pos.y - dest_rect.p0.y) / dest_rect_size.y; + break; + } + } + + vUv *= vi.local_pos.w; + vec2 uv0 = res.uv_rect.p0; + vec2 uv1 = res.uv_rect.p1; + vUvBounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) / texture_size.xyxy; + vUvBounds_NoClamp = vec4(uv0, uv1) / texture_size.xyxy; +} +#endif + +#ifdef WR_FRAGMENT_SHADER +void main(void) { + vec2 uv_linear = vUv / vLocalPos.w; + vec2 uv = clamp(uv_linear, vec2(0.0), vEdge.xy); + uv += max(vec2(0.0), uv_linear - vEdge.zw); + uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv); + uv = clamp(uv, vUvBounds.xy, vUvBounds.zw); + + float in_shadow_rect = init_transform_rough_fs(vLocalPos.xy / vLocalPos.w); + + float texel = TEX_SAMPLE(sColor0, uv).r; + + float alpha = mix(texel, 1.0 - texel, vClipMode.x); + float result = vLocalPos.w > 0.0 ? mix(vClipMode.x, alpha, in_shadow_rect) : 0.0; + + oFragColor = vec4(result); +} + +#ifdef SWGL_DRAW_SPAN +// As with cs_clip_rectangle, this shader spends a lot of time doing clipping and +// combining for every fragment, even if outside of the primitive to initialize +// the clip tile, or inside the inner bounds of the primitive, where the shadow +// is unnecessary. To alleviate this, the span shader attempts to first intersect +// the the local clip bounds, outside of which we can just use a solid fill +// to initialize those clip tile fragments. Once inside the primitive bounds, +// we further intersect with the inner region where no shadow is necessary either +// so that we can commit entire spans of texture within this nine-patch region +// instead of having to do the work of mapping per fragment. +void swgl_drawSpanR8() { + // Perspective is not supported. + if (swgl_interpStep(vLocalPos).w != 0.0) { + return; + } + + // If the span is completely outside the Z-range and clipped out, just + // output clear so we don't need to consider invalid W in the rest of the + // shader. + float w = swgl_forceScalar(vLocalPos.w); + if (w <= 0.0) { + swgl_commitSolidR8(0.0); + return; + } + + // To start, we evaluate the box shadow in both UV and local space relative + // to the local-space position. This will be interpolated across the span to + // track whether we intersect the nine-patch. + w = 1.0 / w; + vec2 uv_linear = vUv * w; + vec2 uv_linear0 = swgl_forceScalar(uv_linear); + vec2 uv_linear_step = swgl_interpStep(vUv).xy * w; + vec2 local_pos = vLocalPos.xy * w; + vec2 local_pos0 = swgl_forceScalar(local_pos); + vec2 local_step = swgl_interpStep(vLocalPos).xy * w; + + // We need to compute the local-space distance to the bounding box and then + // figure out how many processing steps that maps to. If we are stepping in + // a negative direction on an axis, we need to swap the sides of the box + // which we consider as the start or end. If there is no local-space step + // on an axis (i.e. constant Y), we need to take care to force the steps to + // either the start or end of the span depending on if we are inside or + // outside of the bounding box. + vec4 clip_dist = + mix(vTransformBounds, vTransformBounds.zwxy, lessThan(local_step, vec2(0.0)).xyxy) + - local_pos0.xyxy; + clip_dist = + mix(1.0e6 * step(0.0, clip_dist), + clip_dist * recip(local_step).xyxy, + notEqual(local_step, vec2(0.0)).xyxy); + + // Find the start and end of the shadowed region on this span. + float shadow_start = max(clip_dist.x, clip_dist.y); + float shadow_end = min(clip_dist.z, clip_dist.w); + + // Flip the offsets from the start of the span so we can compare against the + // remaining span length which automatically deducts as we commit fragments. + ivec2 shadow_steps = ivec2(clamp( + swgl_SpanLength - swgl_StepSize * vec2(floor(shadow_start), ceil(shadow_end)), + 0.0, swgl_SpanLength)); + int shadow_start_len = shadow_steps.x; + int shadow_end_len = shadow_steps.y; + + // Likewise, once inside the primitive bounds, we also need to track which + // sector of the nine-patch we are in which requires intersecting against + // the inner box instead of the outer box. + vec4 opaque_dist = + mix(vEdge, vEdge.zwxy, lessThan(uv_linear_step, vec2(0.0)).xyxy) + - uv_linear0.xyxy; + opaque_dist = + mix(1.0e6 * step(0.0, opaque_dist), + opaque_dist * recip(uv_linear_step).xyxy, + notEqual(uv_linear_step, vec2(0.0)).xyxy); + + // Unlike for the shadow clipping bounds, here we need to rather find the floor of all + // the offsets so that we don't accidentally process any chunks in the transitional areas + // between sectors of the nine-patch. + ivec4 opaque_steps = ivec4(clamp( + swgl_SpanLength - + swgl_StepSize * + vec4(floor(opaque_dist.x), floor(opaque_dist.y), floor(opaque_dist.z), floor(opaque_dist.w)), + shadow_end_len, swgl_SpanLength)); + + // Fill any initial sections of the span that are clipped out based on clip mode. + if (swgl_SpanLength > shadow_start_len) { + int num_before = swgl_SpanLength - shadow_start_len; + swgl_commitPartialSolidR8(num_before, vClipMode.x); + float steps_before = float(num_before / swgl_StepSize); + uv_linear += steps_before * uv_linear_step; + local_pos += steps_before * local_step; + } + + // This loop tries to repeatedly process entire spans of the nine-patch that map + // to a contiguous spans of texture in the source box shadow. First, we process + // a chunk with per-fragment clipping and mapping in case we're starting on a + // transitional region between sectors of the nine-patch which may need to map + // to different spans of texture per-fragment. After, we find the largest span + // within the current sector before we hit the next transitional region, and + // attempt to commit an entire span of texture therein. + while (swgl_SpanLength > 0) { + // Here we might be in a transitional chunk, so do everything per-fragment. + { + vec2 uv = clamp(uv_linear, vec2(0.0), vEdge.xy); + uv += max(vec2(0.0), uv_linear - vEdge.zw); + uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv); + uv = clamp(uv, vUvBounds.xy, vUvBounds.zw); + + float in_shadow_rect = init_transform_rough_fs(local_pos); + + float texel = TEX_SAMPLE(sColor0, uv).r; + + float alpha = mix(texel, 1.0 - texel, vClipMode.x); + float result = mix(vClipMode.x, alpha, in_shadow_rect); + swgl_commitColorR8(result); + + uv_linear += uv_linear_step; + local_pos += local_step; + } + // If we now hit the end of the clip bounds, just bail out since there is + // no more shadow to map. + if (swgl_SpanLength <= shadow_end_len) { + break; + } + // By here we've determined to be still inside the nine-patch. We need to + // compare against the inner rectangle thresholds to see which sector of + // the nine-patch to use and thus how to map the box shadow texture. Stop + // at least one step before the end of the shadow region to properly clip + // on the boundary. + int num_inside = swgl_SpanLength - swgl_StepSize - shadow_end_len; + vec4 uv_bounds = vUvBounds; + if (swgl_SpanLength >= opaque_steps.y) { + // We're in the top Y band of the nine-patch. + num_inside = min(num_inside, swgl_SpanLength - opaque_steps.y); + } else if (swgl_SpanLength >= opaque_steps.w) { + // We're in the middle Y band of the nine-patch. Set the UV clamp bounds + // to the vertical center texel of the box shadow. + num_inside = min(num_inside, swgl_SpanLength - opaque_steps.w); + uv_bounds.yw = vec2(clamp(mix(vUvBounds_NoClamp.y, vUvBounds_NoClamp.w, vEdge.y), + vUvBounds.y, vUvBounds.w)); + } + if (swgl_SpanLength >= opaque_steps.x) { + // We're in the left X column of the nine-patch. + num_inside = min(num_inside, swgl_SpanLength - opaque_steps.x); + } else if (swgl_SpanLength >= opaque_steps.z) { + // We're in the middle X band of the nine-patch. Set the UV clamp bounds + // to the horizontal center texel of the box shadow. + num_inside = min(num_inside, swgl_SpanLength - opaque_steps.z); + uv_bounds.xz = vec2(clamp(mix(vUvBounds_NoClamp.x, vUvBounds_NoClamp.z, vEdge.x), + vUvBounds.x, vUvBounds.z)); + } + if (num_inside > 0) { + // We have a non-zero span of fragments within the sector. Map to the UV + // start offset of the sector and the UV offset within the sector. + vec2 uv = clamp(uv_linear, vec2(0.0), vEdge.xy); + uv += max(vec2(0.0), uv_linear - vEdge.zw); + uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv); + // If we're in the center sector of the nine-patch, then we only need to + // sample from a single texel of the box shadow. Just sample that single + // texel once and output it for the entire span. Otherwise, we just need + // to commit an actual span of texture from the box shadow. Depending on + // if we are in clip-out mode, we may need to invert the source texture. + if (uv_bounds.xy == uv_bounds.zw) { + uv = clamp(uv, uv_bounds.xy, uv_bounds.zw); + float texel = TEX_SAMPLE(sColor0, uv).r; + float alpha = mix(texel, 1.0 - texel, vClipMode.x); + swgl_commitPartialSolidR8(num_inside, alpha); + } else if (vClipMode.x != 0.0) { + swgl_commitPartialTextureLinearInvertR8(num_inside, sColor0, uv, uv_bounds); + } else { + swgl_commitPartialTextureLinearR8(num_inside, sColor0, uv, uv_bounds); + } + float steps_inside = float(num_inside / swgl_StepSize); + uv_linear += steps_inside * uv_linear_step; + local_pos += steps_inside * local_step; + } + // By here we're probably in a transitional chunk of the nine-patch that + // requires per-fragment processing, so loop around again to the handler + // for that case. + } + + // Fill any remaining sections of the span that are clipped out. + if (swgl_SpanLength > 0) { + swgl_commitPartialSolidR8(swgl_SpanLength, vClipMode.x); + } +} +#endif + +#endif -- cgit v1.2.3