Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync changes from mozilla-central #3831

Merged
merged 3 commits into from Jan 14, 2020
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

Bug 1607746 - Part 1: Move opacity to its own shader in WebRender r=n…

…ical

Opacity is a common effect that is used and the opacit filter path is also used when a stacking
context has an opacity of < 1. The brush_blend shader is slow since it has support for a large
portion of CSS filters; however, opacity is used much more often than the rest of the filters.
This patch adds a simple shader for opacity effects which bypasses the extra overhead in the
brush_blend shader.

Differential Revision: https://phabricator.services.mozilla.com/D59610

[wrupdater] From https://hg.mozilla.org/mozilla-central/rev/b0226237c55e4a08f4deb622fc15fa1e85f39afc
  • Loading branch information
cbrewster authored and moz-gfx committed Jan 14, 2020
commit 7c04f9d8489ed7e7f4476ed476b739ebef60e111
@@ -90,6 +90,7 @@ 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,
@@ -255,6 +256,7 @@ 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) {
@@ -21,6 +21,7 @@
#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);

@@ -70,6 +71,14 @@ int vecs_per_brush(int brush_kind);
#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
@@ -99,6 +108,10 @@ int vecs_per_brush(int brush_kind) {
#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
}
}

@@ -159,6 +172,12 @@ void multi_brush_vs(
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
}
}

@@ -193,6 +212,10 @@ Fragment multi_brush_fs(int brush_kind) {
#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
}
}

@@ -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
@@ -58,6 +58,7 @@ pub enum BrushBatchKind {
YuvImage(ImageBufferKind, YuvFormat, ColorDepth, YuvColorSpace, ColorRange),
RadialGradient,
LinearGradient,
Opacity,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -79,6 +80,7 @@ impl BatchKind {
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,
}
@@ -1366,6 +1368,41 @@ impl BatchBuilder {
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)`
@@ -81,6 +81,7 @@ pub enum BrushShaderKind {
Blend = 6,
MixBlend = 7,
Yuv = 8,
Opacity = 9,
}

#[derive(Debug, Copy, Clone)]
@@ -141,6 +141,10 @@ 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,
@@ -253,6 +257,7 @@ impl BatchKind {
BrushBatchKind::YuvImage(..) => "Brush (YuvImage)",
BrushBatchKind::RadialGradient => "Brush (RadialGradient)",
BrushBatchKind::LinearGradient => "Brush (LinearGradient)",
BrushBatchKind::Opacity => "Brush (Opacity)",
}
}
BatchKind::TextRun(_) => "TextRun",
@@ -271,6 +276,7 @@ impl BatchKind {
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,
@@ -538,6 +538,7 @@ pub struct Shaders {
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
@@ -641,6 +642,16 @@ impl Shaders {
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",
@@ -895,6 +906,7 @@ impl Shaders {
brush_yuv_image,
brush_radial_gradient,
brush_linear_gradient,
brush_opacity,
cs_clip_rectangle_slow,
cs_clip_rectangle_fast,
cs_clip_box_shadow,
@@ -955,6 +967,9 @@ impl Shaders {
.as_mut()
.expect("Unsupported YUV shader kind")
}
BrushBatchKind::Opacity => {
&mut self.brush_opacity
}
};
brush_shader.get(key.blend_mode, debug_flags)
}
@@ -978,6 +993,7 @@ impl Shaders {
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);
@@ -113,6 +113,10 @@ const SHADERS: &[Shader] = &[
name: "brush_linear_gradient",
features: GRADIENT_FEATURES,
},
Shader {
name: "brush_opacity",
features: BRUSH_FEATURES,
},
];

const VERSION_STRING: &str = "#version 300 es\n";
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.