Commit a13c5f52 authored by Xu Xing's avatar Xu Xing Committed by Commit Bot

viz: Support background filter in SkiaRenderer

This passes all current css/filters layout tests and skia renderer
backdrop filter pixel test.

Remove the TODO(skaslev): The software renderer does not support filters yet.

BUG=822857,828728

Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel
Change-Id: I6f96259249612e8655c953bdd6a534ae9f5c6acc
Reviewed-on: https://chromium-review.googlesource.com/985635
Commit-Queue: Xing Xu <xing.xu@intel.com>
Reviewed-by: default avatarenne <enne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#552260}
parent ef786057
...@@ -2486,16 +2486,14 @@ class RendererPixelTestWithBackgroundFilter ...@@ -2486,16 +2486,14 @@ class RendererPixelTestWithBackgroundFilter
gfx::Rect filter_pass_layer_rect_; gfx::Rect filter_pass_layer_rect_;
}; };
// The software renderer does not support background filters yet.
using BackgroundFilterRendererTypes = using BackgroundFilterRendererTypes =
::testing::Types<GLRenderer, SoftwareRenderer>; ::testing::Types<GLRenderer, SkiaRenderer>;
TYPED_TEST_CASE(RendererPixelTestWithBackgroundFilter, TYPED_TEST_CASE(RendererPixelTestWithBackgroundFilter,
BackgroundFilterRendererTypes); BackgroundFilterRendererTypes);
using GLRendererPixelTestWithBackgroundFilter = TYPED_TEST(RendererPixelTestWithBackgroundFilter, InvertFilter) {
RendererPixelTestWithBackgroundFilter<GLRenderer>;
// TODO(skaslev): The software renderer does not support filters yet.
TEST_F(GLRendererPixelTestWithBackgroundFilter, InvertFilter) {
this->background_filters_.Append( this->background_filters_.Append(
cc::FilterOperation::CreateInvertFilter(1.f)); cc::FilterOperation::CreateInvertFilter(1.f));
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/include/effects/SkOverdrawColorFilter.h" #include "third_party/skia/include/effects/SkOverdrawColorFilter.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "ui/gfx/geometry/axis_transform2d.h" #include "ui/gfx/geometry/axis_transform2d.h"
#include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/skia_util.h" #include "ui/gfx/skia_util.h"
...@@ -57,9 +56,8 @@ namespace viz { ...@@ -57,9 +56,8 @@ namespace viz {
struct SkiaRenderer::DrawRenderPassDrawQuadParams { struct SkiaRenderer::DrawRenderPassDrawQuadParams {
// The "in" parameters that will be used when apply filters. // The "in" parameters that will be used when apply filters.
const cc::FilterOperations* filters = nullptr; const cc::FilterOperations* filters = nullptr;
const cc::FilterOperations* background_filters = nullptr;
// The "out" parameters that will be returned for future use. // The "out" parameters returned by filters.
// A Skia image that should be sampled from instead of the original // A Skia image that should be sampled from instead of the original
// contents. // contents.
sk_sp<SkImage> filter_image; sk_sp<SkImage> filter_image;
...@@ -651,7 +649,6 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) { ...@@ -651,7 +649,6 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
DrawRenderPassDrawQuadParams params; DrawRenderPassDrawQuadParams params;
params.filters = FiltersForPass(quad->render_pass_id); params.filters = FiltersForPass(quad->render_pass_id);
params.background_filters = BackgroundFiltersForPass(quad->render_pass_id);
bool can_draw = CalculateRPDQParams(content, quad, &params); bool can_draw = CalculateRPDQParams(content, quad, &params);
if (!can_draw) if (!can_draw)
...@@ -670,8 +667,6 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) { ...@@ -670,8 +667,6 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
QuadVertexRect(), gfx::RectF(quad->rect), QuadVertexRect(), gfx::RectF(quad->rect),
gfx::RectF(quad->visible_rect))); gfx::RectF(quad->visible_rect)));
} }
current_canvas_->drawImageRect(content, content_rect, dest_visible_rect,
&current_paint_);
SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect()); SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect());
...@@ -688,11 +683,19 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) { ...@@ -688,11 +683,19 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
NOTIMPLEMENTED(); NOTIMPLEMENTED();
} }
// TODO(weiliangc): If we have a background filter shader, render its // If we have a background filter shader, render its results first.
// results first. (https://crbug.com/644851) sk_sp<SkShader> background_filter_shader =
if (ShouldApplyBackgroundFilters(quad, params.background_filters)) { GetBackgroundFilterShader(quad, SkShader::kClamp_TileMode);
if (background_filter_shader) {
SkPaint paint;
paint.setShader(std::move(background_filter_shader));
paint.setMaskFilter(current_paint_.refMaskFilter());
current_canvas_->drawRect(dest_visible_rect, paint);
current_paint_.setShader(std::move(shader)); current_paint_.setShader(std::move(shader));
current_canvas_->drawRect(dest_visible_rect, current_paint_); current_canvas_->drawRect(dest_visible_rect, current_paint_);
} else {
current_canvas_->drawImageRect(content, content_rect, dest_visible_rect,
&current_paint_);
} }
} }
...@@ -773,20 +776,17 @@ bool SkiaRenderer::ShouldApplyBackgroundFilters( ...@@ -773,20 +776,17 @@ bool SkiaRenderer::ShouldApplyBackgroundFilters(
return true; return true;
} }
SkBitmap SkiaRenderer::GetBackdropBitmap(const gfx::Rect& bounding_rect) const { sk_sp<SkImage> SkiaRenderer::GetBackdropImage(
SkBitmap bitmap; const gfx::Rect& bounding_rect) const {
bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounding_rect.width(), return root_surface_->makeImageSnapshot()->makeSubset(
bounding_rect.height())); gfx::RectToSkIRect(bounding_rect));
if (!current_canvas_->readPixels(bitmap, bounding_rect.x(),
bounding_rect.y()))
bitmap.reset();
return bitmap;
} }
gfx::Rect SkiaRenderer::GetBackdropBoundingBoxForRenderPassQuad( gfx::Rect SkiaRenderer::GetBackdropBoundingBoxForRenderPassQuad(
const RenderPassDrawQuad* quad, const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform, const gfx::Transform& contents_device_transform,
const cc::FilterOperations* background_filters) const { const cc::FilterOperations* background_filters,
gfx::Rect* unclipped_rect) const {
DCHECK(ShouldApplyBackgroundFilters(quad, background_filters)); DCHECK(ShouldApplyBackgroundFilters(quad, background_filters));
gfx::Rect backdrop_rect = gfx::ToEnclosingRect(cc::MathUtil::MapClippedRect( gfx::Rect backdrop_rect = gfx::ToEnclosingRect(cc::MathUtil::MapClippedRect(
contents_device_transform, QuadVertexRect())); contents_device_transform, QuadVertexRect()));
...@@ -795,18 +795,109 @@ gfx::Rect SkiaRenderer::GetBackdropBoundingBoxForRenderPassQuad( ...@@ -795,18 +795,109 @@ gfx::Rect SkiaRenderer::GetBackdropBoundingBoxForRenderPassQuad(
matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y()); matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y());
backdrop_rect = background_filters->MapRectReverse(backdrop_rect, matrix); backdrop_rect = background_filters->MapRectReverse(backdrop_rect, matrix);
*unclipped_rect = backdrop_rect;
backdrop_rect.Intersect(MoveFromDrawToWindowSpace( backdrop_rect.Intersect(MoveFromDrawToWindowSpace(
current_frame()->current_render_pass->output_rect)); current_frame()->current_render_pass->output_rect));
return backdrop_rect; return backdrop_rect;
} }
// If non-null, auto_bounds will be filled with the automatically-computed
// destination bounds. If null, the output will be the same size as the
// input image.
sk_sp<SkImage> SkiaRenderer::ApplyBackgroundFilters(
SkImageFilter* filter,
const RenderPassDrawQuad* quad,
sk_sp<SkImage> src_image,
const gfx::Rect& rect) const {
if (!filter)
return nullptr;
SkMatrix local_matrix;
local_matrix.setTranslate(quad->filters_origin.x(), quad->filters_origin.y());
local_matrix.postScale(quad->filters_scale.x(), quad->filters_scale.y());
SkImageInfo image_info =
SkImageInfo::Make(rect.width(), rect.height(), src_image->colorType(),
src_image->alphaType(), nullptr);
#if BUILDFLAG(ENABLE_VULKAN)
// TODO(xing.xu): Handle Vulkan related logic here.
#else
GrContext* gr_context = output_surface_->context_provider()->GrContext();
// TODO(weiliangc): Set up correct can_use_lcd_text for SkSurfaceProps flags.
// How to setup is in ResourceProvider. (http://crbug.com/644851)
// LegacyFontHost will get LCD text and skia figures out what type to use.
SkSurfaceProps surface_props(0, SkSurfaceProps::kLegacyFontHost_InitType);
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
gr_context, SkBudgeted::kNo, image_info, 0, kBottomLeft_GrSurfaceOrigin,
&surface_props, false);
#endif
if (!surface) {
return nullptr;
}
SkPaint paint;
// Treat subnormal float values as zero for performance.
cc::ScopedSubnormalFloatDisabler disabler;
paint.setImageFilter(filter->makeWithLocalMatrix(local_matrix));
surface->getCanvas()->translate(-rect.x(), -rect.y());
surface->getCanvas()->drawImage(src_image, rect.x(), rect.y(), &paint);
return surface->makeImageSnapshot();
}
sk_sp<SkShader> SkiaRenderer::GetBackgroundFilterShader( sk_sp<SkShader> SkiaRenderer::GetBackgroundFilterShader(
const RenderPassDrawQuad* quad, const RenderPassDrawQuad* quad,
SkShader::TileMode content_tile_mode) const { SkShader::TileMode content_tile_mode) const {
// TODO(weiliangc): properly implement background filters. (crbug.com/644851) const cc::FilterOperations* background_filters =
NOTIMPLEMENTED(); BackgroundFiltersForPass(quad->render_pass_id);
return nullptr; if (!ShouldApplyBackgroundFilters(quad, background_filters))
return nullptr;
gfx::Transform quad_rect_matrix;
QuadRectTransform(&quad_rect_matrix,
quad->shared_quad_state->quad_to_target_transform,
gfx::RectF(quad->rect));
gfx::Transform contents_device_transform =
current_frame()->window_matrix * current_frame()->projection_matrix *
quad_rect_matrix;
contents_device_transform.FlattenTo2d();
gfx::Rect unclipped_rect;
gfx::Rect backdrop_rect = GetBackdropBoundingBoxForRenderPassQuad(
quad, contents_device_transform, background_filters, &unclipped_rect);
// Figure out the transformations to move it back to pixel space.
gfx::Transform contents_device_transform_inverse;
if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
return nullptr;
SkMatrix filter_backdrop_transform =
contents_device_transform_inverse.matrix();
filter_backdrop_transform.preTranslate(backdrop_rect.x(), backdrop_rect.y());
// Apply the filter to the backdrop.
sk_sp<SkImage> backdrop_image = GetBackdropImage(backdrop_rect);
gfx::Vector2dF clipping_offset =
(unclipped_rect.top_right() - backdrop_rect.top_right()) +
(backdrop_rect.bottom_left() - unclipped_rect.bottom_left());
sk_sp<SkImageFilter> filter =
cc::RenderSurfaceFilters::BuildImageFilter(
*background_filters,
gfx::SizeF(backdrop_image->width(), backdrop_image->height()),
clipping_offset)
->cached_sk_filter_;
sk_sp<SkImage> filter_backdrop_image =
ApplyBackgroundFilters(filter.get(), quad, backdrop_image, backdrop_rect);
if (!filter_backdrop_image)
return nullptr;
return filter_backdrop_image->makeShader(content_tile_mode, content_tile_mode,
&filter_backdrop_transform);
} }
void SkiaRenderer::UpdateRenderPassTextures( void SkiaRenderer::UpdateRenderPassTextures(
......
...@@ -95,8 +95,14 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer { ...@@ -95,8 +95,14 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
gfx::Rect GetBackdropBoundingBoxForRenderPassQuad( gfx::Rect GetBackdropBoundingBoxForRenderPassQuad(
const RenderPassDrawQuad* quad, const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform, const gfx::Transform& contents_device_transform,
const cc::FilterOperations* background_filters) const; const cc::FilterOperations* background_filters,
SkBitmap GetBackdropBitmap(const gfx::Rect& bounding_rect) const; gfx::Rect* unclipped_rect) const;
sk_sp<SkImage> ApplyBackgroundFilters(SkImageFilter* filter,
const RenderPassDrawQuad* quad,
sk_sp<SkImage> src_image,
const gfx::Rect& rect) const;
sk_sp<SkImage> GetBackdropImage(const gfx::Rect& bounding_rect) const;
sk_sp<SkShader> GetBackgroundFilterShader( sk_sp<SkShader> GetBackgroundFilterShader(
const RenderPassDrawQuad* quad, const RenderPassDrawQuad* quad,
SkShader::TileMode content_tile_mode) const; SkShader::TileMode content_tile_mode) const;
......
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