Bug 1887837 - Conic gradient quad shader. r=gw

Differential Revision: https://phabricator.services.mozilla.com/D205985
This commit is contained in:
Nicolas Silva 2024-04-03 12:45:01 +00:00
Родитель 7a3e6b8188
Коммит 30108b870e
10 изменённых файлов: 184 добавлений и 11 удалений

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

@ -0,0 +1,74 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/// This shader renders radial graidents in a color or alpha target.
#include ps_quad,gradient
#define PI 3.141592653589793
// x: start offset, y: offset scale, z: angle
// Packed in to a vector to work around bug 1630356.
flat varying highp vec3 v_start_offset_offset_scale_angle_vec;
#define v_start_offset v_start_offset_offset_scale_angle_vec.x
#define v_offset_scale v_start_offset_offset_scale_angle_vec.y
#define v_angle v_start_offset_offset_scale_angle_vec.z
varying highp vec2 v_dir;
#ifdef WR_VERTEX_SHADER
struct ConicGradient {
vec2 center;
vec2 scale;
float start_offset;
float end_offset;
float angle;
// 1.0 if the gradient should be repeated, 0.0 otherwise.
float repeat;
};
ConicGradient fetch_conic_gradient(int address) {
vec4[2] data = fetch_from_gpu_buffer_2f(address);
return ConicGradient(
data[0].xy,
data[0].zw,
data[1].x,
data[1].y,
data[1].z,
data[1].w
);
}
void pattern_vertex(PrimitiveInfo info) {
ConicGradient gradient = fetch_conic_gradient(info.pattern_input.x);
v_gradient_address.x = info.pattern_input.y;
v_gradient_repeat.x = gradient.repeat;
// Store 1/d where d = end_offset - start_offset
// If d = 0, we can't get its reciprocal. Instead, just use a zero scale.
float d = gradient.end_offset - gradient.start_offset;
v_offset_scale = d != 0.0 ? 1.0 / d : 0.0;
v_angle = PI / 2.0 - gradient.angle;
v_start_offset = gradient.start_offset * v_offset_scale;
v_dir = ((info.local_pos - info.local_prim_rect.p0) * gradient.scale - gradient.center);
}
#endif
#ifdef WR_FRAGMENT_SHADER
vec4 pattern_fragment(vec4 color) {
// Use inverse trig to find the angle offset from the relative position.
vec2 current_dir = v_dir;
float current_angle = atan(current_dir.y, current_dir.x) + v_angle;
float offset = fract(current_angle / (2.0 * PI)) * v_offset_scale - v_start_offset;
color *= sample_gradient(offset);
return color;
}
#endif

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

