Commit 87db6a86 authored by Michael Ludwig's avatar Michael Ludwig Committed by Commit Bot

SkiaRenderer: implify how RPDQ mask images are applied using clipShader

DrawRPDQParams now just holds on to an SkShader that represents the mask image
and the local matrix that needs to be applied to it. This removes a use of
SkShaderMaskFilter that tried to combine the mask shader into the SkPaint of
the draw. Instead, the mask is always applied by using SkCanvas::clipShader,
which helps unify the code between a layer-needing RPDQ, an image RPDQ, and
a solid color RPDQ. Having a mask image also no longer impacts whether or not
a saveLayer() is needed because it is applied last (as desired), so
skia_renderer no longer has to juggle the order that effect is applied in.

Change-Id: I3d9ce085d498fabec42e112b0cb36e9707b96c8e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2303672Reviewed-by: default avatarweiliangc <weiliangc@chromium.org>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Cr-Commit-Position: refs/heads/master@{#789580}
parent 08cb723f
...@@ -425,9 +425,9 @@ struct SkiaRenderer::DrawRPDQParams { ...@@ -425,9 +425,9 @@ struct SkiaRenderer::DrawRPDQParams {
sk_sp<SkColorFilter> color_filter = nullptr; sk_sp<SkColorFilter> color_filter = nullptr;
// Root of the calculated backdrop filter DAG to be applied to the render pass // Root of the calculated backdrop filter DAG to be applied to the render pass
sk_sp<SkImageFilter> backdrop_filter = nullptr; sk_sp<SkImageFilter> backdrop_filter = nullptr;
// Resolved mask image and calculated transform matrix // Resolved mask image and calculated transform matrix baked into an SkShader,
sk_sp<SkImage> mask_image = nullptr; // which will be applied using SkCanvas::clipShader in RPDQ's coord space.
SkMatrix mask_to_quad_matrix; sk_sp<SkShader> mask_shader = nullptr;
// Backdrop border box for the render pass, to clip backdrop-filtered content // Backdrop border box for the render pass, to clip backdrop-filtered content
base::Optional<gfx::RRectF> backdrop_filter_bounds; base::Optional<gfx::RRectF> backdrop_filter_bounds;
// The content space bounds that includes any filtered extents. If empty, // The content space bounds that includes any filtered extents. If empty,
...@@ -540,14 +540,11 @@ SkiaRenderer::DrawQuadParams::DrawQuadParams(const gfx::Transform& cdt, ...@@ -540,14 +540,11 @@ SkiaRenderer::DrawQuadParams::DrawQuadParams(const gfx::Transform& cdt,
enum class SkiaRenderer::BypassMode { enum class SkiaRenderer::BypassMode {
// The RenderPass's contents' blendmode would have made a transparent black // The RenderPass's contents' blendmode would have made a transparent black
// image // image and the RenderPass's own blend mode does not effect transparent black
// and the RenderPass's own blend mode has no effect on transparent black.
kSkip, kSkip,
// The renderPass's contents' creates a transparent image, but the // The renderPass's contents' creates a transparent image, but the
// RenderPass's // RenderPass's own blend mode must still process the transparent pixels (e.g.
// own blend mode must still process the transparent pixels (e.g. certain // certain filters affect transparent black).
// filters
// affect transparent black).
kDrawTransparentQuad, kDrawTransparentQuad,
// Can draw the bypass quad with the modified parameters // Can draw the bypass quad with the modified parameters
kDrawBypassQuad kDrawBypassQuad
...@@ -1145,20 +1142,6 @@ void SkiaRenderer::PrepareCanvasForRPDQ(const DrawRPDQParams& rpdq_params, ...@@ -1145,20 +1142,6 @@ void SkiaRenderer::PrepareCanvasForRPDQ(const DrawRPDQParams& rpdq_params,
} }
} }
if (rpdq_params.mask_image.get()) {
// The old behavior (in skia) was to filter the clipmask based on the
// setting in the layer's paint. Now we can set that to whatever we want
// when we make the clip-shader. For now, I will replicate the old (impl)
// logic.
SkFilterQuality filtering =
layer_paint.getFilterQuality() == kNone_SkFilterQuality
? kNone_SkFilterQuality
: kLow_SkFilterQuality;
current_canvas_->save();
current_canvas_->clipShader(rpdq_params.mask_image->makeShader(
SkTileMode::kClamp, SkTileMode::kClamp,
&rpdq_params.mask_to_quad_matrix, filtering));
}
SkRect bounds = gfx::RectFToSkRect(rpdq_params.bypass_clip.has_value() SkRect bounds = gfx::RectFToSkRect(rpdq_params.bypass_clip.has_value()
? *rpdq_params.bypass_clip ? *rpdq_params.bypass_clip
: params->visible_rect); : params->visible_rect);
...@@ -1196,16 +1179,21 @@ void SkiaRenderer::PreparePaintOrCanvasForRPDQ( ...@@ -1196,16 +1179,21 @@ void SkiaRenderer::PreparePaintOrCanvasForRPDQ(
// the canvas. But there are several requirements in order for the order of // the canvas. But there are several requirements in order for the order of
// operations to be consistent with what RenderPasses require: // operations to be consistent with what RenderPasses require:
// 1. Backdrop filtering always requires a layer. // 1. Backdrop filtering always requires a layer.
// 2. A complex image filter needs a layer if there is a mask, since Skia // 2. The content bypassing the renderpass needs to be clipped before the
// applies the mask filter before the paint's image filter.
// 3. The content bypassing the renderpass needs to be clipped before the
// image filter is evaluated. // image filter is evaluated.
bool needs_bypass_clip = rpdq_params.needs_bypass_clip(params->visible_rect); bool needs_bypass_clip = rpdq_params.needs_bypass_clip(params->visible_rect);
bool needs_save_layer = false; bool needs_save_layer = false;
if (rpdq_params.backdrop_filter) if (rpdq_params.backdrop_filter)
needs_save_layer = true; needs_save_layer = true;
else if (rpdq_params.has_complex_image_filter()) else if (rpdq_params.has_complex_image_filter())
needs_save_layer = rpdq_params.mask_image || needs_bypass_clip; needs_save_layer = needs_bypass_clip;
if (rpdq_params.mask_shader) {
// Apply the mask image using clipShader(), this works the same regardless
// of if we need a saveLayer for image filtering since the clip is applied
// at the end automatically.
current_canvas_->clipShader(rpdq_params.mask_shader);
}
if (needs_save_layer) { if (needs_save_layer) {
PrepareCanvasForRPDQ(rpdq_params, params); PrepareCanvasForRPDQ(rpdq_params, params);
...@@ -1213,12 +1201,10 @@ void SkiaRenderer::PreparePaintOrCanvasForRPDQ( ...@@ -1213,12 +1201,10 @@ void SkiaRenderer::PreparePaintOrCanvasForRPDQ(
paint->setAlphaf(params->opacity); paint->setAlphaf(params->opacity);
paint->setBlendMode(params->blend_mode); paint->setBlendMode(params->blend_mode);
} else { } else {
// At this point, the image filter and/or color filter can be set on the // At this point, the image filter and/or color filter are on the paint.
// paint. If there is a mask image, it can be converted to a mask shader.
DCHECK(!rpdq_params.backdrop_filter); DCHECK(!rpdq_params.backdrop_filter);
if (rpdq_params.color_filter) { if (rpdq_params.color_filter) {
// Use the color filter directly, instead of the image filter; since color // Use the color filter directly, instead of the image filter.
// filters are applied before masks, this could be combined with a mask
if (paint->getColorFilter()) { if (paint->getColorFilter()) {
paint->setColorFilter( paint->setColorFilter(
rpdq_params.color_filter->makeComposed(paint->refColorFilter())); rpdq_params.color_filter->makeComposed(paint->refColorFilter()));
...@@ -1227,9 +1213,7 @@ void SkiaRenderer::PreparePaintOrCanvasForRPDQ( ...@@ -1227,9 +1213,7 @@ void SkiaRenderer::PreparePaintOrCanvasForRPDQ(
} }
DCHECK(paint->getColorFilter()); DCHECK(paint->getColorFilter());
} else if (rpdq_params.image_filter) { } else if (rpdq_params.image_filter) {
// Store the image filter on the paint, but since this effect is applied // Store the image filter on the paint.
// last it's not compatible with masks as a shader
DCHECK(!rpdq_params.mask_image);
if (params->opacity != 1.f) { if (params->opacity != 1.f) {
// Apply opacity as the last step of image filter so it is uniform // Apply opacity as the last step of image filter so it is uniform
// across any overlapping content produced by the image filters. // across any overlapping content produced by the image filters.
...@@ -1242,29 +1226,6 @@ void SkiaRenderer::PreparePaintOrCanvasForRPDQ( ...@@ -1242,29 +1226,6 @@ void SkiaRenderer::PreparePaintOrCanvasForRPDQ(
paint->setImageFilter(rpdq_params.image_filter); paint->setImageFilter(rpdq_params.image_filter);
} }
} }
// This is not an else-if since the color filter image filter can be
// combined with the mask filter correctly.
if (rpdq_params.mask_image) {
// The mask shader is evaluated in the bypass'ed quad's local coordinate
// space, so must update the shader matrix to still sample the image in
// the RP coordinate space.
SkMatrix local_matrix = SkMatrix::I();
if (rpdq_params.bypass_transform.has_value()) {
bool inverted = rpdq_params.bypass_transform->invert(&local_matrix);
// Invertibility was a requirement for being bypassable.
DCHECK(inverted);
}
local_matrix.preConcat(rpdq_params.mask_to_quad_matrix);
auto mask_filter = SkShaderMaskFilter::Make(
rpdq_params.mask_image->makeShader(&local_matrix));
// Confirm that the paint didn't already have a mask filter, and that it's
// captured properly afterwards on the paint.
DCHECK(!paint->getMaskFilter());
paint->setMaskFilter(std::move(mask_filter));
DCHECK(paint->getMaskFilter());
}
} }
// Whether or not we saved a layer, clip the bypassed RenderPass's content // Whether or not we saved a layer, clip the bypassed RenderPass's content
...@@ -1281,8 +1242,12 @@ void SkiaRenderer::PrepareColorOrCanvasForRPDQ( ...@@ -1281,8 +1242,12 @@ void SkiaRenderer::PrepareColorOrCanvasForRPDQ(
// When the draw call only takes a color and not an SkPaint, rpdq params // When the draw call only takes a color and not an SkPaint, rpdq params
// with just a color filter can be handled directly. Otherwise, the rpdq // with just a color filter can be handled directly. Otherwise, the rpdq
// params must use a layer on the canvas. // params must use a layer on the canvas.
bool needs_save_layer = rpdq_params.has_complex_image_filter() || bool needs_save_layer =
rpdq_params.backdrop_filter || rpdq_params.mask_image; rpdq_params.has_complex_image_filter() || rpdq_params.backdrop_filter;
if (rpdq_params.mask_shader) {
current_canvas_->clipShader(rpdq_params.mask_shader);
}
if (needs_save_layer) { if (needs_save_layer) {
PrepareCanvasForRPDQ(rpdq_params, params); PrepareCanvasForRPDQ(rpdq_params, params);
} else if (rpdq_params.color_filter) { } else if (rpdq_params.color_filter) {
...@@ -2326,15 +2291,17 @@ SkiaRenderer::DrawRPDQParams SkiaRenderer::CalculateRPDQParams( ...@@ -2326,15 +2291,17 @@ SkiaRenderer::DrawRPDQParams SkiaRenderer::CalculateRPDQParams(
const SkImage* mask_image = mask_image_builder.sk_image(); const SkImage* mask_image = mask_image_builder.sk_image();
DCHECK_EQ(!!mask_resource_id, !!mask_image); DCHECK_EQ(!!mask_resource_id, !!mask_image);
if (mask_image) { if (mask_image) {
rpdq_params.mask_image = sk_ref_sp(mask_image);
// Scale normalized uv rect into absolute texel coordinates. // Scale normalized uv rect into absolute texel coordinates.
SkRect mask_rect = gfx::RectFToSkRect( SkRect mask_rect = gfx::RectFToSkRect(
gfx::ScaleRect(quad->mask_uv_rect, quad->mask_texture_size.width(), gfx::ScaleRect(quad->mask_uv_rect, quad->mask_texture_size.width(),
quad->mask_texture_size.height())); quad->mask_texture_size.height()));
// Map to full quad rect so that mask coordinates don't change with clipping // Map to full quad rect so that mask coordinates don't change with clipping
rpdq_params.mask_to_quad_matrix = SkMatrix::MakeRectToRect( SkMatrix mask_to_quad_matrix = SkMatrix::MakeRectToRect(
mask_rect, gfx::RectToSkRect(quad->rect), SkMatrix::kFill_ScaleToFit); mask_rect, gfx::RectToSkRect(quad->rect), SkMatrix::kFill_ScaleToFit);
rpdq_params.mask_shader =
mask_image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
&mask_to_quad_matrix, kLow_SkFilterQuality);
} }
const cc::FilterOperations* filters = FiltersForPass(quad->render_pass_id); const cc::FilterOperations* filters = FiltersForPass(quad->render_pass_id);
...@@ -2515,7 +2482,7 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad, ...@@ -2515,7 +2482,7 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad,
// When the RPDQ was needed because of a copy request, it may not require any // When the RPDQ was needed because of a copy request, it may not require any
// advanced filtering/effects at which point it's basically a tiled quad. // advanced filtering/effects at which point it's basically a tiled quad.
if (!rpdq_params.image_filter && !rpdq_params.backdrop_filter && if (!rpdq_params.image_filter && !rpdq_params.backdrop_filter &&
!rpdq_params.mask_image) { !rpdq_params.mask_shader) {
DCHECK(!MustFlushBatchedQuads(quad, nullptr, *params)); DCHECK(!MustFlushBatchedQuads(quad, nullptr, *params));
AddQuadToBatch(content_image.get(), valid_texel_bounds, params); AddQuadToBatch(content_image.get(), valid_texel_bounds, params);
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment