Index: cc/output/gl_renderer.cc |
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc |
index 68fb4566c4a553546d42e7061e31130be9005000..2b3c7b46cf2eec218c8dfdc76501e2af6a1943bd 100644 |
--- a/cc/output/gl_renderer.cc |
+++ b/cc/output/gl_renderer.cc |
@@ -603,11 +603,128 @@ 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 blendMode) { |
+ 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(source_size.width() == source_bitmap_with_filters.width()); |
enne (OOO)
2013/10/11 18:14:35
DCHECK_EQ, please.
rosca
2013/10/16 14:54:47
Done.
|
+ DCHECK(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(blendMode); |
+ 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: |
@@ -633,13 +750,14 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( |
FilterOperations filters = |
RenderSurfaceFilters::Optimize(quad->background_filters); |
- DCHECK(!filters.IsEmpty()); |
+ DCHECK(!filters.IsEmpty() || |
+ quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode); |
// 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 = !filters.IsEmpty() && |
+ !frame->current_render_pass->has_transparent_background; |
DCHECK(!frame->current_texture); |
// TODO(danakj): Do a single readback for both the surface and replica and |
@@ -663,22 +781,30 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( |
} else { |
ResourceProvider::ScopedWriteLockGL lock(resource_provider_, |
device_background_texture->id()); |
- GetFramebufferTexture(lock.texture_id(), |
- device_background_texture->format(), |
- window_rect); |
+ GetFramebufferTextureSubImage(lock.texture_id(), |
+ window_rect); |
} |
- SkBitmap filtered_device_background = |
- ApplyFilters(this, |
- frame->offscreen_context_provider, |
- filters, |
- device_background_texture.get()); |
- if (!filtered_device_background.getTexture()) |
- return scoped_ptr<ScopedResource>(); |
+ int filtered_device_background_texture_id = 0; |
- 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) |
+ filtered_device_background = ApplyFilters(this, |
+ frame->offscreen_context_provider, filters, |
+ device_background_texture.get()); |
+ if (background_changed) |
+ *background_changed = filtered_device_background.getTexture(); |
+ |
+ 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_); |
@@ -749,19 +875,23 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) |
return; |
+ bool applyBlendMode = |
enne (OOO)
2013/10/11 18:14:35
apply_blend_mode
rosca
2013/10/16 14:54:47
Done.
|
+ quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode; |
+ bool backgroundChanged = false; |
enne (OOO)
2013/10/11 18:14:35
background_changed
rosca
2013/10/16 14:54:47
Done.
|
scoped_ptr<ScopedResource> background_texture; |
- if (!quad->background_filters.IsEmpty()) { |
+ if (!quad->background_filters.IsEmpty() || applyBlendMode) { |
// 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( |
+ background_texture = GetBackgroundWithFilters( |
frame, |
quad, |
contents_device_transform, |
- contents_device_transform_inverse); |
+ contents_device_transform_inverse, |
+ &backgroundChanged); |
if (disable_blending) |
SetBlendEnabled(true); |
@@ -815,8 +945,17 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
} |
} |
+ if (background_texture && applyBlendMode) { |
+ 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. |
- if (background_texture) { |
+ if (background_texture && backgroundChanged) { |
DCHECK(background_texture->size() == quad->rect.size()); |
ResourceProvider::ScopedReadLockGL lock(resource_provider_, |
background_texture->id()); |
@@ -2466,6 +2605,23 @@ void GLRenderer::PassOnSkBitmap( |
request->SendBitmapResult(bitmap.Pass()); |
} |
+void GLRenderer::GetFramebufferTextureSubImage(unsigned texture_id, |
+ gfx::Rect window_rect) { |
+ DCHECK(texture_id); |
+ DCHECK_GE(window_rect.x(), 0); |
+ DCHECK_GE(window_rect.y(), 0); |
+ DCHECK_LE(window_rect.right(), current_surface_size_.width()); |
+ DCHECK_LE(window_rect.bottom(), current_surface_size_.height()); |
+ |
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id)); |
+ GLC(context_, |
+ context_->copyTexSubImage2D(GL_TEXTURE_2D, |
+ 0, 0, 0, |
+ window_rect.x(), window_rect.y(), |
+ window_rect.width(), window_rect.height())); |
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0)); |
+} |
+ |
void GLRenderer::GetFramebufferTexture( |
unsigned texture_id, ResourceFormat texture_format, gfx::Rect window_rect) { |
DCHECK(texture_id); |