diff options
author | senorblanco <senorblanco@chromium.org> | 2016-01-20 15:15:00 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-20 23:15:56 +0000 |
commit | 38858c57782f2a32cf4f93fcfcc35c340e665be4 (patch) | |
tree | 8acd71c976261e6938d6fd9bd2423f698e953259 /cc/output | |
parent | b3db8caba11e68278131000999b89df2d1ab44d5 (diff) | |
download | chromium_src-38858c57782f2a32cf4f93fcfcc35c340e665be4.zip chromium_src-38858c57782f2a32cf4f93fcfcc35c340e665be4.tar.gz chromium_src-38858c57782f2a32cf4f93fcfcc35c340e665be4.tar.bz2 |
Accelerated filters should filter unpadded primitives.
Until recently, the Skia image filter infrastructure could
only produce a result image of the same size as its input
image.
For that reason, currently Blink applies filter outsets to
a layer before it passes the layer to cc. So cc sees a
layer padded with transparent black out to the filter
outsets, but has no idea how big the original layer was.
It then passes that to Skia, which produces an image of
the same size.
I've recently fixed Skia to be able to correctly draw from
the original (unpadded) texture size to the correct, padded
texture size. But to take advantage of that, we need Blink
to stop padding the texture (see PaintLayer).
This may result in a destination buffer which is of a
different size than the source, so we modify cc's drawing
to draw the destination rect.
Also, since we're giving the original (unmodified) source
rect to Skia, we no longer need to offset the crop rects
in Blink by the delta between the src and dest rects.
(Note: we can thus remove the crop offset stuff entirely
from Blink, which I'll do in a followup patch.)
Finally, note that the workaround for the
partially-occupied textures implemented (implemented in
https://codereview.chromium.org/909353003) was no
longer working when drawing to exact-size textures, due
to a bug in SkAlphaThresholdFilter. This is fixed in Skia
here: https://codereview.chromium.org/1609573002/. That
will be required to roll into Chrome before this patch can
be landed.
BUG=568196
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel
Review URL: https://codereview.chromium.org/1517693002
Cr-Commit-Position: refs/heads/master@{#370523}
Diffstat (limited to 'cc/output')
-rw-r--r-- | cc/output/gl_renderer.cc | 82 | ||||
-rw-r--r-- | cc/output/gl_renderer.h | 3 | ||||
-rw-r--r-- | cc/output/renderer_pixeltest.cc | 10 |
3 files changed, 66 insertions, 29 deletions
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index acd7bf2..b2502d9 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc @@ -56,6 +56,7 @@ #include "third_party/skia/include/gpu/gl/GrGLInterface.h" #include "ui/gfx/geometry/quad_f.h" #include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/skia_util.h" using gpu::gles2::GLES2Interface; @@ -601,7 +602,8 @@ void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame, static skia::RefPtr<SkImage> ApplyImageFilter( scoped_ptr<GLRenderer::ScopedUseGrContext> use_gr_context, ResourceProvider* resource_provider, - const gfx::Rect& rect, + const gfx::RectF& src_rect, + const gfx::RectF& dst_rect, const gfx::Vector2dF& scale, SkImageFilter* filter, ScopedResource* source_texture_resource) { @@ -634,7 +636,7 @@ static skia::RefPtr<SkImage> ApplyImageFilter( // Create surface to draw into. SkImageInfo dst_info = - SkImageInfo::MakeN32Premul(srcImage->width(), srcImage->height()); + SkImageInfo::MakeN32Premul(dst_rect.width(), dst_rect.height()); skia::RefPtr<SkSurface> surface = skia::AdoptRef(SkSurface::NewRenderTarget( use_gr_context->context(), SkSurface::kYes_Budgeted, dst_info, 0)); if (!surface) { @@ -647,17 +649,17 @@ static skia::RefPtr<SkImage> ApplyImageFilter( // bottom-left, but the orientation is the same, so we must translate the // filter so that it renders at the bottom of the texture to avoid // misregistration. - int y_translate = source_texture_resource->size().height() - rect.height() - - rect.origin().y(); - SkMatrix localM; - localM.setTranslate(-rect.origin().x(), y_translate); - localM.preScale(scale.x(), scale.y()); - skia::RefPtr<SkImageFilter> localIMF = - skia::AdoptRef(filter->newWithLocalMatrix(localM)); + float y_offset = source_texture_resource->size().height() - src_rect.height(); + SkMatrix local_matrix; + local_matrix.setScale(scale.x(), scale.y()); + skia::RefPtr<SkImageFilter> filter_with_local_scale = + skia::AdoptRef(filter->newWithLocalMatrix(local_matrix)); SkPaint paint; - paint.setImageFilter(localIMF.get()); - surface->getCanvas()->drawImage(srcImage.get(), 0, 0, &paint); + paint.setImageFilter(filter_with_local_scale.get()); + surface->getCanvas()->translate(-dst_rect.x(), -dst_rect.y()); + surface->getCanvas()->drawImage(srcImage.get(), src_rect.x(), + src_rect.y() - y_offset, &paint); skia::RefPtr<SkImage> image = skia::AdoptRef(surface->newImageSnapshot()); if (!image || !image->isTextureBacked()) { @@ -822,6 +824,13 @@ gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad( backdrop_rect.Inset(-kOutsetForAntialiasing, -kOutsetForAntialiasing); } + if (!quad->filters.IsEmpty()) { + // If we have filters, grab an extra one-pixel border around the + // background, so texture edge clamping gives us a transparent border + // in case the filter expands the result. + backdrop_rect.Inset(-1, -1, -1, -1); + } + backdrop_rect.Intersect(MoveFromDrawToWindowSpace( frame, frame->current_render_pass->output_rect)); return backdrop_rect; @@ -846,13 +855,14 @@ scoped_ptr<ScopedResource> GLRenderer::GetBackdropTexture( skia::RefPtr<SkImage> GLRenderer::ApplyBackgroundFilters( DrawingFrame* frame, const RenderPassDrawQuad* quad, - ScopedResource* background_texture) { + ScopedResource* background_texture, + const gfx::RectF& rect) { DCHECK(ShouldApplyBackgroundFilters(quad)); skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( quad->background_filters, gfx::SizeF(background_texture->size())); skia::RefPtr<SkImage> background_with_filters = ApplyImageFilter( - ScopedUseGrContext::Create(this, frame), resource_provider_, quad->rect, + ScopedUseGrContext::Create(this, frame), resource_provider_, rect, rect, quad->filters_scale, filter.get(), background_texture); return background_with_filters; } @@ -925,8 +935,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, if (ShouldApplyBackgroundFilters(quad) && background_texture) { // Apply the background filters to R, so that it is applied in the // pixels' coordinate space. - background_image = - ApplyBackgroundFilters(frame, quad, background_texture.get()); + background_image = ApplyBackgroundFilters( + frame, quad, background_texture.get(), gfx::RectF(background_rect)); if (background_image) background_image_id = background_image->getTextureHandle(true); DCHECK(background_image_id); @@ -963,6 +973,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, GLuint filter_image_id = 0; SkScalar color_matrix[20]; bool use_color_matrix = false; + gfx::RectF rect = gfx::RectF(quad->rect); if (!quad->filters.IsEmpty()) { skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( quad->filters, gfx::SizeF(contents_texture->size())); @@ -980,9 +991,28 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, // in the compositor. use_color_matrix = true; } else { - filter_image = ApplyImageFilter( - ScopedUseGrContext::Create(this, frame), resource_provider_, - quad->rect, quad->filters_scale, filter.get(), contents_texture); + gfx::RectF src_rect = rect; + gfx::Vector2dF scale = quad->filters_scale; + // Compute the destination rect for the filtered output. + // Note that we leave the dest rect equal to the src rect when + // a filter chain cannot compute its bounds. This is correct + // behaviour, but Skia is a little conservative at the moment. + // Once Skia makes the fast-bounds traversal crop-rect aware + // (http://skbug.com/4627), this won't be a problem + // for Chrome since Blink always sets a crop rect on the leaf nodes + // of the DAG, making it always computable. + // TODO(senorblanco): remove this comment when http://skbug.com/4627 + // is fixed. + if (filter->canComputeFastBounds()) { + SkRect result_rect; + rect.Scale(1.0f / scale.x(), 1.0f / scale.y()); + filter->computeFastBounds(gfx::RectFToSkRect(rect), &result_rect); + rect = gfx::SkRectToRectF(result_rect); + rect.Scale(scale.x(), scale.y()); + } + filter_image = ApplyImageFilter(ScopedUseGrContext::Create(this, frame), + resource_provider_, src_rect, rect, + scale, filter.get(), contents_texture); if (filter_image) { filter_image_id = filter_image->getTextureHandle(true); DCHECK(filter_image_id); @@ -1096,10 +1126,16 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, program->fragment_shader().FillLocations(&locations); gl_->Uniform1i(locations.sampler, 0); } - float tex_scale_x = - quad->rect.width() / static_cast<float>(contents_texture->size().width()); - float tex_scale_y = quad->rect.height() / - static_cast<float>(contents_texture->size().height()); + float tex_scale_x, tex_scale_y; + if (filter_image) { + // Skia filters always return SkImages with snug textures. + tex_scale_x = tex_scale_y = 1.0f; + } else { + tex_scale_x = quad->rect.width() / + static_cast<float>(contents_texture->size().width()); + tex_scale_y = quad->rect.height() / + static_cast<float>(contents_texture->size().height()); + } DCHECK_LE(tex_scale_x, 1.0f); DCHECK_LE(tex_scale_y, 1.0f); @@ -1197,7 +1233,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, SetShaderOpacity(quad->shared_quad_state->opacity, locations.alpha); SetShaderQuadF(surface_quad, locations.quad); DrawQuadGeometry(frame, quad->shared_quad_state->quad_to_target_transform, - gfx::RectF(quad->rect), locations.matrix); + rect, locations.matrix); // Flush the compositor context before the filter bitmap goes out of // scope, so the draw gets processed before the filter texture gets deleted. diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h index 9599b07..dc3b6dd 100644 --- a/cc/output/gl_renderer.h +++ b/cc/output/gl_renderer.h @@ -176,7 +176,8 @@ class CC_EXPORT GLRenderer : public DirectRenderer { skia::RefPtr<SkImage> ApplyBackgroundFilters( DrawingFrame* frame, const RenderPassDrawQuad* quad, - ScopedResource* background_texture); + ScopedResource* background_texture, + const gfx::RectF& rect); void DrawRenderPassQuad(DrawingFrame* frame, const RenderPassDrawQuad* quadi, diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc index f5afaea..52a9e6b 100644 --- a/cc/output/renderer_pixeltest.cc +++ b/cc/output/renderer_pixeltest.cc @@ -1773,11 +1773,11 @@ class RendererPixelTestWithBackgroundFilter root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); filter_pass_quad->SetNew(shared_state, filter_pass_layer_rect_, filter_pass_layer_rect_, filter_pass_id, - 0, // mask_resource_id - gfx::Vector2dF(), // mask_uv_scale - gfx::Size(), // mask_texture_size - FilterOperations(), // filters - gfx::Vector2dF(), // filters_scale + 0, // mask_resource_id + gfx::Vector2dF(), // mask_uv_scale + gfx::Size(), // mask_texture_size + FilterOperations(), // filters + gfx::Vector2dF(1.0f, 1.0f), // filters_scale this->background_filters_); } |