Bug 1686244 - Accelerate nearest repeat filtering in SWGL. r=jrmuizel

Some sites use pixelated/crisp image-rendering and/or 1x1 images as color
sources. When we hit these, we fall off the fast-path. Try to handle some
of those cases we are finding in the wild, namely nearest filtering and
repeat filtering.

There is some slight movement in the wrench fuzz due to the composite shader
being accelerated in situations it was previously not due to nearest filter.

Differential Revision: https://phabricator.services.mozilla.com/D105864
This commit is contained in:
Lee Salzman 2021-02-22 04:14:39 +00:00
Родитель 7d3755c3f6
Коммит 38845a4afa
15 изменённых файлов: 485 добавлений и 237 удалений

Просмотреть файл

@ -3825,42 +3825,6 @@ pub fn ast_to_hir(state: &mut State, tu: &syntax::TranslationUnit) -> Translatio
vec![Type::new(*s)], vec![Type::new(*s)],
RunClass::Scalar, RunClass::Scalar,
); );
declare_function_ext(
state,
"swgl_textureLayerOffset",
None,
Type::new(Int),
vec![Type::new(*s), Type::new(Float)],
RunClass::Scalar,
);
declare_function(
state,
"swgl_linearQuantize",
None,
Type::new(Vec2),
vec![Type::new(*s), Type::new(Vec2)],
);
declare_function(
state,
"swgl_linearQuantizeStep",
None,
Type::new(Vec2),
vec![Type::new(*s), Type::new(Vec2)],
);
declare_function(
state,
"swgl_commitTextureLinearChunkRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Int)],
);
declare_function(
state,
"swgl_commitTextureLinearChunkColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Int)],
);
declare_function( declare_function(
state, state,
"swgl_commitTextureLinearRGBA8", "swgl_commitTextureLinearRGBA8",
@ -3896,6 +3860,80 @@ pub fn ast_to_hir(state: &mut State, tu: &syntax::TranslationUnit) -> Translatio
Type::new(Void), Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Float), Type::new(Float)], vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Float), Type::new(Float)],
); );
declare_function(
state,
"swgl_commitTextureLinearRepeatRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureLinearRepeatColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureNearestRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureNearestColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureNearestRepeatRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureNearestRepeatColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureRepeatRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4), Type::new(Float)],
);
declare_function(
state,
"swgl_commitTextureRepeatColorRGBA8",
None,
Type::new(Void),
vec![Type::new(*s), Type::new(Vec2), Type::new(Vec4), Type::new(Vec4), Type::new(Vec4), Type::new(Float)],
);
declare_function( declare_function(
state, state,
"swgl_commitGaussianBlurRGBA8", "swgl_commitGaussianBlurRGBA8",

Просмотреть файл

@ -59,29 +59,6 @@ the edge ends on that vertex. The easiest way to understand this ordering
is that for a rectangle (x0,y0,x1,y1) then the edge Nth edge bit corresponds is that for a rectangle (x0,y0,x1,y1) then the edge Nth edge bit corresponds
to the edge where Nth coordinate in the rectangle is constant. to the edge where Nth coordinate in the rectangle is constant.
```
swgl_commitTextureLinearRGBA8(sampler, vec2 uv, vec4 uv_bounds, float layer);
swgl_commitTextureLinearR8(sampler, vec2 uv, vec4 uv_bounds, float layer);
swgl_commitTextureLinearColorRGBA8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color, float layer);
swgl_commitTextureLinearColorR8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color, float layer);
swgl_commitTextureLinearChunkRGBA8(sampler, vec2 uv, int layerOffset);
swgl_commitTextureLinearChunkColorRGBA8(sampler, vec2 uv, vec4 color, int layerOffset);
```
Samples and commits an entire span of texture starting at the given uv and
within the supplied uv bounds from the given layer. The color variations
also accept a supplied color that modulates the result.
The RGBA8 versions may only be used to commit within swgl_drawSpanRGBA8, and
the R8 versions may only be used to commit within swgl_drawSpanR8.
The chunk variations only commit a single chunk rather than an entire span. The
uv coordinates must be clamped beforehand and then scaled appropriately with
swgl_linearQuantize. The layer offset must be resolved to a linear offset with
with swgl_textureLayerOffset.
SWGL tries to use an anti-aliasing method that is reasonably close to WR's SWGL tries to use an anti-aliasing method that is reasonably close to WR's
signed-distance field approximation. WR would normally try to discern the signed-distance field approximation. WR would normally try to discern the
2D local-space coordinates of a given destination pixel relative to the 2D local-space coordinates of a given destination pixel relative to the
@ -105,3 +82,47 @@ Essentially, SWGL just performs anti-aliasing on the actual geometry bounds,
but when the pixels on a span's edge are determined to be partially covered but when the pixels on a span's edge are determined to be partially covered
during span rasterization, it uses the same distance field method as WR on during span rasterization, it uses the same distance field method as WR on
those span boundary pixels to estimate the coverage based on edge slope. those span boundary pixels to estimate the coverage based on edge slope.
```
swgl_commitTextureLinearRGBA8(sampler, vec2 uv, vec4 uv_bounds, float layer);
swgl_commitTextureLinearR8(sampler, vec2 uv, vec4 uv_bounds, float layer);
swgl_commitTextureLinearColorRGBA8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color, float layer);
swgl_commitTextureLinearColorR8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color, float layer);
swgl_commitTextureLinearRepeatRGBA8(sampler, vec2 uv, vec4 uv_repeat, vec4 uv_bounds, float layer);
swgl_commitTextureLinearRepeatColorRGBA8(sampler, vec2 uv, vec4 uv_repeat, vec4 uv_bounds, vec4|float color, float layer);
swgl_commitTextureNearestRGBA8(sampler, vec2 uv, vec4 uv_bounds, float layer);
swgl_commitTextureNearestColorRGBA8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color, float layer);
swgl_commitTextureNearestRepeatRGBA8(sampler, vec2 uv, vec4 uv_repeat, vec4 uv_bounds, float layer);
swgl_commitTextureNearestRepeatColorRGBA8(sampler, vec2 uv, vec4 uv_repeat, vec4 uv_bounds, vec4|float color, float layer);
swgl_commitTextureRGBA8(sampler, vec2 uv, vec4 uv_bounds, float layer);
swgl_commitTextureColorRGBA8(sampler, vec2 uv, vec4 uv_bounds, vec4|float color, float layer);
swgl_commitTextureRepeatRGBA8(sampler, vec2 uv, vec4 uv_repeat, vec4 uv_bounds, float layer);
swgl_commitTextureRepeatColorRGBA8(sampler, vec2 uv, vec4 uv_repeat, vec4 uv_bounds, vec4|float color, float layer);
```
Samples and commits an entire span of texture starting at the given uv and
within the supplied uv bounds from the given layer. The color variations
also accept a supplied color that modulates the result.
The RGBA8 versions may only be used to commit within swgl_drawSpanRGBA8, and
the R8 versions may only be used to commit within swgl_drawSpanR8.
The Linear variations use a linear filter that bilinearly interpolates between
the four samples near the pixel. The Nearest variations use a nearest filter
that chooses the closest aliased sample to the center of the pixel. If neither
Linear nor Nearest is specified in the swgl_commitTexture variation name, then
it will automatically select either the Linear or Nearest variation depending
on the sampler's specified filter.
The Repeat variations require an optional repeat rect that specifies how to
scale and offset the UVs, assuming the UVs are normalized to repeat in the
range 0 to 1. For NearestRepeat variations, it is assumed the repeat rect is
always within the bounds.

Просмотреть файл

@ -3439,20 +3439,20 @@ static ALWAYS_INLINE WideRGBA8 blend_pixels(uint32_t* buf, PackedRGBA8 pdst,
case BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): { case BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): {
WideRGBA8 secondary = WideRGBA8 secondary =
muldiv256(dst, muldiv256(dst,
pack_pixels_RGBA8(fragment_shader->gl_SecondaryFragColor, 256.0f)); pack_pixels_RGBA8(fragment_shader->gl_SecondaryFragColor, 256.49f));
return src + dst - secondary; return src + dst - secondary;
} }
case MASK_BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): { case MASK_BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): {
WideRGBA8 secondary = WideRGBA8 secondary =
muldiv256(dst, muldiv256(dst,
pack_pixels_RGBA8(fragment_shader->gl_SecondaryFragColor, 256.0f)); pack_pixels_RGBA8(fragment_shader->gl_SecondaryFragColor, 256.49f));
WideRGBA8 mask = load_clip_mask(buf, span); WideRGBA8 mask = load_clip_mask(buf, span);
return muldiv255(src, mask) + dst - muldiv255(secondary, mask); return muldiv255(src, mask) + dst - muldiv255(secondary, mask);
} }
case AA_BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): { case AA_BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): {
WideRGBA8 secondary = WideRGBA8 secondary =
muldiv256(dst, muldiv256(dst,
pack_pixels_RGBA8(fragment_shader->gl_SecondaryFragColor, 256.0f)); pack_pixels_RGBA8(fragment_shader->gl_SecondaryFragColor, 256.49f));
DO_AA(RGBA8, { DO_AA(RGBA8, {
src = muldiv256(src, aa); src = muldiv256(src, aa);
secondary = muldiv256(secondary, aa); secondary = muldiv256(secondary, aa);
@ -3462,7 +3462,7 @@ static ALWAYS_INLINE WideRGBA8 blend_pixels(uint32_t* buf, PackedRGBA8 pdst,
case AA_MASK_BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): { case AA_MASK_BLEND_KEY(GL_ONE, GL_ONE_MINUS_SRC1_COLOR): {
WideRGBA8 secondary = WideRGBA8 secondary =
muldiv256(dst, muldiv256(dst,
pack_pixels_RGBA8(fragment_shader->gl_SecondaryFragColor, 256.0f)); pack_pixels_RGBA8(fragment_shader->gl_SecondaryFragColor, 256.49f));
WideRGBA8 mask = load_clip_mask(buf, span); WideRGBA8 mask = load_clip_mask(buf, span);
DO_AA(RGBA8, mask = muldiv256(mask, aa)); DO_AA(RGBA8, mask = muldiv256(mask, aa));
return muldiv255(src, mask) + dst - muldiv255(secondary, mask); return muldiv255(src, mask) + dst - muldiv255(secondary, mask);

Просмотреть файл

@ -1672,6 +1672,14 @@ struct vec4_scalar {
return *this; return *this;
} }
vec4_scalar& operator*=(vec4_scalar a) {
x *= a.x;
y *= a.y;
z *= a.z;
w *= a.w;
return *this;
}
friend bool operator==(const vec4_scalar& l, const vec4_scalar& r) { friend bool operator==(const vec4_scalar& l, const vec4_scalar& r) {
return l.x == r.x && l.y == r.y && l.z == r.z && l.w == r.w; return l.x == r.x && l.y == r.y && l.z == r.z && l.w == r.w;
} }
@ -1866,6 +1874,13 @@ struct vec4 {
w /= a.w; w /= a.w;
return *this; return *this;
} }
vec4& operator*=(vec4 a) {
x *= a.x;
y *= a.y;
z *= a.z;
w *= a.w;
return *this;
}
vec4& operator*=(Float a) { vec4& operator*=(Float a) {
x *= a; x *= a;
y *= a; y *= a;

Просмотреть файл

@ -32,20 +32,22 @@ static ALWAYS_INLINE P applyColor(P src, P color) {
return muldiv256(src, color); return muldiv256(src, color);
} }
static ALWAYS_INLINE PackedRGBA8 applyColor(PackedRGBA8 src, WideRGBA8 color) { static ALWAYS_INLINE WideRGBA8 applyColor(PackedRGBA8 src, WideRGBA8 color) {
return pack(muldiv256(unpack(src), color)); return muldiv256(unpack(src), color);
} }
static ALWAYS_INLINE PackedR8 applyColor(PackedR8 src, WideR8 color) { static ALWAYS_INLINE WideR8 applyColor(PackedR8 src, WideR8 color) {
return pack(muldiv256(unpack(src), color)); return muldiv256(unpack(src), color);
} }
// Packs a color on a scale of 0..256 rather than 0..255 to allow faster scale // Packs a color on a scale of 0..256 rather than 0..255 to allow faster scale
// math with muldiv256. Note that this can cause a slight rounding difference in // math with muldiv256. Note that this can cause a slight rounding difference in
// the result versus the 255 scale. // the result versus the 255 scale. To alleviate this we scale by 256.49, so
// that the color rounds slightly up and in turn causes the the value it scales
// to round slightly up as well.
template <typename P, typename C> template <typename P, typename C>
static ALWAYS_INLINE auto packColor(P* buf, C color) { static ALWAYS_INLINE auto packColor(P* buf, C color) {
return pack_span(buf, color, 256.0f); return pack_span(buf, color, 256.49f);
} }
template <typename P> template <typename P>
@ -57,6 +59,10 @@ static ALWAYS_INLINE void commit_span(uint32_t* buf, WideRGBA8 r) {
unaligned_store(buf, pack(r)); unaligned_store(buf, pack(r));
} }
static ALWAYS_INLINE void commit_span(uint32_t* buf, WideRGBA8 r, int len) {
partial_store_span(buf, pack(r), len);
}
static ALWAYS_INLINE WideRGBA8 blend_span(uint32_t* buf, WideRGBA8 r) { static ALWAYS_INLINE WideRGBA8 blend_span(uint32_t* buf, WideRGBA8 r) {
return blend_pixels(buf, unaligned_load<PackedRGBA8>(buf), r); return blend_pixels(buf, unaligned_load<PackedRGBA8>(buf), r);
} }
@ -69,14 +75,27 @@ static ALWAYS_INLINE void commit_span(uint32_t* buf, PackedRGBA8 r) {
unaligned_store(buf, r); unaligned_store(buf, r);
} }
static ALWAYS_INLINE void commit_span(uint32_t* buf, PackedRGBA8 r, int len) {
partial_store_span(buf, r, len);
}
static ALWAYS_INLINE PackedRGBA8 blend_span(uint32_t* buf, PackedRGBA8 r) { static ALWAYS_INLINE PackedRGBA8 blend_span(uint32_t* buf, PackedRGBA8 r) {
return pack(blend_span(buf, unpack(r))); return pack(blend_span(buf, unpack(r)));
} }
static ALWAYS_INLINE PackedRGBA8 blend_span(uint32_t* buf, PackedRGBA8 r,
int len) {
return pack(blend_span(buf, unpack(r), len));
}
static ALWAYS_INLINE void commit_span(uint8_t* buf, WideR8 r) { static ALWAYS_INLINE void commit_span(uint8_t* buf, WideR8 r) {
unaligned_store(buf, pack(r)); unaligned_store(buf, pack(r));
} }
static ALWAYS_INLINE void commit_span(uint8_t* buf, WideR8 r, int len) {
partial_store_span(buf, pack(r), len);
}
static ALWAYS_INLINE WideR8 blend_span(uint8_t* buf, WideR8 r) { static ALWAYS_INLINE WideR8 blend_span(uint8_t* buf, WideR8 r) {
return blend_pixels(buf, unpack(unaligned_load<PackedR8>(buf)), r); return blend_pixels(buf, unpack(unaligned_load<PackedR8>(buf)), r);
} }
@ -175,6 +194,15 @@ static ALWAYS_INLINE void commit_blend_span(P* buf, R r) {
} }
} }
template <bool BLEND, typename P, typename R>
static ALWAYS_INLINE void commit_blend_span(P* buf, R r, int len) {
if (BLEND) {
commit_span(buf, blend_span(buf, r, len), len);
} else {
commit_span(buf, r, len);
}
}
// Forces a value with vector run-class to have scalar run-class. // Forces a value with vector run-class to have scalar run-class.
template <typename T> template <typename T>
static ALWAYS_INLINE auto swgl_forceScalar(T v) -> decltype(force_scalar(v)) { static ALWAYS_INLINE auto swgl_forceScalar(T v) -> decltype(force_scalar(v)) {
@ -545,9 +573,9 @@ static int blendTextureLinear(S sampler, vec2 uv, int span,
// bounds. This requires a pointer to the destination buffer. An optional color // bounds. This requires a pointer to the destination buffer. An optional color
// modulus can be supplied. // modulus can be supplied.
template <bool BLEND, typename S, typename C, typename P> template <bool BLEND, typename S, typename C, typename P>
static int blendTextureNearest(S sampler, vec2 uv, int span, static int blendTextureNearestFast(S sampler, vec2 uv, int span,
const vec4_scalar& uv_rect, C color, P* buf, const vec4_scalar& uv_rect, C color, P* buf,
float layer = 0) { float layer = 0) {
if (!matchTextureFormat(sampler, buf)) { if (!matchTextureFormat(sampler, buf)) {
return 0; return 0;
} }
@ -587,23 +615,15 @@ static int blendTextureNearest(S sampler, vec2 uv, int span,
int n = max(min(maxX + 1, endX) - curX, 0); int n = max(min(maxX + 1, endX) - curX, 0);
// Try to process as many chunks as possible with full loads and stores. // Try to process as many chunks as possible with full loads and stores.
for (int end = curX + (n & ~3); curX < end; curX += 4, buf += 4) { for (int end = curX + (n & ~3); curX < end; curX += 4, buf += 4) {
auto src = auto src = applyColor(unaligned_load<packed_type>(&row[curX]), color);
applyColor(unpack(unaligned_load<packed_type>(&row[curX])), color);
commit_blend_span<BLEND>(buf, src); commit_blend_span<BLEND>(buf, src);
} }
n &= 3; n &= 3;
// If we have any leftover samples after processing chunks, use partial loads // If we have any leftover samples after processing chunks, use partial loads
// and stores. // and stores.
if (n > 0) { if (n > 0) {
if (BLEND) { auto src = applyColor(partial_load_span<packed_type>(&row[curX], n), color);
auto src = applyColor( commit_blend_span<BLEND>(buf, src, n);
unpack(partial_load_span<packed_type>(&row[curX], n)), color);
partial_store_span(buf, pack(blend_span(buf, src, n)), n);
} else {
auto src =
applyColor(partial_load_span<packed_type>(&row[curX], n), color);
partial_store_span(buf, src, n);
}
buf += n; buf += n;
curX += n; curX += n;
} }
@ -616,6 +636,16 @@ static int blendTextureNearest(S sampler, vec2 uv, int span,
return span; return span;
} }
// We need to verify that the pixel step reasonably approximates stepping
// by a single texel for every pixel we need to reproduce. Try to ensure
// that the margin of error is no more than approximately 2^-7.
template <typename T>
static ALWAYS_INLINE bool spanNeedsScale(int span, T P) {
span &= ~(128 - 1);
span += 128;
return round((P.x.y - P.x.x) * span) != span;
}
// Helper function to decide whether we can safely apply 1:1 nearest filtering // Helper function to decide whether we can safely apply 1:1 nearest filtering
// without diverging too much from the linear filter. // without diverging too much from the linear filter.
template <typename S, typename T> template <typename S, typename T>
@ -625,16 +655,11 @@ static inline LinearFilter needsTextureLinear(S sampler, T P, int span) {
return LINEAR_FILTER_FALLBACK; return LINEAR_FILTER_FALLBACK;
} }
P = samplerScale(sampler, P); P = samplerScale(sampler, P);
// We need to verify that the pixel step reasonably approximates stepping if (spanNeedsScale(span, P)) {
// by a single texel for every pixel we need to reproduce. Try to ensure // If the source region is not flipped and smaller than the destination,
// that the margin of error is no more than approximately 2^-7. // then we can use the upscaling filter since row Y is constant.
span &= ~(128 - 1); return P.x.x <= P.x.y && P.x.y - P.x.x <= 1 ? LINEAR_FILTER_UPSCALE
span += 128; : LINEAR_FILTER_FALLBACK;
float dx = P.x.y - P.x.x;
if (round(dx * span) != span) {
// If the source region is smaller than the destination, then we can use the
// upscaling filter since row Y is constant.
return dx >= 0 && dx <= 1 ? LINEAR_FILTER_UPSCALE : LINEAR_FILTER_FALLBACK;
} }
// Also verify that we're reasonably close to the center of a texel // Also verify that we're reasonably close to the center of a texel
// so that it doesn't look that much different than if a linear filter // so that it doesn't look that much different than if a linear filter
@ -652,59 +677,227 @@ static inline LinearFilter needsTextureLinear(S sampler, T P, int span) {
return LINEAR_FILTER_NEAREST; return LINEAR_FILTER_NEAREST;
} }
// Commit a single chunk from a linear texture fetch // Commit an entire span with linear filtering
#define swgl_commitTextureLinear(format, s, p, uv_rect, color, ...) \ #define swgl_commitTextureLinear(format, s, p, uv_rect, color, ...) \
do { \ do { \
auto packed_color = packColor(swgl_Out##format, color); \ auto packed_color = packColor(swgl_Out##format, color); \
int drawn = 0; \ int drawn = 0; \
if (LinearFilter filter = needsTextureLinear(s, p, swgl_SpanLength)) { \ if (LinearFilter filter = needsTextureLinear(s, p, swgl_SpanLength)) { \
if (blend_key) { \ if (blend_key) { \
drawn = blendTextureLinear<true>(s, p, swgl_SpanLength, uv_rect, \ drawn = blendTextureLinear<true>(s, p, swgl_SpanLength, uv_rect, \
packed_color, swgl_Out##format, \ packed_color, swgl_Out##format, \
filter, __VA_ARGS__); \ filter, __VA_ARGS__); \
} else { \ } else { \
drawn = blendTextureLinear<false>(s, p, swgl_SpanLength, uv_rect, \ drawn = blendTextureLinear<false>(s, p, swgl_SpanLength, uv_rect, \
packed_color, swgl_Out##format, \ packed_color, swgl_Out##format, \
filter, __VA_ARGS__); \ filter, __VA_ARGS__); \
} \ } \
} else if (blend_key) { \ } else if (blend_key) { \
drawn = blendTextureNearest<true>(s, p, swgl_SpanLength, uv_rect, \ drawn = blendTextureNearestFast<true>(s, p, swgl_SpanLength, uv_rect, \
packed_color, swgl_Out##format, \ packed_color, swgl_Out##format, \
__VA_ARGS__); \ __VA_ARGS__); \
} else { \ } else { \
drawn = blendTextureNearest<false>(s, p, swgl_SpanLength, uv_rect, \ drawn = blendTextureNearestFast<false>(s, p, swgl_SpanLength, uv_rect, \
packed_color, swgl_Out##format, \ packed_color, swgl_Out##format, \
__VA_ARGS__); \ __VA_ARGS__); \
} \ } \
swgl_Out##format += drawn; \ swgl_Out##format += drawn; \
swgl_SpanLength -= drawn; \ swgl_SpanLength -= drawn; \
} while (0) } while (0)
#define swgl_commitTextureLinearRGBA8(s, p, uv_rect, ...) \ #define swgl_commitTextureLinearRGBA8(s, p, uv_rect, ...) \
swgl_commitTextureLinear(RGBA8, s, p, uv_rect, NoColor(), __VA_ARGS__) swgl_commitTextureLinear(RGBA8, s, p, uv_rect, NoColor(), __VA_ARGS__)
#define swgl_commitTextureLinearR8(s, p, uv_rect, ...) \ #define swgl_commitTextureLinearR8(s, p, uv_rect, ...) \
swgl_commitTextureLinear(R8, s, p, uv_rect, NoColor(), __VA_ARGS__) swgl_commitTextureLinear(R8, s, p, uv_rect, NoColor(), __VA_ARGS__)
// Commit a single chunk from a linear texture fetch that is scaled by a color // Commit an entire span with linear filtering that is scaled by a color
#define swgl_commitTextureLinearColorRGBA8(s, p, uv_rect, color, ...) \ #define swgl_commitTextureLinearColorRGBA8(s, p, uv_rect, color, ...) \
swgl_commitTextureLinear(RGBA8, s, p, uv_rect, color, __VA_ARGS__) swgl_commitTextureLinear(RGBA8, s, p, uv_rect, color, __VA_ARGS__)
#define swgl_commitTextureLinearColorR8(s, p, uv_rect, color, ...) \ #define swgl_commitTextureLinearColorR8(s, p, uv_rect, color, ...) \
swgl_commitTextureLinear(R8, s, p, uv_rect, color, __VA_ARGS__) swgl_commitTextureLinear(R8, s, p, uv_rect, color, __VA_ARGS__)
// Commit a single chunk from a linear texture fetch // Blends an entire span of texture with linear filtering and repeating UVs.
#define swgl_commitTextureLinearChunk(format, s, p, color, ...) \ template <bool BLEND, typename S, typename C, typename P>
swgl_commitChunk(format, applyColor(textureLinearUnpacked##format( \ static int blendTextureLinearRepeat(S sampler, vec2 uv, int span,
s, ivec2(p), __VA_ARGS__), \ const vec4_scalar& uv_repeat,
packColor(swgl_Out##format, color))) const vec4_scalar& uv_rect, C color, P* buf,
#define swgl_commitTextureLinearChunkRGBA8(s, p, ...) \ float z = 0) {
swgl_commitTextureLinearChunk(RGBA8, s, p, NoColor(), __VA_ARGS__) if (!matchTextureFormat(sampler, buf)) {
#define swgl_commitTextureLinearChunkR8(s, p, ...) \ return 0;
swgl_commitTextureLinearChunk(R8, s, p, NoColor(), __VA_ARGS__) }
// We need to step UVs unscaled and unquantized so that we can modulo them
// with fract. We use uv_scale and uv_offset to map them into the correct
// range.
vec2_scalar uv_step =
float(swgl_StepSize) * vec2_scalar{uv.x.y - uv.x.x, uv.y.y - uv.y.x};
vec2_scalar uv_scale = swgl_linearQuantizeStep(
sampler,
vec2_scalar{uv_repeat.z - uv_repeat.x, uv_repeat.w - uv_repeat.y});
vec2_scalar uv_offset =
swgl_linearQuantize(sampler, vec2_scalar{uv_repeat.x, uv_repeat.y});
vec2_scalar min_uv =
swgl_linearQuantize(sampler, vec2_scalar{uv_rect.x, uv_rect.y});
vec2_scalar max_uv =
swgl_linearQuantize(sampler, vec2_scalar{uv_rect.z, uv_rect.w});
int zoffset = swgl_textureLayerOffset(sampler, z);
for (P* end = buf + span; buf < end; buf += swgl_StepSize, uv += uv_step) {
vec2 repeated_uv = clamp(fract(uv) * uv_scale + uv_offset, min_uv, max_uv);
commit_blend_span<BLEND>(
buf, applyColor(textureLinearUnpacked(buf, sampler, ivec2(repeated_uv),
zoffset),
color));
}
return span;
}
// Commit a single chunk from a linear texture fetch that is scaled by a color // Commit an entire span with linear filtering and repeating UVs
#define swgl_commitTextureLinearChunkColorRGBA8(s, p, color, ...) \ #define swgl_commitTextureLinearRepeat(format, s, p, uv_repeat, uv_rect, \
swgl_commitTextureLinearChunk(RGBA8, s, p, color, __VA_ARGS__) color, ...) \
#define swgl_commitTextureLinearChunkColorR8(s, p, color, ...) \ do { \
swgl_commitTextureLinearChunk(R8, s, p, color, __VA_ARGS__) auto packed_color = packColor(swgl_Out##format, color); \
int drawn = 0; \
if (blend_key) { \
drawn = blendTextureLinearRepeat<true>(s, p, swgl_SpanLength, uv_repeat, \
uv_rect, packed_color, \
swgl_Out##format, __VA_ARGS__); \
} else { \
drawn = blendTextureLinearRepeat<false>( \
s, p, swgl_SpanLength, uv_repeat, uv_rect, packed_color, \
swgl_Out##format, __VA_ARGS__); \
} \
swgl_Out##format += drawn; \
swgl_SpanLength -= drawn; \
} while (0)
#define swgl_commitTextureLinearRepeatRGBA8(s, p, uv_repeat, uv_rect, ...) \
swgl_commitTextureLinearRepeat(RGBA8, s, p, uv_repeat, uv_rect, NoColor(), \
__VA_ARGS__)
#define swgl_commitTextureLinearRepeatColorRGBA8(s, p, uv_repeat, uv_rect, \
color, ...) \
swgl_commitTextureLinearRepeat(RGBA8, s, p, uv_repeat, uv_rect, color, \
__VA_ARGS__)
template <typename S>
static ALWAYS_INLINE PackedRGBA8 textureNearestPacked(UNUSED uint32_t* buf,
S sampler, ivec2 i,
int zoffset) {
return textureNearestPackedRGBA8(sampler, i, zoffset);
}
// Blends an entire span of texture with nearest filtering and either
// repeated or clamped UVs.
template <bool BLEND, bool REPEAT, typename S, typename C, typename P>
static int blendTextureNearestRepeat(S sampler, vec2 uv, int span,
const vec4_scalar& uv_rect, C color,
P* buf, float z = 0) {
if (!matchTextureFormat(sampler, buf)) {
return 0;
}
if (!REPEAT) {
// If clamping, then we step pre-scaled to the sampler. For repeat modes,
// this will be accomplished via uv_scale instead.
uv = samplerScale(sampler, uv);
}
vec2_scalar uv_step =
float(swgl_StepSize) * vec2_scalar{uv.x.y - uv.x.x, uv.y.y - uv.y.x};
vec2_scalar min_uv = samplerScale(sampler, vec2_scalar{uv_rect.x, uv_rect.y});
vec2_scalar max_uv = samplerScale(sampler, vec2_scalar{uv_rect.z, uv_rect.w});
vec2_scalar uv_scale = max_uv - min_uv;
int zoffset = swgl_textureLayerOffset(sampler, z);
// If the effective sampling area of this texture is only a single pixel, then
// treat it as a solid span. For repeat modes, the bounds are specified on
// pixel boundaries, whereas for clamp modes, bounds are on pixel centers, so
// the test varies depending on which. If the sample range on an axis is
// greater than one pixel, we can still check if we don't move far enough from
// the pixel center on that axis to hit the next pixel.
if ((int(min_uv.x) + (REPEAT ? 1 : 0) >= int(max_uv.x) ||
(uv_step.x * span * (REPEAT ? uv_scale.x : 1.0f) < 0.5f)) &&
(int(min_uv.y) + (REPEAT ? 1 : 0) >= int(max_uv.y) ||
(uv_step.y * span * (REPEAT ? uv_scale.y : 1.0f) < 0.5f))) {
vec2 repeated_uv =
REPEAT ? fract(uv) * uv_scale + min_uv : clamp(uv, min_uv, max_uv);
commit_solid_span<BLEND>(
buf,
applyColor(unpack(textureNearestPacked(buf, sampler, ivec2(repeated_uv),
zoffset)),
color),
span);
} else {
for (P* end = buf + span; buf < end; buf += swgl_StepSize, uv += uv_step) {
vec2 repeated_uv =
REPEAT ? fract(uv) * uv_scale + min_uv : clamp(uv, min_uv, max_uv);
commit_blend_span<BLEND>(
buf, applyColor(textureNearestPacked(buf, sampler, ivec2(repeated_uv),
zoffset),
color));
}
}
return span;
}
// Determine if we can use the fast nearest filter for the given nearest mode.
// If the Y coordinate varies more than half a pixel over
// the span (which might cause the texel to alias to the next one), or the span
// needs X scaling, then we have to use the fallback.
template <typename S, typename T>
static ALWAYS_INLINE bool needsNearestFallback(S sampler, T P, int span) {
P = samplerScale(sampler, P);
return (P.y.y - P.y.x) * span >= 0.5f || spanNeedsScale(span, P);
}
// Commit an entire span with nearest filtering and either clamped or repeating
// UVs
#define swgl_commitTextureNearest(format, repeat, s, p, uv_rect, color, ...) \
do { \
auto packed_color = packColor(swgl_Out##format, color); \
int drawn = 0; \
if (repeat || needsNearestFallback(s, p, swgl_SpanLength)) { \
if (blend_key) { \
drawn = blendTextureNearestRepeat<true, repeat>( \
s, p, swgl_SpanLength, uv_rect, packed_color, swgl_Out##format, \
__VA_ARGS__); \
} else { \
drawn = blendTextureNearestRepeat<false, repeat>( \
s, p, swgl_SpanLength, uv_rect, packed_color, swgl_Out##format, \
__VA_ARGS__); \
} \
} else if (blend_key) { \
drawn = blendTextureNearestFast<true>(s, p, swgl_SpanLength, uv_rect, \
packed_color, swgl_Out##format, \
__VA_ARGS__); \
} else { \
drawn = blendTextureNearestFast<false>(s, p, swgl_SpanLength, uv_rect, \
packed_color, swgl_Out##format, \
__VA_ARGS__); \
} \
swgl_Out##format += drawn; \
swgl_SpanLength -= drawn; \
} while (0)
#define swgl_commitTextureNearestRGBA8(s, p, uv_rect, ...) \
swgl_commitTextureNearest(RGBA8, false, s, p, uv_rect, NoColor(), __VA_ARGS__)
#define swgl_commitTextureNearestColorRGBA8(s, p, uv_rect, color, ...) \
swgl_commitTextureNearest(RGBA8, false, s, p, uv_rect, color, __VA_ARGS__)
#define swgl_commitTextureNearestRepeatRGBA8(s, p, uv_repeat, uv_rect, ...) \
swgl_commitTextureNearest(RGBA8, true, s, p, uv_repeat, NoColor(), \
__VA_ARGS__)
#define swgl_commitTextureNearestRepeatColorRGBA8(s, p, uv_repeat, uv_rect, \
color, ...) \
swgl_commitTextureNearest(RGBA8, true, s, p, uv_repeat, color, __VA_ARGS__)
// Commit an entire span of texture with filtering determined by sampler state.
#define swgl_commitTexture(format, s, ...) \
do { \
if (s->filter == TextureFilter::LINEAR) { \
swgl_commitTextureLinear##format(s, __VA_ARGS__); \
} else { \
swgl_commitTextureNearest##format(s, __VA_ARGS__); \
} \
} while (0)
#define swgl_commitTextureRGBA8(...) swgl_commitTexture(RGBA8, __VA_ARGS__)
#define swgl_commitTextureColorRGBA8(...) \
swgl_commitTexture(ColorRGBA8, __VA_ARGS__)
#define swgl_commitTextureRepeatRGBA8(...) \
swgl_commitTexture(RepeatRGBA8, __VA_ARGS__)
#define swgl_commitTextureRepeatColorRGBA8(...) \
swgl_commitTexture(RepeatColorRGBA8, __VA_ARGS__)
// Commit an entire span of a separable pass of a Gaussian blur that falls // Commit an entire span of a separable pass of a Gaussian blur that falls
// within the given radius scaled by supplied coefficients, clamped to uv_rect // within the given radius scaled by supplied coefficients, clamped to uv_rect
@ -792,9 +985,12 @@ static ALWAYS_INLINE PackedRGBA8 sampleYUV(S0 sampler0, ivec2 uv0, int layer0,
} }
template <bool BLEND, typename S0, typename P, typename C = NoColor> template <bool BLEND, typename S0, typename P, typename C = NoColor>
static void blendYUV(P* buf, int span, S0 sampler0, vec2 uv0, static int blendYUV(P* buf, int span, S0 sampler0, vec2 uv0,
const vec4_scalar uv_rect0, float z0, int colorSpace, const vec4_scalar uv_rect0, float z0, int colorSpace,
int rescaleFactor, C color = C()) { int rescaleFactor, C color = C()) {
if (!swgl_isTextureLinear(sampler0)) {
return 0;
}
LINEAR_QUANTIZE_UV(sampler0, uv0, uv_step0, uv_rect0, min_uv0, max_uv0, z0, LINEAR_QUANTIZE_UV(sampler0, uv0, uv_step0, uv_rect0, min_uv0, max_uv0, z0,
layer0); layer0);
auto c = packColor(buf, color); auto c = packColor(buf, color);
@ -805,6 +1001,7 @@ static void blendYUV(P* buf, int span, S0 sampler0, vec2 uv0,
layer0, colorSpace, rescaleFactor), layer0, colorSpace, rescaleFactor),
c)); c));
} }
return span;
} }
template <typename S0, typename S1> template <typename S0, typename S1>
@ -833,10 +1030,13 @@ static ALWAYS_INLINE PackedRGBA8 sampleYUV(S0 sampler0, ivec2 uv0, int layer0,
template <bool BLEND, typename S0, typename S1, typename P, template <bool BLEND, typename S0, typename S1, typename P,
typename C = NoColor> typename C = NoColor>
static void blendYUV(P* buf, int span, S0 sampler0, vec2 uv0, static int blendYUV(P* buf, int span, S0 sampler0, vec2 uv0,
const vec4_scalar uv_rect0, float z0, S1 sampler1, const vec4_scalar uv_rect0, float z0, S1 sampler1, vec2 uv1,
vec2 uv1, const vec4_scalar uv_rect1, float z1, const vec4_scalar uv_rect1, float z1, int colorSpace,
int colorSpace, int rescaleFactor, C color = C()) { int rescaleFactor, C color = C()) {
if (!swgl_isTextureLinear(sampler0) || !swgl_isTextureLinear(sampler1)) {
return 0;
}
LINEAR_QUANTIZE_UV(sampler0, uv0, uv_step0, uv_rect0, min_uv0, max_uv0, z0, LINEAR_QUANTIZE_UV(sampler0, uv0, uv_step0, uv_rect0, min_uv0, max_uv0, z0,
layer0); layer0);
LINEAR_QUANTIZE_UV(sampler1, uv1, uv_step1, uv_rect1, min_uv1, max_uv1, z1, LINEAR_QUANTIZE_UV(sampler1, uv1, uv_step1, uv_rect1, min_uv1, max_uv1, z1,
@ -851,6 +1051,7 @@ static void blendYUV(P* buf, int span, S0 sampler0, vec2 uv0,
colorSpace, rescaleFactor), colorSpace, rescaleFactor),
c)); c));
} }
return span;
} }
template <typename S0, typename S1, typename S2> template <typename S0, typename S1, typename S2>
@ -890,12 +1091,15 @@ static ALWAYS_INLINE PackedRGBA8 sampleYUV(S0 sampler0, ivec2 uv0, int layer0,
template <bool BLEND, typename S0, typename S1, typename S2, typename P, template <bool BLEND, typename S0, typename S1, typename S2, typename P,
typename C = NoColor> typename C = NoColor>
static void blendYUV(P* buf, int span, S0 sampler0, vec2 uv0, static int blendYUV(P* buf, int span, S0 sampler0, vec2 uv0,
const vec4_scalar uv_rect0, float z0, S1 sampler1, const vec4_scalar uv_rect0, float z0, S1 sampler1, vec2 uv1,
vec2 uv1, const vec4_scalar uv_rect1, float z1, const vec4_scalar uv_rect1, float z1, S2 sampler2, vec2 uv2,
S2 sampler2, vec2 uv2, const vec4_scalar uv_rect2, const vec4_scalar uv_rect2, float z2, int colorSpace,
float z2, int colorSpace, int rescaleFactor, int rescaleFactor, C color = C()) {
C color = C()) { if (!swgl_isTextureLinear(sampler0) || !swgl_isTextureLinear(sampler1) ||
!swgl_isTextureLinear(sampler2)) {
return 0;
}
LINEAR_QUANTIZE_UV(sampler0, uv0, uv_step0, uv_rect0, min_uv0, max_uv0, z0, LINEAR_QUANTIZE_UV(sampler0, uv0, uv_step0, uv_rect0, min_uv0, max_uv0, z0,
layer0); layer0);
LINEAR_QUANTIZE_UV(sampler1, uv1, uv_step1, uv_rect1, min_uv1, max_uv1, z1, LINEAR_QUANTIZE_UV(sampler1, uv1, uv_step1, uv_rect1, min_uv1, max_uv1, z1,
@ -914,6 +1118,7 @@ static void blendYUV(P* buf, int span, S0 sampler0, vec2 uv0,
layer2, colorSpace, rescaleFactor), layer2, colorSpace, rescaleFactor),
c)); c));
} }
return span;
} }
// Commit a single chunk of a YUV surface represented by multiple planar // Commit a single chunk of a YUV surface represented by multiple planar
@ -922,15 +1127,16 @@ static void blendYUV(P* buf, int span, S0 sampler0, vec2 uv0,
// selects how many bits of precision must be utilized on conversion. See the // selects how many bits of precision must be utilized on conversion. See the
// sampleYUV dispatcher functions for the various supported plane // sampleYUV dispatcher functions for the various supported plane
// configurations this intrinsic accepts. // configurations this intrinsic accepts.
#define swgl_commitTextureLinearYUV(...) \ #define swgl_commitTextureLinearYUV(...) \
do { \ do { \
if (blend_key) { \ int drawn = 0; \
blendYUV<true>(swgl_OutRGBA8, swgl_SpanLength, __VA_ARGS__); \ if (blend_key) { \
} else { \ drawn = blendYUV<true>(swgl_OutRGBA8, swgl_SpanLength, __VA_ARGS__); \
blendYUV<false>(swgl_OutRGBA8, swgl_SpanLength, __VA_ARGS__); \ } else { \
} \ drawn = blendYUV<false>(swgl_OutRGBA8, swgl_SpanLength, __VA_ARGS__); \
swgl_OutRGBA8 += swgl_SpanLength; \ } \
swgl_SpanLength = 0; \ swgl_OutRGBA8 += drawn; \
swgl_SpanLength -= drawn; \
} while (0) } while (0)
// Commit a single chunk of a YUV surface scaled by a color. // Commit a single chunk of a YUV surface scaled by a color.

Просмотреть файл

@ -1054,6 +1054,17 @@ static PackedRGBA8 textureLinearPackedRGBA8(S sampler, ivec2 i,
return pack(textureLinearUnpackedRGBA8(sampler, i, zoffset)); return pack(textureLinearUnpackedRGBA8(sampler, i, zoffset));
} }
template <typename S>
static PackedRGBA8 textureNearestPackedRGBA8(S sampler, ivec2 i,
int zoffset = 0) {
assert(sampler->format == TextureFormat::RGBA8);
I32 row = computeRow(sampler, i, zoffset, 0);
return combine(unaligned_load<V4<uint8_t>>(&sampler->buf[row.x]),
unaligned_load<V4<uint8_t>>(&sampler->buf[row.y]),
unaligned_load<V4<uint8_t>>(&sampler->buf[row.z]),
unaligned_load<V4<uint8_t>>(&sampler->buf[row.w]));
}
template <typename S> template <typename S>
static PackedR8 textureLinearPackedR8(S sampler, ivec2 i, int zoffset = 0) { static PackedR8 textureLinearPackedR8(S sampler, ivec2 i, int zoffset = 0) {
return pack(textureLinearUnpackedR8(sampler, i, zoffset)); return pack(textureLinearUnpackedR8(sampler, i, zoffset));

Просмотреть файл

@ -273,9 +273,10 @@ void brush_vs(
#ifdef WR_FRAGMENT_SHADER #ifdef WR_FRAGMENT_SHADER
vec2 compute_repeated_uvs(float perspective_divisor) { vec2 compute_repeated_uvs(float perspective_divisor) {
#ifdef WR_FEATURE_REPETITION
vec2 uv_size = v_uv_bounds.zw - v_uv_bounds.xy; vec2 uv_size = v_uv_bounds.zw - v_uv_bounds.xy;
#ifdef WR_FEATURE_ALPHA_PASS #if defined(WR_FEATURE_ALPHA_PASS) && !defined(SWGL_ANTIALIAS)
// This prevents the uv on the top and left parts of the primitive that was inflated // This prevents the uv on the top and left parts of the primitive that was inflated
// for anti-aliasing purposes from going beyound the range covered by the regular // for anti-aliasing purposes from going beyound the range covered by the regular
// (non-inflated) primitive. // (non-inflated) primitive.
@ -293,21 +294,19 @@ vec2 compute_repeated_uvs(float perspective_divisor) {
if (local_uv.y >= v_tile_repeat.y) { if (local_uv.y >= v_tile_repeat.y) {
repeated_uv.y = v_uv_bounds.w; repeated_uv.y = v_uv_bounds.w;
} }
#else #else
vec2 repeated_uv = fract(v_uv * perspective_divisor) * uv_size + v_uv_bounds.xy; vec2 repeated_uv = fract(v_uv * perspective_divisor) * uv_size + v_uv_bounds.xy;
#endif #endif
return repeated_uv; return repeated_uv;
#else
return v_uv * perspective_divisor + v_uv_bounds.xy;
#endif
} }
Fragment brush_fs() { Fragment brush_fs() {
float perspective_divisor = mix(gl_FragCoord.w, 1.0, v_layer_and_perspective.y); float perspective_divisor = mix(gl_FragCoord.w, 1.0, v_layer_and_perspective.y);
#ifdef WR_FEATURE_REPETITION
vec2 repeated_uv = compute_repeated_uvs(perspective_divisor); vec2 repeated_uv = compute_repeated_uvs(perspective_divisor);
#else
vec2 repeated_uv = v_uv * perspective_divisor + v_uv_bounds.xy;
#endif
// Clamp the uvs to avoid sampling artifacts. // Clamp the uvs to avoid sampling artifacts.
vec2 uv = clamp(repeated_uv, v_uv_sample_bounds.xy, v_uv_sample_bounds.zw); vec2 uv = clamp(repeated_uv, v_uv_sample_bounds.xy, v_uv_sample_bounds.zw);
@ -341,7 +340,7 @@ Fragment brush_fs() {
#if defined(SWGL_DRAW_SPAN) && (!defined(WR_FEATURE_ALPHA_PASS) || !defined(WR_FEATURE_DUAL_SOURCE_BLENDING)) #if defined(SWGL_DRAW_SPAN) && (!defined(WR_FEATURE_ALPHA_PASS) || !defined(WR_FEATURE_DUAL_SOURCE_BLENDING))
void swgl_drawSpanRGBA8() { void swgl_drawSpanRGBA8() {
if (!swgl_isTextureRGBA8(sColor0) || !swgl_isTextureLinear(sColor0)) { if (!swgl_isTextureRGBA8(sColor0)) {
return; return;
} }
@ -353,39 +352,29 @@ void swgl_drawSpanRGBA8() {
float perspective_divisor = mix(swgl_forceScalar(gl_FragCoord.w), 1.0, v_layer_and_perspective.y); float perspective_divisor = mix(swgl_forceScalar(gl_FragCoord.w), 1.0, v_layer_and_perspective.y);
#ifndef WR_FEATURE_REPETITION #ifdef WR_FEATURE_REPETITION
vec2 uv = v_uv * perspective_divisor + v_uv_bounds.xy; // Get the UVs before any repetition, scaling, or offsetting has occurred...
vec2 uv = v_uv * perspective_divisor;
#ifdef WR_FEATURE_ALPHA_PASS
if (v_color != vec4(1.0)) {
swgl_commitTextureLinearColorRGBA8(sColor0, uv, v_uv_sample_bounds, v_color, v_layer_and_perspective.x);
return;
}
#endif
swgl_commitTextureLinearRGBA8(sColor0, uv, v_uv_sample_bounds, v_layer_and_perspective.x);
#else #else
int layer = swgl_textureLayerOffset(sColor0, v_layer_and_perspective.x); vec2 uv = compute_repeated_uvs(perspective_divisor);
#endif
#ifdef WR_FEATURE_ALPHA_PASS #ifdef WR_FEATURE_ALPHA_PASS
if (v_color != vec4(1.0)) { if (v_color != vec4(1.0)) {
while (swgl_SpanLength > 0) { #ifdef WR_FEATURE_REPETITION
vec4 color = v_color; swgl_commitTextureRepeatColorRGBA8(sColor0, uv, v_uv_bounds, v_uv_sample_bounds, v_color, v_layer_and_perspective.x);
vec2 repeated_uv = compute_repeated_uvs(perspective_divisor); #else
vec2 uv = clamp(repeated_uv, v_uv_sample_bounds.xy, v_uv_sample_bounds.zw); swgl_commitTextureColorRGBA8(sColor0, uv, v_uv_sample_bounds, v_color, v_layer_and_perspective.x);
swgl_commitTextureLinearChunkColorRGBA8(sColor0, swgl_linearQuantize(sColor0, uv), color, layer);
v_uv += swgl_interpStep(v_uv);
}
return;
}
// No clip or color scaling required, so just fall through to a normal textured span...
#endif #endif
return;
}
// No color scaling required, so just fall through to a normal textured span...
#endif
while (swgl_SpanLength > 0) { #ifdef WR_FEATURE_REPETITION
vec2 repeated_uv = compute_repeated_uvs(perspective_divisor); swgl_commitTextureRepeatRGBA8(sColor0, uv, v_uv_bounds, v_uv_sample_bounds, v_layer_and_perspective.x);
vec2 uv = clamp(repeated_uv, v_uv_sample_bounds.xy, v_uv_sample_bounds.zw); #else
swgl_commitTextureLinearChunkRGBA8(sColor0, swgl_linearQuantize(sColor0, uv), layer); swgl_commitTextureRGBA8(sColor0, uv, v_uv_sample_bounds, v_layer_and_perspective.x);
v_uv += swgl_interpStep(v_uv);
}
#endif #endif
} }
#endif #endif

Просмотреть файл

@ -118,27 +118,15 @@ Fragment brush_fs() {
#ifdef SWGL_DRAW_SPAN #ifdef SWGL_DRAW_SPAN
void swgl_drawSpanRGBA8() { void swgl_drawSpanRGBA8() {
if (vFormat == YUV_FORMAT_PLANAR) { if (vFormat == YUV_FORMAT_PLANAR) {
if (!swgl_isTextureLinear(sColor0) || !swgl_isTextureLinear(sColor1) || !swgl_isTextureLinear(sColor2)) {
return;
}
swgl_commitTextureLinearYUV(sColor0, vUv_Y, vUvBounds_Y, vYuvLayers.x, swgl_commitTextureLinearYUV(sColor0, vUv_Y, vUvBounds_Y, vYuvLayers.x,
sColor1, vUv_U, vUvBounds_U, vYuvLayers.y, sColor1, vUv_U, vUvBounds_U, vYuvLayers.y,
sColor2, vUv_V, vUvBounds_V, vYuvLayers.z, sColor2, vUv_V, vUvBounds_V, vYuvLayers.z,
vYuvColorSpace, vRescaleFactor); vYuvColorSpace, vRescaleFactor);
} else if (vFormat == YUV_FORMAT_NV12) { } else if (vFormat == YUV_FORMAT_NV12) {
if (!swgl_isTextureLinear(sColor0) || !swgl_isTextureLinear(sColor1)) {
return;
}
swgl_commitTextureLinearYUV(sColor0, vUv_Y, vUvBounds_Y, vYuvLayers.x, swgl_commitTextureLinearYUV(sColor0, vUv_Y, vUvBounds_Y, vYuvLayers.x,
sColor1, vUv_U, vUvBounds_U, vYuvLayers.y, sColor1, vUv_U, vUvBounds_U, vYuvLayers.y,
vYuvColorSpace, vRescaleFactor); vYuvColorSpace, vRescaleFactor);
} else if (vFormat == YUV_FORMAT_INTERLEAVED) { } else if (vFormat == YUV_FORMAT_INTERLEAVED) {
if (!swgl_isTextureLinear(sColor0)) {
return;
}
swgl_commitTextureLinearYUV(sColor0, vUv_Y, vUvBounds_Y, vYuvLayers.x, swgl_commitTextureLinearYUV(sColor0, vUv_Y, vUvBounds_Y, vYuvLayers.x,
vYuvColorSpace, vRescaleFactor); vYuvColorSpace, vRescaleFactor);
} }

Просмотреть файл

@ -161,39 +161,23 @@ void main(void) {
void swgl_drawSpanRGBA8() { void swgl_drawSpanRGBA8() {
#ifdef WR_FEATURE_YUV #ifdef WR_FEATURE_YUV
if (vYuvFormat == YUV_FORMAT_PLANAR) { if (vYuvFormat == YUV_FORMAT_PLANAR) {
if (!swgl_isTextureLinear(sColor0) || !swgl_isTextureLinear(sColor1) || !swgl_isTextureLinear(sColor2)) {
return;
}
swgl_commitTextureLinearYUV(sColor0, vUV_y, vUVBounds_y, vYuvLayers.x, swgl_commitTextureLinearYUV(sColor0, vUV_y, vUVBounds_y, vYuvLayers.x,
sColor1, vUV_u, vUVBounds_u, vYuvLayers.y, sColor1, vUV_u, vUVBounds_u, vYuvLayers.y,
sColor2, vUV_v, vUVBounds_v, vYuvLayers.z, sColor2, vUV_v, vUVBounds_v, vYuvLayers.z,
vYuvColorSpace, vRescaleFactor); vYuvColorSpace, vRescaleFactor);
} else if (vYuvFormat == YUV_FORMAT_NV12) { } else if (vYuvFormat == YUV_FORMAT_NV12) {
if (!swgl_isTextureLinear(sColor0) || !swgl_isTextureLinear(sColor1)) {
return;
}
swgl_commitTextureLinearYUV(sColor0, vUV_y, vUVBounds_y, vYuvLayers.x, swgl_commitTextureLinearYUV(sColor0, vUV_y, vUVBounds_y, vYuvLayers.x,
sColor1, vUV_u, vUVBounds_u, vYuvLayers.y, sColor1, vUV_u, vUVBounds_u, vYuvLayers.y,
vYuvColorSpace, vRescaleFactor); vYuvColorSpace, vRescaleFactor);
} else if (vYuvFormat == YUV_FORMAT_INTERLEAVED) { } else if (vYuvFormat == YUV_FORMAT_INTERLEAVED) {
if (!swgl_isTextureLinear(sColor0) || !swgl_isTextureLinear(sColor1)) {
return;
}
swgl_commitTextureLinearYUV(sColor0, vUV_y, vUVBounds_y, vYuvLayers.x, swgl_commitTextureLinearYUV(sColor0, vUV_y, vUVBounds_y, vYuvLayers.x,
vYuvColorSpace, vRescaleFactor); vYuvColorSpace, vRescaleFactor);
} }
#else #else
if (!swgl_isTextureLinear(sColor0)) {
return;
}
if (vColor != vec4(1.0)) { if (vColor != vec4(1.0)) {
swgl_commitTextureLinearColorRGBA8(sColor0, vUv, vUVBounds, vColor, vLayer); swgl_commitTextureColorRGBA8(sColor0, vUv, vUVBounds, vColor, vLayer);
} else { } else {
swgl_commitTextureLinearRGBA8(sColor0, vUv, vUVBounds, vLayer); swgl_commitTextureRGBA8(sColor0, vUv, vUVBounds, vLayer);
} }
#endif #endif
} }

Просмотреть файл

@ -55,7 +55,7 @@ void write_gradient_vertex(
#ifdef WR_FRAGMENT_SHADER #ifdef WR_FRAGMENT_SHADER
vec2 compute_repeated_pos() { vec2 compute_repeated_pos() {
#ifdef WR_FEATURE_ALPHA_PASS #if defined(WR_FEATURE_ALPHA_PASS) && !defined(SWGL_ANTIALIAS)
// Handle top and left inflated edges (see brush_image). // Handle top and left inflated edges (see brush_image).
vec2 local_pos = max(v_pos, vec2(0.0)); vec2 local_pos = max(v_pos, vec2(0.0));

Просмотреть файл

@ -121,14 +121,10 @@ void main(void) {
#ifdef SWGL_DRAW_SPAN #ifdef SWGL_DRAW_SPAN
void swgl_drawSpanRGBA8() { void swgl_drawSpanRGBA8() {
if (!swgl_isTextureLinear(sColor0)) {
return;
}
float perspective_divisor = mix(swgl_forceScalar(gl_FragCoord.w), 1.0, vPerspective); float perspective_divisor = mix(swgl_forceScalar(gl_FragCoord.w), 1.0, vPerspective);
vec2 uv = vUv * perspective_divisor; vec2 uv = vUv * perspective_divisor;
swgl_commitTextureLinearRGBA8(sColor0, uv, vUvSampleBounds, 0.0); swgl_commitTextureRGBA8(sColor0, uv, vUvSampleBounds, 0.0);
} }
#endif #endif

Просмотреть файл

@ -3,8 +3,8 @@ fuzzy(1,32) == multiply-2.yaml multiply-2-ref.yaml
fuzzy(1,32) == color_targets(4) alpha_targets(0) multiply-3.yaml multiply-2-ref.yaml fuzzy(1,32) == color_targets(4) alpha_targets(0) multiply-3.yaml multiply-2-ref.yaml
== difference.yaml difference-ref.yaml == difference.yaml difference-ref.yaml
fuzzy(1,30000) == difference-transparent.yaml difference-transparent-ref.yaml fuzzy(1,30000) == difference-transparent.yaml difference-transparent-ref.yaml
== darken.yaml darken-ref.yaml fuzzy-if(platform(swgl),1,10000) == darken.yaml darken-ref.yaml
== lighten.yaml lighten-ref.yaml fuzzy-if(platform(swgl),1,10000) == lighten.yaml lighten-ref.yaml
fuzzy(1,32) == repeated-difference.yaml repeated-difference-ref.yaml fuzzy(1,32) == repeated-difference.yaml repeated-difference-ref.yaml

Просмотреть файл

@ -4,11 +4,11 @@ platform(linux,mac) == draw_calls(7) color_targets(7) alpha_targets(0) filter-bl
== invisible.yaml invisible-ref.yaml == invisible.yaml invisible-ref.yaml
fuzzy-if(platform(swgl),1,10000) == opacity.yaml opacity-ref.yaml fuzzy-if(platform(swgl),1,10000) == opacity.yaml opacity-ref.yaml
fuzzy-range(<=1,*10000) == opacity-combined.yaml opacity-combined-ref.yaml fuzzy-range(<=1,*10000) == opacity-combined.yaml opacity-combined-ref.yaml
== opacity-overlap.yaml opacity-overlap-ref.yaml fuzzy-if(platform(swgl),1,10000) == opacity-overlap.yaml opacity-overlap-ref.yaml
== filter-brightness.yaml filter-brightness-ref.yaml == filter-brightness.yaml filter-brightness-ref.yaml
== filter-brightness-2.yaml filter-brightness-2-ref.yaml == filter-brightness-2.yaml filter-brightness-2-ref.yaml
== filter-brightness-3.yaml filter-brightness-3-ref.yaml == filter-brightness-3.yaml filter-brightness-3-ref.yaml
== filter-brightness-4.yaml filter-brightness-4-ref.yaml fuzzy-if(platform(swgl),1,10000) == filter-brightness-4.yaml filter-brightness-4-ref.yaml
== filter-component-transfer.yaml filter-component-transfer-ref.yaml == filter-component-transfer.yaml filter-component-transfer-ref.yaml
skip_on(android,device) == filter-color-matrix.yaml filter-color-matrix-ref.yaml # fails on Pixel2 skip_on(android,device) == filter-color-matrix.yaml filter-color-matrix-ref.yaml # fails on Pixel2
== filter-contrast-gray-alpha-1.yaml filter-contrast-gray-alpha-1-ref.yaml == filter-contrast-gray-alpha-1.yaml filter-contrast-gray-alpha-1-ref.yaml

Просмотреть файл

@ -1695,7 +1695,7 @@ fuzzy-if(skiaContent,0-1,0-1) == 751012-1a.html 751012-1-ref.html
fuzzy-if(skiaContent,0-1,0-1) == 751012-1b.html 751012-1-ref.html fuzzy-if(skiaContent,0-1,0-1) == 751012-1b.html 751012-1-ref.html
== 753329-1.html about:blank == 753329-1.html about:blank
== 758561-1.html 758561-1-ref.html == 758561-1.html 758561-1-ref.html
fuzzy-if(true,0-1,0-90) fuzzy-if(skiaContent,0-1,0-320) fuzzy-if(webrender&&swgl,1-1,1382-1382) == 759036-1.html 759036-1-ref.html fuzzy-if(true,0-1,0-90) fuzzy-if(skiaContent,0-1,0-320) == 759036-1.html 759036-1-ref.html
fuzzy-if(true,0-17,0-5886) fuzzy-if(skiaContent,0-9,0-5894) fuzzy-if(geckoview&&webrender&&device,3-3,5831-5855) == 759036-2.html 759036-2-ref.html fuzzy-if(true,0-17,0-5886) fuzzy-if(skiaContent,0-9,0-5894) fuzzy-if(geckoview&&webrender&&device,3-3,5831-5855) == 759036-2.html 759036-2-ref.html
== 776265-1a.html 776265-1-ref.html == 776265-1a.html 776265-1-ref.html
== 776265-1b.html 776265-1-ref.html == 776265-1b.html 776265-1-ref.html
@ -2037,7 +2037,7 @@ fuzzy(0-255,0-4054) == 1415987-1.html 1415987-1-ref.html # this is a large fuzz,
== 1424680.html 1424680-ref.html == 1424680.html 1424680-ref.html
== 1424798-1.html 1424798-ref.html == 1424798-1.html 1424798-ref.html
fuzzy-if(!webrender,0-74,0-2234) == 1425243-1.html 1425243-1-ref.html fuzzy-if(!webrender,0-74,0-2234) == 1425243-1.html 1425243-1-ref.html
fuzzy-if(Android,0-66,0-574) fuzzy-if(d2d,0-89,0-777) fuzzy-if(!Android&&!d2d,0-1,0-31380) fuzzy-if(webrender&&winWidget,1-1,31240-31320) fuzzy-if(webrender&&swgl,1-1,31452-31676) == 1425243-2.html 1425243-2-ref.html fuzzy-if(Android,0-66,0-574) fuzzy-if(d2d,0-89,0-777) fuzzy-if(!Android&&!d2d,0-1,0-31380) fuzzy-if(webrender&&winWidget&&!swgl,1-1,31240-31320) == 1425243-2.html 1425243-2-ref.html
== 1430869.html 1430869-ref.html == 1430869.html 1430869-ref.html
== 1432541.html 1432541-ref.html == 1432541.html 1432541-ref.html
== 1446470.html 1035091-ref.html == 1446470.html 1035091-ref.html

Просмотреть файл

@ -272,7 +272,7 @@ fuzzy-if(webrender&&winWidget,0-1,0-5) == grid-fragmentation-dyn5-027.html grid-
== grid-fragmentation-dyn1-029.html grid-fragmentation-029-ref.html == grid-fragmentation-dyn1-029.html grid-fragmentation-029-ref.html
== grid-fragmentation-dyn2-029.html grid-fragmentation-029-ref.html == grid-fragmentation-dyn2-029.html grid-fragmentation-029-ref.html
== grid-fragmentation-dyn2-030.html grid-fragmentation-030-ref.html == grid-fragmentation-dyn2-030.html grid-fragmentation-030-ref.html
== grid-fragmentation-dyn2-031.html grid-fragmentation-031-ref.html fuzzy-if(webrender&&winWidget&&swgl,0-2,0-30) == grid-fragmentation-dyn2-031.html grid-fragmentation-031-ref.html
== bug1306106.html bug1306106-ref.html == bug1306106.html bug1306106-ref.html
== grid-percent-intrinsic-sizing-001.html grid-percent-intrinsic-sizing-001-ref.html == grid-percent-intrinsic-sizing-001.html grid-percent-intrinsic-sizing-001-ref.html