diff options
-rw-r--r-- | cc/output/gl_renderer.cc | 181 | ||||
-rw-r--r-- | cc/output/gl_renderer.h | 47 | ||||
-rw-r--r-- | cc/output/gl_renderer_pixeltest.cc | 208 | ||||
-rw-r--r-- | cc/output/gl_renderer_unittest.cc | 321 | ||||
-rw-r--r-- | cc/output/shader.cc | 281 | ||||
-rw-r--r-- | cc/output/shader.h | 116 | ||||
-rw-r--r-- | cc/test/layer_tree_pixel_test.cc | 2 | ||||
-rw-r--r-- | cc/test/pixel_test.cc | 6 | ||||
-rw-r--r-- | cc/test/pixel_test.h | 3 | ||||
-rw-r--r-- | cc/test/pixel_test_utils.cc | 14 | ||||
-rw-r--r-- | cc/test/pixel_test_utils.h | 6 | ||||
-rw-r--r-- | cc/test/render_pass_test_utils.cc | 22 | ||||
-rw-r--r-- | cc/test/render_pass_test_utils.h | 8 | ||||
-rw-r--r-- | ui/compositor/layer_unittest.cc | 12 |
14 files changed, 1185 insertions, 42 deletions
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index 4d630a1..aac1543 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc @@ -37,6 +37,7 @@ #include "third_party/khronos/GLES2/gl2ext.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/skia/include/gpu/GrTexture.h" #include "third_party/skia/include/gpu/SkGpuDevice.h" @@ -663,9 +664,19 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame& frame, // FIXME: Cache this value so that we don't have to do it for both the surface // and its replica. Apply filters to the contents texture. SkBitmap filter_bitmap; + SkScalar color_matrix[20]; + bool use_color_matrix = false; if (quad->filter) { - filter_bitmap = - ApplyImageFilter(this, quad->filter.get(), contents_texture); + SkColorFilter* cf; + if ((quad->filter->asColorFilter(&cf)) && cf->asColorMatrix(color_matrix) && + !quad->filter->getInput(0)) { + // We have a single color matrix as a filter; apply it locally + // in the compositor. + use_color_matrix = true; + } else { + filter_bitmap = + ApplyImageFilter(this, quad->filter.get(), contents_texture); + } } else { filter_bitmap = ApplyFilters(this, quad->filters, contents_texture); } @@ -724,10 +735,12 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame& frame, int shader_mask_tex_coord_offset_location = -1; int shader_matrix_location = -1; int shader_alpha_location = -1; + int shader_color_matrix_location = -1; + int shader_color_offset_location = -1; int shader_tex_transform_location = -1; int shader_tex_scale_location = -1; - if (use_aa && mask_texture_id) { + if (use_aa && mask_texture_id && !use_color_matrix) { const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA(); SetUseProgram(program->program()); GLC(Context(), @@ -744,7 +757,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame& frame, shader_matrix_location = program->vertex_shader().matrix_location(); shader_alpha_location = program->fragment_shader().alpha_location(); shader_tex_scale_location = program->vertex_shader().tex_scale_location(); - } else if (!use_aa && mask_texture_id) { + } else if (!use_aa && mask_texture_id && !use_color_matrix) { const RenderPassMaskProgram* program = GetRenderPassMaskProgram(); SetUseProgram(program->program()); GLC(Context(), @@ -760,7 +773,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame& frame, shader_alpha_location = program->fragment_shader().alpha_location(); shader_tex_transform_location = program->vertex_shader().tex_transform_location(); - } else if (use_aa && !mask_texture_id) { + } else if (use_aa && !mask_texture_id && !use_color_matrix) { const RenderPassProgramAA* program = GetRenderPassProgramAA(); SetUseProgram(program->program()); GLC(Context(), @@ -771,6 +784,80 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame& frame, shader_matrix_location = program->vertex_shader().matrix_location(); shader_alpha_location = program->fragment_shader().alpha_location(); shader_tex_scale_location = program->vertex_shader().tex_scale_location(); + } else if (use_aa && mask_texture_id && use_color_matrix) { + const RenderPassMaskColorMatrixProgramAA* program = + GetRenderPassMaskColorMatrixProgramAA(); + SetUseProgram(program->program()); + GLC(Context(), + Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + + shader_matrix_location = program->vertex_shader().matrix_location(); + shader_quad_location = program->vertex_shader().point_location(); + shader_tex_scale_location = program->vertex_shader().tex_scale_location(); + shader_edge_location = program->fragment_shader().edge_location(); + shader_alpha_location = program->fragment_shader().alpha_location(); + shader_mask_sampler_location = + program->fragment_shader().mask_sampler_location(); + shader_mask_tex_coord_scale_location = + program->fragment_shader().mask_tex_coord_scale_location(); + shader_mask_tex_coord_offset_location = + program->fragment_shader().mask_tex_coord_offset_location(); + shader_color_matrix_location = + program->fragment_shader().color_matrix_location(); + shader_color_offset_location = + program->fragment_shader().color_offset_location(); + } else if (use_aa && !mask_texture_id && use_color_matrix) { + const RenderPassColorMatrixProgramAA* program = + GetRenderPassColorMatrixProgramAA(); + SetUseProgram(program->program()); + GLC(Context(), + Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + + shader_matrix_location = program->vertex_shader().matrix_location(); + shader_quad_location = program->vertex_shader().point_location(); + shader_tex_scale_location = program->vertex_shader().tex_scale_location(); + shader_edge_location = program->fragment_shader().edge_location(); + shader_alpha_location = program->fragment_shader().alpha_location(); + shader_color_matrix_location = + program->fragment_shader().color_matrix_location(); + shader_color_offset_location = + program->fragment_shader().color_offset_location(); + } else if (!use_aa && mask_texture_id && use_color_matrix) { + const RenderPassMaskColorMatrixProgram* program = + GetRenderPassMaskColorMatrixProgram(); + SetUseProgram(program->program()); + GLC(Context(), + Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + + shader_matrix_location = program->vertex_shader().matrix_location(); + shader_tex_transform_location = + program->vertex_shader().tex_transform_location(); + shader_mask_sampler_location = + program->fragment_shader().mask_sampler_location(); + shader_mask_tex_coord_scale_location = + program->fragment_shader().mask_tex_coord_scale_location(); + shader_mask_tex_coord_offset_location = + program->fragment_shader().mask_tex_coord_offset_location(); + shader_alpha_location = program->fragment_shader().alpha_location(); + shader_color_matrix_location = + program->fragment_shader().color_matrix_location(); + shader_color_offset_location = + program->fragment_shader().color_offset_location(); + } else if (!use_aa && !mask_texture_id && use_color_matrix) { + const RenderPassColorMatrixProgram* program = + GetRenderPassColorMatrixProgram(); + SetUseProgram(program->program()); + GLC(Context(), + Context()->uniform1i(program->fragment_shader().sampler_location(), 0)); + + shader_matrix_location = program->vertex_shader().matrix_location(); + shader_tex_transform_location = + program->vertex_shader().tex_transform_location(); + shader_alpha_location = program->fragment_shader().alpha_location(); + shader_color_matrix_location = + program->fragment_shader().color_matrix_location(); + shader_color_offset_location = + program->fragment_shader().color_offset_location(); } else { const RenderPassProgram* program = GetRenderPassProgram(); SetUseProgram(program->program()); @@ -782,7 +869,6 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame& frame, shader_tex_transform_location = program->vertex_shader().tex_transform_location(); } - float tex_scale_x = quad->rect.width() / static_cast<float>(contents_texture->size().width()); float tex_scale_y = quad->rect.height() / @@ -830,6 +916,26 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame& frame, GLC(Context(), Context()->uniform3fv(shader_edge_location, 8, edge)); } + if (shader_color_matrix_location != -1) { + float matrix[16]; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) + matrix[i * 4 + j] = SkScalarToFloat(color_matrix[j * 5 + i]); + } + GLC(Context(), + Context()->uniformMatrix4fv( + shader_color_matrix_location, 1, false, matrix)); + } + static const float kScale = 1.0f / 255.0f; + if (shader_color_offset_location != -1) { + float offset[4]; + for (int i = 0; i < 4; ++i) + offset[i] = SkScalarToFloat(color_matrix[i * 5 + 4]) * kScale; + + GLC(Context(), + Context()->uniform4fv(shader_color_offset_location, 1, offset)); + } + // 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, @@ -2060,6 +2166,61 @@ GLRenderer::GetRenderPassMaskProgramAA() { return render_pass_mask_program_aa_.get(); } +const GLRenderer::RenderPassColorMatrixProgram* +GLRenderer::GetRenderPassColorMatrixProgram() { + if (!render_pass_color_matrix_program_) + render_pass_color_matrix_program_ = + make_scoped_ptr(new RenderPassColorMatrixProgram(context_)); + if (!render_pass_color_matrix_program_->initialized()) { + TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgram::initialize"); + render_pass_color_matrix_program_->Initialize(context_, + is_using_bind_uniform_); + } + return render_pass_color_matrix_program_.get(); +} + +const GLRenderer::RenderPassColorMatrixProgramAA* +GLRenderer::GetRenderPassColorMatrixProgramAA() { + if (!render_pass_color_matrix_program_aa_) + render_pass_color_matrix_program_aa_ = + make_scoped_ptr(new RenderPassColorMatrixProgramAA(context_)); + if (!render_pass_color_matrix_program_aa_->initialized()) { + TRACE_EVENT0("cc", + "GLRenderer::renderPassColorMatrixProgramAA::initialize"); + render_pass_color_matrix_program_aa_->Initialize(context_, + is_using_bind_uniform_); + } + return render_pass_color_matrix_program_aa_.get(); +} + +const GLRenderer::RenderPassMaskColorMatrixProgram* +GLRenderer::GetRenderPassMaskColorMatrixProgram() { + if (!render_pass_mask_color_matrix_program_) + render_pass_mask_color_matrix_program_ = + make_scoped_ptr(new RenderPassMaskColorMatrixProgram(context_)); + if (!render_pass_mask_color_matrix_program_->initialized()) { + TRACE_EVENT0("cc", + "GLRenderer::renderPassMaskColorMatrixProgram::initialize"); + render_pass_mask_color_matrix_program_->Initialize(context_, + is_using_bind_uniform_); + } + return render_pass_mask_color_matrix_program_.get(); +} + +const GLRenderer::RenderPassMaskColorMatrixProgramAA* +GLRenderer::GetRenderPassMaskColorMatrixProgramAA() { + if (!render_pass_mask_color_matrix_program_aa_) + render_pass_mask_color_matrix_program_aa_ = + make_scoped_ptr(new RenderPassMaskColorMatrixProgramAA(context_)); + if (!render_pass_mask_color_matrix_program_aa_->initialized()) { + TRACE_EVENT0("cc", + "GLRenderer::renderPassMaskColorMatrixProgramAA::initialize"); + render_pass_mask_color_matrix_program_aa_->Initialize( + context_, is_using_bind_uniform_); + } + return render_pass_mask_color_matrix_program_aa_.get(); +} + const GLRenderer::TileProgram* GLRenderer::GetTileProgram() { DCHECK(tile_program_); if (!tile_program_->initialized()) { @@ -2205,6 +2366,14 @@ void GLRenderer::CleanupSharedObjects() { render_pass_mask_program_aa_->Cleanup(context_); if (render_pass_program_aa_) render_pass_program_aa_->Cleanup(context_); + if (render_pass_color_matrix_program_) + render_pass_color_matrix_program_->Cleanup(context_); + if (render_pass_mask_color_matrix_program_aa_) + render_pass_mask_color_matrix_program_aa_->Cleanup(context_); + if (render_pass_color_matrix_program_aa_) + render_pass_color_matrix_program_aa_->Cleanup(context_); + if (render_pass_mask_color_matrix_program_) + render_pass_mask_color_matrix_program_->Cleanup(context_); if (texture_program_) texture_program_->Cleanup(context_); diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h index 8dd2c64..5087e10 100644 --- a/cc/output/gl_renderer.h +++ b/cc/output/gl_renderer.h @@ -111,6 +111,7 @@ class CC_EXPORT GLRenderer : virtual void FinishDrawingQuadList() OVERRIDE; private: + friend class GLRendererShaderPixelTest; friend class GLRendererShaderTest; static void ToGLMatrix(float* gl_matrix, const gfx::Transform& transform); @@ -219,6 +220,15 @@ class CC_EXPORT GLRenderer : typedef ProgramBinding<VertexShaderPosTex, FragmentShaderCheckerboard> TileCheckerboardProgram; + // Texture shaders. + typedef ProgramBinding<VertexShaderPosTexTransform, + FragmentShaderRGBATexVaryingAlpha> TextureProgram; + typedef ProgramBinding<VertexShaderPosTexTransformFlip, + FragmentShaderRGBATexVaryingAlpha> TextureProgramFlip; + typedef ProgramBinding<VertexShaderPosTexTransform, + FragmentShaderRGBATexRectVaryingAlpha> + TextureIOSurfaceProgram; + // Render surface shaders. typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexAlpha> RenderPassProgram; @@ -228,15 +238,18 @@ class CC_EXPORT GLRenderer : RenderPassProgramAA; typedef ProgramBinding<VertexShaderQuad, FragmentShaderRGBATexAlphaMaskAA> RenderPassMaskProgramAA; - - // Texture shaders. typedef ProgramBinding<VertexShaderPosTexTransform, - FragmentShaderRGBATexVaryingAlpha> TextureProgram; - typedef ProgramBinding<VertexShaderPosTexTransformFlip, - FragmentShaderRGBATexVaryingAlpha> TextureProgramFlip; + FragmentShaderRGBATexColorMatrixAlpha> + RenderPassColorMatrixProgram; + typedef ProgramBinding<VertexShaderQuad, + FragmentShaderRGBATexAlphaMaskColorMatrixAA> + RenderPassMaskColorMatrixProgramAA; + typedef ProgramBinding<VertexShaderQuad, + FragmentShaderRGBATexAlphaColorMatrixAA> + RenderPassColorMatrixProgramAA; typedef ProgramBinding<VertexShaderPosTexTransform, - FragmentShaderRGBATexRectVaryingAlpha> - TextureIOSurfaceProgram; + FragmentShaderRGBATexAlphaMaskColorMatrix> + RenderPassMaskColorMatrixProgram; // Video shaders. typedef ProgramBinding<VertexShaderVideoTransform, @@ -265,6 +278,11 @@ class CC_EXPORT GLRenderer : const RenderPassProgramAA* GetRenderPassProgramAA(); const RenderPassMaskProgram* GetRenderPassMaskProgram(); const RenderPassMaskProgramAA* GetRenderPassMaskProgramAA(); + const RenderPassColorMatrixProgram* GetRenderPassColorMatrixProgram(); + const RenderPassColorMatrixProgramAA* GetRenderPassColorMatrixProgramAA(); + const RenderPassMaskColorMatrixProgram* GetRenderPassMaskColorMatrixProgram(); + const RenderPassMaskColorMatrixProgramAA* + GetRenderPassMaskColorMatrixProgramAA(); const TextureProgram* GetTextureProgram(); const TextureProgramFlip* GetTextureProgramFlip(); @@ -285,14 +303,21 @@ class CC_EXPORT GLRenderer : scoped_ptr<TileProgramSwizzleAA> tile_program_swizzle_aa_; scoped_ptr<TileCheckerboardProgram> tile_checkerboard_program_; + scoped_ptr<TextureProgram> texture_program_; + scoped_ptr<TextureProgramFlip> texture_program_flip_; + scoped_ptr<TextureIOSurfaceProgram> texture_io_surface_program_; + scoped_ptr<RenderPassProgram> render_pass_program_; scoped_ptr<RenderPassProgramAA> render_pass_program_aa_; scoped_ptr<RenderPassMaskProgram> render_pass_mask_program_; scoped_ptr<RenderPassMaskProgramAA> render_pass_mask_program_aa_; - - scoped_ptr<TextureProgram> texture_program_; - scoped_ptr<TextureProgramFlip> texture_program_flip_; - scoped_ptr<TextureIOSurfaceProgram> texture_io_surface_program_; + scoped_ptr<RenderPassColorMatrixProgram> render_pass_color_matrix_program_; + scoped_ptr<RenderPassColorMatrixProgramAA> + render_pass_color_matrix_program_aa_; + scoped_ptr<RenderPassMaskColorMatrixProgram> + render_pass_mask_color_matrix_program_; + scoped_ptr<RenderPassMaskColorMatrixProgramAA> + render_pass_mask_color_matrix_program_aa_; scoped_ptr<VideoYUVProgram> video_yuv_program_; scoped_ptr<VideoStreamTextureProgram> video_stream_texture_program_; diff --git a/cc/output/gl_renderer_pixeltest.cc b/cc/output/gl_renderer_pixeltest.cc index fbccce1..fcbe32b 100644 --- a/cc/output/gl_renderer_pixeltest.cc +++ b/cc/output/gl_renderer_pixeltest.cc @@ -4,8 +4,13 @@ #include "cc/output/gl_renderer.h" +#include "cc/layers/append_quads_data.h" #include "cc/quads/draw_quad.h" #include "cc/test/pixel_test.h" +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/effects/SkColorFilterImageFilter.h" +#include "third_party/skia/include/effects/SkColorMatrixFilter.h" namespace cc { namespace { @@ -90,7 +95,202 @@ TEST_F(GLRendererPixelTest, SimpleGreenRect) { renderer_->DrawFrame(pass_list); EXPECT_TRUE(PixelsMatchReference( - base::FilePath(FILE_PATH_LITERAL("green.png")))); + base::FilePath(FILE_PATH_LITERAL("green.png")), true)); +} + +TEST_F(GLRendererPixelTest, fastPassColorFilterAlpha) { + gfx::Rect viewport_rect(device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + shared_state->opacity = 0.5f; + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + device_viewport_size_.width() / 2, + device_viewport_size_.height()), + SK_ColorBLUE); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(device_viewport_size_.width() / 2, + 0, + device_viewport_size_.width() / 2, + device_viewport_size_.height()), + SK_ColorYELLOW); + + scoped_ptr<SharedQuadState> blank_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create(); + white->SetNew(blank_state.get(), + viewport_rect, + SK_ColorWHITE); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(white.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + + SkScalar matrix[20]; + float amount = 0.5f; + matrix[0] = 0.213f + 0.787f * amount; + matrix[1] = 0.715f - 0.715f * amount; + matrix[2] = 1.f - (matrix[0] + matrix[1]); + matrix[3] = matrix[4] = 0; + matrix[5] = 0.213f - 0.213f * amount; + matrix[6] = 0.715f + 0.285f * amount; + matrix[7] = 1.f - (matrix[5] + matrix[6]); + matrix[8] = matrix[9] = 0; + matrix[10] = 0.213f - 0.213f * amount; + matrix[11] = 0.715f - 0.715f * amount; + matrix[12] = 1.f - (matrix[10] + matrix[11]); + matrix[13] = matrix[14] = 0; + matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0; + matrix[18] = 1; + skia::RefPtr<SkColorFilter> colorFilter(skia::AdoptRef( + new SkColorMatrixFilter(matrix))); + skia::RefPtr<SkImageFilter> filter = + skia::AdoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), NULL)); + + scoped_ptr<RenderPassDrawQuad> render_pass_quad = RenderPassDrawQuad::Create(); + render_pass_quad->SetNew(pass_shared_state.get(), + pass_rect, + child_pass_id, + false, + 0, + pass_rect, + gfx::RectF(), + WebKit::WebFilterOperations(), + filter, + WebKit::WebFilterOperations()); + + root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + renderer_->SetEnlargePassTextureAmountForTesting(gfx::Vector2d(50, 75)); + renderer_->DecideRenderPassAllocationsForFrame(pass_list); + renderer_->DrawFrame(pass_list); + + EXPECT_TRUE(PixelsMatchReference( + base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")), false)); +} + +TEST_F(GLRendererPixelTest, fastPassColorFilterAlphaTranslation) { + gfx::Rect viewport_rect(device_viewport_size_); + + RenderPass::Id root_pass_id(1, 1); + scoped_ptr<RenderPass> root_pass = + CreateTestRootRenderPass(root_pass_id, viewport_rect); + + RenderPass::Id child_pass_id(2, 2); + gfx::Rect pass_rect(device_viewport_size_); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> child_pass = + CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root); + + gfx::Transform content_to_target_transform; + scoped_ptr<SharedQuadState> shared_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + shared_state->opacity = 0.5f; + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(shared_state.get(), + gfx::Rect(0, + 0, + device_viewport_size_.width() / 2, + device_viewport_size_.height()), + SK_ColorBLUE); + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(shared_state.get(), + gfx::Rect(device_viewport_size_.width() / 2, + 0, + device_viewport_size_.width() / 2, + device_viewport_size_.height()), + SK_ColorYELLOW); + + scoped_ptr<SharedQuadState> blank_state = + CreateTestSharedQuadState(content_to_target_transform, viewport_rect); + + scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create(); + white->SetNew(blank_state.get(), + viewport_rect, + SK_ColorWHITE); + + child_pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + child_pass->quad_list.push_back(white.PassAs<DrawQuad>()); + + scoped_ptr<SharedQuadState> pass_shared_state = + CreateTestSharedQuadState(gfx::Transform(), pass_rect); + + SkScalar matrix[20]; + float amount = 0.5f; + matrix[0] = 0.213f + 0.787f * amount; + matrix[1] = 0.715f - 0.715f * amount; + matrix[2] = 1.f - (matrix[0] + matrix[1]); + matrix[3] = 0; + matrix[4] = 20.f; + matrix[5] = 0.213f - 0.213f * amount; + matrix[6] = 0.715f + 0.285f * amount; + matrix[7] = 1.f - (matrix[5] + matrix[6]); + matrix[8] = 0; + matrix[9] = 200.f; + matrix[10] = 0.213f - 0.213f * amount; + matrix[11] = 0.715f - 0.715f * amount; + matrix[12] = 1.f - (matrix[10] + matrix[11]); + matrix[13] = 0; + matrix[14] = 1.5f; + matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0; + matrix[18] = 1; + skia::RefPtr<SkColorFilter> colorFilter(skia::AdoptRef( + new SkColorMatrixFilter(matrix))); + skia::RefPtr<SkImageFilter> filter = + skia::AdoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), NULL)); + + scoped_ptr<RenderPassDrawQuad> render_pass_quad = + RenderPassDrawQuad::Create(); + render_pass_quad->SetNew(pass_shared_state.get(), + pass_rect, + child_pass_id, + false, + 0, + pass_rect, + gfx::RectF(), + WebKit::WebFilterOperations(), + filter, + WebKit::WebFilterOperations()); + + root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>()); + RenderPassList pass_list; + + pass_list.push_back(child_pass.Pass()); + pass_list.push_back(root_pass.Pass()); + + renderer_->SetEnlargePassTextureAmountForTesting(gfx::Vector2d(50, 75)); + renderer_->DecideRenderPassAllocationsForFrame(pass_list); + renderer_->DrawFrame(pass_list); + + EXPECT_TRUE(PixelsMatchReference( + base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha_translate.png")), + false)); } TEST_F(GLRendererPixelTest, RenderPassChangesSize) { @@ -144,7 +344,7 @@ TEST_F(GLRendererPixelTest, RenderPassChangesSize) { renderer_->DrawFrame(pass_list); EXPECT_TRUE(PixelsMatchReference( - base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")))); + base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")), true)); } class GLRendererPixelTestWithBackgroundFilter : public GLRendererPixelTest { @@ -271,7 +471,7 @@ TEST_F(GLRendererPixelTestWithBackgroundFilter, InvertFilter) { DrawFrame(); EXPECT_TRUE(PixelsMatchReference( - base::FilePath(FILE_PATH_LITERAL("background_filter.png")))); + base::FilePath(FILE_PATH_LITERAL("background_filter.png")), true)); } TEST_F(GLRendererPixelTest, AntiAliasing) { @@ -317,7 +517,7 @@ TEST_F(GLRendererPixelTest, AntiAliasing) { renderer_->DrawFrame(pass_list); EXPECT_TRUE(PixelsMatchReference( - base::FilePath(FILE_PATH_LITERAL("anti_aliasing.png")))); + base::FilePath(FILE_PATH_LITERAL("anti_aliasing.png")), true)); } #endif diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc index 21a00d0..09e6439 100644 --- a/cc/output/gl_renderer_unittest.cc +++ b/cc/output/gl_renderer_unittest.cc @@ -5,12 +5,12 @@ #include "cc/output/gl_renderer.h" #include "cc/output/compositor_frame_metadata.h" -#include "cc/quads/draw_quad.h" #include "cc/resources/prioritized_resource_manager.h" #include "cc/resources/resource_provider.h" #include "cc/test/fake_impl_proxy.h" #include "cc/test/fake_layer_tree_host_impl.h" #include "cc/test/fake_output_surface.h" +#include "cc/test/mock_quad_culler.h" #include "cc/test/pixel_test.h" #include "cc/test/render_pass_test_common.h" #include "cc/test/render_pass_test_utils.h" @@ -18,6 +18,10 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/khronos/GLES2/gl2.h" +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/effects/SkColorFilterImageFilter.h" +#include "third_party/skia/include/effects/SkColorMatrixFilter.h" #include "ui/gfx/transform.h" using namespace WebKit; @@ -40,7 +44,7 @@ namespace cc { } while (false) // Explicitly named to be a friend in GLRenderer for shader access. -class GLRendererShaderTest : public PixelTest { +class GLRendererShaderPixelTest : public PixelTest { public: void TestShaders() { ASSERT_FALSE(renderer_->IsContextLost()); @@ -55,6 +59,10 @@ class GLRendererShaderTest : public PixelTest { EXPECT_PROGRAM_VALID(renderer_->GetRenderPassProgramAA()); EXPECT_PROGRAM_VALID(renderer_->GetRenderPassMaskProgram()); EXPECT_PROGRAM_VALID(renderer_->GetRenderPassMaskProgramAA()); + EXPECT_PROGRAM_VALID(renderer_->GetRenderPassColorMatrixProgram()); + EXPECT_PROGRAM_VALID(renderer_->GetRenderPassMaskColorMatrixProgramAA()); + EXPECT_PROGRAM_VALID(renderer_->GetRenderPassColorMatrixProgramAA()); + EXPECT_PROGRAM_VALID(renderer_->GetRenderPassMaskColorMatrixProgram()); EXPECT_PROGRAM_VALID(renderer_->GetTextureProgram()); EXPECT_PROGRAM_VALID(renderer_->GetTextureProgramFlip()); EXPECT_PROGRAM_VALID(renderer_->GetTextureIOSurfaceProgram()); @@ -74,7 +82,7 @@ class GLRendererShaderTest : public PixelTest { namespace { #if !defined(OS_ANDROID) -TEST_F(GLRendererShaderTest, AllShadersCompile) { TestShaders(); } +TEST_F(GLRendererShaderPixelTest, AllShadersCompile) { TestShaders(); } #endif class FrameCountingMemoryAllocationSettingContext : @@ -232,7 +240,77 @@ class GLRendererTest : public testing::Test { FakeRendererGL renderer_; }; -// Test GLRenderer DiscardBackbuffer functionality: +// Closing the namespace here so that GLRendererShaderTest can take advantage +// of the friend relationship with GLRenderer and all of the mock classes +// declared above it. +} // namespace + +class GLRendererShaderTest : public testing::Test { +protected: + GLRendererShaderTest() + : output_surface_(FakeOutputSurface::Create3d()) + , resource_provider_(ResourceProvider::Create(output_surface_.get())) + , renderer_(GLRenderer::Create(&mock_client_, output_surface_.get(), resource_provider_.get())) + { + } + + void TestRenderPassProgram() { + EXPECT_PROGRAM_VALID(renderer_->render_pass_program_); + EXPECT_TRUE(renderer_->program_shadow_ == + renderer_->render_pass_program_->program()); + } + + void TestRenderPassColorMatrixProgram() { + EXPECT_PROGRAM_VALID(renderer_->render_pass_color_matrix_program_); + EXPECT_TRUE(renderer_->program_shadow_ == + renderer_->render_pass_color_matrix_program_->program()); + } + + void TestRenderPassMaskProgram() { + EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_program_); + EXPECT_TRUE(renderer_->program_shadow_ == + renderer_->render_pass_mask_program_->program()); + } + + void TestRenderPassMaskColorMatrixProgram() { + EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_color_matrix_program_); + EXPECT_TRUE(renderer_->program_shadow_ == + renderer_->render_pass_mask_color_matrix_program_->program()); + } + + void TestRenderPassProgramAA() { + EXPECT_PROGRAM_VALID(renderer_->render_pass_program_aa_); + EXPECT_TRUE(renderer_->program_shadow_ == + renderer_->render_pass_program_aa_->program()); + } + + void TestRenderPassColorMatrixProgramAA() { + EXPECT_PROGRAM_VALID(renderer_->render_pass_color_matrix_program_aa_); + EXPECT_TRUE(renderer_->program_shadow_ == + renderer_->render_pass_color_matrix_program_aa_->program()); + } + + void TestRenderPassMaskProgramAA() { + EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_program_); + EXPECT_TRUE(renderer_->program_shadow_ == + renderer_->render_pass_program_aa_->program()); + } + + void TestRenderPassMaskColorMatrixProgramAA() { + EXPECT_PROGRAM_VALID(renderer_->render_pass_mask_color_matrix_program_aa_); + EXPECT_TRUE(renderer_->program_shadow_ == + renderer_->render_pass_color_matrix_program_aa_->program()); + } + + scoped_ptr<OutputSurface> output_surface_; + FakeRendererClient mock_client_; + scoped_ptr<ResourceProvider> resource_provider_; + scoped_ptr<GLRenderer> renderer_; +}; + +namespace { + +// Test GLRenderer discardBackbuffer functionality: // Suggest recreating framebuffer when one already exists. // Expected: it does nothing. TEST_F(GLRendererTest, SuggestBackbufferYesWhenItAlreadyExistsShouldDoNothing) { @@ -907,6 +985,241 @@ TEST(GLRendererTest2, ScissorTestWhenClearing) { renderer.DrawFrame(*mock_client.render_passes_in_draw_order()); } +TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) { + gfx::Rect viewportRect(mock_client_.DeviceViewportSize()); + ScopedPtrVector<RenderPass>& renderPasses = + *mock_client_.render_passes_in_draw_order(); + + gfx::Rect grandChildRect(25, 25); + RenderPass::Id grandChildPassId(3, 0); + TestRenderPass* grandChildPass; + + gfx::Rect childRect(50, 50); + RenderPass::Id childPassId(2, 0); + TestRenderPass* childPass; + + RenderPass::Id rootPassId(1, 0); + TestRenderPass* rootPass; + + cc::ResourceProvider::ResourceId mask = + resource_provider_->CreateResource(gfx::Size(20, 12), + resource_provider_->best_texture_format(), + ResourceProvider::TextureUsageAny); + resource_provider_->AllocateForTesting(mask); + + SkScalar matrix[20]; + float amount = 0.5f; + matrix[0] = 0.213f + 0.787f * amount; + matrix[1] = 0.715f - 0.715f * amount; + matrix[2] = 1.f - (matrix[0] + matrix[1]); + matrix[3] = matrix[4] = 0; + matrix[5] = 0.213f - 0.213f * amount; + matrix[6] = 0.715f + 0.285f * amount; + matrix[7] = 1.f - (matrix[5] + matrix[6]); + matrix[8] = matrix[9] = 0; + matrix[10] = 0.213f - 0.213f * amount; + matrix[11] = 0.715f - 0.715f * amount; + matrix[12] = 1.f - (matrix[10] + matrix[11]); + matrix[13] = matrix[14] = 0; + matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0; + matrix[18] = 1; + skia::RefPtr<SkColorFilter> colorFilter(skia::AdoptRef( + new SkColorMatrixFilter(matrix))); + skia::RefPtr<SkImageFilter> filter = + skia::AdoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), NULL)); + + gfx::Transform transform_causing_aa; + transform_causing_aa.Rotate(20.0); + + // RenderPassProgram + renderPasses.clear(); + + grandChildPass = AddRenderPass(renderPasses, grandChildPassId, grandChildRect, + gfx::Transform()); + AddClippedQuad(grandChildPass, grandChildRect, SK_ColorYELLOW); + + childPass = AddRenderPass(renderPasses, childPassId, childRect, + gfx::Transform()); + AddQuad(childPass, childRect, SK_ColorBLUE); + + rootPass = AddRenderPass(renderPasses, rootPassId, viewportRect, + gfx::Transform()); + AddQuad(rootPass, viewportRect, SK_ColorGREEN); + + AddRenderPassQuad(rootPass, childPass, 0, skia::RefPtr<SkImageFilter>(), + gfx::Transform()); + AddRenderPassQuad(childPass, grandChildPass); + + renderer_->DecideRenderPassAllocationsForFrame( + *mock_client_.render_passes_in_draw_order()); + renderer_->DrawFrame(*mock_client_.render_passes_in_draw_order()); + TestRenderPassProgram(); + + // RenderPassColorMatrixProgram + renderPasses.clear(); + + grandChildPass = AddRenderPass(renderPasses, grandChildPassId, grandChildRect, + transform_causing_aa); + AddClippedQuad(grandChildPass, grandChildRect, SK_ColorYELLOW); + + childPass = AddRenderPass(renderPasses, childPassId, childRect, + transform_causing_aa); + AddQuad(childPass, childRect, SK_ColorBLUE); + + rootPass = AddRenderPass(renderPasses, rootPassId, viewportRect, + gfx::Transform()); + AddQuad(rootPass, viewportRect, SK_ColorGREEN); + + AddRenderPassQuad(rootPass, childPass, 0, filter, gfx::Transform()); + AddRenderPassQuad(childPass, grandChildPass); + + renderer_->DecideRenderPassAllocationsForFrame( + *mock_client_.render_passes_in_draw_order()); + renderer_->DrawFrame(*mock_client_.render_passes_in_draw_order()); + TestRenderPassColorMatrixProgram(); + + // RenderPassMaskProgram + renderPasses.clear(); + + grandChildPass = AddRenderPass(renderPasses, grandChildPassId, grandChildRect, + gfx::Transform()); + AddClippedQuad(grandChildPass, grandChildRect, SK_ColorYELLOW); + + childPass = AddRenderPass(renderPasses, childPassId, childRect, + gfx::Transform()); + AddQuad(childPass, childRect, SK_ColorBLUE); + + rootPass = AddRenderPass(renderPasses, rootPassId, viewportRect, + gfx::Transform()); + AddQuad(rootPass, viewportRect, SK_ColorGREEN); + + AddRenderPassQuad(rootPass, childPass, mask, skia::RefPtr<SkImageFilter>(), + gfx::Transform()); + AddRenderPassQuad(childPass, grandChildPass); + + renderer_->DecideRenderPassAllocationsForFrame( + *mock_client_.render_passes_in_draw_order()); + renderer_->DrawFrame(*mock_client_.render_passes_in_draw_order()); + TestRenderPassMaskProgram(); + + // RenderPassMaskColorMatrixProgram + renderPasses.clear(); + + grandChildPass = AddRenderPass(renderPasses, grandChildPassId, grandChildRect, + gfx::Transform()); + AddClippedQuad(grandChildPass, grandChildRect, SK_ColorYELLOW); + + childPass = AddRenderPass(renderPasses, childPassId, childRect, + gfx::Transform()); + AddQuad(childPass, childRect, SK_ColorBLUE); + + rootPass = AddRenderPass(renderPasses, rootPassId, viewportRect, + gfx::Transform()); + AddQuad(rootPass, viewportRect, SK_ColorGREEN); + + AddRenderPassQuad(rootPass, childPass, mask, filter, gfx::Transform()); + AddRenderPassQuad(childPass, grandChildPass); + + renderer_->DecideRenderPassAllocationsForFrame( + *mock_client_.render_passes_in_draw_order()); + renderer_->DrawFrame(*mock_client_.render_passes_in_draw_order()); + TestRenderPassMaskColorMatrixProgram(); + + // RenderPassProgramAA + renderPasses.clear(); + + grandChildPass = AddRenderPass(renderPasses, grandChildPassId, grandChildRect, + transform_causing_aa); + AddClippedQuad(grandChildPass, grandChildRect, SK_ColorYELLOW); + + childPass = AddRenderPass(renderPasses, childPassId, childRect, + transform_causing_aa); + AddQuad(childPass, childRect, SK_ColorBLUE); + + rootPass = AddRenderPass(renderPasses, rootPassId, viewportRect, + gfx::Transform()); + AddQuad(rootPass, viewportRect, SK_ColorGREEN); + + AddRenderPassQuad(rootPass, childPass, 0, skia::RefPtr<SkImageFilter>(), + transform_causing_aa); + AddRenderPassQuad(childPass, grandChildPass); + + renderer_->DecideRenderPassAllocationsForFrame( + *mock_client_.render_passes_in_draw_order()); + renderer_->DrawFrame(*mock_client_.render_passes_in_draw_order()); + TestRenderPassProgramAA(); + + // RenderPassColorMatrixProgramAA + renderPasses.clear(); + + grandChildPass = AddRenderPass(renderPasses, grandChildPassId, grandChildRect, + transform_causing_aa); + AddClippedQuad(grandChildPass, grandChildRect, SK_ColorYELLOW); + + childPass = AddRenderPass(renderPasses, childPassId, childRect, + transform_causing_aa); + AddQuad(childPass, childRect, SK_ColorBLUE); + + rootPass = AddRenderPass(renderPasses, rootPassId, viewportRect, + gfx::Transform()); + AddQuad(rootPass, viewportRect, SK_ColorGREEN); + + AddRenderPassQuad(rootPass, childPass, 0, filter, transform_causing_aa); + AddRenderPassQuad(childPass, grandChildPass); + + renderer_->DecideRenderPassAllocationsForFrame( + *mock_client_.render_passes_in_draw_order()); + renderer_->DrawFrame(*mock_client_.render_passes_in_draw_order()); + TestRenderPassColorMatrixProgramAA(); + + // RenderPassMaskProgramAA + renderPasses.clear(); + + grandChildPass = AddRenderPass(renderPasses, grandChildPassId, grandChildRect, + transform_causing_aa); + AddClippedQuad(grandChildPass, grandChildRect, SK_ColorYELLOW); + + childPass = AddRenderPass(renderPasses, childPassId, childRect, + transform_causing_aa); + AddQuad(childPass, childRect, SK_ColorBLUE); + + rootPass = AddRenderPass(renderPasses, rootPassId, viewportRect, + gfx::Transform()); + AddQuad(rootPass, viewportRect, SK_ColorGREEN); + + AddRenderPassQuad(rootPass, childPass, mask, skia::RefPtr<SkImageFilter>(), + transform_causing_aa); + AddRenderPassQuad(childPass, grandChildPass); + + renderer_->DecideRenderPassAllocationsForFrame( + *mock_client_.render_passes_in_draw_order()); + renderer_->DrawFrame(*mock_client_.render_passes_in_draw_order()); + TestRenderPassMaskProgramAA(); + + // RenderPassMaskColorMatrixProgramAA + renderPasses.clear(); + + grandChildPass = AddRenderPass(renderPasses, grandChildPassId, grandChildRect, + transform_causing_aa); + AddClippedQuad(grandChildPass, grandChildRect, SK_ColorYELLOW); + + childPass = AddRenderPass(renderPasses, childPassId, childRect, + transform_causing_aa); + AddQuad(childPass, childRect, SK_ColorBLUE); + + rootPass = AddRenderPass(renderPasses, rootPassId, viewportRect, + transform_causing_aa); + AddQuad(rootPass, viewportRect, SK_ColorGREEN); + + AddRenderPassQuad(rootPass, childPass, mask, filter, transform_causing_aa); + AddRenderPassQuad(childPass, grandChildPass); + + renderer_->DecideRenderPassAllocationsForFrame( + *mock_client_.render_passes_in_draw_order()); + renderer_->DrawFrame(*mock_client_.render_passes_in_draw_order()); + TestRenderPassMaskColorMatrixProgramAA(); +} + class OutputSurfaceMockContext : public TestWebGraphicsContext3D { public: // Specifically override methods even if they are unused (used in conjunction diff --git a/cc/output/shader.cc b/cc/output/shader.cc index 0200b6d..142e459 100644 --- a/cc/output/shader.cc +++ b/cc/output/shader.cc @@ -420,6 +420,41 @@ void FragmentTexAlphaBinding::Init(WebGraphicsContext3D* context, DCHECK(sampler_location_ != -1 && alpha_location_ != -1); } +FragmentTexColorMatrixAlphaBinding::FragmentTexColorMatrixAlphaBinding() + : sampler_location_(-1) + , alpha_location_(-1) + , color_matrix_location_(-1) + , color_offset_location_(-1) {} + +void FragmentTexColorMatrixAlphaBinding::Init(WebGraphicsContext3D* context, + unsigned program, + bool usingBindUniform, + int* baseUniformIndex) { + static const char* shaderUniforms[] = { + "s_texture", + "alpha", + "colorMatrix", + "colorOffset", + }; + int locations[4]; + + GetProgramUniformLocations(context, + program, + shaderUniforms, + arraysize(shaderUniforms), + arraysize(locations), + locations, + usingBindUniform, + baseUniformIndex); + + sampler_location_ = locations[0]; + alpha_location_ = locations[1]; + color_matrix_location_ = locations[2]; + color_offset_location_ = locations[3]; + DCHECK(sampler_location_ != -1 && alpha_location_ != -1 && + color_matrix_location_ != -1 && color_offset_location_ != -1); +} + FragmentTexOpaqueBinding::FragmentTexOpaqueBinding() : sampler_location_(-1) {} @@ -494,6 +529,26 @@ std::string FragmentShaderRGBATexAlpha::GetShaderString() const { ); } +std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderString() const { + return SHADER( + precision mediump float; + varying vec2 v_texCoord; + uniform sampler2D s_texture; + uniform float alpha; + uniform mat4 colorMatrix; + uniform vec4 colorOffset; + void main() { + vec4 texColor = texture2D(s_texture, v_texCoord); + float nonZeroAlpha = max(texColor.a, 0.00001); + texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha); + texColor = colorMatrix * texColor + colorOffset; + texColor.rgb *= texColor.a; + texColor = clamp(texColor, 0.0, 1.0); + gl_FragColor = texColor * alpha; + } + ); +} + std::string FragmentShaderRGBATexVaryingAlpha::GetShaderString() const { return SHADER( precision mediump float; @@ -847,6 +902,232 @@ std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderString() const { ); } +FragmentShaderRGBATexAlphaMaskColorMatrixAA::FragmentShaderRGBATexAlphaMaskColorMatrixAA() + : sampler_location_(-1) + , mask_sampler_location_(-1) + , alpha_location_(-1) + , edge_location_(-1) + , mask_tex_coord_scale_location_(-1) + , color_matrix_location_(-1) + , color_offset_location_(-1) {} + +void FragmentShaderRGBATexAlphaMaskColorMatrixAA::Init( + WebGraphicsContext3D* context, + unsigned program, + bool usingBindUniform, + int* baseUniformIndex) { + static const char* shaderUniforms[] = { + "s_texture", + "s_mask", + "alpha", + "edge", + "maskTexCoordScale", + "maskTexCoordOffset", + "colorMatrix", + "colorOffset", + }; + int locations[8]; + + GetProgramUniformLocations(context, + program, + shaderUniforms, + arraysize(shaderUniforms), + arraysize(locations), + locations, + usingBindUniform, + baseUniformIndex); + + sampler_location_ = locations[0]; + mask_sampler_location_ = locations[1]; + alpha_location_ = locations[2]; + edge_location_ = locations[3]; + mask_tex_coord_scale_location_ = locations[4]; + mask_tex_coord_offset_location_ = locations[5]; + color_matrix_location_ = locations[6]; + color_offset_location_ = locations[7]; + DCHECK(sampler_location_ != -1 && mask_sampler_location_ != -1 && + alpha_location_ != -1 && edge_location_ != -1 && + color_matrix_location_ != -1 && color_offset_location_ != -1); +} + +std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString() const { + return SHADER( + precision mediump float; + varying vec2 v_texCoord; + uniform sampler2D s_texture; + uniform sampler2D s_mask; + uniform vec2 maskTexCoordScale; + uniform vec2 maskTexCoordOffset; + uniform mat4 colorMatrix; + uniform vec4 colorOffset; + uniform float alpha; + uniform vec3 edge[8]; + void main() { + vec4 texColor = texture2D(s_texture, v_texCoord); + float nonZeroAlpha = max(texColor.a, 0.00001); + texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha); + texColor = colorMatrix * texColor + colorOffset; + texColor.rgb *= texColor.a; + texColor = clamp(texColor, 0.0, 1.0); + vec2 maskTexCoord = + vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x, + maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y); + vec4 maskColor = texture2D(s_mask, maskTexCoord); + vec3 pos = vec3(gl_FragCoord.xy, 1); + float a0 = clamp(dot(edge[0], pos), 0.0, 1.0); + float a1 = clamp(dot(edge[1], pos), 0.0, 1.0); + float a2 = clamp(dot(edge[2], pos), 0.0, 1.0); + float a3 = clamp(dot(edge[3], pos), 0.0, 1.0); + float a4 = clamp(dot(edge[4], pos), 0.0, 1.0); + float a5 = clamp(dot(edge[5], pos), 0.0, 1.0); + float a6 = clamp(dot(edge[6], pos), 0.0, 1.0); + float a7 = clamp(dot(edge[7], pos), 0.0, 1.0); + gl_FragColor = + vec4(texColor.x, texColor.y, texColor.z, texColor.w) * + alpha * maskColor.w * min(min(a0, a2) * min(a1, a3), min(a4, a6) * + min(a5, a7)); + } + ); +} + +FragmentShaderRGBATexAlphaColorMatrixAA::FragmentShaderRGBATexAlphaColorMatrixAA() + : sampler_location_(-1) + , alpha_location_(-1) + , edge_location_(-1) + , color_matrix_location_(-1) + , color_offset_location_(-1) {} + +void FragmentShaderRGBATexAlphaColorMatrixAA::Init( + WebGraphicsContext3D* context, unsigned program, bool usingBindUniform, + int* baseUniformIndex) { + static const char* shaderUniforms[] = { + "s_texture", + "alpha", + "edge", + "colorMatrix", + "colorOffset", + }; + int locations[5]; + + GetProgramUniformLocations(context, + program, + shaderUniforms, + arraysize(shaderUniforms), + arraysize(locations), + locations, + usingBindUniform, + baseUniformIndex); + + sampler_location_ = locations[0]; + alpha_location_ = locations[1]; + edge_location_ = locations[2]; + color_matrix_location_ = locations[3]; + color_offset_location_ = locations[4]; + DCHECK(sampler_location_ != -1 && alpha_location_ != -1 && + edge_location_ != -1 && color_matrix_location_ != -1 && + color_offset_location_ != -1); +} + +std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderString() const { + return SHADER( + precision mediump float; + varying vec2 v_texCoord; + uniform sampler2D s_texture; + uniform float alpha; + uniform mat4 colorMatrix; + uniform vec4 colorOffset; + uniform vec3 edge[8]; + void main() { + vec4 texColor = texture2D(s_texture, v_texCoord); + float nonZeroAlpha = max(texColor.a, 0.00001); + texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha); + texColor = colorMatrix * texColor + colorOffset; + texColor.rgb *= texColor.a; + texColor = clamp(texColor, 0.0, 1.0); + vec3 pos = vec3(gl_FragCoord.xy, 1); + float a0 = clamp(dot(edge[0], pos), 0.0, 1.0); + float a1 = clamp(dot(edge[1], pos), 0.0, 1.0); + float a2 = clamp(dot(edge[2], pos), 0.0, 1.0); + float a3 = clamp(dot(edge[3], pos), 0.0, 1.0); + float a4 = clamp(dot(edge[4], pos), 0.0, 1.0); + float a5 = clamp(dot(edge[5], pos), 0.0, 1.0); + float a6 = clamp(dot(edge[6], pos), 0.0, 1.0); + float a7 = clamp(dot(edge[7], pos), 0.0, 1.0); + gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * + alpha * min(min(a0, a2) * min(a1, a3), min(a4, a6) * min(a5, a7)); + } + ); +} + +FragmentShaderRGBATexAlphaMaskColorMatrix::FragmentShaderRGBATexAlphaMaskColorMatrix() + : sampler_location_(-1) + , mask_sampler_location_(-1) + , alpha_location_(-1) + , mask_tex_coord_scale_location_(-1) {} + +void FragmentShaderRGBATexAlphaMaskColorMatrix::Init( + WebGraphicsContext3D* context, unsigned program, bool usingBindUniform, + int* baseUniformIndex) { + static const char* shaderUniforms[] = { + "s_texture", + "s_mask", + "alpha", + "maskTexCoordScale", + "maskTexCoordOffset", + "colorMatrix", + "colorOffset", + }; + int locations[7]; + + GetProgramUniformLocations(context, + program, + shaderUniforms, + arraysize(shaderUniforms), + arraysize(locations), + locations, + usingBindUniform, + baseUniformIndex); + + sampler_location_ = locations[0]; + mask_sampler_location_ = locations[1]; + alpha_location_ = locations[2]; + mask_tex_coord_scale_location_ = locations[3]; + mask_tex_coord_offset_location_ = locations[4]; + color_matrix_location_ = locations[5]; + color_offset_location_ = locations[6]; + DCHECK(sampler_location_ != -1 && mask_sampler_location_ != -1 && + alpha_location_ != -1 && color_matrix_location_ != -1 && + color_offset_location_ != -1); +} + +std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderString() const { + return SHADER( + precision mediump float; + varying vec2 v_texCoord; + uniform sampler2D s_texture; + uniform sampler2D s_mask; + uniform vec2 maskTexCoordScale; + uniform vec2 maskTexCoordOffset; + uniform mat4 colorMatrix; + uniform vec4 colorOffset; + uniform float alpha; + void main() { + vec4 texColor = texture2D(s_texture, v_texCoord); + float nonZeroAlpha = max(texColor.a, 0.00001); + texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha); + texColor = colorMatrix * texColor + colorOffset; + texColor.rgb *= texColor.a; + texColor = clamp(texColor, 0.0, 1.0); + vec2 maskTexCoord = + vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x, + maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y); + vec4 maskColor = texture2D(s_mask, maskTexCoord); + gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * + alpha * maskColor.w; + } + ); +} + FragmentShaderYUVVideo::FragmentShaderYUVVideo() : y_texture_location_(-1), u_texture_location_(-1), diff --git a/cc/output/shader.h b/cc/output/shader.h index fb8d658..3dc265d 100644 --- a/cc/output/shader.h +++ b/cc/output/shader.h @@ -103,7 +103,7 @@ class VertexShaderQuad { VertexShaderQuad(); void Init(WebKit::WebGraphicsContext3D*, - unsigned program, + unsigned program, bool using_bind_uniform, int* base_uniform_index); std::string GetShaderString() const; @@ -176,6 +176,28 @@ class FragmentTexAlphaBinding { int alpha_location_; }; +class FragmentTexColorMatrixAlphaBinding { +public: + FragmentTexColorMatrixAlphaBinding(); + + void Init(WebKit::WebGraphicsContext3D*, + unsigned program, + bool usingBindUniform, + int* baseUniformIndex); + int alpha_location() const { return alpha_location_; } + int color_matrix_location() const { return color_matrix_location_; } + int color_offset_location() const { return color_offset_location_; } + int edge_location() const { return -1; } + int fragment_tex_transform_location() const { return -1; } + int sampler_location() const { return sampler_location_; } + +private: + int sampler_location_; + int alpha_location_; + int color_matrix_location_; + int color_offset_location_; +}; + class FragmentTexOpaqueBinding { public: FragmentTexOpaqueBinding(); @@ -203,6 +225,11 @@ class FragmentShaderRGBATexAlpha : public FragmentTexAlphaBinding { std::string GetShaderString() const; }; +class FragmentShaderRGBATexColorMatrixAlpha : public FragmentTexColorMatrixAlphaBinding { +public: + std::string GetShaderString() const; +}; + class FragmentShaderRGBATexRectVaryingAlpha : public FragmentTexAlphaBinding { public: std::string GetShaderString() const; @@ -353,6 +380,93 @@ class FragmentShaderRGBATexAlphaMaskAA { int mask_tex_coord_offset_location_; }; +class FragmentShaderRGBATexAlphaMaskColorMatrixAA { +public: + FragmentShaderRGBATexAlphaMaskColorMatrixAA(); + std::string GetShaderString() const; + + void Init(WebKit::WebGraphicsContext3D*, + unsigned program, + bool usingBindUniform, + int* baseUniformIndex); + int alpha_location() const { return alpha_location_; } + int sampler_location() const { return sampler_location_; } + int mask_sampler_location() const { return mask_sampler_location_; } + int edge_location() const { return edge_location_; } + int mask_tex_coord_scale_location() const { + return mask_tex_coord_scale_location_; + } + int mask_tex_coord_offset_location() const { + return mask_tex_coord_offset_location_; + } + int color_matrix_location() const { return color_matrix_location_; } + int color_offset_location() const { return color_offset_location_; } + +private: + int sampler_location_; + int mask_sampler_location_; + int alpha_location_; + int edge_location_; + int mask_tex_coord_scale_location_; + int mask_tex_coord_offset_location_; + int color_matrix_location_; + int color_offset_location_; +}; + +class FragmentShaderRGBATexAlphaColorMatrixAA { +public: + FragmentShaderRGBATexAlphaColorMatrixAA(); + std::string GetShaderString() const; + + void Init(WebKit::WebGraphicsContext3D*, + unsigned program, + bool usingBindUniform, + int* baseUniformIndex); + int alpha_location() const { return alpha_location_; } + int sampler_location() const { return sampler_location_; } + int edge_location() const { return edge_location_; } + int color_matrix_location() const { return color_matrix_location_; } + int color_offset_location() const { return color_offset_location_; } + +private: + int sampler_location_; + int alpha_location_; + int edge_location_; + int color_matrix_location_; + int color_offset_location_; +}; + +class FragmentShaderRGBATexAlphaMaskColorMatrix { +public: + FragmentShaderRGBATexAlphaMaskColorMatrix(); + std::string GetShaderString() const; + + void Init(WebKit::WebGraphicsContext3D*, + unsigned program, + bool usingBindUniform, + int* baseUniformIndex); + int alpha_location() const { return alpha_location_; } + int sampler_location() const { return sampler_location_; } + int mask_sampler_location() const { return mask_sampler_location_; } + int mask_tex_coord_scale_location() const { + return mask_tex_coord_scale_location_; + } + int mask_tex_coord_offset_location() const { + return mask_tex_coord_offset_location_; + } + int color_matrix_location() const { return color_matrix_location_; } + int color_offset_location() const { return color_offset_location_; } + +private: + int sampler_location_; + int mask_sampler_location_; + int alpha_location_; + int mask_tex_coord_scale_location_; + int mask_tex_coord_offset_location_; + int color_matrix_location_; + int color_offset_location_; +}; + class FragmentShaderYUVVideo { public: FragmentShaderYUVVideo(); diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc index bb8e64e..e68cd79 100644 --- a/cc/test/layer_tree_pixel_test.cc +++ b/cc/test/layer_tree_pixel_test.cc @@ -66,7 +66,7 @@ void LayerTreePixelTest::SwapBuffersOnThread(LayerTreeHostImpl* host_impl, // To rebaseline: // EXPECT_TRUE(WritePNGFile(bitmap, test_data_dir.Append(ref_file_))); - EXPECT_TRUE(IsSameAsPNGFile(bitmap, test_data_dir.Append(ref_file_))); + EXPECT_TRUE(IsSameAsPNGFile(bitmap, test_data_dir.Append(ref_file_), true)); EndTest(); } diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index 4b44ecb..040f5f3 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc @@ -75,7 +75,8 @@ void PixelTest::SetUp() { resource_provider_->set_offscreen_context_provider(offscreen_contexts); } -bool PixelTest::PixelsMatchReference(const base::FilePath& ref_file) { +bool PixelTest::PixelsMatchReference(const base::FilePath& ref_file, + bool discard_transparency) { gfx::Rect device_viewport_rect(device_viewport_size_); SkBitmap bitmap; @@ -93,7 +94,8 @@ bool PixelTest::PixelsMatchReference(const base::FilePath& ref_file) { // To rebaseline: // return WritePNGFile(bitmap, test_data_dir.Append(ref_file)); - return IsSameAsPNGFile(bitmap, test_data_dir.Append(ref_file)); + return IsSameAsPNGFile(bitmap, test_data_dir.Append(ref_file), + discard_transparency); } } // namespace cc diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h index 40acb33..3762d60 100644 --- a/cc/test/pixel_test.h +++ b/cc/test/pixel_test.h @@ -21,7 +21,8 @@ class PixelTest : public testing::Test { virtual void SetUp() OVERRIDE; - bool PixelsMatchReference(const base::FilePath& ref_file); + bool PixelsMatchReference(const base::FilePath& ref_file, + bool discard_transparency); gfx::Size device_viewport_size_; scoped_ptr<OutputSurface> output_surface_; diff --git a/cc/test/pixel_test_utils.cc b/cc/test/pixel_test_utils.cc index ead2f6f..cedb386 100644 --- a/cc/test/pixel_test_utils.cc +++ b/cc/test/pixel_test_utils.cc @@ -14,9 +14,9 @@ namespace cc { -bool WritePNGFile(const SkBitmap& bitmap, const base::FilePath& file_path) { +bool WritePNGFile(const SkBitmap& bitmap, const base::FilePath& file_path, + bool discard_transparency) { std::vector<unsigned char> png_data; - const bool discard_transparency = true; if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, discard_transparency, &png_data) && @@ -37,7 +37,8 @@ bool ReadPNGFile(const base::FilePath& file_path, SkBitmap* bitmap) { bitmap); } -bool IsSameAsPNGFile(const SkBitmap& gen_bmp, base::FilePath ref_img_path) { +bool IsSameAsPNGFile(const SkBitmap& gen_bmp, base::FilePath ref_img_path, + bool discard_transparency) { SkBitmap ref_bmp; if (!ReadPNGFile(ref_img_path, &ref_bmp)) { LOG(ERROR) << "Cannot read reference image: " << ref_img_path.value(); @@ -60,7 +61,12 @@ bool IsSameAsPNGFile(const SkBitmap& gen_bmp, base::FilePath ref_img_path) { SkAutoLockPixels lock_ref_bmp(ref_bmp); // The reference images were saved with no alpha channel. Use the mask to // set alpha to 0. - uint32_t kAlphaMask = 0x00FFFFFF; + uint32_t kAlphaMask; + if (discard_transparency) + kAlphaMask = 0x00FFFFFF; + else + kAlphaMask = 0xFFFFFFFF; + for (int x = 0; x < gen_bmp.width(); ++x) { for (int y = 0; y < gen_bmp.height(); ++y) { if ((*gen_bmp.getAddr32(x, y) & kAlphaMask) != diff --git a/cc/test/pixel_test_utils.h b/cc/test/pixel_test_utils.h index 29dad87..2ee2ecd 100644 --- a/cc/test/pixel_test_utils.h +++ b/cc/test/pixel_test_utils.h @@ -13,7 +13,8 @@ namespace cc { // Encodes a bitmap into a PNG and write to disk. Returns true on success. The // parent directory does not have to exist. -bool WritePNGFile(const SkBitmap& bitmap, const base::FilePath& file_path); +bool WritePNGFile(const SkBitmap& bitmap, const base::FilePath& file_path, + bool discard_transparency); // Reads and decodes a PNG image to a bitmap. Returns true on success. The PNG // should have been encoded using |gfx::PNGCodec::Encode|. @@ -21,7 +22,8 @@ bool ReadPNGFile(const base::FilePath& file_path, SkBitmap* bitmap); // Compares with a PNG file on disk, and returns true if it is the same as // the given image. |ref_img_path| is absolute. -bool IsSameAsPNGFile(const SkBitmap& gen_bmp, base::FilePath ref_img_path); +bool IsSameAsPNGFile(const SkBitmap& gen_bmp, base::FilePath ref_img_path, + bool discard_transparency); } // namespace cc diff --git a/cc/test/render_pass_test_utils.cc b/cc/test/render_pass_test_utils.cc index 94d0f64..24cb778 100644 --- a/cc/test/render_pass_test_utils.cc +++ b/cc/test/render_pass_test_utils.cc @@ -9,6 +9,7 @@ #include "cc/quads/render_pass_draw_quad.h" #include "cc/quads/shared_quad_state.h" #include "cc/quads/solid_color_draw_quad.h" +#include "cc/resources/resource_provider.h" #include "cc/test/mock_quad_culler.h" #include "cc/test/render_pass_test_common.h" #include "ui/gfx/rect.h" @@ -73,4 +74,25 @@ void AddRenderPassQuad(TestRenderPass* to_pass, quad_sink.Append(quad.PassAs<DrawQuad>(), &data); } +void AddRenderPassQuad(TestRenderPass* to_pass, + TestRenderPass* contributing_pass, + ResourceProvider::ResourceId mask_resource_id, + skia::RefPtr<SkImageFilter> filter, + gfx::Transform transform) { + MockQuadCuller quad_sink(&to_pass->quad_list, + &to_pass->shared_quad_state_list); + AppendQuadsData data(to_pass->id); + gfx::Rect output_rect = contributing_pass->output_rect; + SharedQuadState* shared_state = + quad_sink.UseSharedQuadState(SharedQuadState::Create()); + shared_state->SetAll( + transform, output_rect.size(), output_rect, output_rect, false, 1); + scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create(); + quad->SetNew(shared_state, output_rect, contributing_pass->id, false, + mask_resource_id, output_rect, gfx::RectF(), + WebKit::WebFilterOperations(), + filter, WebKit::WebFilterOperations()); + quad_sink.Append(quad.PassAs<DrawQuad>(), &data); +} + } // namespace cc diff --git a/cc/test/render_pass_test_utils.h b/cc/test/render_pass_test_utils.h index 83e5d90..fdc6366 100644 --- a/cc/test/render_pass_test_utils.h +++ b/cc/test/render_pass_test_utils.h @@ -7,6 +7,7 @@ #include "cc/base/scoped_ptr_vector.h" #include "cc/quads/render_pass.h" +#include "cc/resources/resource_provider.h" #include "third_party/skia/include/core/SkColor.h" namespace gfx { @@ -41,6 +42,13 @@ SolidColorDrawQuad* AddClippedQuad(TestRenderPass* pass, void AddRenderPassQuad(TestRenderPass* to_pass, TestRenderPass* contributing_pass); +// Adds a render pass quad with the given mask resource, filter, and transform. +void AddRenderPassQuad(TestRenderPass* toPass, + TestRenderPass* contributingPass, + ResourceProvider::ResourceId mask_resource_id, + skia::RefPtr<SkImageFilter> filter, + gfx::Transform transform); + } // namespace cc #endif // CC_TEST_RENDER_PASS_TEST_UTILS_H_ diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc index aaba292..5dda85f 100644 --- a/ui/compositor/layer_unittest.cc +++ b/ui/compositor/layer_unittest.cc @@ -919,35 +919,35 @@ TEST_F(LayerWithRealCompositorTest, MAYBE_ModifyHierarchy) { ASSERT_TRUE(ReadPixels(&bitmap)); ASSERT_FALSE(bitmap.empty()); // WritePNGFile(bitmap, ref_img1); - EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img1)); + EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img1, true)); l0->StackAtTop(l11.get()); DrawTree(l0.get()); ASSERT_TRUE(ReadPixels(&bitmap)); ASSERT_FALSE(bitmap.empty()); // WritePNGFile(bitmap, ref_img2); - EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img2)); + EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img2, true)); // l11 is already at the front, should have no effect. l0->StackAtTop(l11.get()); DrawTree(l0.get()); ASSERT_TRUE(ReadPixels(&bitmap)); ASSERT_FALSE(bitmap.empty()); - EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img2)); + EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img2, true)); // l11 is already at the front, should have no effect. l0->StackAbove(l11.get(), l12.get()); DrawTree(l0.get()); ASSERT_TRUE(ReadPixels(&bitmap)); ASSERT_FALSE(bitmap.empty()); - EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img2)); + EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img2, true)); // should restore to original configuration l0->StackAbove(l12.get(), l11.get()); DrawTree(l0.get()); ASSERT_TRUE(ReadPixels(&bitmap)); ASSERT_FALSE(bitmap.empty()); - EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img1)); + EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img1, true)); } // Opacity is rendered correctly. @@ -971,7 +971,7 @@ TEST_F(LayerWithRealCompositorTest, MAYBE_Opacity) { ASSERT_TRUE(ReadPixels(&bitmap)); ASSERT_FALSE(bitmap.empty()); // WritePNGFile(bitmap, ref_img); - EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img)); + EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img, true)); } namespace { |