commit 451979278c24abac24eb482e75cfe9e41c4bbec6
parent e34c7c802d31a19ab860b94898d2d1d28b4a36aa
Author: Nicolas Silva <nical@fastmail.com>
Date: Mon, 13 Oct 2025 09:07:54 +0000
Bug 1978773 - Fix validatation of precise gradient addresses. r=lsalzman
The existing function is overly conservative for precise gradients because the latter require less storage per gradient stop.
Differential Revision: https://phabricator.services.mozilla.com/D268169
Diffstat:
3 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/gfx/wr/glsl-to-cxx/src/hir.rs b/gfx/wr/glsl-to-cxx/src/hir.rs
@@ -3956,6 +3956,14 @@ pub fn ast_to_hir(state: &mut State, tu: &syntax::TranslationUnit) -> Translatio
vec![Type::new(Sampler2D), Type::new(IVec2), Type::new(Int)],
RunClass::Scalar,
);
+ declare_function_ext(
+ state,
+ "swgl_validateGradientFromStops",
+ None,
+ Type::new(Int),
+ vec![Type::new(Sampler2D), Type::new(IVec2), Type::new(Int)],
+ RunClass::Scalar,
+ );
declare_function(
state,
"swgl_commitLinearGradientRGBA8",
diff --git a/gfx/wr/swgl/src/swgl_ext.h b/gfx/wr/swgl/src/swgl_ext.h
@@ -1349,6 +1349,20 @@ static inline int swgl_validateGradient(sampler2D sampler, ivec2_scalar address,
: -1;
}
+static inline int swgl_validateGradientFromStops(sampler2D sampler, ivec2_scalar address,
+ int entries) {
+ // 1px (4 floats per color stop).
+ int colors_size = entries;
+ // 4 stop offsets (4 floats) per px.
+ int stops_size = ((entries + 3) & ~3) / 4;
+ return sampler->format == TextureFormat::RGBA32F && address.y >= 0 &&
+ address.y < int(sampler->height) && address.x >= 0 &&
+ address.x < int(sampler->width) && entries > 0 &&
+ address.x + colors_size + stops_size <= int(sampler->width)
+ ? address.y * sampler->stride + address.x * 4
+ : -1;
+}
+
static inline WideRGBA8 sampleGradient(sampler2D sampler, int address,
Float entry) {
assert(sampler->format == TextureFormat::RGBA32F);
diff --git a/gfx/wr/webrender/res/ps_quad_gradient.glsl b/gfx/wr/webrender/res/ps_quad_gradient.glsl
@@ -365,11 +365,9 @@ void swgl_drawSpanRGBA8() {
int stop_count = v_gradient_header.y;
int colors_address = v_gradient_header.w;
- int colors_addr = swgl_validateGradient(sGpuBufferF, get_gpu_buffer_uv(colors_address),
- stop_count);
- int offsets_addr = swgl_validateGradient(sGpuBufferF, get_gpu_buffer_uv(colors_address + stop_count),
- stop_count);
- if (offsets_addr < 0 || colors_addr < 0) {
+ int colors_addr = swgl_validateGradientFromStops(sGpuBufferF, get_gpu_buffer_uv(colors_address),
+ stop_count);
+ if (colors_addr < 0) {
// The gradient is invalid, this should not happen. We can't fall back to
// the regular shader code because it expects the gradient stop offsets
// to be laid out for a tree traversal but we laid them out linearly because
@@ -379,6 +377,7 @@ void swgl_drawSpanRGBA8() {
return;
}
+ int offsets_addr = colors_addr + stop_count * 4;
vec2 pos = v_interpolated_data.xy;
float start_radius = v_flat_data.x;
bool repeat = v_gradient_header.z != 0.0;