| Index: cc/output/gl_renderer.cc
|
| diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
|
| index c0cf1381adb9ac8e466cb44b723704aec225b767..cc9a752ecf5cda3c8406bb6a92f9503a3cf4dbe3 100644
|
| --- a/cc/output/gl_renderer.cc
|
| +++ b/cc/output/gl_renderer.cc
|
| @@ -576,11 +576,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:
|
| @@ -607,14 +725,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).
|
| @@ -649,18 +767,28 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
|
| 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>();
|
| + SkBitmap filtered_device_background;
|
| + if (apply_background_filters) {
|
| + filtered_device_background =
|
| + ApplyImageFilter(this,
|
| + frame->offscreen_context_provider,
|
| + quad->rect.origin(),
|
| + filter.get(),
|
| + device_background_texture.get());
|
| + }
|
| + *background_changed = (filtered_device_background.getTexture() != NULL);
|
|
|
| - GrTexture* texture =
|
| - reinterpret_cast<GrTexture*>(filtered_device_background.getTexture());
|
| - int filtered_device_background_texture_id = texture->getTextureHandle();
|
| + int filtered_device_background_texture_id = 0;
|
| + 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_);
|
| @@ -731,19 +859,24 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
|
| if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
|
| return;
|
|
|
| + bool need_background_texture =
|
| + quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode ||
|
| + !quad->background_filters.IsEmpty();
|
| + bool background_changed = false;
|
| scoped_ptr<ScopedResource> background_texture;
|
| - if (!quad->background_filters.IsEmpty()) {
|
| + if (need_background_texture) {
|
| // 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);
|
| @@ -782,8 +915,19 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
|
| }
|
| }
|
|
|
| - // Draw the background texture if there is one.
|
| - if (background_texture) {
|
| + if (quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode &&
|
| + background_texture) {
|
| + 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 it has some filters applied.
|
| + if (background_texture && background_changed) {
|
| DCHECK(background_texture->size() == quad->rect.size());
|
| ResourceProvider::ScopedReadLockGL lock(resource_provider_,
|
| background_texture->id());
|
|
|