| author | Connor Brewster <connorbrewster@yahoo.com> |
| Mon, 13 Jan 2020 16:05:57 +0000 | |
| changeset 509964 | b0226237c55e4a08f4deb622fc15fa1e85f39afc |
| parent 509963 | f2d90a6dd7c60b35bcbae8ab9e59c147631c02b6 |
| child 509965 | b2de33dc3f66665fa3fc53798ec24cfa2bb6d39a |
| push id | 37012 |
| push user | apavel@mozilla.com |
| push date | Tue, 14 Jan 2020 03:45:02 +0000 |
| treeherder | mozilla-central@d1406439c461 [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | nical |
| bugs | 1607746 |
| milestone | 74.0a1 |
| first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/wr/webrender/res/brush.glsl +++ b/gfx/wr/webrender/res/brush.glsl @@ -85,16 +85,17 @@ void name( // Forward-declare all brush vertex entry points. FWD_DECLARE_VS_FUNCTION(image_brush_vs) FWD_DECLARE_VS_FUNCTION(solid_brush_vs) FWD_DECLARE_VS_FUNCTION(blend_brush_vs) FWD_DECLARE_VS_FUNCTION(mix_blend_brush_vs) FWD_DECLARE_VS_FUNCTION(linear_gradient_brush_vs) FWD_DECLARE_VS_FUNCTION(radial_gradient_brush_vs) FWD_DECLARE_VS_FUNCTION(yuv_brush_vs) +FWD_DECLARE_VS_FUNCTION(opacity_brush_vs) void multi_brush_vs( VertexInfo vi, int prim_address, RectWithSize local_rect, RectWithSize segment_rect, ivec4 prim_user_data, int specific_resource_address, @@ -250,16 +251,17 @@ struct Fragment { // Foward-declare all brush entry-points. Fragment image_brush_fs(); Fragment solid_brush_fs(); Fragment blend_brush_fs(); Fragment mix_blend_brush_fs(); Fragment linear_gradient_brush_fs(); Fragment radial_gradient_brush_fs(); Fragment yuv_brush_fs(); +Fragment opacity_brush_fs(); Fragment multi_brush_fs(int brush_kind); void main(void) { #ifdef WR_FEATURE_DEBUG_OVERDRAW oFragColor = WR_DEBUG_OVERDRAW_COLOR; #else // Run the specific brush FS code to output the color.
--- a/gfx/wr/webrender/res/brush_multi.glsl +++ b/gfx/wr/webrender/res/brush_multi.glsl @@ -16,16 +16,17 @@ #define BRUSH_KIND_SOLID 1 #define BRUSH_KIND_IMAGE 2 #define BRUSH_KIND_TEXT 3 #define BRUSH_KIND_LINEAR_GRADIENT 4 #define BRUSH_KIND_RADIAL_GRADIENT 5 #define BRUSH_KIND_BLEND 6 #define BRUSH_KIND_MIX_BLEND 7 #define BRUSH_KIND_YV 8 +#define BRUSH_KIND_OPACITY 9 int vecs_per_brush(int brush_kind); #include shared,prim_shared,brush #ifdef WR_FEATURE_IMAGE_BRUSH #include brush_image #endif @@ -65,16 +66,24 @@ int vecs_per_brush(int brush_kind); #undef VECS_PER_SPECIFIC_BRUSH #undef WR_BRUSH_VS_FUNCTION #undef WR_BRUSH_FS_FUNCTION #ifdef WR_FEATURE_RADIAL_GRADIENT_BRUSH #include brush_radial_gradient #endif +#undef VECS_PER_SPECIFIC_BRUSH +#undef WR_BRUSH_VS_FUNCTION +#undef WR_BRUSH_FS_FUNCTION + +#ifdef WR_FEATURE_OPACITY_BRUSH +#include brush_opacity +#endif + int vecs_per_brush(int brush_kind) { switch (brush_kind) { // The default arm should never be taken, we let it point to whichever shader // is enabled first to satisfy ANGLE validation. default: #ifdef WR_FEATURE_IMAGE_BRUSH case BRUSH_KIND_IMAGE: return VECS_PER_IMAGE_BRUSH; @@ -94,16 +103,20 @@ int vecs_per_brush(int brush_kind) { #ifdef WR_FEATURE_LINEAR_GRADIENT_BRUSH case BRUSH_KIND_LINEAR_GRADIENT: return VECS_PER_LINEAR_GRADIENT_BRUSH; #endif #ifdef WR_FEATURE_RADIAL_GRADIENT_BRUSH case BRUSH_KIND_RADIAL_GRADIENT: return VECS_PER_RADIAL_GRADIENT_BRUSH; #endif + + #ifdef WR_FEATURE_OPACITY_BRUSH + case BRUSH_KIND_OPACITY: return VECS_PER_OPACITY_BRUSH; + #endif } } #define BRUSH_VS_PARAMS vi, prim_address, local_rect, segment_rect, \ prim_user_data, specific_resource_address, transform, pic_task, \ brush_flags, texel_rect @@ -154,16 +167,22 @@ void multi_brush_vs( break; #endif #ifdef WR_FEATURE_RADIAL_GRADIENT_BRUSH case BRUSH_KIND_RADIAL_GRADIENT: radial_gradient_brush_vs(BRUSH_VS_PARAMS); break; #endif + + #ifdef WR_FEATURE_OPACITY_BRUSH + case BRUSH_KIND_OPACITY: + opacity_brush_vs(BRUSH_VS_PARAMS); + break; + #endif } } #endif // WR_VERTEX_SHADER #ifdef WR_FRAGMENT_SHADER Fragment multi_brush_fs(int brush_kind) { @@ -188,12 +207,16 @@ Fragment multi_brush_fs(int brush_kind) #ifdef WR_FEATURE_LINEAR_GRADIENT_BRUSH case BRUSH_KIND_LINEAR_GRADIENT: return linear_gradient_brush_fs(); #endif #ifdef WR_FEATURE_RADIAL_GRADIENT_BRUSH case BRUSH_KIND_RADIAL_GRADIENT: return radial_gradient_brush_fs(); #endif + + #ifdef WR_FEATURE_OPACITY_BRUSH + case BRUSH_KIND_OPACITY: return opacity_brush_fs(); + #endif } } #endif
new file mode 100644 --- /dev/null +++ b/gfx/wr/webrender/res/brush_opacity.glsl @@ -0,0 +1,91 @@ +/* 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/. */ + +#define VECS_PER_OPACITY_BRUSH 3 +#define VECS_PER_SPECIFIC_BRUSH VECS_PER_OPACITY_BRUSH + +#define WR_BRUSH_VS_FUNCTION opacity_brush_vs +#define WR_BRUSH_FS_FUNCTION opacity_brush_fs + +#include shared,prim_shared,brush + +// Interpolated UV coordinates to sample. +#define V_UV varying_vec4_0.zw +#define V_LOCAL_POS varying_vec4_0.xy + +// Normalized bounds of the source image in the texture. +#define V_UV_BOUNDS flat_varying_vec4_1 + +// Layer index to sample. +#define V_LAYER flat_varying_vec4_2.x +// Flag to allow perspective interpolation of UV. +#define V_PERSPECTIVE flat_varying_vec4_2.y + +#define V_OPACITY flat_varying_vec4_2.z + +#ifdef WR_VERTEX_SHADER +void opacity_brush_vs( + VertexInfo vi, + int prim_address, + RectWithSize local_rect, + RectWithSize segment_rect, + ivec4 prim_user_data, + int specific_resource_address, + mat4 transform, + PictureTask pic_task, + int brush_flags, + vec4 unused +) { + ImageResource res = fetch_image_resource(prim_user_data.x); + vec2 uv0 = res.uv_rect.p0; + vec2 uv1 = res.uv_rect.p1; + + vec2 texture_size = vec2(textureSize(sColor0, 0).xy); + vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size; + f = get_image_quad_uv(prim_user_data.x, f); + vec2 uv = mix(uv0, uv1, f); + float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0; + + V_UV = uv / texture_size * mix(vi.world_pos.w, 1.0, perspective_interpolate); + V_LAYER = res.layer; + V_PERSPECTIVE = perspective_interpolate; + + // TODO: The image shader treats this differently: deflate the rect by half a pixel on each side and + // clamp the uv in the frame shader. Does it make sense to do the same here? + V_UV_BOUNDS = vec4(uv0, uv1) / texture_size.xyxy; + V_LOCAL_POS = vi.local_pos; + + V_OPACITY = float(prim_user_data.y) / 65536.0; +} +#endif + +#ifdef WR_FRAGMENT_SHADER +Fragment opacity_brush_fs() { + float perspective_divisor = mix(gl_FragCoord.w, 1.0, V_PERSPECTIVE); + vec2 uv = V_UV * perspective_divisor; + vec4 Cs = texture(sColor0, vec3(uv, V_LAYER)); + + // Un-premultiply the input. + float alpha = Cs.a; + vec3 color = alpha != 0.0 ? Cs.rgb / alpha : Cs.rgb; + + alpha *= V_OPACITY; + + // Fail-safe to ensure that we don't sample outside the rendered + // portion of a blend source. + alpha *= min(point_inside_rect(uv, V_UV_BOUNDS.xy, V_UV_BOUNDS.zw), + init_transform_fs(V_LOCAL_POS)); + + // Pre-multiply the alpha into the output value. + return Fragment(alpha * vec4(color, 1.0)); +} +#endif + +// Undef macro names that could be re-defined by other shaders. +#undef V_UV +#undef V_LOCAL_POS +#undef V_UV_BOUNDS +#undef V_LAYER +#undef V_PERSPECTIVE +#undef V_OPACITY
--- a/gfx/wr/webrender/src/batch.rs +++ b/gfx/wr/webrender/src/batch.rs @@ -53,16 +53,17 @@ pub enum BrushBatchKind { MixBlend { task_id: RenderTaskId, source_id: RenderTaskId, backdrop_id: RenderTaskId, }, YuvImage(ImageBufferKind, YuvFormat, ColorDepth, YuvColorSpace, ColorRange), RadialGradient, LinearGradient, + Opacity, } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum BatchKind { SplitComposite, TextRun(GlyphFormat), @@ -74,16 +75,17 @@ impl BatchKind { match self { BatchKind::Brush(BrushBatchKind::Solid) => BrushShaderKind::Solid, BatchKind::Brush(BrushBatchKind::Image(..)) => BrushShaderKind::Image, BatchKind::Brush(BrushBatchKind::LinearGradient) => BrushShaderKind::LinearGradient, BatchKind::Brush(BrushBatchKind::RadialGradient) => BrushShaderKind::RadialGradient, BatchKind::Brush(BrushBatchKind::Blend) => BrushShaderKind::Blend, BatchKind::Brush(BrushBatchKind::MixBlend { .. }) => BrushShaderKind::MixBlend, BatchKind::Brush(BrushBatchKind::YuvImage(..)) => BrushShaderKind::Yuv, + BatchKind::Brush(BrushBatchKind::Opacity) => BrushShaderKind::Opacity, BatchKind::TextRun(..) => BrushShaderKind::Text, _ => BrushShaderKind::None, } } } /// Optional textures that can be used as a source in the shaders. /// Textures that are not used by the batch are equal to TextureId::invalid(). @@ -1361,16 +1363,51 @@ impl BatchBuilder { EdgeAaSegmentMask::empty(), clip_task_address.unwrap(), brush_flags, content_prim_header_index, content_uv_rect_address, prim_vis_mask, ); } + Filter::Opacity(_, amount) => { + let amount = (amount * 65536.0) as i32; + + let (uv_rect_address, textures) = render_tasks.resolve_surface( + surface_task.expect("bug: surface must be allocated by now"), + gpu_cache, + ); + + let key = BatchKey::new( + BatchKind::Brush(BrushBatchKind::Opacity), + BlendMode::PremultipliedAlpha, + textures, + ); + + let prim_header_index = prim_headers.push(&prim_header, z_id, [ + uv_rect_address.as_int(), + amount, + 0, + 0, + ]); + + self.add_brush_instance_to_batches( + key, + batch_features, + bounding_rect, + z_id, + INVALID_SEGMENT_INDEX, + EdgeAaSegmentMask::empty(), + clip_task_address.unwrap(), + brush_flags, + prim_header_index, + 0, + prim_vis_mask, + ); + } _ => { let filter_mode = match filter { Filter::Identity => 1, // matches `Contrast(1)` Filter::Blur(..) => 0, Filter::Contrast(..) => 1, Filter::Grayscale(..) => 2, Filter::HueRotate(..) => 3, Filter::Invert(..) => 4,
--- a/gfx/wr/webrender/src/gpu_types.rs +++ b/gfx/wr/webrender/src/gpu_types.rs @@ -76,16 +76,17 @@ pub enum BrushShaderKind { Solid = 1, Image = 2, Text = 3, LinearGradient = 4, RadialGradient = 5, Blend = 6, MixBlend = 7, Yuv = 8, + Opacity = 9, } #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[repr(C)] pub enum RasterizationSpace { Local = 0,
--- a/gfx/wr/webrender/src/renderer.rs +++ b/gfx/wr/webrender/src/renderer.rs @@ -136,16 +136,20 @@ pub const MAX_VERTEX_TEXTURE_WIDTH: usiz /// Enabling this toggle would force the GPU cache scattered texture to /// be resized every frame, which enables GPU debuggers to see if this /// is performed correctly. const GPU_CACHE_RESIZE_TEST: bool = false; /// Number of GPU blocks per UV rectangle provided for an image. pub const BLOCKS_PER_UV_RECT: usize = 2; +const GPU_TAG_BRUSH_OPACITY: GpuProfileTag = GpuProfileTag { + label: "B_Opacity", + color: debug_colors::DARKMAGENTA, +}; const GPU_TAG_BRUSH_LINEAR_GRADIENT: GpuProfileTag = GpuProfileTag { label: "B_LinearGradient", color: debug_colors::POWDERBLUE, }; const GPU_TAG_BRUSH_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag { label: "B_RadialGradient", color: debug_colors::LIGHTPINK, }; @@ -248,16 +252,17 @@ impl BatchKind { match kind { BrushBatchKind::Solid => "Brush (Solid)", BrushBatchKind::Image(..) => "Brush (Image)", BrushBatchKind::Blend => "Brush (Blend)", BrushBatchKind::MixBlend { .. } => "Brush (Composite)", BrushBatchKind::YuvImage(..) => "Brush (YuvImage)", BrushBatchKind::RadialGradient => "Brush (RadialGradient)", BrushBatchKind::LinearGradient => "Brush (LinearGradient)", + BrushBatchKind::Opacity => "Brush (Opacity)", } } BatchKind::TextRun(_) => "TextRun", } } fn sampler_tag(&self) -> GpuProfileTag { match *self { @@ -266,16 +271,17 @@ impl BatchKind { match kind { BrushBatchKind::Solid => GPU_TAG_BRUSH_SOLID, BrushBatchKind::Image(..) => GPU_TAG_BRUSH_IMAGE, BrushBatchKind::Blend => GPU_TAG_BRUSH_BLEND, BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND, BrushBatchKind::YuvImage(..) => GPU_TAG_BRUSH_YUV_IMAGE, BrushBatchKind::RadialGradient => GPU_TAG_BRUSH_RADIAL_GRADIENT, BrushBatchKind::LinearGradient => GPU_TAG_BRUSH_LINEAR_GRADIENT, + BrushBatchKind::Opacity => GPU_TAG_BRUSH_OPACITY, } } BatchKind::TextRun(_) => GPU_TAG_PRIM_TEXT_RUN, } } } fn flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Option<bool> {
--- a/gfx/wr/webrender/src/shade.rs +++ b/gfx/wr/webrender/src/shade.rs @@ -533,16 +533,17 @@ pub struct Shaders { brush_solid: BrushShader, brush_image: Vec<Option<BrushShader>>, brush_fast_image: Vec<Option<BrushShader>>, brush_blend: BrushShader, brush_mix_blend: BrushShader, brush_yuv_image: Vec<Option<BrushShader>>, brush_radial_gradient: BrushShader, brush_linear_gradient: BrushShader, + brush_opacity: BrushShader, /// These are "cache clip shaders". These shaders are used to /// draw clip instances into the cached clip mask. The results /// of these shaders are also used by the primitive shaders. pub cs_clip_rectangle_slow: LazilyCompiledShader, pub cs_clip_rectangle_fast: LazilyCompiledShader, pub cs_clip_box_shadow: LazilyCompiledShader, pub cs_clip_image: LazilyCompiledShader, @@ -636,16 +637,26 @@ impl Shaders { &[] }, options.precache_flags, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, )?; + let brush_opacity = BrushShader::new( + "brush_opacity", + device, + &[], + options.precache_flags, + false /* advanced blend */, + false /* dual source */, + use_pixel_local_storage, + )?; + let cs_blur_a8 = LazilyCompiledShader::new( ShaderKind::Cache(VertexArrayKind::Blur), "cs_blur", &["ALPHA_TARGET"], device, options.precache_flags, )?; @@ -890,16 +901,17 @@ impl Shaders { brush_solid, brush_image, brush_fast_image, brush_blend, brush_mix_blend, brush_yuv_image, brush_radial_gradient, brush_linear_gradient, + brush_opacity, cs_clip_rectangle_slow, cs_clip_rectangle_fast, cs_clip_box_shadow, cs_clip_image, pls_init, pls_resolve, ps_text_run, ps_text_run_dual_source, @@ -950,16 +962,19 @@ impl Shaders { } BrushBatchKind::YuvImage(image_buffer_kind, ..) => { let shader_index = Self::get_yuv_shader_index(image_buffer_kind); self.brush_yuv_image[shader_index] .as_mut() .expect("Unsupported YUV shader kind") } + BrushBatchKind::Opacity => { + &mut self.brush_opacity + } }; brush_shader.get(key.blend_mode, debug_flags) } BatchKind::TextRun(glyph_format) => { let text_shader = match key.blend_mode { BlendMode::SubpixelDualSource => &mut self.ps_text_run_dual_source, _ => &mut self.ps_text_run, }; @@ -973,16 +988,17 @@ impl Shaders { self.cs_blur_a8.deinit(device); self.cs_blur_rgba8.deinit(device); self.cs_svg_filter.deinit(device); self.brush_solid.deinit(device); self.brush_blend.deinit(device); self.brush_mix_blend.deinit(device); self.brush_radial_gradient.deinit(device); self.brush_linear_gradient.deinit(device); + self.brush_opacity.deinit(device); self.cs_clip_rectangle_slow.deinit(device); self.cs_clip_rectangle_fast.deinit(device); self.cs_clip_box_shadow.deinit(device); self.cs_clip_image.deinit(device); self.pls_init.deinit(device); self.pls_resolve.deinit(device); self.ps_text_run.deinit(device); self.ps_text_run_dual_source.deinit(device);
--- a/gfx/wr/webrender/tests/angle_shader_validation.rs +++ b/gfx/wr/webrender/tests/angle_shader_validation.rs @@ -108,16 +108,20 @@ const SHADERS: &[Shader] = &[ Shader { name: "brush_radial_gradient", features: GRADIENT_FEATURES, }, Shader { name: "brush_linear_gradient", features: GRADIENT_FEATURES, }, + Shader { + name: "brush_opacity", + features: BRUSH_FEATURES, + }, ]; const VERSION_STRING: &str = "#version 300 es\n"; #[test] fn validate_shaders() { mozangle::shaders::initialize().unwrap();