Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Unified Diff: cc/output/gl_renderer.cc

Issue 23455060: mix-blend-mode implementation for accelerated layers (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressing comments #40 Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: cc/output/gl_renderer.cc
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 8c201aa94ed75671213b45237b887d8a6cc20e54..831d6b60e3bb130ef26ea17956f9446edca6f814 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -167,6 +167,7 @@ GLRenderer::GLRenderer(RendererClient* client,
texture_mailbox_deleter_(texture_mailbox_deleter),
is_backbuffer_discarded_(false),
is_using_bind_uniform_(false),
+ is_using_texture_storage_(false),
visible_(true),
is_scissor_enabled_(false),
stencil_shadow_(false),
@@ -213,6 +214,7 @@ bool GLRenderer::Initialize() {
context_caps.discard_framebuffer;
is_using_bind_uniform_ = context_caps.bind_uniform_location;
+ is_using_texture_storage_ = context_caps.texture_storage;
enne (OOO) 2013/11/06 22:40:19 This is a little too magical for me. It makes ass
rosca 2013/11/07 01:58:16 Done.
if (!InitializeSharedObjects())
return false;
@@ -565,11 +567,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:
@@ -596,14 +716,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).
@@ -628,24 +748,35 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
device_background_texture->id());
GetFramebufferTexture(lock.texture_id(),
device_background_texture->format(),
- window_rect);
+ window_rect,
+ is_using_texture_storage_);
}
+ int filtered_device_background_texture_id = 0;
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)
+ filtered_device_background =
+ ApplyImageFilter(this,
+ frame->offscreen_context_provider,
+ quad->rect.origin(),
+ filter.get(),
+ device_background_texture.get());
+ if (background_changed)
+ *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_);
@@ -716,19 +847,23 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
return;
+ bool apply_blend_mode =
+ 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);
@@ -767,8 +902,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.
- if (background_texture) {
+ if (background_texture && background_changed) {
DCHECK(background_texture->size() == quad->rect.size());
ResourceProvider::ScopedReadLockGL lock(resource_provider_,
background_texture->id());
@@ -2171,7 +2316,7 @@ void GLRenderer::GetFramebufferPixelsAsync(
GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GLC(context_, context_->texParameteri(
GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- GetFramebufferTexture(texture_id, RGBA_8888, window_rect);
+ GetFramebufferTexture(texture_id, RGBA_8888, window_rect, false);
gpu::Mailbox mailbox;
unsigned sync_point = 0;
@@ -2262,9 +2407,8 @@ void GLRenderer::DoGetFramebufferPixels(
GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
// Copy the contents of the current (IOSurface-backed) framebuffer into a
// temporary texture.
- GetFramebufferTexture(temporary_texture,
- RGBA_8888,
- gfx::Rect(current_surface_size_));
+ GetFramebufferTexture(
+ temporary_texture, RGBA_8888, gfx::Rect(current_surface_size_), false);
temporary_fbo = context_->createFramebuffer();
// Attach this texture to an FBO, and perform the readback from that FBO.
GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, temporary_fbo));
@@ -2410,8 +2554,10 @@ void GLRenderer::PassOnSkBitmap(
request->SendBitmapResult(bitmap.Pass());
}
-void GLRenderer::GetFramebufferTexture(
- unsigned texture_id, ResourceFormat texture_format, gfx::Rect window_rect) {
+void GLRenderer::GetFramebufferTexture(unsigned texture_id,
+ ResourceFormat texture_format,
+ gfx::Rect window_rect,
+ bool is_texture_storage) {
DCHECK(texture_id);
DCHECK_GE(window_rect.x(), 0);
DCHECK_GE(window_rect.y(), 0);
@@ -2419,16 +2565,31 @@ void GLRenderer::GetFramebufferTexture(
DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
- GLC(context_,
- context_->copyTexImage2D(
- GL_TEXTURE_2D,
- 0,
- GLDataFormat(texture_format),
- window_rect.x(),
- window_rect.y(),
- window_rect.width(),
- window_rect.height(),
- 0));
+
+ // if the texture is allocated using texStorage2DEXT, its structure is
+ // immutable and we cannot use copyTexImage2D
+ if (!is_texture_storage) {
+ GLC(context_,
+ context_->copyTexImage2D(GL_TEXTURE_2D,
+ 0,
+ GLDataFormat(texture_format),
+ window_rect.x(),
+ window_rect.y(),
+ window_rect.width(),
+ window_rect.height(),
+ 0));
+ } else {
+ 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));
}

Powered by Google App Engine
This is Rietveld 408576698