зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1887837 - Conic gradient quad shader. r=gw
Differential Revision: https://phabricator.services.mozilla.com/D205985
This commit is contained in:
Родитель
7a3e6b8188
Коммит
30108b870e
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче