| Index: cc/output/gl_renderer.cc
|
| diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
|
| index 6357793c0e2308e24d3032daf4f96ab4e5b1e878..b2d5153767d252f3e2e7b1acd62f05be03eb7ea7 100644
|
| --- a/cc/output/gl_renderer.cc
|
| +++ b/cc/output/gl_renderer.cc
|
| @@ -850,85 +850,109 @@ static skia::RefPtr<SkImage> ApplyBlendModeWithBackdrop(
|
| return image;
|
| }
|
|
|
| -scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters(
|
| - DrawingFrame* frame,
|
| - const RenderPassDrawQuad* quad,
|
| - const gfx::Transform& contents_device_transform,
|
| - const gfx::Transform& contents_device_transform_inverse,
|
| - bool* background_changed) {
|
| - // This method draws a background filter, which applies a filter to any pixels
|
| - // behind the quad and seen through its background. The algorithm works as
|
| - // follows:
|
| - // 1. Compute a bounding box around the pixels that will be visible through
|
| - // the quad.
|
| - // 2. Read the pixels in the bounding box into a buffer R.
|
| - // 3. Apply the background filter to R, so that it is applied in the pixels'
|
| - // coordinate space.
|
| - // 4. Apply the quad's inverse transform to map the pixels in R into the
|
| - // quad's content space. This implicitly clips R by the content bounds of the
|
| - // quad since the destination texture has bounds matching the quad's content.
|
| - // 5. Draw the background texture for the contents using the same transform as
|
| - // used to draw the contents itself. This is done without blending to replace
|
| - // the current background pixels with the new filtered background.
|
| - // 6. Draw the contents of the quad over drop of the new background with
|
| - // blending, as per usual. The filtered background pixels will show through
|
| - // any non-opaque pixels in this draws.
|
| - //
|
| - // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
|
| -
|
| - // TODO(danakj): When this algorithm changes, update
|
| - // LayerTreeHost::PrioritizeTextures() accordingly.
|
| +bool GLRenderer::ShouldApplyBackgroundFilters(DrawingFrame* frame,
|
| + const RenderPassDrawQuad* quad) {
|
| + if (quad->background_filters.IsEmpty())
|
| + return false;
|
|
|
| // TODO(danakj): We only allow background filters on an opaque render surface
|
| // because other surfaces may contain translucent pixels, and the contents
|
| // behind those translucent pixels wouldn't have the filter applied.
|
| - bool apply_background_filters =
|
| - !frame->current_render_pass->has_transparent_background;
|
| - DCHECK(!frame->current_texture);
|
| + if (frame->current_render_pass->has_transparent_background)
|
| + return false;
|
|
|
| // TODO(ajuma): Add support for reference filters once
|
| // FilterOperations::GetOutsets supports reference filters.
|
| - if (apply_background_filters && quad->background_filters.HasReferenceFilter())
|
| - apply_background_filters = false;
|
| + if (quad->background_filters.HasReferenceFilter())
|
| + return false;
|
| + return true;
|
| +}
|
|
|
| - // TODO(danakj): Do a single readback for both the surface and replica and
|
| - // cache the filtered results (once filter textures are not reused).
|
| - gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
|
| +gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad(
|
| + DrawingFrame* frame,
|
| + const RenderPassDrawQuad* quad,
|
| + const gfx::Transform& contents_device_transform) {
|
| + gfx::Rect backdrop_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
|
| contents_device_transform, SharedGeometryQuad().BoundingBox()));
|
|
|
| - int top, right, bottom, left;
|
| - quad->background_filters.GetOutsets(&top, &right, &bottom, &left);
|
| - window_rect.Inset(-left, -top, -right, -bottom);
|
| + if (ShouldApplyBackgroundFilters(frame, quad)) {
|
| + int top, right, bottom, left;
|
| + quad->background_filters.GetOutsets(&top, &right, &bottom, &left);
|
| + backdrop_rect.Inset(-left, -top, -right, -bottom);
|
| + }
|
|
|
| - window_rect.Intersect(
|
| + backdrop_rect.Intersect(
|
| MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect));
|
| + return backdrop_rect;
|
| +}
|
|
|
| +scoped_ptr<ScopedResource> GLRenderer::GetBackdropTexture(
|
| + const gfx::Rect& bounding_rect) {
|
| scoped_ptr<ScopedResource> device_background_texture =
|
| ScopedResource::Create(resource_provider_);
|
| // CopyTexImage2D fails when called on a texture having immutable storage.
|
| device_background_texture->Allocate(
|
| - window_rect.size(), ResourceProvider::TextureHintDefault, RGBA_8888);
|
| + bounding_rect.size(), ResourceProvider::TextureHintDefault, RGBA_8888);
|
| {
|
| ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
|
| device_background_texture->id());
|
| GetFramebufferTexture(
|
| - lock.texture_id(), device_background_texture->format(), window_rect);
|
| + lock.texture_id(), device_background_texture->format(), bounding_rect);
|
| }
|
| + return device_background_texture.Pass();
|
| +}
|
|
|
| +skia::RefPtr<SkImage> GLRenderer::ApplyBackgroundFilters(
|
| + DrawingFrame* frame,
|
| + const RenderPassDrawQuad* quad,
|
| + ScopedResource* background_texture) {
|
| + DCHECK(ShouldApplyBackgroundFilters(frame, quad));
|
| skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
|
| - quad->background_filters, device_background_texture->size());
|
| + quad->background_filters, background_texture->size());
|
|
|
| - skia::RefPtr<SkImage> filtered_device_background;
|
| - if (apply_background_filters) {
|
| - filtered_device_background =
|
| - ApplyImageFilter(ScopedUseGrContext::Create(this, frame),
|
| - resource_provider_,
|
| - quad->rect.origin(),
|
| - quad->filters_scale,
|
| - filter.get(),
|
| - device_background_texture.get());
|
| - }
|
| - *background_changed = (filtered_device_background != NULL);
|
| + skia::RefPtr<SkImage> background_with_filters =
|
| + ApplyImageFilter(ScopedUseGrContext::Create(this, frame),
|
| + resource_provider_,
|
| + quad->rect.origin(),
|
| + quad->filters_scale,
|
| + filter.get(),
|
| + background_texture);
|
| + return background_with_filters;
|
| +}
|
| +
|
| +scoped_ptr<ScopedResource>
|
| +GLRenderer::ApplyInverseTransformForBackgroundFilters(
|
| + DrawingFrame* frame,
|
| + const RenderPassDrawQuad* quad,
|
| + const gfx::Transform& contents_device_transform_inverse,
|
| + ScopedResource* device_background_texture,
|
| + skia::RefPtr<SkImage> filtered_device_background,
|
| + const gfx::Rect& backdrop_bounding_rect) {
|
| + // This method draws a background filter, which applies a filter to any pixels
|
| + // behind the quad and seen through its background. The algorithm works as
|
| + // follows:
|
| + // 1. Read the pixels in the bounding box into a buffer.
|
| + // Moved to GLRenderer::GetBackdropBoundingBoxForRenderPassQuad().
|
| + // 2. Read the pixels in the bounding box into a buffer R.
|
| + // Moved to GLRenderer::GetBackdropTexture().
|
| + // 3. Apply the background filter to R, so that it is applied in the pixels'
|
| + // coordinate space. Moved to GLRenderer::ApplyBackgroundFilters().
|
| + // 4. Apply the quad's inverse transform to map the pixels in R into the
|
| + // quad's content space. This implicitly clips R by the content bounds of the
|
| + // quad since the destination texture has bounds matching the quad's content.
|
| + // 5. Draw the background texture for the contents using the same transform as
|
| + // used to draw the contents itself. This is done without blending to replace
|
| + // the current background pixels with the new filtered background.
|
| + // 6. Draw the contents of the quad over drop of the new background with
|
| + // blending, as per usual. The filtered background pixels will show through
|
| + // any non-opaque pixels in this draws.
|
| + //
|
| + // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
|
| +
|
| + // TODO(danakj): When this algorithm changes, update
|
| + // LayerTreeHost::PrioritizeTextures() accordingly.
|
| +
|
| + DCHECK(device_background_texture);
|
|
|
| int filtered_device_background_texture_id = 0;
|
| scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
|
| @@ -966,15 +990,15 @@ scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters(
|
| gl_->Clear(GL_COLOR_BUFFER_BIT);
|
| #endif
|
|
|
| - // The filtered_deveice_background_texture is oriented the same as the frame
|
| - // buffer. The transform we are copying with has a vertical flip, as well as
|
| + // The background_texture is oriented the same as the frame buffer.
|
| + // The transform we are copying with has a vertical flip, as well as
|
| // the |device_to_framebuffer_transform|, which cancel each other out. So do
|
| // not flip the contents in the shader to maintain orientation.
|
| bool flip_vertically = false;
|
|
|
| CopyTextureToFramebuffer(frame,
|
| filtered_device_background_texture_id,
|
| - window_rect,
|
| + backdrop_bounding_rect,
|
| device_to_framebuffer_transform,
|
| flip_vertically);
|
| }
|
| @@ -1009,8 +1033,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
|
| return;
|
|
|
| bool need_background_texture = !ShouldApplyBlendModeUsingBlendFunc(quad) ||
|
| - !quad->background_filters.IsEmpty();
|
| - bool background_changed = false;
|
| + ShouldApplyBackgroundFilters(frame, quad);
|
| +
|
| scoped_ptr<ScopedResource> background_texture;
|
| if (need_background_texture) {
|
| // The pixels from the filtered background should completely replace the
|
| @@ -1019,12 +1043,33 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
|
| if (disable_blending)
|
| SetBlendEnabled(false);
|
|
|
| - background_texture =
|
| - GetBackgroundWithFilters(frame,
|
| - quad,
|
| - contents_device_transform,
|
| - contents_device_transform_inverse,
|
| - &background_changed);
|
| + // Compute a bounding box around the pixels that will be visible through
|
| + // the quad.
|
| + gfx::Rect backdrop_rect = GetBackdropBoundingBoxForRenderPassQuad(
|
| + frame, quad, contents_device_transform);
|
| +
|
| + // Read the pixels in the bounding box into a buffer R.
|
| + scoped_ptr<ScopedResource> scoped_background_texture =
|
| + GetBackdropTexture(backdrop_rect);
|
| +
|
| + skia::RefPtr<SkImage> background_with_filters;
|
| + if (ShouldApplyBackgroundFilters(frame, quad)) {
|
| + // Apply the background filters to R, so that it is applied in the pixels'
|
| + // coordinate space.
|
| + background_with_filters =
|
| + ApplyBackgroundFilters(frame, quad, scoped_background_texture.get());
|
| + }
|
| + // Apply the quad's inverse transform to map the pixels in R into the
|
| + // quad's content space. This implicitly clips R by the content bounds of
|
| + // the quad since the destination texture has bounds matching the quad's
|
| + // content.
|
| + background_texture = ApplyInverseTransformForBackgroundFilters(
|
| + frame,
|
| + quad,
|
| + contents_device_transform_inverse,
|
| + scoped_background_texture.get(),
|
| + background_with_filters,
|
| + backdrop_rect);
|
|
|
| if (disable_blending)
|
| SetBlendEnabled(true);
|
| @@ -1063,6 +1108,9 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
|
| }
|
| }
|
|
|
| + // If blending is applied using shaders, the background texture with
|
| + // filters will be used as backdrop for blending operation, so we don't
|
| + // need to copy it to the frame buffer.
|
| if (background_texture && !ShouldApplyBlendModeUsingBlendFunc(quad)) {
|
| filter_bitmap =
|
| ApplyBlendModeWithBackdrop(ScopedUseGrContext::Create(this, frame),
|
| @@ -1071,10 +1119,9 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
|
| contents_texture,
|
| background_texture.get(),
|
| quad->shared_quad_state->blend_mode);
|
| - }
|
| -
|
| - // Draw the background texture if it has some filters applied.
|
| - if (background_texture && background_changed) {
|
| + } else if (background_texture) {
|
| + // Draw the background texture if it has some filters applied.
|
| + DCHECK(ShouldApplyBackgroundFilters(frame, quad));
|
| DCHECK(background_texture->size() == quad->rect.size());
|
| ResourceProvider::ScopedReadLockGL lock(resource_provider_,
|
| background_texture->id());
|
|
|