summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrosca <rosca@adobe.com>2014-10-22 02:54:12 -0700
committerCommit bot <commit-bot@chromium.org>2014-10-22 09:55:42 +0000
commit7b73f83a1d6c212c3f4bc915f495baf1b4671dbf (patch)
treeb5aab8594d131c702f314455b03c89b2d7396c14
parent547c1dd78570986435140b5f632ef927fd5168f8 (diff)
downloadchromium_src-7b73f83a1d6c212c3f4bc915f495baf1b4671dbf.zip
chromium_src-7b73f83a1d6c212c3f4bc915f495baf1b4671dbf.tar.gz
chromium_src-7b73f83a1d6c212c3f4bc915f495baf1b4671dbf.tar.bz2
Implement mix-blend-mode in GL renderer using shaders.
This implementation brings in several improvements for blending: - it's done faster, due to reducing the number of readbacks. - the backdrop doesn't suffer any transformation, so the result is more correct. - the results are similar to the ones obtained using the software paths. - blending is always applied after filters, even when the filters can be expressed using a color matrix. The initial experiment: https://codereview.chromium.org/555133002/. BUG=243223 Review URL: https://codereview.chromium.org/658483003 Cr-Commit-Position: refs/heads/master@{#300657}
-rw-r--r--cc/layers/delegated_renderer_layer_impl_unittest.cc7
-rw-r--r--cc/output/gl_renderer.cc533
-rw-r--r--cc/output/gl_renderer.h55
-rw-r--r--cc/output/gl_renderer_unittest.cc493
-rw-r--r--cc/output/program_binding.h5
-rw-r--r--cc/output/shader.cc373
-rw-r--r--cc/output/shader.h78
-rw-r--r--cc/output/software_renderer.cc6
-rw-r--r--cc/test/data/background_filter_blur_off_axis.pngbin7289 -> 7304 bytes
-rw-r--r--cc/test/data/blending_render_pass.pngbin0 -> 2765 bytes
-rw-r--r--cc/test/data/blending_render_pass_cm.pngbin0 -> 2876 bytes
-rw-r--r--cc/test/data/blending_render_pass_mask.pngbin0 -> 3568 bytes
-rw-r--r--cc/test/data/blending_render_pass_mask_cm.pngbin0 -> 3719 bytes
-rw-r--r--cc/test/render_pass_test_utils.cc5
-rw-r--r--cc/test/render_pass_test_utils.h3
-rw-r--r--cc/trees/layer_tree_host_pixeltest_blending.cc311
-rw-r--r--cc/trees/layer_tree_settings.cc1
-rw-r--r--cc/trees/layer_tree_settings.h1
18 files changed, 1346 insertions, 525 deletions
diff --git a/cc/layers/delegated_renderer_layer_impl_unittest.cc b/cc/layers/delegated_renderer_layer_impl_unittest.cc
index e66cc766..3fb1c48 100644
--- a/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -1416,7 +1416,12 @@ TEST_F(DelegatedRendererLayerImplTest, Occlusion) {
pass1_id,
gfx::Rect(layer_size),
gfx::Transform());
- AddRenderPassQuad(pass1, pass2, 0, FilterOperations(), transform);
+ AddRenderPassQuad(pass1,
+ pass2,
+ 0,
+ FilterOperations(),
+ transform,
+ SkXfermode::kSrcOver_Mode);
delegated_renderer_layer_impl->SetFrameDataForRenderPasses(
1.f, &delegated_render_passes);
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 61d233a..3c6bbfe 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -124,6 +124,44 @@ SamplerType SamplerTypeFromTextureTarget(GLenum target) {
}
}
+BlendMode BlendModeFromSkXfermode(SkXfermode::Mode mode) {
+ switch (mode) {
+ case SkXfermode::kSrcOver_Mode:
+ return BlendModeNormal;
+ case SkXfermode::kOverlay_Mode:
+ return BlendModeOverlay;
+ case SkXfermode::kDarken_Mode:
+ return BlendModeDarken;
+ case SkXfermode::kLighten_Mode:
+ return BlendModeLighten;
+ case SkXfermode::kColorDodge_Mode:
+ return BlendModeColorDodge;
+ case SkXfermode::kColorBurn_Mode:
+ return BlendModeColorBurn;
+ case SkXfermode::kHardLight_Mode:
+ return BlendModeHardLight;
+ case SkXfermode::kSoftLight_Mode:
+ return BlendModeSoftLight;
+ case SkXfermode::kDifference_Mode:
+ return BlendModeDifference;
+ case SkXfermode::kExclusion_Mode:
+ return BlendModeExclusion;
+ case SkXfermode::kMultiply_Mode:
+ return BlendModeMultiply;
+ case SkXfermode::kHue_Mode:
+ return BlendModeHue;
+ case SkXfermode::kSaturation_Mode:
+ return BlendModeSaturation;
+ case SkXfermode::kColor_Mode:
+ return BlendModeColor;
+ case SkXfermode::kLuminosity_Mode:
+ return BlendModeLuminosity;
+ default:
+ NOTREACHED();
+ return BlendModeNormal;
+ }
+}
+
// Smallest unit that impact anti-aliasing output. We use this to
// determine when anti-aliasing is unnecessary.
const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
@@ -724,140 +762,6 @@ void GLRenderer::RestoreBlendFuncToDefault(SkXfermode::Mode blend_mode) {
GLC(gl_, gl_->BlendEquation(GL_FUNC_ADD));
}
-static skia::RefPtr<SkImage> ApplyBlendModeWithBackdrop(
- scoped_ptr<GLRenderer::ScopedUseGrContext> use_gr_context,
- ResourceProvider* resource_provider,
- skia::RefPtr<SkImage> source_bitmap_with_filters,
- ScopedResource* source_texture_resource,
- ScopedResource* background_texture_resource,
- SkXfermode::Mode blend_mode) {
- if (!use_gr_context)
- 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) {
- 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(
- resource_provider, source_texture_resource->id()));
- source_texture_with_filters_id = lock->texture_id();
- }
-
- ResourceProvider::ScopedReadLockGL lock_background(
- resource_provider, background_texture_resource->id());
-
- // 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(use_gr_context->context()->wrapBackendTexture(
- backend_texture_description));
- if (!source_texture) {
- TRACE_EVENT_INSTANT0(
- "cc",
- "ApplyBlendModeWithBackdrop wrap source texture failed",
- TRACE_EVENT_SCOPE_THREAD);
- return skia::RefPtr<SkImage>();
- }
-
- 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(use_gr_context->context()->wrapBackendTexture(
- backend_texture_description));
- if (!background_texture) {
- TRACE_EVENT_INSTANT0(
- "cc",
- "ApplyBlendModeWithBackdrop wrap background texture failed",
- TRACE_EVENT_SCOPE_THREAD);
- return skia::RefPtr<SkImage>();
- }
-
- SkImageInfo source_info =
- SkImageInfo::MakeN32Premul(source_size.width(), source_size.height());
- // Place the platform texture inside an SkBitmap.
- SkBitmap source;
- source.setInfo(source_info);
- skia::RefPtr<SkGrPixelRef> source_pixel_ref =
- skia::AdoptRef(new SkGrPixelRef(source_info, source_texture.get()));
- source.setPixelRef(source_pixel_ref.get());
-
- SkImageInfo background_info = SkImageInfo::MakeN32Premul(
- background_size.width(), background_size.height());
-
- SkBitmap background;
- background.setInfo(background_info);
- skia::RefPtr<SkGrPixelRef> background_pixel_ref =
- skia::AdoptRef(new SkGrPixelRef(
- background_info, 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;
- skia::RefPtr<GrTexture> backing_store =
- skia::AdoptRef(use_gr_context->context()->refScratchTexture(
- desc, GrContext::kExact_ScratchTexMatch));
- if (!backing_store) {
- TRACE_EVENT_INSTANT0(
- "cc",
- "ApplyBlendModeWithBackdrop scratch texture allocation failed",
- TRACE_EVENT_SCOPE_THREAD);
- return source_bitmap_with_filters;
- }
-
- // Create a device and canvas using that backing store.
- skia::RefPtr<SkSurface> surface = skia::AdoptRef(
- SkSurface::NewRenderTargetDirect(backing_store->asRenderTarget()));
- if (!surface)
- return skia::RefPtr<SkImage>();
- skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas());
-
- // 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);
-
- skia::RefPtr<SkImage> image = skia::AdoptRef(surface->newImageSnapshot());
- if (!image || !image->getTexture()) {
- return skia::RefPtr<SkImage>();
- }
-
- // Flush the GrContext to ensure all buffered GL calls are drawn to the
- // backing store before we access and return it, and have cc begin using the
- // GL context again.
- canvas->flush();
-
- return image;
-}
-
bool GLRenderer::ShouldApplyBackgroundFilters(DrawingFrame* frame,
const RenderPassDrawQuad* quad) {
if (quad->background_filters.IsEmpty())
@@ -879,7 +783,8 @@ bool GLRenderer::ShouldApplyBackgroundFilters(DrawingFrame* frame,
gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad(
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
- const gfx::Transform& contents_device_transform) {
+ const gfx::Transform& contents_device_transform,
+ bool use_aa) {
gfx::Rect backdrop_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
contents_device_transform, SharedGeometryQuad().BoundingBox()));
@@ -889,6 +794,11 @@ gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad(
backdrop_rect.Inset(-left, -top, -right, -bottom);
}
+ if (!backdrop_rect.IsEmpty() && use_aa) {
+ const int kOutsetForAntialiasing = 1;
+ backdrop_rect.Inset(-kOutsetForAntialiasing, -kOutsetForAntialiasing);
+ }
+
backdrop_rect.Intersect(
MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect));
return backdrop_rect;
@@ -933,7 +843,6 @@ 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
@@ -960,18 +869,9 @@ GLRenderer::ApplyInverseTransformForBackgroundFilters(
// TODO(danakj): When this algorithm changes, update
// LayerTreeHost::PrioritizeTextures() accordingly.
- DCHECK(device_background_texture);
+ DCHECK(filtered_device_background);
- int filtered_device_background_texture_id = 0;
- scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
- if (filtered_device_background) {
- GrTexture* texture = 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();
- }
+ GrTexture* texture = filtered_device_background->getTexture();
scoped_ptr<ScopedResource> background_texture =
ScopedResource::Create(resource_provider_);
@@ -1005,7 +905,7 @@ GLRenderer::ApplyInverseTransformForBackgroundFilters(
bool flip_vertically = false;
CopyTextureToFramebuffer(frame,
- filtered_device_background_texture_id,
+ texture->getTextureHandle(),
backdrop_bounding_rect,
device_to_framebuffer_transform,
flip_vertically);
@@ -1021,9 +921,9 @@ GLRenderer::ApplyInverseTransformForBackgroundFilters(
void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
const RenderPassDrawQuad* quad) {
SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode;
- SetBlendEnabled(quad->ShouldDrawWithBlending() ||
- (!IsDefaultBlendMode(blend_mode) &&
- CanApplyBlendModeUsingBlendFunc(blend_mode)));
+ SetBlendEnabled(
+ CanApplyBlendModeUsingBlendFunc(blend_mode) &&
+ (quad->ShouldDrawWithBlending() || !IsDefaultBlendMode(blend_mode)));
ScopedResource* contents_texture =
render_pass_textures_.get(quad->render_pass_id);
@@ -1042,44 +942,70 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
return;
+ bool clipped = false;
+ gfx::QuadF device_quad = MathUtil::MapQuad(
+ contents_device_transform, SharedGeometryQuad(), &clipped);
+ // Use anti-aliasing programs only when necessary.
+ bool use_aa =
+ !clipped &&
+ (settings_->force_antialiasing || !device_quad.IsRectilinear() ||
+ !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(),
+ kAntiAliasingEpsilon));
+
bool need_background_texture = !CanApplyBlendModeUsingBlendFunc(blend_mode) ||
ShouldApplyBackgroundFilters(frame, quad);
scoped_ptr<ScopedResource> background_texture;
+ skia::RefPtr<SkImage> background_image;
+ gfx::Rect background_rect;
if (need_background_texture) {
+ // Compute a bounding box around the pixels that will be visible through
+ // the quad.
+ background_rect = GetBackdropBoundingBoxForRenderPassQuad(
+ frame, quad, contents_device_transform, use_aa);
+ }
+
+ if (!background_rect.IsEmpty()) {
// The pixels from the filtered background should completely replace the
// current pixel values.
bool disable_blending = blend_enabled();
if (disable_blending)
SetBlendEnabled(false);
- // 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);
+ GetBackdropTexture(background_rect);
skia::RefPtr<SkImage> background_with_filters;
- if (ShouldApplyBackgroundFilters(frame, quad)) {
+ if (ShouldApplyBackgroundFilters(frame, quad) &&
+ scoped_background_texture) {
// 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 (CanApplyBlendModeUsingBlendFunc(blend_mode) &&
+ background_with_filters) {
+ // The background with filters will be copied to the frame buffer.
+ // 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,
+ background_with_filters,
+ background_rect);
+ } else if (!CanApplyBlendModeUsingBlendFunc(blend_mode)) {
+ if (background_with_filters) {
+ // The background with filters will be used as backdrop for blending.
+ background_image = background_with_filters;
+ } else {
+ background_texture = scoped_background_texture.Pass();
+ }
+ }
if (disable_blending)
SetBlendEnabled(true);
@@ -1117,49 +1043,27 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
}
}
- if (background_texture) {
- if (CanApplyBlendModeUsingBlendFunc(blend_mode)) {
- // 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());
-
- // The background_texture is oriented the same as the frame buffer. The
- // transform we are copying with has a vertical flip, so flip the contents
- // in the shader to maintain orientation
- bool flip_vertically = true;
-
- CopyTextureToFramebuffer(frame,
- lock.texture_id(),
- quad->rect,
- quad->quadTransform(),
- flip_vertically);
- } else {
- // 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.
- filter_image =
- ApplyBlendModeWithBackdrop(ScopedUseGrContext::Create(this, frame),
- resource_provider_,
- filter_image,
- contents_texture,
- background_texture.get(),
- quad->shared_quad_state->blend_mode);
- }
+ if (background_texture && ShouldApplyBackgroundFilters(frame, quad)) {
+ // Draw the background texture if it has some filters applied.
+ DCHECK(CanApplyBlendModeUsingBlendFunc(blend_mode));
+ DCHECK(background_texture->size() == quad->rect.size());
+ ResourceProvider::ScopedReadLockGL lock(resource_provider_,
+ background_texture->id());
+
+ // The background_texture is oriented the same as the frame buffer. The
+ // transform we are copying with has a vertical flip, so flip the contents
+ // in the shader to maintain orientation
+ bool flip_vertically = true;
+
+ CopyTextureToFramebuffer(frame,
+ lock.texture_id(),
+ quad->rect,
+ quad->quadTransform(),
+ flip_vertically);
}
- bool clipped = false;
- gfx::QuadF device_quad = MathUtil::MapQuad(
- contents_device_transform, SharedGeometryQuad(), &clipped);
LayerQuad device_layer_bounds(gfx::QuadF(device_quad.BoundingBox()));
LayerQuad device_layer_edges(device_quad);
-
- // Use anti-aliasing programs only when necessary.
- bool use_aa =
- !clipped && (!device_quad.IsRectilinear() ||
- !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(),
- kAntiAliasingEpsilon));
if (use_aa) {
device_layer_bounds.InflateAntiAliasingDistance();
device_layer_edges.InflateAntiAliasingDistance();
@@ -1211,10 +1115,17 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
int shader_color_matrix_location = -1;
int shader_color_offset_location = -1;
int shader_tex_transform_location = -1;
+ int shader_backdrop_location = -1;
+ int shader_backdrop_rect_location = -1;
+
+ BlendMode shader_blend_mode = ((background_texture || background_image) &&
+ !CanApplyBlendModeUsingBlendFunc(blend_mode))
+ ? BlendModeFromSkXfermode(blend_mode)
+ : BlendModeNormal;
if (use_aa && mask_texture_id && !use_color_matrix) {
const RenderPassMaskProgramAA* program =
- GetRenderPassMaskProgramAA(tex_coord_precision);
+ GetRenderPassMaskProgramAA(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1231,9 +1142,12 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
shader_alpha_location = program->fragment_shader().alpha_location();
shader_tex_transform_location =
program->vertex_shader().tex_transform_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (!use_aa && mask_texture_id && !use_color_matrix) {
const RenderPassMaskProgram* program =
- GetRenderPassMaskProgram(tex_coord_precision);
+ GetRenderPassMaskProgram(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1247,9 +1161,12 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
shader_alpha_location = program->fragment_shader().alpha_location();
shader_tex_transform_location =
program->vertex_shader().tex_transform_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (use_aa && !mask_texture_id && !use_color_matrix) {
const RenderPassProgramAA* program =
- GetRenderPassProgramAA(tex_coord_precision);
+ GetRenderPassProgramAA(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1260,9 +1177,13 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
shader_alpha_location = program->fragment_shader().alpha_location();
shader_tex_transform_location =
program->vertex_shader().tex_transform_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (use_aa && mask_texture_id && use_color_matrix) {
const RenderPassMaskColorMatrixProgramAA* program =
- GetRenderPassMaskColorMatrixProgramAA(tex_coord_precision);
+ GetRenderPassMaskColorMatrixProgramAA(tex_coord_precision,
+ shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1283,9 +1204,13 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
program->fragment_shader().color_matrix_location();
shader_color_offset_location =
program->fragment_shader().color_offset_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (use_aa && !mask_texture_id && use_color_matrix) {
const RenderPassColorMatrixProgramAA* program =
- GetRenderPassColorMatrixProgramAA(tex_coord_precision);
+ GetRenderPassColorMatrixProgramAA(tex_coord_precision,
+ shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1300,9 +1225,13 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
program->fragment_shader().color_matrix_location();
shader_color_offset_location =
program->fragment_shader().color_offset_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (!use_aa && mask_texture_id && use_color_matrix) {
const RenderPassMaskColorMatrixProgram* program =
- GetRenderPassMaskColorMatrixProgram(tex_coord_precision);
+ GetRenderPassMaskColorMatrixProgram(tex_coord_precision,
+ shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1320,9 +1249,12 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
program->fragment_shader().color_matrix_location();
shader_color_offset_location =
program->fragment_shader().color_offset_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (!use_aa && !mask_texture_id && use_color_matrix) {
const RenderPassColorMatrixProgram* program =
- GetRenderPassColorMatrixProgram(tex_coord_precision);
+ GetRenderPassColorMatrixProgram(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1334,9 +1266,12 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
program->fragment_shader().color_matrix_location();
shader_color_offset_location =
program->fragment_shader().color_offset_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else {
const RenderPassProgram* program =
- GetRenderPassProgram(tex_coord_precision);
+ GetRenderPassProgram(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1344,6 +1279,9 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
shader_alpha_location = program->fragment_shader().alpha_location();
shader_tex_transform_location =
program->vertex_shader().tex_transform_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
}
float tex_scale_x =
quad->rect.width() / static_cast<float>(contents_texture->size().width());
@@ -1363,6 +1301,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
tex_scale_x,
-tex_scale_y));
+ GLint last_texture_unit = 0;
scoped_ptr<ResourceProvider::ScopedSamplerGL> shader_mask_sampler_lock;
if (shader_mask_sampler_location != -1) {
DCHECK_NE(shader_mask_tex_coord_scale_location, 1);
@@ -1383,6 +1322,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
gl_->Uniform2f(shader_mask_tex_coord_scale_location,
mask_uv_rect.width() / tex_scale_x,
-mask_uv_rect.height() / tex_scale_y));
+
+ last_texture_unit = 1;
}
if (shader_edge_location != -1) {
@@ -1418,6 +1359,37 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
GLC(gl_, gl_->Uniform4fv(shader_color_offset_location, 1, offset));
}
+ scoped_ptr<ResourceProvider::ScopedSamplerGL> shader_background_sampler_lock;
+ if (shader_backdrop_location != -1) {
+ DCHECK(background_texture || background_image);
+ DCHECK_NE(shader_backdrop_location, 0);
+ DCHECK_NE(shader_backdrop_rect_location, 0);
+
+ GLC(gl_, gl_->Uniform1i(shader_backdrop_location, ++last_texture_unit));
+
+ GLC(gl_,
+ gl_->Uniform4f(shader_backdrop_rect_location,
+ background_rect.x(),
+ background_rect.y(),
+ background_rect.width(),
+ background_rect.height()));
+
+ if (background_image) {
+ GrTexture* texture = background_image->getTexture();
+ GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0 + last_texture_unit));
+ gl_->BindTexture(GL_TEXTURE_2D, texture->getTextureHandle());
+ GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0));
+ } else {
+ shader_background_sampler_lock = make_scoped_ptr(
+ new ResourceProvider::ScopedSamplerGL(resource_provider_,
+ background_texture->id(),
+ GL_TEXTURE0 + last_texture_unit,
+ GL_LINEAR));
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ shader_background_sampler_lock->target());
+ }
+ }
+
// Map device space quad to surface space. contents_device_transform has no 3d
// component since it was flattened, so we don't need to project.
gfx::QuadF surface_quad = MathUtil::MapQuad(contents_device_transform_inverse,
@@ -2353,7 +2325,8 @@ void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame,
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
gl_, &highp_threshold_cache_, highp_threshold_min_, rect.bottom_right());
- const RenderPassProgram* program = GetRenderPassProgram(tex_coord_precision);
+ const RenderPassProgram* program =
+ GetRenderPassProgram(tex_coord_precision, BlendModeNormal);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -2832,112 +2805,155 @@ const GLRenderer::SolidColorProgramAA* GLRenderer::GetSolidColorProgramAA() {
}
const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
- RenderPassProgram* program = &render_pass_program_[precision];
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
+ RenderPassProgram* program = &render_pass_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
- RenderPassProgramAA* program = &render_pass_program_aa_[precision];
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
+ RenderPassProgramAA* program =
+ &render_pass_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassMaskProgram* GLRenderer::GetRenderPassMaskProgram(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
- RenderPassMaskProgram* program = &render_pass_mask_program_[precision];
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
+ RenderPassMaskProgram* program =
+ &render_pass_mask_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassMaskProgramAA*
-GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
- RenderPassMaskProgramAA* program = &render_pass_mask_program_aa_[precision];
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
+ RenderPassMaskProgramAA* program =
+ &render_pass_mask_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassColorMatrixProgram*
-GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
RenderPassColorMatrixProgram* program =
- &render_pass_color_matrix_program_[precision];
+ &render_pass_color_matrix_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassColorMatrixProgramAA*
-GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
RenderPassColorMatrixProgramAA* program =
- &render_pass_color_matrix_program_aa_[precision];
+ &render_pass_color_matrix_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::renderPassColorMatrixProgramAA::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassMaskColorMatrixProgram*
-GLRenderer::GetRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassMaskColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
RenderPassMaskColorMatrixProgram* program =
- &render_pass_mask_color_matrix_program_[precision];
+ &render_pass_mask_color_matrix_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::renderPassMaskColorMatrixProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassMaskColorMatrixProgramAA*
-GLRenderer::GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
RenderPassMaskColorMatrixProgramAA* program =
- &render_pass_mask_color_matrix_program_aa_[precision];
+ &render_pass_mask_color_matrix_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::renderPassMaskColorMatrixProgramAA::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
@@ -3163,15 +3179,16 @@ void GLRenderer::CleanupSharedObjects() {
tile_program_aa_[i][j].Cleanup(gl_);
tile_program_swizzle_aa_[i][j].Cleanup(gl_);
}
-
- render_pass_mask_program_[i].Cleanup(gl_);
- render_pass_program_[i].Cleanup(gl_);
- render_pass_mask_program_aa_[i].Cleanup(gl_);
- render_pass_program_aa_[i].Cleanup(gl_);
- render_pass_color_matrix_program_[i].Cleanup(gl_);
- render_pass_mask_color_matrix_program_aa_[i].Cleanup(gl_);
- render_pass_color_matrix_program_aa_[i].Cleanup(gl_);
- render_pass_mask_color_matrix_program_[i].Cleanup(gl_);
+ for (int j = 0; j < NumBlendModes; j++) {
+ render_pass_mask_program_[i][j].Cleanup(gl_);
+ render_pass_program_[i][j].Cleanup(gl_);
+ render_pass_mask_program_aa_[i][j].Cleanup(gl_);
+ render_pass_program_aa_[i][j].Cleanup(gl_);
+ render_pass_color_matrix_program_[i][j].Cleanup(gl_);
+ render_pass_mask_color_matrix_program_aa_[i][j].Cleanup(gl_);
+ render_pass_color_matrix_program_aa_[i][j].Cleanup(gl_);
+ render_pass_mask_color_matrix_program_[i][j].Cleanup(gl_);
+ }
texture_program_[i].Cleanup(gl_);
nonpremultiplied_texture_program_[i].Cleanup(gl_);
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index a379dc0..676e7b7 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -153,7 +153,8 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
gfx::Rect GetBackdropBoundingBoxForRenderPassQuad(
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
- const gfx::Transform& contents_device_transform);
+ const gfx::Transform& contents_device_transform,
+ bool use_aa);
scoped_ptr<ScopedResource> GetBackdropTexture(const gfx::Rect& bounding_rect);
static bool ShouldApplyBackgroundFilters(DrawingFrame* frame,
@@ -166,7 +167,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform_inverse,
- ScopedResource* background_texture,
skia::RefPtr<SkImage> backdrop_bitmap,
const gfx::Rect& backdrop_bounding_rect);
@@ -328,22 +328,28 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
const TileCheckerboardProgram* GetTileCheckerboardProgram();
- const RenderPassProgram* GetRenderPassProgram(
- TexCoordPrecision precision);
- const RenderPassProgramAA* GetRenderPassProgramAA(
- TexCoordPrecision precision);
+ const RenderPassProgram* GetRenderPassProgram(TexCoordPrecision precision,
+ BlendMode blend_mode);
+ const RenderPassProgramAA* GetRenderPassProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassMaskProgram* GetRenderPassMaskProgram(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassMaskProgramAA* GetRenderPassMaskProgramAA(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassColorMatrixProgram* GetRenderPassColorMatrixProgram(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassColorMatrixProgramAA* GetRenderPassColorMatrixProgramAA(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassMaskColorMatrixProgram* GetRenderPassMaskColorMatrixProgram(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassMaskColorMatrixProgramAA*
- GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision);
+ GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode);
const TextureProgram* GetTextureProgram(
TexCoordPrecision precision);
@@ -388,18 +394,21 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
nonpremultiplied_texture_background_program_[NumTexCoordPrecisions];
TextureProgram texture_io_surface_program_[NumTexCoordPrecisions];
- RenderPassProgram render_pass_program_[NumTexCoordPrecisions];
- RenderPassProgramAA render_pass_program_aa_[NumTexCoordPrecisions];
- RenderPassMaskProgram render_pass_mask_program_[NumTexCoordPrecisions];
- RenderPassMaskProgramAA render_pass_mask_program_aa_[NumTexCoordPrecisions];
+ RenderPassProgram render_pass_program_[NumTexCoordPrecisions][NumBlendModes];
+ RenderPassProgramAA
+ render_pass_program_aa_[NumTexCoordPrecisions][NumBlendModes];
+ RenderPassMaskProgram
+ render_pass_mask_program_[NumTexCoordPrecisions][NumBlendModes];
+ RenderPassMaskProgramAA
+ render_pass_mask_program_aa_[NumTexCoordPrecisions][NumBlendModes];
RenderPassColorMatrixProgram
- render_pass_color_matrix_program_[NumTexCoordPrecisions];
- RenderPassColorMatrixProgramAA
- render_pass_color_matrix_program_aa_[NumTexCoordPrecisions];
- RenderPassMaskColorMatrixProgram
- render_pass_mask_color_matrix_program_[NumTexCoordPrecisions];
- RenderPassMaskColorMatrixProgramAA
- render_pass_mask_color_matrix_program_aa_[NumTexCoordPrecisions];
+ render_pass_color_matrix_program_[NumTexCoordPrecisions][NumBlendModes];
+ RenderPassColorMatrixProgramAA render_pass_color_matrix_program_aa_
+ [NumTexCoordPrecisions][NumBlendModes];
+ RenderPassMaskColorMatrixProgram render_pass_mask_color_matrix_program_
+ [NumTexCoordPrecisions][NumBlendModes];
+ RenderPassMaskColorMatrixProgramAA render_pass_mask_color_matrix_program_aa_
+ [NumTexCoordPrecisions][NumBlendModes];
VideoYUVProgram video_yuv_program_[NumTexCoordPrecisions];
VideoYUVAProgram video_yuva_program_[NumTexCoordPrecisions];
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index 6234e9e..8de90c4 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -55,6 +55,44 @@ class GLRendererTest : public testing::Test {
EXPECT_TRUE((program_binding)->initialized()); \
} while (false)
+static inline SkXfermode::Mode BlendModeToSkXfermode(BlendMode blend_mode) {
+ switch (blend_mode) {
+ case BlendModeNormal:
+ return SkXfermode::kSrcOver_Mode;
+ case BlendModeOverlay:
+ return SkXfermode::kOverlay_Mode;
+ case BlendModeDarken:
+ return SkXfermode::kDarken_Mode;
+ case BlendModeLighten:
+ return SkXfermode::kLighten_Mode;
+ case BlendModeColorDodge:
+ return SkXfermode::kColorDodge_Mode;
+ case BlendModeColorBurn:
+ return SkXfermode::kColorBurn_Mode;
+ case BlendModeHardLight:
+ return SkXfermode::kHardLight_Mode;
+ case BlendModeSoftLight:
+ return SkXfermode::kSoftLight_Mode;
+ case BlendModeDifference:
+ return SkXfermode::kDifference_Mode;
+ case BlendModeExclusion:
+ return SkXfermode::kExclusion_Mode;
+ case BlendModeMultiply:
+ return SkXfermode::kMultiply_Mode;
+ case BlendModeHue:
+ return SkXfermode::kHue_Mode;
+ case BlendModeSaturation:
+ return SkXfermode::kSaturation_Mode;
+ case BlendModeColor:
+ return SkXfermode::kColor_Mode;
+ case BlendModeLuminosity:
+ return SkXfermode::kLuminosity_Mode;
+ case NumBlendModes:
+ NOTREACHED();
+ }
+ return SkXfermode::kSrcOver_Mode;
+}
+
// Explicitly named to be a friend in GLRenderer for shader access.
class GLRendererShaderPixelTest : public GLRendererPixelTest {
public:
@@ -70,18 +108,25 @@ class GLRendererShaderPixelTest : public GLRendererPixelTest {
}
void TestShadersWithTexCoordPrecision(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgram(precision));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgramAA(precision));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgram(precision));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgramAA(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassColorMatrixProgram(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassMaskColorMatrixProgramAA(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassColorMatrixProgramAA(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassMaskColorMatrixProgram(precision));
+ for (int i = 0; i < NumBlendModes; ++i) {
+ BlendMode blend_mode = static_cast<BlendMode>(i);
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgram(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgramAA(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassMaskProgram(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassMaskProgramAA(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassColorMatrixProgram(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgramAA(
+ precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassColorMatrixProgramAA(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgram(
+ precision, blend_mode));
+ }
EXPECT_PROGRAM_VALID(renderer()->GetTextureProgram(precision));
EXPECT_PROGRAM_VALID(
renderer()->GetNonPremultipliedTextureProgram(precision));
@@ -202,61 +247,84 @@ class GLRendererShaderTest : public GLRendererTest {
resource_provider_.get()));
}
- void TestRenderPassProgram(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(&renderer_->render_pass_program_[precision]);
- EXPECT_EQ(renderer_->render_pass_program_[precision].program(),
- renderer_->program_shadow_);
- }
-
- void TestRenderPassColorMatrixProgram(TexCoordPrecision precision) {
+ void TestRenderPassProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
- &renderer_->render_pass_color_matrix_program_[precision]);
- EXPECT_EQ(renderer_->render_pass_color_matrix_program_[precision].program(),
+ &renderer_->render_pass_program_[precision][blend_mode]);
+ EXPECT_EQ(renderer_->render_pass_program_[precision][blend_mode].program(),
renderer_->program_shadow_);
}
- void TestRenderPassMaskProgram(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_program_[precision]);
- EXPECT_EQ(renderer_->render_pass_mask_program_[precision].program(),
- renderer_->program_shadow_);
+ void TestRenderPassColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_->render_pass_color_matrix_program_[precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_->render_pass_color_matrix_program_[precision][blend_mode]
+ .program(),
+ renderer_->program_shadow_);
}
- void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) {
+ void TestRenderPassMaskProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
- &renderer_->render_pass_mask_color_matrix_program_[precision]);
+ &renderer_->render_pass_mask_program_[precision][blend_mode]);
EXPECT_EQ(
- renderer_->render_pass_mask_color_matrix_program_[precision].program(),
+ renderer_->render_pass_mask_program_[precision][blend_mode].program(),
renderer_->program_shadow_);
}
- void TestRenderPassProgramAA(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(&renderer_->render_pass_program_aa_[precision]);
- EXPECT_EQ(renderer_->render_pass_program_aa_[precision].program(),
- renderer_->program_shadow_);
+ void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_
+ ->render_pass_mask_color_matrix_program_[precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_->render_pass_mask_color_matrix_program_[precision][blend_mode]
+ .program(),
+ renderer_->program_shadow_);
}
- void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision) {
+ void TestRenderPassProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
- &renderer_->render_pass_color_matrix_program_aa_[precision]);
+ &renderer_->render_pass_program_aa_[precision][blend_mode]);
EXPECT_EQ(
- renderer_->render_pass_color_matrix_program_aa_[precision].program(),
+ renderer_->render_pass_program_aa_[precision][blend_mode].program(),
renderer_->program_shadow_);
}
- void TestRenderPassMaskProgramAA(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_program_aa_[precision]);
- EXPECT_EQ(renderer_->render_pass_mask_program_aa_[precision].program(),
- renderer_->program_shadow_);
+ void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_
+ ->render_pass_color_matrix_program_aa_[precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_->render_pass_color_matrix_program_aa_[precision][blend_mode]
+ .program(),
+ renderer_->program_shadow_);
}
- void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) {
+ void TestRenderPassMaskProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
- &renderer_->render_pass_mask_color_matrix_program_aa_[precision]);
- EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_aa_[precision]
+ &renderer_->render_pass_mask_program_aa_[precision][blend_mode]);
+ EXPECT_EQ(renderer_->render_pass_mask_program_aa_[precision][blend_mode]
.program(),
renderer_->program_shadow_);
}
+ void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_color_matrix_program_aa_
+ [precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_
+ ->render_pass_mask_color_matrix_program_aa_[precision][blend_mode]
+ .program(),
+ renderer_->program_shadow_);
+ }
+
void TestSolidColorProgramAA() {
EXPECT_PROGRAM_VALID(&renderer_->solid_color_program_aa_);
EXPECT_EQ(renderer_->solid_color_program_aa_.program(),
@@ -1348,191 +1416,224 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
gfx::Transform transform_causing_aa;
transform_causing_aa.Rotate(20.0);
- // RenderPassProgram
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- gfx::Transform());
+ for (int i = 0; i < NumBlendModes; ++i) {
+ BlendMode blend_mode = static_cast<BlendMode>(i);
+ SkXfermode::Mode xfer_mode = BlendModeToSkXfermode(blend_mode);
+ // RenderPassProgram
+ render_passes_in_draw_order_.clear();
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
+
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ 0,
+ FilterOperations(),
+ gfx::Transform(),
+ xfer_mode);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassProgram(TexCoordPrecisionMedium, blend_mode);
- AddRenderPassQuad(
- root_pass, child_pass, 0, FilterOperations(), gfx::Transform());
+ // RenderPassColorMatrixProgram
+ render_passes_in_draw_order_.clear();
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassProgram(TexCoordPrecisionMedium);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- // RenderPassColorMatrixProgram
- render_passes_in_draw_order_.clear();
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ AddRenderPassQuad(
+ root_pass, child_pass, 0, filters, gfx::Transform(), xfer_mode);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassColorMatrixProgram(TexCoordPrecisionMedium, blend_mode);
- AddRenderPassQuad(root_pass, child_pass, 0, filters, gfx::Transform());
+ // RenderPassMaskProgram
+ render_passes_in_draw_order_.clear();
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassColorMatrixProgram(TexCoordPrecisionMedium);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
- // RenderPassMaskProgram
- render_passes_in_draw_order_.clear();
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- gfx::Transform());
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ mask,
+ FilterOperations(),
+ gfx::Transform(),
+ xfer_mode);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskProgram(TexCoordPrecisionMedium, blend_mode);
- AddRenderPassQuad(
- root_pass, child_pass, mask, FilterOperations(), gfx::Transform());
+ // RenderPassMaskColorMatrixProgram
+ render_passes_in_draw_order_.clear();
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassMaskProgram(TexCoordPrecisionMedium);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
- // RenderPassMaskColorMatrixProgram
- render_passes_in_draw_order_.clear();
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- gfx::Transform());
+ AddRenderPassQuad(
+ root_pass, child_pass, mask, filters, gfx::Transform(), xfer_mode);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
-
- AddRenderPassQuad(root_pass, child_pass, mask, filters, gfx::Transform());
-
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassMaskColorMatrixProgram(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskColorMatrixProgram(TexCoordPrecisionMedium, blend_mode);
- // RenderPassProgramAA
- render_passes_in_draw_order_.clear();
+ // RenderPassProgramAA
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(
- root_pass, child_pass, 0, FilterOperations(), transform_causing_aa);
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ 0,
+ FilterOperations(),
+ transform_causing_aa,
+ xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassProgramAA(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassProgramAA(TexCoordPrecisionMedium, blend_mode);
- // RenderPassColorMatrixProgramAA
- render_passes_in_draw_order_.clear();
+ // RenderPassColorMatrixProgramAA
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(root_pass, child_pass, 0, filters, transform_causing_aa);
+ AddRenderPassQuad(
+ root_pass, child_pass, 0, filters, transform_causing_aa, xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassColorMatrixProgramAA(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassColorMatrixProgramAA(TexCoordPrecisionMedium, blend_mode);
- // RenderPassMaskProgramAA
- render_passes_in_draw_order_.clear();
+ // RenderPassMaskProgramAA
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(
- root_pass, child_pass, mask, FilterOperations(), transform_causing_aa);
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ mask,
+ FilterOperations(),
+ transform_causing_aa,
+ xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassMaskProgramAA(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskProgramAA(TexCoordPrecisionMedium, blend_mode);
- // RenderPassMaskColorMatrixProgramAA
- render_passes_in_draw_order_.clear();
+ // RenderPassMaskColorMatrixProgramAA
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- transform_causing_aa);
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ transform_causing_aa);
- AddRenderPassQuad(root_pass, child_pass, mask, filters, transform_causing_aa);
+ AddRenderPassQuad(
+ root_pass, child_pass, mask, filters, transform_causing_aa, xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecisionMedium, blend_mode);
+ }
}
// At this time, the AA code path cannot be taken if the surface's rect would
@@ -1567,8 +1668,12 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) {
viewport_rect,
gfx::Transform());
- AddRenderPassQuad(
- root_pass, child_pass, 0, FilterOperations(), transform_preventing_aa);
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ 0,
+ FilterOperations(),
+ transform_preventing_aa,
+ SkXfermode::kSrcOver_Mode);
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
@@ -1579,7 +1684,7 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) {
// If use_aa incorrectly ignores clipping, it will use the
// RenderPassProgramAA shader instead of the RenderPassProgram.
- TestRenderPassProgram(TexCoordPrecisionMedium);
+ TestRenderPassProgram(TexCoordPrecisionMedium, BlendModeNormal);
}
TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
diff --git a/cc/output/program_binding.h b/cc/output/program_binding.h
index 912329e..722c782 100644
--- a/cc/output/program_binding.h
+++ b/cc/output/program_binding.h
@@ -58,13 +58,16 @@ class ProgramBinding : public ProgramBindingBase {
void Initialize(ContextProvider* context_provider,
TexCoordPrecision precision,
- SamplerType sampler) {
+ SamplerType sampler,
+ BlendMode blend_mode = BlendModeNormal) {
DCHECK(context_provider);
DCHECK(!initialized_);
if (context_provider->IsContextLost())
return;
+ fragment_shader_.set_blend_mode(blend_mode);
+
if (!ProgramBindingBase::Init(
context_provider->ContextGL(),
vertex_shader_.GetShaderString(),
diff --git a/cc/output/shader.cc b/cc/output/shader.cc
index 8a25214..98bde8d 100644
--- a/cc/output/shader.cc
+++ b/cc/output/shader.cc
@@ -13,9 +13,10 @@
#define SHADER0(Src) #Src
#define VERTEX_SHADER(Src) SetVertexTexCoordPrecision(SHADER0(Src))
-#define FRAGMENT_SHADER(Src) \
- SetFragmentTexCoordPrecision(precision, \
- SetFragmentSamplerType(sampler, SHADER0(Src)))
+#define FRAGMENT_SHADER(Src) \
+ SetFragmentTexCoordPrecision( \
+ precision, \
+ SetFragmentSamplerType(sampler, SetBlendModeFunctions(SHADER0(Src))))
using gpu::gles2::GLES2Interface;
@@ -666,6 +667,308 @@ std::string VertexShaderVideoTransform::GetShaderString() const {
// clang-format on
}
+#define BLEND_MODE_UNIFORMS "s_backdropTexture", "backdropRect"
+#define UNUSED_BLEND_MODE_UNIFORMS (is_default_blend_mode() ? 2 : 0)
+#define BLEND_MODE_SET_LOCATIONS(X, POS) \
+ if (!is_default_blend_mode()) { \
+ DCHECK_LT(static_cast<size_t>(POS) + 1, arraysize(X)); \
+ backdrop_location_ = locations[POS]; \
+ backdrop_rect_location_ = locations[POS + 1]; \
+ }
+
+FragmentTexBlendMode::FragmentTexBlendMode()
+ : backdrop_location_(-1),
+ backdrop_rect_location_(-1),
+ blend_mode_(BlendModeNormal) {
+}
+
+std::string FragmentTexBlendMode::SetBlendModeFunctions(
+ std::string shader_string) const {
+ if (shader_string.find("ApplyBlendMode") == std::string::npos)
+ return shader_string;
+
+ if (is_default_blend_mode()) {
+ return "#define ApplyBlendMode(X) (X)\n" + shader_string;
+ }
+
+ // clang-format off
+ static const std::string kFunctionApplyBlendMode = SHADER0(
+ // clang-format on
+ uniform SamplerType s_backdropTexture;
+ uniform TexCoordPrecision vec4 backdropRect;
+
+ vec4 GetBackdropColor() {
+ TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
+ bgTexCoord.x /= backdropRect.z;
+ bgTexCoord.y /= backdropRect.w;
+ return TextureLookup(s_backdropTexture, bgTexCoord);
+ }
+
+ vec4 ApplyBlendMode(vec4 src) {
+ vec4 dst = GetBackdropColor();
+ return Blend(src, dst);
+ }
+ // clang-format off
+ );
+ // clang-format on
+
+ return "precision mediump float;" + GetHelperFunctions() +
+ GetBlendFunction() + kFunctionApplyBlendMode + shader_string;
+}
+
+std::string FragmentTexBlendMode::GetHelperFunctions() const {
+ // clang-format off
+ static const std::string kFunctionHardLight = SHADER0(
+ // clang-format on
+ vec3 hardLight(vec4 src, vec4 dst) {
+ vec3 result;
+ result.r =
+ (2.0 * src.r <= src.a)
+ ? (2.0 * src.r * dst.r)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.r) * (src.a - src.r));
+ result.g =
+ (2.0 * src.g <= src.a)
+ ? (2.0 * src.g * dst.g)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.g) * (src.a - src.g));
+ result.b =
+ (2.0 * src.b <= src.a)
+ ? (2.0 * src.b * dst.b)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.b) * (src.a - src.b));
+ result.rgb += src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
+ return result;
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionColorDodgeComponent = SHADER0(
+ // clang-format on
+ float getColorDodgeComponent(
+ float srcc, float srca, float dstc, float dsta) {
+ if (0.0 == dstc)
+ return srcc * (1.0 - dsta);
+ float d = srca - srcc;
+ if (0.0 == d)
+ return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ d = min(dsta, dstc * srca / d);
+ return d * srca + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionColorBurnComponent = SHADER0(
+ // clang-format on
+ float getColorBurnComponent(
+ float srcc, float srca, float dstc, float dsta) {
+ if (dsta == dstc)
+ return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ if (0.0 == srcc)
+ return dstc * (1.0 - srca);
+ float d = max(0.0, dsta - (dsta - dstc) * srca / srcc);
+ return srca * d + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionSoftLightComponentPosDstAlpha = SHADER0(
+ // clang-format on
+ float getSoftLightComponent(
+ float srcc, float srca, float dstc, float dsta) {
+ if (2.0 * srcc <= srca) {
+ return (dstc * dstc * (srca - 2.0 * srcc)) / dsta +
+ (1.0 - dsta) * srcc + dstc * (-srca + 2.0 * srcc + 1.0);
+ } else if (4.0 * dstc <= dsta) {
+ float DSqd = dstc * dstc;
+ float DCub = DSqd * dstc;
+ float DaSqd = dsta * dsta;
+ float DaCub = DaSqd * dsta;
+ return (-DaCub * srcc +
+ DaSqd * (srcc - dstc * (3.0 * srca - 6.0 * srcc - 1.0)) +
+ 12.0 * dsta * DSqd * (srca - 2.0 * srcc) -
+ 16.0 * DCub * (srca - 2.0 * srcc)) /
+ DaSqd;
+ } else {
+ return -sqrt(dsta * dstc) * (srca - 2.0 * srcc) - dsta * srcc +
+ dstc * (srca - 2.0 * srcc + 1.0) + srcc;
+ }
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionLum = SHADER0(
+ // clang-format on
+ float luminance(vec3 color) { return dot(vec3(0.3, 0.59, 0.11), color); }
+
+ vec3 set_luminance(vec3 hueSat, float alpha, vec3 lumColor) {
+ float diff = luminance(lumColor - hueSat);
+ vec3 outColor = hueSat + diff;
+ float outLum = luminance(outColor);
+ float minComp = min(min(outColor.r, outColor.g), outColor.b);
+ float maxComp = max(max(outColor.r, outColor.g), outColor.b);
+ if (minComp < 0.0) {
+ outColor = outLum +
+ ((outColor - vec3(outLum, outLum, outLum)) * outLum) /
+ (outLum - minComp);
+ }
+ if (maxComp > alpha) {
+ outColor =
+ outLum +
+ ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /
+ (maxComp - outLum);
+ }
+ return outColor;
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionSat = SHADER0(
+ // clang-format on
+ float saturation(vec3 color) {
+ return max(max(color.r, color.g), color.b) -
+ min(min(color.r, color.g), color.b);
+ }
+
+ vec3 set_saturation_helper(
+ float minComp, float midComp, float maxComp, float sat) {
+ if (minComp < maxComp) {
+ vec3 result;
+ result.r = 0.0;
+ result.g = sat * (midComp - minComp) / (maxComp - minComp);
+ result.b = sat;
+ return result;
+ } else {
+ return vec3(0, 0, 0);
+ }
+ }
+
+ vec3 set_saturation(vec3 hueLumColor, vec3 satColor) {
+ float sat = saturation(satColor);
+ if (hueLumColor.r <= hueLumColor.g) {
+ if (hueLumColor.g <= hueLumColor.b) {
+ hueLumColor.rgb = set_saturation_helper(
+ hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);
+ } else if (hueLumColor.r <= hueLumColor.b) {
+ hueLumColor.rbg = set_saturation_helper(
+ hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);
+ } else {
+ hueLumColor.brg = set_saturation_helper(
+ hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);
+ }
+ } else if (hueLumColor.r <= hueLumColor.b) {
+ hueLumColor.grb = set_saturation_helper(
+ hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);
+ } else if (hueLumColor.g <= hueLumColor.b) {
+ hueLumColor.gbr = set_saturation_helper(
+ hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);
+ } else {
+ hueLumColor.bgr = set_saturation_helper(
+ hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);
+ }
+ return hueLumColor;
+ }
+ // clang-format off
+ );
+ // clang-format on
+
+ switch (blend_mode_) {
+ case BlendModeOverlay:
+ case BlendModeHardLight:
+ return kFunctionHardLight;
+ case BlendModeColorDodge:
+ return kFunctionColorDodgeComponent;
+ case BlendModeColorBurn:
+ return kFunctionColorBurnComponent;
+ case BlendModeSoftLight:
+ return kFunctionSoftLightComponentPosDstAlpha;
+ case BlendModeHue:
+ case BlendModeSaturation:
+ return kFunctionLum + kFunctionSat;
+ case BlendModeColor:
+ case BlendModeLuminosity:
+ return kFunctionLum;
+ default:
+ return std::string();
+ }
+}
+
+std::string FragmentTexBlendMode::GetBlendFunction() const {
+ return "vec4 Blend(vec4 src, vec4 dst) {"
+ " vec4 result;"
+ " result.a = src.a + (1.0 - src.a) * dst.a;" +
+ GetBlendFunctionBodyForRGB() +
+ " return result;"
+ "}";
+}
+
+std::string FragmentTexBlendMode::GetBlendFunctionBodyForRGB() const {
+ switch (blend_mode_) {
+ case BlendModeLighten:
+ return "result.rgb = max((1.0 - src.a) * dst.rgb + src.rgb,"
+ " (1.0 - dst.a) * src.rgb + dst.rgb);";
+ case BlendModeOverlay:
+ return "result.rgb = hardLight(dst, src);";
+ case BlendModeDarken:
+ return "result.rgb = min((1.0 - src.a) * dst.rgb + src.rgb,"
+ " (1.0 - dst.a) * src.rgb + dst.rgb);";
+ case BlendModeColorDodge:
+ return "result.r = getColorDodgeComponent(src.r, src.a, dst.r, dst.a);"
+ "result.g = getColorDodgeComponent(src.g, src.a, dst.g, dst.a);"
+ "result.b = getColorDodgeComponent(src.b, src.a, dst.b, dst.a);";
+ case BlendModeColorBurn:
+ return "result.r = getColorBurnComponent(src.r, src.a, dst.r, dst.a);"
+ "result.g = getColorBurnComponent(src.g, src.a, dst.g, dst.a);"
+ "result.b = getColorBurnComponent(src.b, src.a, dst.b, dst.a);";
+ case BlendModeHardLight:
+ return "result.rgb = hardLight(src, dst);";
+ case BlendModeSoftLight:
+ return "if (0.0 == dst.a) {"
+ " result.rgb = src.rgb;"
+ "} else {"
+ " result.r = getSoftLightComponent(src.r, src.a, dst.r, dst.a);"
+ " result.g = getSoftLightComponent(src.g, src.a, dst.g, dst.a);"
+ " result.b = getSoftLightComponent(src.b, src.a, dst.b, dst.a);"
+ "}";
+ case BlendModeDifference:
+ return "result.rgb = src.rgb + dst.rgb -"
+ " 2.0 * min(src.rgb * dst.a, dst.rgb * src.a);";
+ case BlendModeExclusion:
+ return "result.rgb = dst.rgb + src.rgb - 2.0 * dst.rgb * src.rgb;";
+ case BlendModeMultiply:
+ return "result.rgb = (1.0 - src.a) * dst.rgb +"
+ " (1.0 - dst.a) * src.rgb + src.rgb * dst.rgb;";
+ case BlendModeHue:
+ return "vec4 dstSrcAlpha = dst * src.a;"
+ "result.rgb ="
+ " set_luminance(set_saturation(src.rgb * dst.a,"
+ " dstSrcAlpha.rgb),"
+ " dstSrcAlpha.a,"
+ " dstSrcAlpha.rgb);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BlendModeSaturation:
+ return "vec4 dstSrcAlpha = dst * src.a;"
+ "result.rgb = set_luminance(set_saturation(dstSrcAlpha.rgb,"
+ " src.rgb * dst.a),"
+ " dstSrcAlpha.a,"
+ " dstSrcAlpha.rgb);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BlendModeColor:
+ return "vec4 srcDstAlpha = src * dst.a;"
+ "result.rgb = set_luminance(srcDstAlpha.rgb,"
+ " srcDstAlpha.a,"
+ " dst.rgb * src.a);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BlendModeLuminosity:
+ return "vec4 srcDstAlpha = src * dst.a;"
+ "result.rgb = set_luminance(dst.rgb * src.a,"
+ " srcDstAlpha.a,"
+ " srcDstAlpha.rgb);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ default:
+ NOTREACHED();
+ // simple alpha compositing
+ return "result.rgb = src.rgb * src.a + dst.rgb * dst.a * (1 - src.a)";
+ }
+}
+
FragmentTexAlphaBinding::FragmentTexAlphaBinding()
: sampler_location_(-1), alpha_location_(-1) {
}
@@ -674,18 +977,19 @@ void FragmentTexAlphaBinding::Init(GLES2Interface* context,
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "alpha",
+ "s_texture", "alpha", BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
sampler_location_ = locations[0];
alpha_location_ = locations[1];
+ BLEND_MODE_SET_LOCATIONS(locations, 2);
}
FragmentTexColorMatrixAlphaBinding::FragmentTexColorMatrixAlphaBinding()
@@ -699,13 +1003,13 @@ void FragmentTexColorMatrixAlphaBinding::Init(GLES2Interface* context,
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "alpha", "colorMatrix", "colorOffset",
+ "s_texture", "alpha", "colorMatrix", "colorOffset", BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -713,6 +1017,7 @@ void FragmentTexColorMatrixAlphaBinding::Init(GLES2Interface* context,
alpha_location_ = locations[1];
color_matrix_location_ = locations[2];
color_offset_location_ = locations[3];
+ BLEND_MODE_SET_LOCATIONS(locations, 4);
}
FragmentTexOpaqueBinding::FragmentTexOpaqueBinding() : sampler_location_(-1) {
@@ -747,7 +1052,7 @@ std::string FragmentShaderRGBATexAlpha::GetShaderString(
uniform float alpha;
void main() {
vec4 texColor = TextureLookup(s_texture, v_texCoord);
- gl_FragColor = texColor * alpha;
+ gl_FragColor = ApplyBlendMode(texColor * alpha);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -773,7 +1078,7 @@ std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderString(
texColor = colorMatrix * texColor + colorOffset;
texColor.rgb *= texColor.a;
texColor = clamp(texColor, 0.0, 1.0);
- gl_FragColor = texColor * alpha;
+ gl_FragColor = ApplyBlendMode(texColor * alpha);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -966,18 +1271,19 @@ void FragmentShaderRGBATexAlphaAA::Init(GLES2Interface* context,
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "alpha",
+ "s_texture", "alpha", BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
sampler_location_ = locations[0];
alpha_location_ = locations[1];
+ BLEND_MODE_SET_LOCATIONS(locations, 2);
}
std::string FragmentShaderRGBATexAlphaAA::GetShaderString(
@@ -997,7 +1303,7 @@ std::string FragmentShaderRGBATexAlphaAA::GetShaderString(
vec4 d4 = min(edge_dist[0], edge_dist[1]);
vec2 d2 = min(d4.xz, d4.yw);
float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = texColor * alpha * aa;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1097,13 +1403,18 @@ void FragmentShaderRGBATexAlphaMask::Init(GLES2Interface* context,
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "s_mask", "alpha", "maskTexCoordScale", "maskTexCoordOffset",
+ "s_texture",
+ "s_mask",
+ "alpha",
+ "maskTexCoordScale",
+ "maskTexCoordOffset",
+ BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1112,6 +1423,7 @@ void FragmentShaderRGBATexAlphaMask::Init(GLES2Interface* context,
alpha_location_ = locations[2];
mask_tex_coord_scale_location_ = locations[3];
mask_tex_coord_offset_location_ = locations[4];
+ BLEND_MODE_SET_LOCATIONS(locations, 5);
}
std::string FragmentShaderRGBATexAlphaMask::GetShaderString(
@@ -1133,7 +1445,7 @@ std::string FragmentShaderRGBATexAlphaMask::GetShaderString(
vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
- gl_FragColor = texColor * alpha * maskColor.w;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1152,13 +1464,18 @@ void FragmentShaderRGBATexAlphaMaskAA::Init(GLES2Interface* context,
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "s_mask", "alpha", "maskTexCoordScale", "maskTexCoordOffset",
+ "s_texture",
+ "s_mask",
+ "alpha",
+ "maskTexCoordScale",
+ "maskTexCoordOffset",
+ BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1167,6 +1484,7 @@ void FragmentShaderRGBATexAlphaMaskAA::Init(GLES2Interface* context,
alpha_location_ = locations[2];
mask_tex_coord_scale_location_ = locations[3];
mask_tex_coord_offset_location_ = locations[4];
+ BLEND_MODE_SET_LOCATIONS(locations, 5);
}
std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderString(
@@ -1193,7 +1511,7 @@ std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderString(
vec4 d4 = min(edge_dist[0], edge_dist[1]);
vec2 d2 = min(d4.xz, d4.yw);
float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = texColor * alpha * maskColor.w * aa;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1222,12 +1540,13 @@ void FragmentShaderRGBATexAlphaMaskColorMatrixAA::Init(
"maskTexCoordOffset",
"colorMatrix",
"colorOffset",
+ BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1238,6 +1557,7 @@ void FragmentShaderRGBATexAlphaMaskColorMatrixAA::Init(
mask_tex_coord_offset_location_ = locations[4];
color_matrix_location_ = locations[5];
color_offset_location_ = locations[6];
+ BLEND_MODE_SET_LOCATIONS(locations, 7);
}
std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString(
@@ -1271,7 +1591,7 @@ std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString(
vec4 d4 = min(edge_dist[0], edge_dist[1]);
vec2 d2 = min(d4.xz, d4.yw);
float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = texColor * alpha * maskColor.w * aa;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1290,13 +1610,13 @@ void FragmentShaderRGBATexAlphaColorMatrixAA::Init(GLES2Interface* context,
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "alpha", "colorMatrix", "colorOffset",
+ "s_texture", "alpha", "colorMatrix", "colorOffset", BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1304,6 +1624,7 @@ void FragmentShaderRGBATexAlphaColorMatrixAA::Init(GLES2Interface* context,
alpha_location_ = locations[1];
color_matrix_location_ = locations[2];
color_offset_location_ = locations[3];
+ BLEND_MODE_SET_LOCATIONS(locations, 4);
}
std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderString(
@@ -1330,7 +1651,7 @@ std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderString(
vec4 d4 = min(edge_dist[0], edge_dist[1]);
vec2 d2 = min(d4.xz, d4.yw);
float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = texColor * alpha * aa;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1356,12 +1677,13 @@ void FragmentShaderRGBATexAlphaMaskColorMatrix::Init(GLES2Interface* context,
"maskTexCoordOffset",
"colorMatrix",
"colorOffset",
+ BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1372,6 +1694,7 @@ void FragmentShaderRGBATexAlphaMaskColorMatrix::Init(GLES2Interface* context,
mask_tex_coord_offset_location_ = locations[4];
color_matrix_location_ = locations[5];
color_offset_location_ = locations[6];
+ BLEND_MODE_SET_LOCATIONS(locations, 7);
}
std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderString(
@@ -1400,7 +1723,7 @@ std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderString(
vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
- gl_FragColor = texColor * alpha * maskColor.w;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
}
// clang-format off
); // NOLINT(whitespace/parens)
diff --git a/cc/output/shader.h b/cc/output/shader.h
index 3039c80..0384366 100644
--- a/cc/output/shader.h
+++ b/cc/output/shader.h
@@ -38,6 +38,25 @@ enum SamplerType {
NumSamplerTypes = 4
};
+enum BlendMode {
+ BlendModeNormal,
+ BlendModeOverlay,
+ BlendModeDarken,
+ BlendModeLighten,
+ BlendModeColorDodge,
+ BlendModeColorBurn,
+ BlendModeHardLight,
+ BlendModeSoftLight,
+ BlendModeDifference,
+ BlendModeExclusion,
+ BlendModeMultiply,
+ BlendModeHue,
+ BlendModeSaturation,
+ BlendModeColor,
+ BlendModeLuminosity,
+ NumBlendModes
+};
+
// Note: The highp_threshold_cache must be provided by the caller to make
// the caching multi-thread/context safe in an easy low-overhead manner.
// The caller must make sure to clear highp_threshold_cache to 0, so it can be
@@ -279,7 +298,32 @@ class VertexShaderVideoTransform {
DISALLOW_COPY_AND_ASSIGN(VertexShaderVideoTransform);
};
-class FragmentTexAlphaBinding {
+class FragmentTexBlendMode {
+ public:
+ int backdrop_location() const { return backdrop_location_; }
+ int backdrop_rect_location() const { return backdrop_rect_location_; }
+
+ BlendMode blend_mode() const { return blend_mode_; }
+ void set_blend_mode(BlendMode blend_mode) { blend_mode_ = blend_mode; }
+ bool is_default_blend_mode() const { return blend_mode_ == BlendModeNormal; }
+
+ protected:
+ FragmentTexBlendMode();
+
+ std::string SetBlendModeFunctions(std::string shader_string) const;
+
+ int backdrop_location_;
+ int backdrop_rect_location_;
+
+ private:
+ BlendMode blend_mode_;
+
+ std::string GetHelperFunctions() const;
+ std::string GetBlendFunction() const;
+ std::string GetBlendFunctionBodyForRGB() const;
+};
+
+class FragmentTexAlphaBinding : public FragmentTexBlendMode {
public:
FragmentTexAlphaBinding();
@@ -297,7 +341,7 @@ class FragmentTexAlphaBinding {
DISALLOW_COPY_AND_ASSIGN(FragmentTexAlphaBinding);
};
-class FragmentTexColorMatrixAlphaBinding {
+class FragmentTexColorMatrixAlphaBinding : public FragmentTexBlendMode {
public:
FragmentTexColorMatrixAlphaBinding();
@@ -317,7 +361,7 @@ class FragmentTexColorMatrixAlphaBinding {
int color_offset_location_;
};
-class FragmentTexOpaqueBinding {
+class FragmentTexOpaqueBinding : public FragmentTexBlendMode {
public:
FragmentTexOpaqueBinding();
@@ -335,7 +379,7 @@ class FragmentTexOpaqueBinding {
DISALLOW_COPY_AND_ASSIGN(FragmentTexOpaqueBinding);
};
-class FragmentTexBackgroundBinding {
+class FragmentTexBackgroundBinding : public FragmentTexBlendMode {
public:
FragmentTexBackgroundBinding();
@@ -417,7 +461,7 @@ class FragmentShaderRGBATexSwizzleOpaque : public FragmentTexOpaqueBinding {
TexCoordPrecision precision, SamplerType sampler) const;
};
-class FragmentShaderRGBATexAlphaAA {
+class FragmentShaderRGBATexAlphaAA : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaAA();
@@ -437,7 +481,7 @@ class FragmentShaderRGBATexAlphaAA {
DISALLOW_COPY_AND_ASSIGN(FragmentShaderRGBATexAlphaAA);
};
-class FragmentTexClampAlphaAABinding {
+class FragmentTexClampAlphaAABinding : public FragmentTexBlendMode {
public:
FragmentTexClampAlphaAABinding();
@@ -473,7 +517,7 @@ class FragmentShaderRGBATexClampSwizzleAlphaAA
TexCoordPrecision precision, SamplerType sampler) const;
};
-class FragmentShaderRGBATexAlphaMask {
+class FragmentShaderRGBATexAlphaMask : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaMask();
std::string GetShaderString(
@@ -502,7 +546,7 @@ class FragmentShaderRGBATexAlphaMask {
DISALLOW_COPY_AND_ASSIGN(FragmentShaderRGBATexAlphaMask);
};
-class FragmentShaderRGBATexAlphaMaskAA {
+class FragmentShaderRGBATexAlphaMaskAA : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaMaskAA();
std::string GetShaderString(
@@ -531,7 +575,8 @@ class FragmentShaderRGBATexAlphaMaskAA {
DISALLOW_COPY_AND_ASSIGN(FragmentShaderRGBATexAlphaMaskAA);
};
-class FragmentShaderRGBATexAlphaMaskColorMatrixAA {
+class FragmentShaderRGBATexAlphaMaskColorMatrixAA
+ : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaMaskColorMatrixAA();
std::string GetShaderString(
@@ -562,7 +607,7 @@ class FragmentShaderRGBATexAlphaMaskColorMatrixAA {
int color_offset_location_;
};
-class FragmentShaderRGBATexAlphaColorMatrixAA {
+class FragmentShaderRGBATexAlphaColorMatrixAA : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaColorMatrixAA();
std::string GetShaderString(
@@ -583,7 +628,7 @@ class FragmentShaderRGBATexAlphaColorMatrixAA {
int color_offset_location_;
};
-class FragmentShaderRGBATexAlphaMaskColorMatrix {
+class FragmentShaderRGBATexAlphaMaskColorMatrix : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaMaskColorMatrix();
std::string GetShaderString(
@@ -614,7 +659,7 @@ class FragmentShaderRGBATexAlphaMaskColorMatrix {
int color_offset_location_;
};
-class FragmentShaderYUVVideo {
+class FragmentShaderYUVVideo : public FragmentTexBlendMode {
public:
FragmentShaderYUVVideo();
std::string GetShaderString(
@@ -641,8 +686,7 @@ class FragmentShaderYUVVideo {
DISALLOW_COPY_AND_ASSIGN(FragmentShaderYUVVideo);
};
-
-class FragmentShaderYUVAVideo {
+class FragmentShaderYUVAVideo : public FragmentTexBlendMode {
public:
FragmentShaderYUVAVideo();
std::string GetShaderString(
@@ -672,7 +716,7 @@ class FragmentShaderYUVAVideo {
DISALLOW_COPY_AND_ASSIGN(FragmentShaderYUVAVideo);
};
-class FragmentShaderColor {
+class FragmentShaderColor : public FragmentTexBlendMode {
public:
FragmentShaderColor();
std::string GetShaderString(
@@ -689,7 +733,7 @@ class FragmentShaderColor {
DISALLOW_COPY_AND_ASSIGN(FragmentShaderColor);
};
-class FragmentShaderColorAA {
+class FragmentShaderColorAA : public FragmentTexBlendMode {
public:
FragmentShaderColorAA();
std::string GetShaderString(
@@ -706,7 +750,7 @@ class FragmentShaderColorAA {
DISALLOW_COPY_AND_ASSIGN(FragmentShaderColorAA);
};
-class FragmentShaderCheckerboard {
+class FragmentShaderCheckerboard : public FragmentTexBlendMode {
public:
FragmentShaderCheckerboard();
std::string GetShaderString(
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index c3cb828..acc897f 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -239,14 +239,16 @@ void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
current_canvas_->setMatrix(sk_device_matrix);
current_paint_.reset();
- if (!IsScaleAndIntegerTranslate(sk_device_matrix)) {
+ if (settings_->force_antialiasing ||
+ !IsScaleAndIntegerTranslate(sk_device_matrix)) {
// TODO(danakj): Until we can enable AA only on exterior edges of the
// layer, disable AA if any interior edges are present. crbug.com/248175
bool all_four_edges_are_exterior = quad->IsTopEdge() &&
quad->IsLeftEdge() &&
quad->IsBottomEdge() &&
quad->IsRightEdge();
- if (settings_->allow_antialiasing && all_four_edges_are_exterior)
+ if (settings_->allow_antialiasing &&
+ (settings_->force_antialiasing || all_four_edges_are_exterior))
current_paint_.setAntiAlias(true);
current_paint_.setFilterLevel(SkPaint::kLow_FilterLevel);
}
diff --git a/cc/test/data/background_filter_blur_off_axis.png b/cc/test/data/background_filter_blur_off_axis.png
index b5777f4..050ec54 100644
--- a/cc/test/data/background_filter_blur_off_axis.png
+++ b/cc/test/data/background_filter_blur_off_axis.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass.png b/cc/test/data/blending_render_pass.png
new file mode 100644
index 0000000..76fe369
--- /dev/null
+++ b/cc/test/data/blending_render_pass.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass_cm.png b/cc/test/data/blending_render_pass_cm.png
new file mode 100644
index 0000000..9a72d44
--- /dev/null
+++ b/cc/test/data/blending_render_pass_cm.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass_mask.png b/cc/test/data/blending_render_pass_mask.png
new file mode 100644
index 0000000..8b63f35
--- /dev/null
+++ b/cc/test/data/blending_render_pass_mask.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass_mask_cm.png b/cc/test/data/blending_render_pass_mask_cm.png
new file mode 100644
index 0000000..4e210aa
--- /dev/null
+++ b/cc/test/data/blending_render_pass_mask_cm.png
Binary files differ
diff --git a/cc/test/render_pass_test_utils.cc b/cc/test/render_pass_test_utils.cc
index 519c74a..c923b63 100644
--- a/cc/test/render_pass_test_utils.cc
+++ b/cc/test/render_pass_test_utils.cc
@@ -111,7 +111,8 @@ void AddRenderPassQuad(TestRenderPass* to_pass,
TestRenderPass* contributing_pass,
ResourceProvider::ResourceId mask_resource_id,
const FilterOperations& filters,
- gfx::Transform transform) {
+ gfx::Transform transform,
+ SkXfermode::Mode blend_mode) {
gfx::Rect output_rect = contributing_pass->output_rect;
SharedQuadState* shared_state = to_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(transform,
@@ -120,7 +121,7 @@ void AddRenderPassQuad(TestRenderPass* to_pass,
output_rect,
false,
1,
- SkXfermode::kSrcOver_Mode,
+ blend_mode,
0);
RenderPassDrawQuad* quad =
to_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
diff --git a/cc/test/render_pass_test_utils.h b/cc/test/render_pass_test_utils.h
index 7bf026c..49ea113 100644
--- a/cc/test/render_pass_test_utils.h
+++ b/cc/test/render_pass_test_utils.h
@@ -53,7 +53,8 @@ void AddRenderPassQuad(TestRenderPass* toPass,
TestRenderPass* contributing_pass,
ResourceProvider::ResourceId mask_resource_id,
const FilterOperations& filters,
- gfx::Transform transform);
+ gfx::Transform transform,
+ SkXfermode::Mode blend_mode);
} // namespace cc
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
index f01d426..bebd612 100644
--- a/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "cc/layers/image_layer.h"
#include "cc/layers/solid_color_layer.h"
-#include "cc/layers/texture_layer.h"
#include "cc/test/layer_tree_pixel_test.h"
#include "cc/test/pixel_comparator.h"
@@ -22,7 +22,36 @@ SkXfermode::Mode const kBlendModes[] = {
SkXfermode::kHue_Mode, SkXfermode::kSaturation_Mode,
SkXfermode::kColor_Mode, SkXfermode::kLuminosity_Mode};
+SkColor kCSSTestColors[] = {
+ 0xffff0000, // red
+ 0xff00ff00, // lime
+ 0xff0000ff, // blue
+ 0xff00ffff, // aqua
+ 0xffff00ff, // fuchsia
+ 0xffffff00, // yellow
+ 0xff008000, // green
+ 0xff800000, // maroon
+ 0xff000080, // navy
+ 0xff800080, // purple
+ 0xff808000, // olive
+ 0xff008080, // teal
+ 0xfffa8072, // salmon
+ 0xffc0c0c0, // silver
+ 0xff000000, // black
+ 0xff808080, // gray
+ 0x80000000, // black with transparency
+ 0xffffffff, // white
+ 0x80ffffff, // white with transparency
+ 0x00000000 // transparent
+};
+
const int kBlendModesCount = arraysize(kBlendModes);
+const int kCSSTestColorsCount = arraysize(kCSSTestColors);
+
+using RenderPassOptions = uint32;
+const uint32 kUseMasks = 1 << 0;
+const uint32 kUseAntialiasing = 1 << 1;
+const uint32 kUseColorMatrix = 1 << 2;
class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
public:
@@ -30,6 +59,10 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true));
}
+ virtual void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->force_antialiasing = force_antialiasing_;
+ }
+
protected:
void RunBlendingWithRootPixelTestType(PixelTestType type) {
const int kLaneWidth = 15;
@@ -82,6 +115,175 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
root,
base::FilePath(FILE_PATH_LITERAL("blending_transparent.png")));
}
+
+ scoped_refptr<Layer> CreateColorfulBackdropLayer(int width, int height) {
+ // Draw the backdrop with horizontal lanes.
+ const int kLaneWidth = width;
+ const int kLaneHeight = height / kCSSTestColorsCount;
+ SkBitmap backing_store;
+ backing_store.allocN32Pixels(width, height);
+ SkCanvas canvas(backing_store);
+ canvas.clear(SK_ColorTRANSPARENT);
+ for (int i = 0; i < kCSSTestColorsCount; ++i) {
+ SkPaint paint;
+ paint.setColor(kCSSTestColors[i]);
+ canvas.drawRect(
+ SkRect::MakeXYWH(0, i * kLaneHeight, kLaneWidth, kLaneHeight), paint);
+ }
+ scoped_refptr<ImageLayer> layer = ImageLayer::Create();
+ layer->SetIsDrawable(true);
+ layer->SetBounds(gfx::Size(width, height));
+ layer->SetBitmap(backing_store);
+ return layer;
+ }
+
+ void SetupMaskLayer(scoped_refptr<Layer> layer) {
+ const int kMaskOffset = 5;
+ gfx::Size bounds = layer->bounds();
+ scoped_refptr<ImageLayer> mask = ImageLayer::Create();
+ mask->SetIsDrawable(true);
+ mask->SetIsMask(true);
+ mask->SetBounds(bounds);
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(bounds.width(), bounds.height());
+ SkCanvas canvas(bitmap);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.clear(SK_ColorTRANSPARENT);
+ canvas.drawRect(SkRect::MakeXYWH(kMaskOffset,
+ kMaskOffset,
+ bounds.width() - kMaskOffset * 2,
+ bounds.height() - kMaskOffset * 2),
+ paint);
+ mask->SetBitmap(bitmap);
+ layer->SetMaskLayer(mask.get());
+ }
+
+ void SetupColorMatrix(scoped_refptr<Layer> layer) {
+ FilterOperations filter_operations;
+ filter_operations.Append(FilterOperation::CreateSepiaFilter(1.f));
+ layer->SetFilters(filter_operations);
+ }
+
+ void CreateBlendingColorLayers(int width,
+ int height,
+ scoped_refptr<Layer> background,
+ RenderPassOptions flags) {
+ const int kLanesCount = kBlendModesCount + 4;
+ int lane_width = width / kLanesCount;
+ const SkColor kMiscOpaqueColor = 0xffc86464;
+ const SkColor kMiscTransparentColor = 0x80c86464;
+ const SkXfermode::Mode kCoeffBlendMode = SkXfermode::kScreen_Mode;
+ const SkXfermode::Mode kShaderBlendMode = SkXfermode::kColorBurn_Mode;
+ // add vertical lanes with each of the blend modes
+ for (int i = 0; i < kLanesCount; ++i) {
+ gfx::Rect child_rect(i * lane_width, 0, lane_width, height);
+ SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
+ float opacity = 1.f;
+ SkColor color = kMiscOpaqueColor;
+
+ if (i < kBlendModesCount) {
+ blend_mode = kBlendModes[i];
+ } else if (i == kBlendModesCount) {
+ blend_mode = kCoeffBlendMode;
+ opacity = 0.5f;
+ } else if (i == kBlendModesCount + 1) {
+ blend_mode = kCoeffBlendMode;
+ color = kMiscTransparentColor;
+ } else if (i == kBlendModesCount + 2) {
+ blend_mode = kShaderBlendMode;
+ opacity = 0.5f;
+ } else if (i == kBlendModesCount + 3) {
+ blend_mode = kShaderBlendMode;
+ color = kMiscTransparentColor;
+ }
+
+ scoped_refptr<SolidColorLayer> lane =
+ CreateSolidColorLayer(child_rect, color);
+ lane->SetBlendMode(blend_mode);
+ lane->SetOpacity(opacity);
+ lane->SetForceRenderSurface(true);
+ if (flags & kUseMasks)
+ SetupMaskLayer(lane);
+ if (flags & kUseColorMatrix) {
+ SetupColorMatrix(lane);
+ }
+ background->AddChild(lane);
+ }
+ }
+
+ void RunBlendingWithRenderPass(PixelTestType type,
+ const base::FilePath::CharType* expected_path,
+ RenderPassOptions flags) {
+ const int kRootSize = 400;
+
+ scoped_refptr<SolidColorLayer> root =
+ CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), SK_ColorWHITE);
+ scoped_refptr<Layer> background =
+ CreateColorfulBackdropLayer(kRootSize, kRootSize);
+
+ background->SetIsRootForIsolatedGroup(true);
+ root->AddChild(background);
+
+ CreateBlendingColorLayers(kRootSize, kRootSize, background.get(), flags);
+
+ this->impl_side_painting_ = false;
+ this->force_antialiasing_ = (flags & kUseAntialiasing);
+
+ if ((flags & kUseAntialiasing) && (type == GL_WITH_BITMAP)) {
+ // Anti aliasing causes differences up to 7 pixels at the edges.
+ int large_error_allowed = 7;
+ // Blending results might differ with one pixel.
+ int small_error_allowed = 1;
+ // Most of the errors are one pixel errors.
+ float percentage_pixels_small_error = 12.5f;
+ // Because of anti-aliasing, around 3% of pixels (at the edges) have
+ // bigger errors (from small_error_allowed + 1 to large_error_allowed).
+ float percentage_pixels_error = 15.0f;
+ // The average error is still close to 1.
+ float average_error_allowed_in_bad_pixels = 1.3f;
+
+ // The sepia filter generates more small errors, but the number of large
+ // errors remains around 3%.
+ if (flags & kUseColorMatrix) {
+ percentage_pixels_small_error = 26.f;
+ percentage_pixels_error = 29.f;
+ }
+
+ // Anti-aliased pixels in combination with non-separable blend modes and
+ // a white background produces several black pixels (6 for these tests).
+ // Having a mask will hide the black pixels.
+ // TODO(rosca): fix this issue for non-separable blend modes.
+ if (!(flags & kUseMasks))
+ large_error_allowed = 255;
+
+ pixel_comparator_.reset(
+ new FuzzyPixelComparator(false, // discard_alpha
+ percentage_pixels_error,
+ percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels,
+ large_error_allowed,
+ small_error_allowed));
+ } else if ((flags & kUseColorMatrix) && (type == GL_WITH_BITMAP)) {
+ float percentage_pixels_error = 100.f;
+ float percentage_pixels_small_error = 0.f;
+ float average_error_allowed_in_bad_pixels = 1.f;
+ int large_error_allowed = 2;
+ int small_error_allowed = 0;
+ pixel_comparator_.reset(
+ new FuzzyPixelComparator(false, // discard_alpha
+ percentage_pixels_error,
+ percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels,
+ large_error_allowed,
+ small_error_allowed));
+ }
+
+ RunPixelTest(type, root, base::FilePath(expected_path));
+ }
+
+ bool force_antialiasing_ = false;
};
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) {
@@ -128,6 +330,113 @@ TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_Software) {
RunBlendingWithTransparentPixelTestType(SOFTWARE_WITH_BITMAP);
}
+// Tests for render passes
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_GL) {
+ RunBlendingWithRenderPass(
+ GL_WITH_BITMAP, FILE_PATH_LITERAL("blending_render_pass.png"), 0);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_Software) {
+ RunBlendingWithRenderPass(
+ SOFTWARE_WITH_BITMAP, FILE_PATH_LITERAL("blending_render_pass.png"), 0);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseAntialiasing);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseAntialiasing);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMask_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMask_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMaskAA_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskAA_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrix_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassColorMatrix_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrixAA_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ kUseAntialiasing | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassColorMatrixAA_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ kUseAntialiasing | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskColorMatrix_GL) {
+ RunBlendingWithRenderPass(
+ GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
+ kUseMasks | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskColorMatrix_Software) {
+ RunBlendingWithRenderPass(
+ SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
+ kUseMasks | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskColorMatrixAA_GL) {
+ RunBlendingWithRenderPass(
+ GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskColorMatrixAA_Software) {
+ RunBlendingWithRenderPass(
+ SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix);
+}
+
} // namespace
} // namespace cc
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 8e11015..e4d5f1d 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -15,6 +15,7 @@ namespace cc {
LayerTreeSettings::LayerTreeSettings()
: impl_side_painting(false),
allow_antialiasing(true),
+ force_antialiasing(false),
throttle_frame_production(true),
single_thread_proxy_scheduler(true),
begin_frame_scheduling_enabled(false),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index c0c1453..fff1084 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -20,6 +20,7 @@ class CC_EXPORT LayerTreeSettings {
bool impl_side_painting;
bool allow_antialiasing;
+ bool force_antialiasing;
bool throttle_frame_production;
bool single_thread_proxy_scheduler;
bool begin_frame_scheduling_enabled;