Bug 1702638 - Set a maximum resolution for conic gradients. r=gw

This patch avoids rasterizing huge conic gradient render tasks by setting a max resolution on each axis and passing a scale factor to the shader (simply reducing the resolution and stretching a conic gradient would be incorrect when the scaling isn't the same on the x and y axis).

Differential Revision: https://phabricator.services.mozilla.com/D111134
This commit is contained in:
Nicolas Silva 2021-04-12 11:22:10 +00:00
Родитель 139b65259c
Коммит c7fd490fc2
4 изменённых файлов: 37 добавлений и 6 удалений

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

@ -20,6 +20,7 @@ flat varying float v_angle;
// Rectangle in origin+size format
PER_INSTANCE in vec4 aTaskRect;
PER_INSTANCE in vec2 aCenter;
PER_INSTANCE in vec2 aScale;
PER_INSTANCE in float aStartOffset;
PER_INSTANCE in float aEndOffset;
PER_INSTANCE in float aAngle;
@ -41,7 +42,7 @@ void main(void) {
// v_pos and v_center are in a coordinate space relative to the task rect
// (so they are independent of the task origin).
v_center = aCenter * v_offset_scale;
v_pos = aTaskRect.zw * aPosition.xy * v_offset_scale;
v_pos = aTaskRect.zw * aPosition.xy * v_offset_scale * aScale;
v_gradient_repeat = float(aExtendMode == EXTEND_MODE_REPEAT);
v_gradient_address = aGradientStopsAddress;

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

@ -8,6 +8,7 @@
//!
//! Conic gradients are rendered via cached render tasks and composited with the image brush.
use euclid::vec2;
use api::{ExtendMode, GradientStop, PremultipliedColorF};
use api::units::*;
use crate::scene_building::IsVisible;
@ -90,6 +91,8 @@ pub struct ConicGradientTemplate {
pub extend_mode: ExtendMode,
pub center: DevicePoint,
pub params: ConicGradientParams,
pub task_size: DeviceIntSize,
pub scale: DeviceVector2D,
pub stretch_size: LayoutSize,
pub tile_spacing: LayoutSize,
pub brush_segments: Vec<BrushSegment>,
@ -132,12 +135,29 @@ impl From<ConicGradientKey> for ConicGradientTemplate {
stretch_size.width = stretch_size.width.min(common.prim_rect.size.width);
stretch_size.height = stretch_size.height.min(common.prim_rect.size.height);
// Avoid rendering enormous gradients. Radial gradients are mostly made of soft transitions,
// so it is unlikely that rendering at a higher resolution that 1024 would produce noticeable
// differences, especially with 8 bits per channel.
const MAX_SIZE: f32 = 1024.0;
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;
task_size.width = MAX_SIZE;
}
if task_size.height > MAX_SIZE {
scale.y = MAX_SIZE / task_size.height;
task_size.height = MAX_SIZE;
}
ConicGradientTemplate {
common,
center: DevicePoint::new(item.center.x, item.center.y),
extend_mode: item.extend_mode,
params: item.params,
stretch_size,
task_size: task_size.to_i32(),
scale,
tile_spacing: item.tile_spacing.into(),
brush_segments,
stops_opacity,
@ -188,10 +208,10 @@ impl ConicGradientTemplate {
);
}
let task_size = self.stretch_size.to_i32().cast_unit();
let cache_key = ConicGradientCacheKey {
size: task_size,
size: self.task_size,
center: PointKey { x: self.center.x, y: self.center.y },
scale: PointKey { x: self.scale.x, y: self.scale.y },
start_offset: FloatKey(self.params.start_offset),
end_offset: FloatKey(self.params.end_offset),
angle: FloatKey(self.params.angle),
@ -201,7 +221,7 @@ impl ConicGradientTemplate {
let task_id = frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
size: task_size,
size: self.task_size,
kind: RenderTaskCacheKeyKind::ConicGradient(cache_key),
},
frame_state.gpu_cache,
@ -212,9 +232,10 @@ impl ConicGradientTemplate {
frame_state.surfaces,
|rg_builder| {
rg_builder.add().init(RenderTask::new_dynamic(
task_size,
self.task_size,
RenderTaskKind::ConicGradient(ConicGradientTask {
extend_mode: self.extend_mode,
scale: self.scale,
center: self.center,
params: self.params.clone(),
stops: self.stops_handle,
@ -288,6 +309,7 @@ impl IsVisible for ConicGradient {
pub struct ConicGradientTask {
pub extend_mode: ExtendMode,
pub center: DevicePoint,
pub scale: DeviceVector2D,
pub params: ConicGradientParams,
pub stops: GpuCacheHandle,
}
@ -297,6 +319,7 @@ impl ConicGradientTask {
ConicGradientInstance {
task_rect: target_rect.to_f32(),
center: self.center,
scale: self.scale,
start_offset: self.params.start_offset,
end_offset: self.params.end_offset,
angle: self.params.angle,
@ -316,6 +339,7 @@ impl ConicGradientTask {
pub struct ConicGradientInstance {
pub task_rect: DeviceRect,
pub center: DevicePoint,
pub scale: DeviceVector2D,
pub start_offset: f32,
pub end_offset: f32,
pub angle: f32,
@ -329,6 +353,7 @@ pub struct ConicGradientInstance {
pub struct ConicGradientCacheKey {
pub size: DeviceIntSize,
pub center: PointKey,
pub scale: PointKey,
pub start_offset: FloatKey,
pub end_offset: FloatKey,
pub angle: FloatKey,

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

@ -354,6 +354,6 @@ fn test_struct_sizes() {
assert_eq!(mem::size_of::<RadialGradientKey>(), 96, "RadialGradientKey size changed");
assert_eq!(mem::size_of::<ConicGradient>(), 72, "ConicGradient size changed");
assert_eq!(mem::size_of::<ConicGradientTemplate>(), 128, "ConicGradientTemplate size changed");
assert_eq!(mem::size_of::<ConicGradientTemplate>(), 144, "ConicGradientTemplate size changed");
assert_eq!(mem::size_of::<ConicGradientKey>(), 96, "ConicGradientKey size changed");
}

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

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