Index: cc/output/gl_renderer.cc |
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc |
index 7a3065a32fffca76354ea8c32faaeec49051b9ca..0ff918084208f6b331dd68ea8f318b5e9b6a3816 100644 |
--- a/cc/output/gl_renderer.cc |
+++ b/cc/output/gl_renderer.cc |
@@ -562,11 +562,129 @@ static SkBitmap ApplyImageFilter(GLRenderer* renderer, |
return device.accessBitmap(false); |
} |
-scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( |
+static SkBitmap ApplyBlendModeWithBackdrop( |
+ GLRenderer* renderer, |
+ ContextProvider* offscreen_contexts, |
+ SkBitmap source_bitmap_with_filters, |
+ ScopedResource* source_texture_resource, |
+ ScopedResource* background_texture_resource, |
+ SkXfermode::Mode blend_mode) { |
+ if (!offscreen_contexts || !offscreen_contexts->GrContext()) |
+ return source_bitmap_with_filters; |
+ |
+ DCHECK(background_texture_resource); |
+ DCHECK(source_texture_resource); |
+ |
+ gfx::Size source_size = source_texture_resource->size(); |
+ gfx::Size background_size = background_texture_resource->size(); |
+ |
+ DCHECK_LE(background_size.width(), source_size.width()); |
+ DCHECK_LE(background_size.height(), source_size.height()); |
+ |
+ int source_texture_with_filters_id; |
+ scoped_ptr<ResourceProvider::ScopedReadLockGL> lock; |
+ if (source_bitmap_with_filters.getTexture()) { |
+ DCHECK_EQ(source_size.width(), source_bitmap_with_filters.width()); |
+ DCHECK_EQ(source_size.height(), source_bitmap_with_filters.height()); |
+ GrTexture* texture = |
+ reinterpret_cast<GrTexture*>(source_bitmap_with_filters.getTexture()); |
+ source_texture_with_filters_id = texture->getTextureHandle(); |
+ } else { |
+ lock.reset(new ResourceProvider::ScopedReadLockGL( |
+ renderer->resource_provider(), source_texture_resource->id())); |
+ source_texture_with_filters_id = lock->texture_id(); |
+ } |
+ |
+ ResourceProvider::ScopedReadLockGL lock_background( |
+ renderer->resource_provider(), background_texture_resource->id()); |
+ |
+ // Flush the compositor context to ensure that textures there are available |
+ // in the shared context. Do this after locking/creating the compositor |
+ // texture. |
+ renderer->resource_provider()->Flush(); |
+ |
+ // Make sure skia uses the correct GL context. |
+ offscreen_contexts->Context3d()->makeContextCurrent(); |
+ |
+ // Wrap the source texture in a Ganesh platform texture. |
+ GrBackendTextureDesc backend_texture_description; |
+ backend_texture_description.fConfig = kSkia8888_GrPixelConfig; |
+ backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin; |
+ |
+ backend_texture_description.fWidth = source_size.width(); |
+ backend_texture_description.fHeight = source_size.height(); |
+ backend_texture_description.fTextureHandle = source_texture_with_filters_id; |
+ skia::RefPtr<GrTexture> source_texture = |
+ skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture( |
+ backend_texture_description)); |
+ |
+ backend_texture_description.fWidth = background_size.width(); |
+ backend_texture_description.fHeight = background_size.height(); |
+ backend_texture_description.fTextureHandle = lock_background.texture_id(); |
+ skia::RefPtr<GrTexture> background_texture = |
+ skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture( |
+ backend_texture_description)); |
+ |
+ // Place the platform texture inside an SkBitmap. |
+ SkBitmap source; |
+ source.setConfig( |
+ SkBitmap::kARGB_8888_Config, source_size.width(), source_size.height()); |
+ skia::RefPtr<SkGrPixelRef> source_pixel_ref = |
+ skia::AdoptRef(new SkGrPixelRef(source_texture.get())); |
+ source.setPixelRef(source_pixel_ref.get()); |
+ |
+ SkBitmap background; |
+ background.setConfig(SkBitmap::kARGB_8888_Config, |
+ background_size.width(), |
+ background_size.height()); |
+ skia::RefPtr<SkGrPixelRef> background_pixel_ref = |
+ skia::AdoptRef(new SkGrPixelRef(background_texture.get())); |
+ background.setPixelRef(background_pixel_ref.get()); |
+ |
+ // Create a scratch texture for backing store. |
+ GrTextureDesc desc; |
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; |
+ desc.fSampleCnt = 0; |
+ desc.fWidth = source.width(); |
+ desc.fHeight = source.height(); |
+ desc.fConfig = kSkia8888_GrPixelConfig; |
+ desc.fOrigin = kBottomLeft_GrSurfaceOrigin; |
+ GrAutoScratchTexture scratch_texture( |
+ offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch); |
+ skia::RefPtr<GrTexture> backing_store = |
+ skia::AdoptRef(scratch_texture.detach()); |
+ |
+ // Create a device and canvas using that backing store. |
+ SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get()); |
+ SkCanvas canvas(&device); |
+ |
+ // Draw the source bitmap through the filter to the canvas. |
+ canvas.clear(SK_ColorTRANSPARENT); |
+ canvas.drawSprite(background, 0, 0); |
+ SkPaint paint; |
+ paint.setXfermodeMode(blend_mode); |
+ canvas.drawSprite(source, 0, 0, &paint); |
+ |
+ // Flush skia context so that all the rendered stuff appears on the |
+ // texture. |
+ offscreen_contexts->GrContext()->flush(); |
+ |
+ // Flush the GL context so rendering results from this context are |
+ // visible in the compositor's context. |
+ offscreen_contexts->Context3d()->flush(); |
+ |
+ // Use the compositor's GL context again. |
+ renderer->Context()->makeContextCurrent(); |
+ |
+ return device.accessBitmap(false); |
+} |
+ |
+scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters( |
DrawingFrame* frame, |
const RenderPassDrawQuad* quad, |
const gfx::Transform& contents_device_transform, |
- const gfx::Transform& contents_device_transform_inverse) { |
+ 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: |
@@ -593,14 +711,14 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( |
// 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. |
- if (frame->current_render_pass->has_transparent_background) |
- return scoped_ptr<ScopedResource>(); |
+ bool apply_background_filters = |
+ !frame->current_render_pass->has_transparent_background; |
DCHECK(!frame->current_texture); |
// TODO(ajuma): Add support for reference filters once |
// FilterOperations::GetOutsets supports reference filters. |
- if (quad->background_filters.HasReferenceFilter()) |
- return scoped_ptr<ScopedResource>(); |
+ if (apply_background_filters && quad->background_filters.HasReferenceFilter()) |
+ apply_background_filters = false; |
// TODO(danakj): Do a single readback for both the surface and replica and |
// cache the filtered results (once filter textures are not reused). |
@@ -616,9 +734,10 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( |
scoped_ptr<ScopedResource> device_background_texture = |
ScopedResource::create(resource_provider_); |
- if (!device_background_texture->Allocate(window_rect.size(), |
- ResourceProvider::TextureUsageAny, |
- RGBA_8888)) { |
+ if (!device_background_texture->Allocate( |
+ window_rect.size(), |
+ ResourceProvider::TextureUsageFramebuffer, |
danakj
2013/11/13 21:02:03
Why this change? We don't bind this texture to be
rosca
2013/11/14 21:56:34
The device_background_texture's format has been re
danakj
2013/11/20 03:32:50
If this is fixing background filters entirely, the
rosca
2013/11/20 21:52:04
I run into this problem by forcing some background
|
+ RGBA_8888)) { |
return scoped_ptr<ScopedResource>(); |
} else { |
ResourceProvider::ScopedWriteLockGL lock(resource_provider_, |
@@ -628,21 +747,31 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( |
window_rect); |
} |
+ int filtered_device_background_texture_id = 0; |
danakj
2013/11/13 21:02:03
move this down to above line 765?
rosca
2013/11/14 21:56:34
Done.
|
skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( |
quad->background_filters, device_background_texture->size()); |
- SkBitmap filtered_device_background = |
- ApplyImageFilter(this, |
- frame->offscreen_context_provider, |
- quad->rect.origin(), |
- filter.get(), |
- device_background_texture.get()); |
- if (!filtered_device_background.getTexture()) |
- return scoped_ptr<ScopedResource>(); |
- |
- GrTexture* texture = |
- reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); |
- int filtered_device_background_texture_id = texture->getTextureHandle(); |
+ SkBitmap filtered_device_background; |
+ if (apply_background_filters) |
danakj
2013/11/13 21:02:03
need {}
rosca
2013/11/14 21:56:34
Done.
|
+ filtered_device_background = |
+ ApplyImageFilter(this, |
+ frame->offscreen_context_provider, |
+ quad->rect.origin(), |
+ filter.get(), |
+ device_background_texture.get()); |
+ if (background_changed) |
danakj
2013/11/13 21:02:03
why make this optional? i'd prefer to just always
rosca
2013/11/14 21:56:34
Done.
|
+ *background_changed = (filtered_device_background.getTexture() != NULL); |
+ |
+ scoped_ptr<ResourceProvider::ScopedReadLockGL> lock; |
+ if (filtered_device_background.getTexture()) { |
+ GrTexture* texture = |
+ reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); |
+ filtered_device_background_texture_id = texture->getTextureHandle(); |
+ } else { |
+ lock.reset(new ResourceProvider::ScopedReadLockGL( |
+ resource_provider_, device_background_texture->id())); |
+ filtered_device_background_texture_id = lock->texture_id(); |
+ } |
scoped_ptr<ScopedResource> background_texture = |
ScopedResource::create(resource_provider_); |
@@ -713,19 +842,23 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) |
return; |
+ bool apply_blend_mode = |
danakj
2013/11/13 21:02:03
can this be
bool need_background_texture =
blen
rosca
2013/11/14 21:56:34
Done.
|
+ quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode; |
+ bool background_changed = false; |
scoped_ptr<ScopedResource> background_texture; |
- if (!quad->background_filters.IsEmpty()) { |
+ if (!quad->background_filters.IsEmpty() || apply_blend_mode) { |
// The pixels from the filtered background should completely replace the |
// current pixel values. |
bool disable_blending = blend_enabled(); |
if (disable_blending) |
SetBlendEnabled(false); |
- background_texture = DrawBackgroundFilters( |
- frame, |
- quad, |
- contents_device_transform, |
- contents_device_transform_inverse); |
+ background_texture = |
+ GetBackgroundWithFilters(frame, |
+ quad, |
+ contents_device_transform, |
+ contents_device_transform_inverse, |
+ &background_changed); |
if (disable_blending) |
SetBlendEnabled(true); |
@@ -764,8 +897,18 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
} |
} |
+ if (background_texture && apply_blend_mode) { |
+ filter_bitmap = |
+ ApplyBlendModeWithBackdrop(this, |
+ frame->offscreen_context_provider, |
+ filter_bitmap, |
+ contents_texture, |
+ background_texture.get(), |
+ quad->shared_quad_state->blend_mode); |
+ } |
+ |
// Draw the background texture if there is one. |
danakj
2013/11/13 21:02:03
update this comment
rosca
2013/11/14 21:56:34
Done.
|
- if (background_texture) { |
+ if (background_texture && background_changed) { |
DCHECK(background_texture->size() == quad->rect.size()); |
ResourceProvider::ScopedReadLockGL lock(resource_provider_, |
background_texture->id()); |