diff options
author | alokp@chromium.org <alokp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-29 00:35:12 +0000 |
---|---|---|
committer | alokp@chromium.org <alokp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-29 00:35:12 +0000 |
commit | b54beedcc27bea274dba8bdaa55948d4a0447a63 (patch) | |
tree | 99ae61ad320b30b66eec65de7544e9301bf828da /cc | |
parent | 44a4becb395b09648a40f261a9a91343fe322cad (diff) | |
download | chromium_src-b54beedcc27bea274dba8bdaa55948d4a0447a63.zip chromium_src-b54beedcc27bea274dba8bdaa55948d4a0447a63.tar.gz chromium_src-b54beedcc27bea274dba8bdaa55948d4a0447a63.tar.bz2 |
Premultiply alpha in shader for non-premultiplied textures.
Instead of using different blending equations we can perform
the pre-multiplication in the shader itself.
I am working on improving the performance of compositing canvas
elements with opaque background. This requires blending the
canvas texture with the background color in the shader. The
implementation of this blending equation becomes much easier if
we can assume that textures are always premultiplied.
BUG=236982
TEST=compositing/webgl/webgl-nonpremultiplied-blend.html
Review URL: https://chromiumcodereview.appspot.com/16943021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209246 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r-- | cc/output/gl_renderer.cc | 78 | ||||
-rw-r--r-- | cc/output/gl_renderer.h | 8 | ||||
-rw-r--r-- | cc/output/gl_renderer_draw_cache.h | 2 | ||||
-rw-r--r-- | cc/output/gl_renderer_unittest.cc | 2 | ||||
-rw-r--r-- | cc/output/shader.cc | 15 | ||||
-rw-r--r-- | cc/output/shader.h | 5 |
6 files changed, 65 insertions, 45 deletions
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index 960198d..901ba9a 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc @@ -1686,23 +1686,6 @@ void GLRenderer::FlushTextureQuadCache() { GLC(Context(), Context()->bindTexture(GL_TEXTURE_2D, locked_quad.texture_id())); - // set up premultiplied alpha. - if (!draw_cache_.use_premultiplied_alpha) { - // As it turns out, the premultiplied alpha blending function (ONE, - // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to - // anything less than 1.0f if it is initialized to that value! Therefore, - // premultiplied_alpha being false is the first situation we can generally - // see an alpha channel less than 1.0f coming out of the compositor. This is - // causing platform differences in some layout tests (see - // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use - // a separate blend function for the alpha channel to avoid modifying it. - // Don't use colorMask() for this as it has performance implications on some - // platforms. - GLC(Context(), - Context()->blendFuncSeparate( - GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)); - } - COMPILE_ASSERT( sizeof(Float4) == 4 * sizeof(float), // NOLINT(runtime/sizeof) struct_is_densely_packed); @@ -1735,10 +1718,6 @@ void GLRenderer::FlushTextureQuadCache() { GL_UNSIGNED_SHORT, 0)); - // Clean up after ourselves (reset state set above). - if (!draw_cache_.use_premultiplied_alpha) - GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); - // Clear the cache. draw_cache_.program_id = 0; draw_cache_.uv_xform_data.resize(0); @@ -1754,19 +1733,22 @@ void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame, // Choose the correct texture program binding TexTransformTextureProgramBinding binding; - binding.Set(GetTextureProgram(tex_coord_precision), Context()); + if (quad->premultiplied_alpha) { + binding.Set(GetTextureProgram(tex_coord_precision), Context()); + } else { + binding.Set(GetNonPremultipliedTextureProgram(tex_coord_precision), + Context()); + } int resource_id = quad->resource_id; if (draw_cache_.program_id != binding.program_id || draw_cache_.resource_id != resource_id || - draw_cache_.use_premultiplied_alpha != quad->premultiplied_alpha || draw_cache_.needs_blending != quad->ShouldDrawWithBlending() || draw_cache_.matrix_data.size() >= 8) { FlushTextureQuadCache(); draw_cache_.program_id = binding.program_id; draw_cache_.resource_id = resource_id; - draw_cache_.use_premultiplied_alpha = quad->premultiplied_alpha; draw_cache_.needs_blending = quad->ShouldDrawWithBlending(); draw_cache_.uv_xform_location = binding.tex_transform_location; @@ -1802,7 +1784,12 @@ void GLRenderer::DrawTextureQuad(const DrawingFrame* frame, quad->shared_quad_state->visible_content_rect.bottom_right()); TexTransformTextureProgramBinding binding; - binding.Set(GetTextureProgram(tex_coord_precision), Context()); + if (quad->premultiplied_alpha) { + binding.Set(GetTextureProgram(tex_coord_precision), Context()); + } else { + binding.Set(GetNonPremultipliedTextureProgram(tex_coord_precision), + Context()); + } SetUseProgram(binding.program_id); GLC(Context(), Context()->uniform1i(binding.sampler_location, 0)); Float4 uv_xform = UVTransform(quad); @@ -1820,27 +1807,8 @@ void GLRenderer::DrawTextureQuad(const DrawingFrame* frame, ResourceProvider::ScopedSamplerGL quad_resource_lock( resource_provider_, quad->resource_id, GL_TEXTURE_2D, GL_LINEAR); - if (!quad->premultiplied_alpha) { - // As it turns out, the premultiplied alpha blending function (ONE, - // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to - // anything less than 1.0f if it is initialized to that value! Therefore, - // premultiplied_alpha being false is the first situation we can generally - // see an alpha channel less than 1.0f coming out of the compositor. This is - // causing platform differences in some layout tests (see - // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use - // a separate blend function for the alpha channel to avoid modifying it. - // Don't use colorMask() for this as it has performance implications on some - // platforms. - GLC(Context(), - Context()->blendFuncSeparate( - GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)); - } - DrawQuadGeometry( frame, quad->quadTransform(), quad->rect, binding.matrix_location); - - if (!quad->premultiplied_alpha) - GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); } void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame, @@ -2824,6 +2792,24 @@ const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram( return program.get(); } +const GLRenderer::NonPremultipliedTextureProgram* + GLRenderer::GetNonPremultipliedTextureProgram(TexCoordPrecision precision) { + scoped_ptr<NonPremultipliedTextureProgram>& program = + (precision == TexCoordPrecisionHigh) ? + nonpremultiplied_texture_program_highp_ : + nonpremultiplied_texture_program_; + if (!program) { + program = make_scoped_ptr( + new NonPremultipliedTextureProgram(context_, precision)); + } + if (!program->initialized()) { + TRACE_EVENT0("cc", + "GLRenderer::NonPremultipliedTextureProgram::Initialize"); + program->Initialize(context_, is_using_bind_uniform_); + } + return program.get(); +} + const GLRenderer::TextureIOSurfaceProgram* GLRenderer::GetTextureIOSurfaceProgram(TexCoordPrecision precision) { scoped_ptr<TextureIOSurfaceProgram>& program = @@ -2953,11 +2939,15 @@ void GLRenderer::CleanupSharedObjects() { if (texture_program_) texture_program_->Cleanup(context_); + if (nonpremultiplied_texture_program_) + nonpremultiplied_texture_program_->Cleanup(context_); if (texture_io_surface_program_) texture_io_surface_program_->Cleanup(context_); if (texture_program_highp_) texture_program_highp_->Cleanup(context_); + if (nonpremultiplied_texture_program_highp_) + nonpremultiplied_texture_program_highp_->Cleanup(context_); if (texture_io_surface_program_highp_) texture_io_surface_program_highp_->Cleanup(context_); diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h index 32e89d3..db59e5b 100644 --- a/cc/output/gl_renderer.h +++ b/cc/output/gl_renderer.h @@ -265,6 +265,9 @@ class CC_EXPORT GLRenderer typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexVaryingAlpha> TextureProgram; typedef ProgramBinding<VertexShaderPosTexTransform, + FragmentShaderRGBATexPremultiplyAlpha> + NonPremultipliedTextureProgram; + typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexRectVaryingAlpha> TextureIOSurfaceProgram; @@ -337,6 +340,8 @@ class CC_EXPORT GLRenderer const TextureProgram* GetTextureProgram( TexCoordPrecision precision); + const NonPremultipliedTextureProgram* GetNonPremultipliedTextureProgram( + TexCoordPrecision precision); const TextureIOSurfaceProgram* GetTextureIOSurfaceProgram( TexCoordPrecision precision); @@ -367,9 +372,12 @@ class CC_EXPORT GLRenderer scoped_ptr<TileProgramSwizzleAA> tile_program_swizzle_aa_highp_; scoped_ptr<TextureProgram> texture_program_; + scoped_ptr<NonPremultipliedTextureProgram> nonpremultiplied_texture_program_; scoped_ptr<TextureIOSurfaceProgram> texture_io_surface_program_; scoped_ptr<TextureProgram> texture_program_highp_; + scoped_ptr<NonPremultipliedTextureProgram> + nonpremultiplied_texture_program_highp_; scoped_ptr<TextureIOSurfaceProgram> texture_io_surface_program_highp_; scoped_ptr<RenderPassProgram> render_pass_program_; diff --git a/cc/output/gl_renderer_draw_cache.h b/cc/output/gl_renderer_draw_cache.h index e99cc27..85369ef 100644 --- a/cc/output/gl_renderer_draw_cache.h +++ b/cc/output/gl_renderer_draw_cache.h @@ -31,7 +31,6 @@ struct TexturedQuadDrawCache { // Values tracked to determine if textured quads may be coalesced. int program_id; int resource_id; - bool use_premultiplied_alpha; bool needs_blending; // Information about the program binding that is required to draw. @@ -45,6 +44,7 @@ struct TexturedQuadDrawCache { std::vector<float> vertex_opacity_data; std::vector<Float16> matrix_data; + private: DISALLOW_COPY_AND_ASSIGN(TexturedQuadDrawCache); }; diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc index 97c73fa..34443e3 100644 --- a/cc/output/gl_renderer_unittest.cc +++ b/cc/output/gl_renderer_unittest.cc @@ -93,6 +93,8 @@ class GLRendererShaderPixelTest : public GLRendererPixelTest { EXPECT_PROGRAM_VALID( renderer()->GetRenderPassMaskColorMatrixProgram(precision)); EXPECT_PROGRAM_VALID(renderer()->GetTextureProgram(precision)); + EXPECT_PROGRAM_VALID( + renderer()->GetNonPremultipliedTextureProgram(precision)); EXPECT_PROGRAM_VALID(renderer()->GetTextureIOSurfaceProgram(precision)); EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVProgram(precision)); EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVAProgram(precision)); diff --git a/cc/output/shader.cc b/cc/output/shader.cc index 385c72d..6e1f6c5 100644 --- a/cc/output/shader.cc +++ b/cc/output/shader.cc @@ -682,6 +682,21 @@ std::string FragmentShaderRGBATexVaryingAlpha::GetShaderString( ); // NOLINT(whitespace/parens) } +std::string FragmentShaderRGBATexPremultiplyAlpha::GetShaderString( + TexCoordPrecision precision) const { + return FRAGMENT_SHADER( + precision mediump float; + varying TexCoordPrecision vec2 v_texCoord; + varying float v_alpha; + uniform sampler2D s_texture; + void main() { + vec4 texColor = texture2D(s_texture, v_texCoord); + texColor.rgb *= texColor.a; + gl_FragColor = texColor * v_alpha; + } + ); // NOLINT(whitespace/parens) +} + std::string FragmentShaderRGBATexRectVaryingAlpha::GetShaderString( TexCoordPrecision precision) const { return "#extension GL_ARB_texture_rectangle : require\n" + diff --git a/cc/output/shader.h b/cc/output/shader.h index 44eedef..7910e59 100644 --- a/cc/output/shader.h +++ b/cc/output/shader.h @@ -283,6 +283,11 @@ class FragmentShaderRGBATexVaryingAlpha : public FragmentTexOpaqueBinding { std::string GetShaderString(TexCoordPrecision precision) const; }; +class FragmentShaderRGBATexPremultiplyAlpha : public FragmentTexOpaqueBinding { + public: + std::string GetShaderString(TexCoordPrecision precision) const; +}; + class FragmentShaderRGBATexAlpha : public FragmentTexAlphaBinding { public: std::string GetShaderString(TexCoordPrecision precision) const; |