Commit 8f933f0c authored by Xu Xing's avatar Xu Xing Committed by Commit Bot

viz: Support filter in SkiaRenderer

TODOs:
Support flip_texture. crbug.com/822859.
Support SkColorFilter. crbug.com/823182

BUG=822857

Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.android:android_optional_gpu_tests_rel
Change-Id: Ic442e5d544929cca8f43c911dea231e51aeaaaed
Reviewed-on: https://chromium-review.googlesource.com/912326Reviewed-by: default avatarenne <enne@chromium.org>
Commit-Queue: Xing Xu <xing.xu@intel.com>
Cr-Commit-Position: refs/heads/master@{#544915}
parent 7450bde6
......@@ -270,6 +270,22 @@ gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
return ComputeEnclosingClippedRect(h1, h2, h3, h4);
}
gfx::QuadF MathUtil::InverseMapQuadToLocalSpace(
const gfx::Transform& device_transform,
const gfx::QuadF& device_quad) {
gfx::Transform inverse_device_transform(gfx::Transform::kSkipInitialization);
DCHECK(device_transform.IsInvertible());
bool did_invert = device_transform.GetInverse(&inverse_device_transform);
DCHECK(did_invert);
bool clipped = false;
gfx::QuadF local_quad =
MathUtil::MapQuad(inverse_device_transform, device_quad, &clipped);
// We should not DCHECK(!clipped) here, because anti-aliasing inflation may
// cause device_quad to become clipped. To our knowledge this scenario does
// not need to be handled differently than the unclipped case.
return local_quad;
}
gfx::Rect MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
const gfx::Transform& transform,
const gfx::Rect& rect) {
......
......@@ -159,6 +159,13 @@ class CC_BASE_EXPORT MathUtil {
static gfx::RectF ProjectClippedRect(const gfx::Transform& transform,
const gfx::RectF& rect);
// Map device space quad to local space. Device_transform has no 3d
// component since it was flattened, so we don't need to project. We should
// have already checked that the transform was invertible before this call.
static gfx::QuadF InverseMapQuadToLocalSpace(
const gfx::Transform& device_transform,
const gfx::QuadF& device_quad);
// This function is only valid when the transform preserves 2d axis
// alignment and the resulting rect will not be clipped.
static gfx::Rect MapEnclosedRectWith2dAxisAlignedTransform(
......
......@@ -24,6 +24,7 @@
namespace viz {
class GLRenderer;
class SkiaRenderer;
class SoftwareRenderer;
} // namespace viz
......@@ -155,6 +156,7 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
// raster.
friend class PaintFlags;
friend class viz::GLRenderer;
friend class viz::SkiaRenderer;
friend class viz::SoftwareRenderer;
const Type type_;
......
......@@ -127,6 +127,8 @@ viz_component("common") {
"resources/single_release_callback.h",
"resources/transferable_resource.cc",
"resources/transferable_resource.h",
"skia_helper.cc",
"skia_helper.h",
"surfaces/child_local_surface_id_allocator.cc",
"surfaces/child_local_surface_id_allocator.h",
"surfaces/frame_sink_id.cc",
......
# Please consult components/viz/README.md about allowable dependencies.
specific_include_rules = {
"skia_helper.(cc|h)": [
"+cc/base",
"+third_party/skia",
],
# DEPS for GLHelper and friends which are in the root common/ directory.
"(yuv_readback|gl_helper).*\.(cc|h)": [
"+gpu/GLES2",
......
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/common/skia_helper.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
#include "ui/gfx/skia_util.h"
namespace viz {
sk_sp<SkImage> SkiaHelper::ApplyImageFilter(sk_sp<SkImage> src_image,
const gfx::RectF& src_rect,
const gfx::RectF& dst_rect,
const gfx::Vector2dF& scale,
sk_sp<SkImageFilter> filter,
SkIPoint* offset,
SkIRect* subset,
const gfx::PointF& origin) {
if (!filter)
return nullptr;
if (!src_image) {
TRACE_EVENT_INSTANT0("cc",
"ApplyImageFilter wrap background texture failed",
TRACE_EVENT_SCOPE_THREAD);
return nullptr;
}
// Big filters can sometimes fallback to CPU. Therefore, we need
// to disable subnormal floats for performance and security reasons.
cc::ScopedSubnormalFloatDisabler disabler;
SkMatrix local_matrix;
local_matrix.setTranslate(origin.x(), origin.y());
local_matrix.postScale(scale.x(), scale.y());
local_matrix.postTranslate(-src_rect.x(), -src_rect.y());
SkIRect clip_bounds = gfx::RectFToSkRect(dst_rect).roundOut();
clip_bounds.offset(-src_rect.x(), -src_rect.y());
filter = filter->makeWithLocalMatrix(local_matrix);
SkIRect in_subset = SkIRect::MakeWH(src_rect.width(), src_rect.height());
sk_sp<SkImage> image = src_image->makeWithFilter(filter.get(), in_subset,
clip_bounds, subset, offset);
if (!image || !image->isTextureBacked()) {
return nullptr;
}
// Force a flush of the Skia pipeline before we switch back to the compositor
// context.
image->getTextureHandle(true);
CHECK(image->isTextureBacked());
return image;
}
} // namespace viz
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_VIZ_COMMON_SKIA_HELPER_H_
#define COMPONENTS_VIZ_COMMON_SKIA_HELPER_H_
#include "components/viz/common/viz_common_export.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace viz {
class VIZ_COMMON_EXPORT SkiaHelper {
public:
static sk_sp<SkImage> ApplyImageFilter(sk_sp<SkImage> src_image,
const gfx::RectF& src_rect,
const gfx::RectF& dst_rect,
const gfx::Vector2dF& scale,
sk_sp<SkImageFilter> filter,
SkIPoint* offset,
SkIRect* subset,
const gfx::PointF& origin);
};
} // namespace viz
#endif // COMPONENTS_VIZ_COMMON_SKIA_HELPER_H_
......@@ -44,6 +44,7 @@
#include "components/viz/common/resources/resource_fence.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/resources/resource_id.h"
#include "components/viz/common/skia_helper.h"
#include "components/viz/service/display/draw_polygon.h"
#include "components/viz/service/display/dynamic_geometry_binding.h"
#include "components/viz/service/display/layer_quad.h"
......@@ -566,58 +567,6 @@ static sk_sp<SkImage> WrapTexture(uint32_t texture_id,
nullptr);
}
static sk_sp<SkImage> ApplyImageFilter(
std::unique_ptr<GLRenderer::ScopedUseGrContext> use_gr_context,
const gfx::RectF& src_rect,
const gfx::RectF& dst_rect,
const gfx::Vector2dF& scale,
sk_sp<SkImageFilter> filter,
GLuint texture_id,
GLenum target,
const gfx::Size& size,
SkIPoint* offset,
SkIRect* subset,
bool flip_texture,
const gfx::PointF& origin) {
if (!filter || !use_gr_context)
return nullptr;
sk_sp<SkImage> src_image = WrapTexture(
texture_id, target, size, use_gr_context->context(), flip_texture);
if (!src_image) {
TRACE_EVENT_INSTANT0("cc",
"ApplyImageFilter wrap background texture failed",
TRACE_EVENT_SCOPE_THREAD);
return nullptr;
}
// Big filters can sometimes fallback to CPU. Therefore, we need
// to disable subnormal floats for performance and security reasons.
cc::ScopedSubnormalFloatDisabler disabler;
SkMatrix local_matrix;
local_matrix.setTranslate(origin.x(), origin.y());
local_matrix.postScale(scale.x(), scale.y());
local_matrix.postTranslate(-src_rect.x(), -src_rect.y());
SkIRect clip_bounds = gfx::RectFToSkRect(dst_rect).roundOut();
clip_bounds.offset(-src_rect.x(), -src_rect.y());
filter = filter->makeWithLocalMatrix(local_matrix);
SkIRect in_subset = SkIRect::MakeWH(src_rect.width(), src_rect.height());
sk_sp<SkImage> image = src_image->makeWithFilter(filter.get(), in_subset,
clip_bounds, subset, offset);
if (!image || !image->isTextureBacked()) {
return nullptr;
}
// Force a flush of the Skia pipeline before we switch back to the compositor
// context.
image->getTextureHandle(true);
CHECK(image->isTextureBacked());
return image;
}
static gfx::RectF CenteredRect(const gfx::Rect& tile_rect) {
return gfx::RectF(
gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()),
......@@ -918,24 +867,6 @@ sk_sp<SkImage> GLRenderer::ApplyBackgroundFilters(
return image;
}
// Map device space quad to local space. Device_transform has no 3d
// component since it was flattened, so we don't need to project. We should
// have already checked that the transform was uninvertible before this call.
gfx::QuadF MapQuadToLocalSpace(const gfx::Transform& device_transform,
const gfx::QuadF& device_quad) {
gfx::Transform inverse_device_transform(gfx::Transform::kSkipInitialization);
DCHECK(device_transform.IsInvertible());
bool did_invert = device_transform.GetInverse(&inverse_device_transform);
DCHECK(did_invert);
bool clipped = false;
gfx::QuadF local_quad =
cc::MathUtil::MapQuad(inverse_device_transform, device_quad, &clipped);
// We should not DCHECK(!clipped) here, because anti-aliasing inflation may
// cause device_quad to become clipped. To our knowledge this scenario does
// not need to be handled differently than the unclipped case.
return local_quad;
}
const TileDrawQuad* GLRenderer::CanPassBeDrawnDirectly(const RenderPass* pass) {
#if defined(OS_MACOSX)
// On Macs, this path can sometimes lead to all black output.
......@@ -1208,8 +1139,12 @@ bool GLRenderer::UpdateRPDQWithSkiaFilters(
clip_rect = current_draw_rect_;
}
gfx::Transform transform = params->quad_to_target_transform;
if (!transform.IsInvertible()) {
return false;
}
gfx::QuadF clip_quad = gfx::QuadF(gfx::RectF(clip_rect));
gfx::QuadF local_clip = MapQuadToLocalSpace(transform, clip_quad);
gfx::QuadF local_clip =
cc::MathUtil::InverseMapQuadToLocalSpace(transform, clip_quad);
params->dst_rect.Intersect(local_clip.BoundingBox());
// If we've been fully clipped out (by crop rect or clipping), there's
// nothing to draw.
......@@ -1219,28 +1154,34 @@ bool GLRenderer::UpdateRPDQWithSkiaFilters(
SkIPoint offset;
SkIRect subset;
gfx::RectF src_rect(quad->rect);
auto use_gr_context = ScopedUseGrContext::Create(this);
if (!use_gr_context)
return false;
if (params->contents_texture) {
params->contents_and_bypass_color_space =
params->contents_texture->color_space();
params->filter_image = ApplyImageFilter(
ScopedUseGrContext::Create(this), src_rect, params->dst_rect,
quad->filters_scale, std::move(filter),
params->contents_texture->id(), GL_TEXTURE_2D,
params->contents_texture->size(), &offset, &subset,
params->flip_texture, quad->filters_origin);
sk_sp<SkImage> src_image =
WrapTexture(params->contents_texture->id(), GL_TEXTURE_2D,
params->contents_texture->size(),
use_gr_context->context(), params->flip_texture);
params->filter_image = SkiaHelper::ApplyImageFilter(
src_image, src_rect, params->dst_rect, quad->filters_scale,
std::move(filter), &offset, &subset, quad->filters_origin);
} else {
cc::DisplayResourceProvider::ScopedReadLockGL
prefilter_bypass_quad_texture_lock(
resource_provider_, params->bypass_quad_texture.resource_id);
params->contents_and_bypass_color_space =
prefilter_bypass_quad_texture_lock.color_space();
params->filter_image = ApplyImageFilter(
ScopedUseGrContext::Create(this), src_rect, params->dst_rect,
quad->filters_scale, std::move(filter),
prefilter_bypass_quad_texture_lock.texture_id(),
prefilter_bypass_quad_texture_lock.target(),
prefilter_bypass_quad_texture_lock.size(), &offset, &subset,
params->flip_texture, quad->filters_origin);
sk_sp<SkImage> src_image =
WrapTexture(prefilter_bypass_quad_texture_lock.texture_id(),
prefilter_bypass_quad_texture_lock.target(),
prefilter_bypass_quad_texture_lock.size(),
use_gr_context->context(), params->flip_texture);
params->filter_image = SkiaHelper::ApplyImageFilter(
src_image, src_rect, params->dst_rect, quad->filters_scale,
std::move(filter), &offset, &subset, quad->filters_origin);
}
if (!params->filter_image)
......@@ -1705,7 +1646,8 @@ void GLRenderer::SetupQuadForClippingAndAntialiasing(
quad);
}
*local_quad = MapQuadToLocalSpace(device_transform, device_quad);
*local_quad =
cc::MathUtil::InverseMapQuadToLocalSpace(device_transform, device_quad);
}
// static
......@@ -1745,7 +1687,8 @@ void GLRenderer::SetupRenderPassQuadForClippingAndAntialiasing(
device_quad = device_layer_edges.ToQuadF();
}
*local_quad = MapQuadToLocalSpace(device_transform, device_quad);
*local_quad =
cc::MathUtil::InverseMapQuadToLocalSpace(device_transform, device_quad);
}
void GLRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad,
......
......@@ -9,6 +9,7 @@
#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
#include "cc/paint/render_surface_filters.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/quads/debug_border_draw_quad.h"
......@@ -20,6 +21,7 @@
#include "components/viz/common/resources/platform_color.h"
#include "components/viz/common/resources/resource_fence.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/skia_helper.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display/renderer_utils.h"
......@@ -28,15 +30,12 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkColorSpaceXformCanvas.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkOverdrawCanvas.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/include/effects/SkOverdrawColorFilter.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/rect_conversions.h"
#include "ui/gfx/skia_util.h"
......@@ -54,6 +53,20 @@
#endif
namespace viz {
// Parameters needed to draw a RenderPassDrawQuad.
struct DrawRenderPassDrawQuadParams {
// The "in" parameters that will be used when apply filters.
const cc::FilterOperations* filters = nullptr;
const cc::FilterOperations* background_filters = nullptr;
// The "out" parameters that will be returned for future use.
// A Skia image that should be sampled from instead of the original
// contents.
sk_sp<SkImage> filter_image;
gfx::Point src_offset;
gfx::RectF dst_rect;
gfx::RectF tex_coord_rect;
};
SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
......@@ -552,6 +565,73 @@ void SkiaRenderer::DrawTileQuad(const TileDrawQuad* quad) {
&current_paint_);
}
bool SkiaRenderer::CalculateRPDQParams(sk_sp<SkImage> content,
const RenderPassDrawQuad* quad,
DrawRenderPassDrawQuadParams* params) {
auto iter = render_pass_backings_.find(quad->render_pass_id);
DCHECK(render_pass_backings_.end() != iter);
if (params->filters == nullptr) {
return true;
}
// This function is called after AllocateRenderPassResourceIfNeeded, so there
// should be backing ready.
RenderPassBacking& content_texture = iter->second;
DCHECK(!params->filters->IsEmpty());
gfx::Size size(content_texture.render_pass_surface->width(),
content_texture.render_pass_surface->height());
auto paint_filter = cc::RenderSurfaceFilters::BuildImageFilter(
*params->filters, gfx::SizeF(size));
auto filter = paint_filter ? paint_filter->cached_sk_filter_ : nullptr;
// Apply filters to the content texture.
// TODO(xing.xu): Support SkColorFilter here. (https://crbug.com/823182)
if (filter) {
gfx::Rect clip_rect = quad->shared_quad_state->clip_rect;
if (clip_rect.IsEmpty()) {
clip_rect = current_draw_rect_;
}
gfx::Transform transform =
quad->shared_quad_state->quad_to_target_transform;
gfx::QuadF clip_quad = gfx::QuadF(gfx::RectF(clip_rect));
gfx::QuadF local_clip =
cc::MathUtil::InverseMapQuadToLocalSpace(transform, clip_quad);
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());
gfx::RectF dst_rect(params->filters
? params->filters->MapRect(quad->rect, local_matrix)
: quad->rect);
dst_rect.Intersect(local_clip.BoundingBox());
// If we've been fully clipped out (by crop rect or clipping), there's
// nothing to draw.
if (dst_rect.IsEmpty()) {
return false;
}
SkIPoint offset;
SkIRect subset;
gfx::RectF src_rect(quad->rect);
// TODO(xing.xu): Support flip_texture. (https://crbug.com/822859)
params->filter_image = SkiaHelper::ApplyImageFilter(
content, src_rect, dst_rect, quad->filters_scale, std::move(filter),
&offset, &subset, quad->filters_origin);
if (!params->filter_image)
return false;
params->dst_rect =
gfx::RectF(src_rect.x() + offset.fX, src_rect.y() + offset.fY,
subset.width(), subset.height());
params->src_offset.SetPoint(subset.x(), subset.y());
gfx::RectF tex_rect =
gfx::RectF(gfx::PointF(params->src_offset), params->dst_rect.size());
params->tex_coord_rect = tex_rect;
}
return true;
}
void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
auto iter = render_pass_backings_.find(quad->render_pass_id);
DCHECK(render_pass_backings_.end() != iter);
......@@ -562,23 +642,31 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
sk_sp<SkImage> content =
content_texture.render_pass_surface->makeImageSnapshot();
SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect());
SkRect dest_visible_rect =
gfx::RectFToSkRect(cc::MathUtil::ScaleRectProportional(
QuadVertexRect(), gfx::RectF(quad->rect),
gfx::RectF(quad->visible_rect)));
SkRect content_rect = RectFToSkRect(quad->tex_coord_rect);
current_canvas_->drawImageRect(content, content_rect, dest_visible_rect,
&current_paint_);
DrawRenderPassDrawQuadParams params;
params.filters = FiltersForPass(quad->render_pass_id);
params.background_filters = BackgroundFiltersForPass(quad->render_pass_id);
bool can_draw = CalculateRPDQParams(content, quad, &params);
const cc::FilterOperations* filters = FiltersForPass(quad->render_pass_id);
if (!can_draw)
return;
// TODO(weiliangc): Implement filters. (crbug.com/644851)
if (filters) {
NOTIMPLEMENTED();
SkRect content_rect;
SkRect dest_visible_rect;
if (params.filter_image) {
content_rect = RectFToSkRect(params.tex_coord_rect);
dest_visible_rect = gfx::RectFToSkRect(cc::MathUtil::ScaleRectProportional(
QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(params.dst_rect)));
content = params.filter_image;
} else {
content_rect = RectFToSkRect(quad->tex_coord_rect);
dest_visible_rect = gfx::RectFToSkRect(cc::MathUtil::ScaleRectProportional(
QuadVertexRect(), gfx::RectF(quad->rect),
gfx::RectF(quad->visible_rect)));
}
current_canvas_->drawImageRect(content, content_rect, dest_visible_rect,
&current_paint_);
SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect());
SkMatrix content_mat;
content_mat.setRectToRect(content_rect, dest_rect,
SkMatrix::kFill_ScaleToFit);
......@@ -587,16 +675,17 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
shader = content->makeShader(SkShader::kClamp_TileMode,
SkShader::kClamp_TileMode, &content_mat);
// TODO(weiliangc): Implement mask. (crbug.com/644851)
// TODO(weiliangc): Implement mask. (https://crbug.com/644851)
if (quad->mask_resource_id()) {
NOTIMPLEMENTED();
}
// TODO(weiliangc): If we have a background filter shader, render its results
// first. (crbug.com/644851)
current_paint_.setShader(std::move(shader));
current_canvas_->drawRect(dest_visible_rect, current_paint_);
// TODO(weiliangc): If we have a background filter shader, render its
// results first. (https://crbug.com/644851)
if (ShouldApplyBackgroundFilters(quad, params.background_filters)) {
current_paint_.setShader(std::move(shader));
current_canvas_->drawRect(dest_visible_rect, current_paint_);
}
}
void SkiaRenderer::DrawUnsupportedQuad(const DrawQuad* quad) {
......@@ -652,18 +741,6 @@ bool SkiaRenderer::ShouldApplyBackgroundFilters(
return true;
}
// 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 bitmap.
sk_sp<SkImage> SkiaRenderer::ApplyImageFilter(SkImageFilter* filter,
const RenderPassDrawQuad* quad,
const SkBitmap& to_filter,
SkIRect* auto_bounds) const {
// TODO(weiliangc): Implement image filter. (crbug.com/644851)
NOTIMPLEMENTED();
return nullptr;
}
SkBitmap SkiaRenderer::GetBackdropBitmap(const gfx::Rect& bounding_rect) const {
SkBitmap bitmap;
bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounding_rect.width(),
......
......@@ -26,6 +26,7 @@ class PictureDrawQuad;
class SolidColorDrawQuad;
class TextureDrawQuad;
class TileDrawQuad;
struct DrawRenderPassDrawQuadParams;
class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
public:
......@@ -83,13 +84,13 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
void DrawTextureQuad(const TextureDrawQuad* quad);
void DrawTileQuad(const TileDrawQuad* quad);
void DrawUnsupportedQuad(const DrawQuad* quad);
bool CalculateRPDQParams(sk_sp<SkImage> src_image,
const RenderPassDrawQuad* quad,
DrawRenderPassDrawQuadParams* params);
bool ShouldApplyBackgroundFilters(
const RenderPassDrawQuad* quad,
const cc::FilterOperations* background_filters) const;
sk_sp<SkImage> ApplyImageFilter(SkImageFilter* filter,
const RenderPassDrawQuad* quad,
const SkBitmap& to_filter,
SkIRect* auto_bounds) const;
gfx::Rect GetBackdropBoundingBoxForRenderPassQuad(
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform,
......
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