Bug 1706678 - Fix cached gradient scaling. r=gfx-reviewers,lsalzman

Large gradients are cached scaled down and stretched back by the image brush. Because the scaling factor is non-uniform the shader has to take it into account. The previous implementation was incorrectly accounting for the scale.

Differential Revision: https://phabricator.services.mozilla.com/D113753
This commit is contained in:
Nicolas Silva 2021-05-03 09:12:42 +00:00
Родитель 2f83f1a6f4
Коммит 720d336a44
12 изменённых файлов: 84 добавлений и 16 удалений

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

@ -15,6 +15,7 @@ flat varying float v_start_radius;
// Rectangle in origin+size format
PER_INSTANCE in vec4 aTaskRect;
PER_INSTANCE in vec2 aCenter;
PER_INSTANCE in vec2 aScale;
PER_INSTANCE in float aStartRadius;
PER_INSTANCE in float aEndRadius;
PER_INSTANCE in float aXYRatio;
@ -37,7 +38,7 @@ void main(void) {
// v_pos is in a coordinate space relative to the task rect
// (so it is independent of the task origin).
v_pos = (aTaskRect.zw * aPosition.xy - aCenter) * radius_scale;
v_pos = (aTaskRect.zw * aPosition.xy * aScale - aCenter) * radius_scale;
v_pos.y *= aXYRatio;
v_gradient_repeat = float(aExtendMode == EXTEND_MODE_REPEAT);

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

@ -142,11 +142,11 @@ impl From<ConicGradientKey> for ConicGradientTemplate {
let mut task_size: DeviceSize = stretch_size.cast_unit();
let mut scale = vec2(1.0, 1.0);
if task_size.width > MAX_SIZE {
scale.x = MAX_SIZE / task_size.width;
scale.x = task_size.width / MAX_SIZE;
task_size.width = MAX_SIZE;
}
if task_size.height > MAX_SIZE {
scale.y = MAX_SIZE / task_size.height;
scale.y = task_size.height / MAX_SIZE;
task_size.height = MAX_SIZE;
}

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

@ -377,7 +377,7 @@ fn test_struct_sizes() {
assert_eq!(mem::size_of::<LinearGradientKey>(), 88, "LinearGradientKey size changed");
assert_eq!(mem::size_of::<RadialGradient>(), 72, "RadialGradient size changed");
assert_eq!(mem::size_of::<RadialGradientTemplate>(), 136, "RadialGradientTemplate size changed");
assert_eq!(mem::size_of::<RadialGradientTemplate>(), 144, "RadialGradientTemplate size changed");
assert_eq!(mem::size_of::<RadialGradientKey>(), 96, "RadialGradientKey size changed");
assert_eq!(mem::size_of::<ConicGradient>(), 72, "ConicGradient size changed");

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

@ -96,6 +96,7 @@ pub struct RadialGradientTemplate {
pub params: RadialGradientParams,
pub center: DevicePoint,
pub task_size: DeviceIntSize,
pub scale: DeviceVector2D,
pub stretch_size: LayoutSize,
pub tile_spacing: LayoutSize,
pub brush_segments: Vec<BrushSegment>,
@ -143,30 +144,24 @@ impl From<RadialGradientKey> for RadialGradientTemplate {
// differences, especially with 8 bits per channel.
const MAX_SIZE: f32 = 1024.0;
let mut task_size: DeviceSize = stretch_size.cast_unit();
let mut center = DevicePoint::new(item.center.x, item.center.y);
let mut params = item.params;
let mut scale = vec2(1.0, 1.0);
if task_size.width > MAX_SIZE {
let sx = MAX_SIZE / task_size.width;
scale.x = task_size.width/ MAX_SIZE;
task_size.width = MAX_SIZE;
params.ratio_xy *= sx;
center.x *= sx;
params.start_radius *= sx;
params.end_radius *= sx;
}
if task_size.height > MAX_SIZE {
let sy = MAX_SIZE / task_size.height;
scale.y = task_size.height /MAX_SIZE;
task_size.height = MAX_SIZE;
params.ratio_xy /= sy;
center.y *= sy;
}
RadialGradientTemplate {
common,
center,
center: DevicePoint::new(item.center.x, item.center.y),
extend_mode: item.extend_mode,
params,
params: item.params,
stretch_size,
task_size: task_size.ceil().to_i32(),
scale,
tile_spacing: item.tile_spacing.into(),
brush_segments,
stops_opacity,
@ -221,6 +216,7 @@ impl RadialGradientTemplate {
let cache_key = RadialGradientCacheKey {
size: task_size,
center: PointKey { x: self.center.x, y: self.center.y },
scale: PointKey { x: self.scale.x, y: self.scale.y },
start_radius: FloatKey(self.params.start_radius),
end_radius: FloatKey(self.params.end_radius),
ratio_xy: FloatKey(self.params.ratio_xy),
@ -245,6 +241,7 @@ impl RadialGradientTemplate {
RenderTaskKind::RadialGradient(RadialGradientTask {
extend_mode: self.extend_mode,
center: self.center,
scale: self.scale,
params: self.params.clone(),
stops: self.stops_handle,
}),
@ -317,6 +314,7 @@ impl IsVisible for RadialGradient {
pub struct RadialGradientTask {
pub extend_mode: ExtendMode,
pub center: DevicePoint,
pub scale: DeviceVector2D,
pub params: RadialGradientParams,
pub stops: GpuCacheHandle,
}
@ -326,6 +324,7 @@ impl RadialGradientTask {
RadialGradientInstance {
task_rect: target_rect.to_f32(),
center: self.center,
scale: self.scale,
start_radius: self.params.start_radius,
end_radius: self.params.end_radius,
ratio_xy: self.params.ratio_xy,
@ -345,6 +344,7 @@ impl RadialGradientTask {
pub struct RadialGradientInstance {
pub task_rect: DeviceRect,
pub center: DevicePoint,
pub scale: DeviceVector2D,
pub start_radius: f32,
pub end_radius: f32,
pub ratio_xy: f32,
@ -358,6 +358,7 @@ pub struct RadialGradientInstance {
pub struct RadialGradientCacheKey {
pub size: DeviceIntSize,
pub center: PointKey,
pub scale: PointKey,
pub start_radius: FloatKey,
pub end_radius: FloatKey,
pub ratio_xy: FloatKey,

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

@ -186,6 +186,11 @@ pub mod desc {
count: 2,
kind: VertexAttributeKind::F32,
},
VertexAttribute {
name: "aScale",
count: 2,
kind: VertexAttributeKind::F32,
},
VertexAttribute {
name: "aStartRadius",
count: 1,

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

@ -0,0 +1,16 @@
---
root:
items:
- type: rect
bounds: 50 50 2000 300
color: blue
- type: conic-gradient
bounds: 50 50 2000 300
center: 150 150
angle: 0.0
stops: [0.0, red,
0.125, blue,
0.375, blue,
0.5, yellow,
1.0, red]

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

@ -0,0 +1,12 @@
---
root:
items:
- type: conic-gradient
bounds: 50 50 2000 300
center: 150 150
angle: 0.0
stops: [0.0, red,
0.125, blue,
0.375, blue,
0.5, yellow,
1.0, red]

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

@ -0,0 +1,12 @@
---
root:
items:
- type: rect
bounds: 50 50 2000 300
color: blue
- type: gradient
bounds: 50 50 400 300
start: 0 0
end: 100 20
stops: [0.0, red, 1.0, blue]

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

@ -0,0 +1,8 @@
---
root:
items:
- type: gradient
bounds: 50 50 2000 300
start: 0 0
end: 100 20
stops: [0.0, red, 1.0, blue]

Двоичные данные
gfx/wr/wrench/reftests/gradient/radial-large-ref.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 36 KiB

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

@ -0,0 +1,8 @@
---
root:
items:
- type: radial-gradient
bounds: 50 50 2000 300
center: 1000 150
radius: 900 200
stops: [0, red, 1, blue]

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

@ -110,3 +110,8 @@ fuzzy-range(<=1,1) == gradient_cache_hardstop_clip.yaml gradient_cache_hardstop_
# Exercise the radial gradient optimization code path
== radial-optimized.yaml radial-optimized-ref.yaml
== radial-tiling-optimized.yaml radial-tiling-optimized-ref.yaml
# Exercise the cached gradient scaling code path
fuzzy(2,23000) == linear-large.yaml linear-large-ref.yaml
== conic-large.yaml conic-large-ref.yaml
fuzzy(1,7000) == radial-large.yaml radial-large-ref.png