Skip to content

Commit

Permalink
Bug 1797721 - Handle tile repeat in brush_linear_gradient SWGL span s…
Browse files Browse the repository at this point in the history
  • Loading branch information
lsalzman committed Oct 29, 2022
1 parent 96a3252 commit 510e2ba
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 42 deletions.
3 changes: 2 additions & 1 deletion glsl-to-cxx/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3960,7 +3960,8 @@ pub fn ast_to_hir(state: &mut State, tu: &syntax::TranslationUnit) -> Translatio
"swgl_commitLinearGradientRGBA8",
None,
Type::new(Void),
vec![Type::new(Sampler2D), Type::new(Int), Type::new(Float), Type::new(Bool), Type::new(Float)],
vec![Type::new(Sampler2D), Type::new(Int), Type::new(Float), Type::new(Bool), Type::new(Bool),
Type::new(Vec2), Type::new(Vec2), Type::new(Float)],
);
declare_function(
state,
Expand Down
82 changes: 57 additions & 25 deletions swgl/src/swgl_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1388,25 +1388,51 @@ static inline WideRGBA8 sampleGradient(sampler2D sampler, int address,
// gradient, then interpolating between those larger gradients within the span.
template <bool BLEND>
static bool commitLinearGradient(sampler2D sampler, int address, float size,
bool repeat, Float offset, uint32_t* buf,
int span) {
bool tileRepeat, bool gradientRepeat, vec2 pos,
const vec2_scalar& scaleDir, float startOffset,
uint32_t* buf, int span) {
assert(sampler->format == TextureFormat::RGBA32F);
assert(address >= 0 && address < int(sampler->height * sampler->stride));
GradientStops* stops = (GradientStops*)&sampler->buf[address];
// Get the chunk delta from the difference in offset steps. This represents
// how far within the gradient table we advance for every step in output,
// normalized to gradient table size.
float delta = (offset.y - offset.x) * 4.0f;
vec2_scalar posStep = dFdx(pos) * 4.0f;
float delta = dot(posStep, scaleDir);
if (!isfinite(delta)) {
return false;
}
// If we have a repeating brush, then the position will be modulo the [0,1)
// interval. Compute coefficients that can be used to quickly evaluate the
// distance to the interval boundary where the offset will wrap.
vec2_scalar distCoeffsX = {0.25f * span, 0.0f};
vec2_scalar distCoeffsY = distCoeffsX;
if (tileRepeat) {
if (posStep.x != 0.0f) {
distCoeffsX = vec2_scalar{step(0.0f, posStep.x), 1.0f} * recip(posStep.x);
}
if (posStep.y != 0.0f) {
distCoeffsY = vec2_scalar{step(0.0f, posStep.y), 1.0f} * recip(posStep.y);
}
}
for (; span > 0;) {
// Try to process as many chunks as are within the span if possible.
float chunks = 0.25f * span;
vec2 repeatPos = pos;
if (tileRepeat) {
// If this is a repeating brush, then limit the chunks to not cross the
// interval boundaries.
repeatPos = fract(pos);
chunks = min(chunks, distCoeffsX.x - repeatPos.x.x * distCoeffsX.y);
chunks = min(chunks, distCoeffsY.x - repeatPos.y.x * distCoeffsY.y);
}
// Compute the gradient offset from the position.
Float offset =
repeatPos.x * scaleDir.x + repeatPos.y * scaleDir.y - startOffset;
// If repeat is desired, we need to limit the offset to a fractional value.
if (repeat) {
if (gradientRepeat) {
offset = fract(offset);
}
// Try to process as many chunks as are within the span if possible.
float chunks = 0.25f * span;
// To properly handle both clamping and repeating of the table offset, we
// need to ensure we don't run past the 0 and 1 points. Here we compute the
// intercept points depending on whether advancing forwards or backwards in
Expand Down Expand Up @@ -1517,8 +1543,12 @@ static bool commitLinearGradient(sampler2D sampler, int address, float size,
}
// Otherwise, assume we're in a transitional section of the gradient that
// will probably require per-sample table lookups, so fall through below.
offset += inside * delta;
if (repeat) {
// We need to re-evaluate the position and offset first, though.
pos += posStep * float(inside);
repeatPos = tileRepeat ? fract(pos) : pos;
offset =
repeatPos.x * scaleDir.x + repeatPos.y * scaleDir.y - startOffset;
if (gradientRepeat) {
offset = fract(offset);
}
}
Expand All @@ -1532,7 +1562,7 @@ static bool commitLinearGradient(sampler2D sampler, int address, float size,
commit_blend_span<BLEND>(buf, sampleGradient(sampler, address, entry));
span -= 4;
buf += 4;
offset += delta;
pos += posStep;
}
return true;
}
Expand All @@ -1543,22 +1573,24 @@ static bool commitLinearGradient(sampler2D sampler, int address, float size,
// each to deal with clamping. Repeating will be handled if necessary. The
// initial offset within the table is used to designate where to start the span
// and how to step through the gradient table.
#define swgl_commitLinearGradientRGBA8(sampler, address, size, repeat, offset) \
do { \
bool drawn = false; \
if (blend_key) { \
drawn = \
commitLinearGradient<true>(sampler, address, size, repeat, offset, \
swgl_OutRGBA8, swgl_SpanLength); \
} else { \
drawn = \
commitLinearGradient<false>(sampler, address, size, repeat, offset, \
swgl_OutRGBA8, swgl_SpanLength); \
} \
if (drawn) { \
swgl_OutRGBA8 += swgl_SpanLength; \
swgl_SpanLength = 0; \
} \
#define swgl_commitLinearGradientRGBA8(sampler, address, size, tileRepeat, \
gradientRepeat, pos, scaleDir, \
startOffset) \
do { \
bool drawn = false; \
if (blend_key) { \
drawn = commitLinearGradient<true>( \
sampler, address, size, tileRepeat, gradientRepeat, pos, scaleDir, \
startOffset, swgl_OutRGBA8, swgl_SpanLength); \
} else { \
drawn = commitLinearGradient<false>( \
sampler, address, size, tileRepeat, gradientRepeat, pos, scaleDir, \
startOffset, swgl_OutRGBA8, swgl_SpanLength); \
} \
if (drawn) { \
swgl_OutRGBA8 += swgl_SpanLength; \
swgl_SpanLength = 0; \
} \
} while (0)

template <bool CLAMP, typename V>
Expand Down
17 changes: 4 additions & 13 deletions webrender/res/brush_linear_gradient.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -82,22 +82,13 @@ Fragment brush_fs() {

#ifdef SWGL_DRAW_SPAN
void swgl_drawSpanRGBA8() {
int address = swgl_validateGradient(sGpuCache, get_gpu_cache_uv(v_gradient_address.x), int(GRADIENT_ENTRIES + 2.0));
int address = swgl_validateGradient(sGpuCache, get_gpu_cache_uv(v_gradient_address.x), int(GRADIENT_ENTRIES + 2.0));
if (address < 0) {
return;
}
#ifndef WR_FEATURE_ALPHA_PASS
swgl_commitLinearGradientRGBA8(sGpuCache, address, GRADIENT_ENTRIES, v_gradient_repeat.x != 0.0,
get_gradient_offset(v_pos));
#else
while (swgl_SpanLength > 0) {
float offset = get_gradient_offset(compute_repeated_pos());
if (v_gradient_repeat.x != 0.0) offset = fract(offset);
float entry = clamp_gradient_entry(offset);
swgl_commitGradientRGBA8(sGpuCache, address, entry);
v_pos += swgl_interpStep(v_pos);
}
#endif

swgl_commitLinearGradientRGBA8(sGpuCache, address, GRADIENT_ENTRIES, true, v_gradient_repeat.x != 0.0,
v_pos, v_scale_dir, v_start_offset.x);
}
#endif

Expand Down
5 changes: 2 additions & 3 deletions webrender/res/cs_linear_gradient.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@ void swgl_drawSpanRGBA8() {
return;
}

float offset = dot(v_pos, v_scale_dir) - v_start_offset.x;
swgl_commitLinearGradientRGBA8(sGpuCache, address, GRADIENT_ENTRIES, v_gradient_repeat.x != 0.0,
offset);
swgl_commitLinearGradientRGBA8(sGpuCache, address, GRADIENT_ENTRIES, false, v_gradient_repeat.x != 0.0,
v_pos, v_scale_dir, v_start_offset.x);
}
#endif

Expand Down

0 comments on commit 510e2ba

Please sign in to comment.