@ -11,12 +11,13 @@ use api::{ColorF, PremultipliedColorF};
pub enum PatternKind {
ColorOrTexture = 0,
RadialGradient = 1,
ConicGradient = 2,
Mask = 2,
Mask = 3,
// When adding patterns, don't forget to update the NUM_PATTERNS constant.
}
pub const NUM_PATTERNS: u32 = 3;
pub const NUM_PATTERNS: u32 = 4;
impl PatternKind {
pub fn from_u32(val: u32) -> Self {

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

@ -28,7 +28,7 @@ use crate::prim_store::line_dec::MAX_LINE_DECORATION_RESOLUTION;
use crate::prim_store::*;
use crate::quad;
use crate::pattern::Pattern;
use crate::prim_store::gradient::{radial_gradient_pattern, GradientGpuBlockBuilder};
use crate::prim_store::gradient::{radial_gradient_pattern, conic_gradient_pattern, GradientGpuBlockBuilder};
use crate::render_backend::DataStores;
use crate::render_task_graph::RenderTaskId;
use crate::render_task_cache::RenderTaskCacheKeyKind;
@ -244,6 +244,7 @@ fn prepare_prim_for_render(
let should_update_clip_task = match prim_instance.kind {
PrimitiveInstanceKind::Rectangle { use_legacy_path: ref mut no_quads, .. }
| PrimitiveInstanceKind::RadialGradient { cached: ref mut no_quads, .. }
| PrimitiveInstanceKind::ConicGradient { cached: ref mut no_quads, .. }
=> {
*no_quads = disable_quad_path || !can_use_clip_chain_for_quad_path(
&prim_instance.vis.clip_chain,
@ -868,10 +869,43 @@ fn prepare_interned_prim_for_render(
}
}
}
PrimitiveInstanceKind::ConicGradient { data_handle, ref mut visible_tiles_range, .. } => {
PrimitiveInstanceKind::ConicGradient { data_handle, ref mut visible_tiles_range, cached, .. } => {
profile_scope!("ConicGradient");
let prim_data = &mut data_stores.conic_grad[*data_handle];
if !*cached {
// The scaling parameter is used to compensate for when we reduce the size
// of the render task for cached gradients. Here we aren't applying any.
let no_scale = DeviceVector2D::one();
let pattern = conic_gradient_pattern(
prim_data.center,
no_scale,
&prim_data.params,
prim_data.extend_mode,
&prim_data.stops,
&mut frame_state.frame_gpu_data,
);
quad::push_quad(
&pattern,
&prim_data.common.prim_rect,
prim_instance_index,
prim_spatial_node_index,
&prim_instance.vis.clip_chain,
device_pixel_scale,
frame_context,
pic_context,
targets,
&data_stores.clip,
frame_state,
pic_state,
scratch,
);
return;
}
prim_data.common.may_need_repetition = prim_data.stretch_size.width < prim_data.common.prim_rect.width()
|| prim_data.stretch_size.height < prim_data.common.prim_rect.height();

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

@ -11,6 +11,7 @@
use euclid::vec2;
use api::{ExtendMode, GradientStop, PremultipliedColorF};
use api::units::*;
use crate::pattern::{Pattern, PatternKind, PatternShaderInput};
use crate::scene_building::IsVisible;
use crate::frame_builder::FrameBuildingState;
use crate::intern::{Internable, InternDebug, Handle as InternHandle};
@ -22,8 +23,8 @@ use crate::prim_store::{NinePatchDescriptor, PointKey, SizeKey, InternablePrimit
use crate::render_task::{RenderTask, RenderTaskKind};
use crate::render_task_graph::RenderTaskId;
use crate::render_task_cache::{RenderTaskCacheKeyKind, RenderTaskCacheKey, RenderTaskParent};
use crate::renderer::GpuBufferAddress;
use crate::picture::{SurfaceIndex};
use crate::renderer::{GpuBufferAddress, GpuBufferBuilder};
use crate::picture::SurfaceIndex;
use std::{hash, ops::{Deref, DerefMut}};
use super::{stops_and_min_alpha, GradientStopKey, GradientGpuBlockBuilder};
@ -329,6 +330,7 @@ impl InternablePrimitive for ConicGradient {
PrimitiveInstanceKind::ConicGradient {
data_handle,
visible_tiles_range: GradientTileRange::empty(),
cached: true,
}
}
}
@ -397,3 +399,44 @@ pub struct ConicGradientCacheKey {
pub stops: Vec<GradientStopKey>,
}
pub fn conic_gradient_pattern(
center: DevicePoint,
scale: DeviceVector2D,
params: &ConicGradientParams,
extend_mode: ExtendMode,
stops: &[GradientStop],
gpu_buffer_builder: &mut GpuBufferBuilder
) -> Pattern {
let mut writer = gpu_buffer_builder.f32.write_blocks(2);
writer.push_one([
center.x,
center.y,
scale.x,
scale.y,
]);
writer.push_one([
params.start_offset,
params.end_offset,
params.angle,
if extend_mode == ExtendMode::Repeat { 1.0 } else { 0.0 }
]);
let gradient_address = writer.finish();
let stops_address = GradientGpuBlockBuilder::build(
false,
&mut gpu_buffer_builder.f32,
&stops,
);
let is_opaque = stops.iter().all(|stop| stop.color.a >= 1.0);
Pattern {
kind: PatternKind::ConicGradient,
shader_input: PatternShaderInput(
gradient_address.as_int(),
stops_address.as_int(),
),
base_color: PremultipliedColorF::WHITE,
is_opaque,
}
}

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

@ -1035,6 +1035,7 @@ pub enum PrimitiveInstanceKind {
/// Handle to the common interned data for this primitive.
data_handle: ConicGradientDataHandle,
visible_tiles_range: GradientTileRange,
cached: bool,
},
/// Clear out a rect, used for special effects.
Clear {

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

@ -263,7 +263,7 @@ impl RenderTarget for ColorRenderTarget {
used_rect,
resolve_ops: Vec::new(),
clear_color: Some(ColorF::TRANSPARENT),
prim_instances: [Vec::new(), Vec::new(), Vec::new()],
prim_instances: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
prim_instances_with_scissor: FastHashMap::default(),
clip_masks: ClipMaskInstanceList::new(),
}

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

@ -197,7 +197,7 @@ const GPU_TAG_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag {
label: "C_RadialGradient",
color: debug_colors::BROWN,
};
const GPU_TAG_CACHE_CONIC_GRADIENT: GpuProfileTag = GpuProfileTag {
const GPU_TAG_CONIC_GRADIENT: GpuProfileTag = GpuProfileTag {
label: "C_ConicGradient",
color: debug_colors::BROWN,
};
@ -289,6 +289,7 @@ impl BatchKind {
BatchKind::TextRun(_) => GPU_TAG_PRIM_TEXT_RUN,
BatchKind::Quad(PatternKind::ColorOrTexture) => GPU_TAG_PRIMITIVE,
BatchKind::Quad(PatternKind::RadialGradient) => GPU_TAG_RADIAL_GRADIENT,
BatchKind::Quad(PatternKind::ConicGradient) => GPU_TAG_CONIC_GRADIENT,
BatchKind::Quad(PatternKind::Mask) => GPU_TAG_INDIRECT_MASK,
}
}
@ -4096,7 +4097,7 @@ impl Renderer {
// Draw any conic gradients for this target.
if !target.conic_gradients.is_empty() {
let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_CONIC_GRADIENT);
let _timer = self.gpu_profiler.start_timer(GPU_TAG_CONIC_GRADIENT);
self.set_blend(false, FramebufferKind::Other);

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

@ -633,6 +633,7 @@ pub struct Shaders {
ps_split_composite: LazilyCompiledShader,
pub ps_quad_textured: LazilyCompiledShader,
pub ps_quad_radial_gradient: LazilyCompiledShader,
pub ps_quad_conic_gradient: LazilyCompiledShader,
pub ps_mask: LazilyCompiledShader,
pub ps_mask_fast: LazilyCompiledShader,
pub ps_clear: LazilyCompiledShader,
@ -899,6 +900,16 @@ impl Shaders {
profile,
)?;
let ps_quad_conic_gradient = LazilyCompiledShader::new(
ShaderKind::Primitive,
"ps_quad_conic_gradient",
&[],
device,
options.precache_flags,
&shader_list,
profile,
)?;
let ps_split_composite = LazilyCompiledShader::new(
ShaderKind::Primitive,
"ps_split_composite",
@ -1134,6 +1145,7 @@ impl Shaders {
ps_text_run_dual_source,
ps_quad_textured,
ps_quad_radial_gradient,
ps_quad_conic_gradient,
ps_mask,
ps_mask_fast,
ps_split_composite,
@ -1173,6 +1185,7 @@ impl Shaders {
match pattern {
PatternKind::ColorOrTexture => &mut self.ps_quad_textured,
PatternKind::RadialGradient => &mut self.ps_quad_radial_gradient,
PatternKind::ConicGradient => &mut self.ps_quad_conic_gradient,
PatternKind::Mask => unreachable!(),
}
}
@ -1191,6 +1204,9 @@ impl Shaders {
BatchKind::Quad(PatternKind::RadialGradient) => {
&mut self.ps_quad_radial_gradient
}
BatchKind::Quad(PatternKind::ConicGradient) => {
&mut self.ps_quad_conic_gradient
}
BatchKind::Quad(PatternKind::Mask) => {
unreachable!();
}
@ -1322,6 +1338,7 @@ impl Shaders {
self.ps_split_composite.deinit(device);
self.ps_quad_textured.deinit(device);
self.ps_quad_radial_gradient.deinit(device);
self.ps_quad_conic_gradient.deinit(device);
self.ps_mask.deinit(device);
self.ps_mask_fast.deinit(device);
self.ps_clear.deinit(device);

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

@ -230,6 +230,8 @@ pub fn get_shader_features(flags: ShaderFeatureFlags) -> ShaderFeatures {
shaders.insert("ps_quad_radial_gradient", vec![base_prim_features.finish()]);
shaders.insert("ps_quad_conic_gradient", vec![base_prim_features.finish()]);
shaders.insert("ps_clear", vec![base_prim_features.finish()]);
shaders.insert("ps_copy", vec![base_prim_features.finish()]);

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

@ -88,7 +88,7 @@ fuzzy(1,57) == conic-simple.yaml conic-simple.png
fuzzy(255,302) == conic-angle.yaml conic-angle.png
== conic-center.yaml conic-center.png
fuzzy(1,2) == conic-angle-wraparound.yaml conic-angle.yaml
fuzzy-if(env(android,device),254,146) fuzzy-if(not(env(android,device)),1,1) == conic-angle-wraparound-negative.yaml conic-angle.yaml # Android device is Samsung Galaxy A51
fuzzy-if(env(android,device),255,155) fuzzy-if(not(env(android,device)),1,1) == conic-angle-wraparound-negative.yaml conic-angle.yaml # Android device is Samsung Galaxy A51
fuzzy(1,333) == conic-color-wheel.yaml conic-color-wheel.png
# gradient caching tests
@ -118,7 +118,7 @@ fuzzy-range(<=1,1) == gradient_cache_hardstop_clip.yaml gradient_cache_hardstop_
# 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-if(env(android,device),254,1) == conic-large-hard-stop.yaml conic-large-hard-stop-ref.yaml # Android device is Samsung Galaxy A51
fuzzy-if(env(android,device),255,1) == conic-large-hard-stop.yaml conic-large-hard-stop-ref.yaml # Android device is Samsung Galaxy A51
fuzzy(1,80000) == radial-large.yaml radial-large-ref.png
# crash tests