diff options
-rw-r--r-- | cc/output/gl_renderer.cc | 32 | ||||
-rw-r--r-- | cc/output/gl_renderer_pixeltest.cc | 52 | ||||
-rw-r--r-- | cc/output/gl_renderer_unittest.cc | 34 | ||||
-rw-r--r-- | cc/test/render_pass_test_utils.cc | 16 | ||||
-rw-r--r-- | cc/test/render_pass_test_utils.h | 6 | ||||
-rw-r--r-- | ui/gfx/rect_conversions.cc | 18 | ||||
-rw-r--r-- | ui/gfx/rect_conversions.h | 5 |
7 files changed, 151 insertions, 12 deletions
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index cf7b64b..19b215b 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc @@ -81,6 +81,10 @@ bool NeedsIOSurfaceReadbackWorkaround() { #endif } +// Smallest unit that impact anti-aliasing output. We use this to +// determine when anti-aliasing is unnecessary. +const float kAntiAliasingEpsilon = 1.0f / 1024.0f; + } // anonymous namespace scoped_ptr<GLRenderer> GLRenderer::Create(RendererClient* client, @@ -715,7 +719,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, // Use anti-aliasing programs only when necessary. bool use_aa = (!device_quad.IsRectilinear() || - !device_quad.BoundingBox().IsExpressibleAsRect()); + !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(), + kAntiAliasingEpsilon)); if (use_aa) { device_layer_bounds.InflateAntiAliasingDistance(); device_layer_edges.InflateAntiAliasingDistance(); @@ -1011,11 +1016,11 @@ bool GLRenderer::SetupQuadForAntialiasing( device_transform, gfx::QuadF(quad->visibleContentRect()), &clipped); DCHECK(!clipped); - // TODO(reveman): Axis-aligned is not enough to avoid anti-aliasing. - // Bounding rectangle for quad also needs to be expressible as an integer - // rectangle. crbug.com/169374 bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear(); - bool use_aa = !clipped && !is_axis_aligned_in_target && quad->IsEdge(); + bool is_nearest_rect_within_epsilon = is_axis_aligned_in_target && + gfx::IsNearestRectWithinDistance(device_layer_quad.BoundingBox(), + kAntiAliasingEpsilon); + bool use_aa = !clipped && !is_nearest_rect_within_epsilon && quad->IsEdge(); if (!use_aa) return false; @@ -1200,13 +1205,16 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame, // is mapped to the unit square by the vertex shader and mapped // back to normalized texture coordinates by the fragment shader // after being clamped to 0-1 range. - const float epsilon = 1.0f / 1024.0f; - float tex_clamp_x = std::min(0.5f, 0.5f * clamp_tex_rect.width() - epsilon); - float tex_clamp_y = std::min(0.5f, 0.5f * clamp_tex_rect.height() - epsilon); - float geom_clamp_x = std::min(tex_clamp_x * tex_to_geom_scale_x, - 0.5f * clamp_geom_rect.width() - epsilon); - float geom_clamp_y = std::min(tex_clamp_y * tex_to_geom_scale_y, - 0.5f * clamp_geom_rect.height() - epsilon); + float tex_clamp_x = std::min( + 0.5f, 0.5f * clamp_tex_rect.width() - kAntiAliasingEpsilon); + float tex_clamp_y = std::min( + 0.5f, 0.5f * clamp_tex_rect.height() - kAntiAliasingEpsilon); + float geom_clamp_x = std::min( + tex_clamp_x * tex_to_geom_scale_x, + 0.5f * clamp_geom_rect.width() - kAntiAliasingEpsilon); + float geom_clamp_y = std::min( + tex_clamp_y * tex_to_geom_scale_y, + 0.5f * clamp_geom_rect.height() - kAntiAliasingEpsilon); clamp_geom_rect.Inset(geom_clamp_x, geom_clamp_y, geom_clamp_x, geom_clamp_y); clamp_tex_rect.Inset(tex_clamp_x, tex_clamp_y, tex_clamp_x, tex_clamp_y); diff --git a/cc/output/gl_renderer_pixeltest.cc b/cc/output/gl_renderer_pixeltest.cc index 064b78b..8da1b24 100644 --- a/cc/output/gl_renderer_pixeltest.cc +++ b/cc/output/gl_renderer_pixeltest.cc @@ -524,6 +524,58 @@ TEST_F(GLRendererPixelTest, AntiAliasing) { base::FilePath(FILE_PATH_LITERAL("anti_aliasing.png")), ExactPixelComparator(true))); } + +TEST_F(GLRendererPixelTest, AxisAligned) { + gfx::Rect rect(0, 0, 200, 200); + + RenderPass::Id id(1, 1); + gfx::Transform transform_to_root; + scoped_ptr<RenderPass> pass = + CreateTestRenderPass(id, rect, transform_to_root); + + gfx::Transform red_content_to_target_transform; + red_content_to_target_transform.Translate(50, 50); + red_content_to_target_transform.Scale( + 0.5f + 1.0f / (rect.width() * 2.0f), + 0.5f + 1.0f / (rect.height() * 2.0f)); + scoped_ptr<SharedQuadState> red_shared_state = + CreateTestSharedQuadState(red_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> red = SolidColorDrawQuad::Create(); + red->SetNew(red_shared_state.get(), rect, SK_ColorRED); + + pass->quad_list.push_back(red.PassAs<DrawQuad>()); + + gfx::Transform yellow_content_to_target_transform; + yellow_content_to_target_transform.Translate(25.5f, 25.5f); + yellow_content_to_target_transform.Scale(0.5f, 0.5f); + scoped_ptr<SharedQuadState> yellow_shared_state = + CreateTestSharedQuadState(yellow_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create(); + yellow->SetNew(yellow_shared_state.get(), rect, SK_ColorYELLOW); + + pass->quad_list.push_back(yellow.PassAs<DrawQuad>()); + + gfx::Transform blue_content_to_target_transform; + scoped_ptr<SharedQuadState> blue_shared_state = + CreateTestSharedQuadState(blue_content_to_target_transform, rect); + + scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create(); + blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE); + + pass->quad_list.push_back(blue.PassAs<DrawQuad>()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + renderer_->DrawFrame(&pass_list); + + EXPECT_TRUE(PixelsMatchReference( + base::FilePath(FILE_PATH_LITERAL("axis_aligned.png")), + ExactPixelComparator(true))); +} + #endif } // namespace diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc index ef56cc2..bbd261a 100644 --- a/cc/output/gl_renderer_unittest.cc +++ b/cc/output/gl_renderer_unittest.cc @@ -325,6 +325,12 @@ class GLRendererShaderTest : public testing::Test { renderer_->render_pass_color_matrix_program_aa_->program()); } + void TestSolidColorProgramAA() { + EXPECT_PROGRAM_VALID(renderer_->solid_color_program_aa_); + EXPECT_TRUE(renderer_->program_shadow_ == + renderer_->solid_color_program_aa_->program()); + } + scoped_ptr<OutputSurface> output_surface_; FakeRendererClient mock_client_; scoped_ptr<ResourceProvider> resource_provider_; @@ -1271,6 +1277,34 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) { TestRenderPassMaskColorMatrixProgramAA(); } +TEST_F(GLRendererShaderTest, DrawSolidColorShader) { + gfx::Rect viewport_rect(mock_client_.DeviceViewportSize()); + ScopedPtrVector<RenderPass>* render_passes = + mock_client_.render_passes_in_draw_order(); + + RenderPass::Id root_pass_id(1, 0); + TestRenderPass* root_pass; + + gfx::Transform pixel_aligned_transform_causing_aa; + pixel_aligned_transform_causing_aa.Translate(25.5f, 25.5f); + pixel_aligned_transform_causing_aa.Scale(0.5f, 0.5f); + + render_passes->clear(); + + root_pass = AddRenderPass( + render_passes, root_pass_id, viewport_rect, gfx::Transform()); + AddTransformedQuad(root_pass, + viewport_rect, + SK_ColorYELLOW, + pixel_aligned_transform_causing_aa); + + renderer_->DecideRenderPassAllocationsForFrame( + *mock_client_.render_passes_in_draw_order()); + renderer_->DrawFrame(mock_client_.render_passes_in_draw_order()); + + TestSolidColorProgramAA(); +} + class OutputSurfaceMockContext : public TestWebGraphicsContext3D { public: // Specifically override methods even if they are unused (used in conjunction diff --git a/cc/test/render_pass_test_utils.cc b/cc/test/render_pass_test_utils.cc index 24cb778..719be7f 100644 --- a/cc/test/render_pass_test_utils.cc +++ b/cc/test/render_pass_test_utils.cc @@ -57,6 +57,22 @@ SolidColorDrawQuad* AddClippedQuad(TestRenderPass* pass, return quad_ptr; } +SolidColorDrawQuad* AddTransformedQuad(TestRenderPass* pass, + gfx::Rect rect, + SkColor color, + const gfx::Transform& transform) { + MockQuadCuller quad_sink(&pass->quad_list, &pass->shared_quad_state_list); + AppendQuadsData data(pass->id); + SharedQuadState* shared_state = + quad_sink.UseSharedQuadState(SharedQuadState::Create()); + shared_state->SetAll(transform, rect.size(), rect, rect, false, 1); + scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create(); + quad->SetNew(shared_state, rect, color); + SolidColorDrawQuad* quad_ptr = quad.get(); + quad_sink.Append(quad.PassAs<DrawQuad>(), &data); + return quad_ptr; +} + void AddRenderPassQuad(TestRenderPass* to_pass, TestRenderPass* contributing_pass) { MockQuadCuller quad_sink(&to_pass->quad_list, diff --git a/cc/test/render_pass_test_utils.h b/cc/test/render_pass_test_utils.h index fdc6366..01a7ca0 100644 --- a/cc/test/render_pass_test_utils.h +++ b/cc/test/render_pass_test_utils.h @@ -38,6 +38,12 @@ SolidColorDrawQuad* AddClippedQuad(TestRenderPass* pass, gfx::Rect rect, SkColor color); +// Adds a solid quad with a transform to a given render pass. +SolidColorDrawQuad* AddTransformedQuad(TestRenderPass* pass, + gfx::Rect rect, + SkColor color, + const gfx::Transform& transform); + // Adds a render pass quad to an existing render pass. void AddRenderPassQuad(TestRenderPass* to_pass, TestRenderPass* contributing_pass); diff --git a/ui/gfx/rect_conversions.cc b/ui/gfx/rect_conversions.cc index 251c0371..c548828 100644 --- a/ui/gfx/rect_conversions.cc +++ b/ui/gfx/rect_conversions.cc @@ -52,6 +52,24 @@ Rect ToNearestRect(const RectF& rect) { return Rect(min_x, min_y, max_x - min_x, max_y - min_y); } +bool IsNearestRectWithinDistance(const gfx::RectF& rect, float distance) { + float float_min_x = rect.x(); + float float_min_y = rect.y(); + float float_max_x = rect.right(); + float float_max_y = rect.bottom(); + + int min_x = ToRoundedInt(float_min_x); + int min_y = ToRoundedInt(float_min_y); + int max_x = ToRoundedInt(float_max_x); + int max_y = ToRoundedInt(float_max_y); + + return + (std::abs(min_x - float_min_x) < distance) && + (std::abs(min_y - float_min_y) < distance) && + (std::abs(max_x - float_max_x) < distance) && + (std::abs(max_y - float_max_y) < distance); +} + Rect ToFlooredRectDeprecated(const RectF& rect) { return Rect(ToFlooredInt(rect.x()), ToFlooredInt(rect.y()), diff --git a/ui/gfx/rect_conversions.h b/ui/gfx/rect_conversions.h index 7c971b3..854fb6e 100644 --- a/ui/gfx/rect_conversions.h +++ b/ui/gfx/rect_conversions.h @@ -22,6 +22,11 @@ UI_EXPORT Rect ToEnclosedRect(const RectF& rect); // you should use a different method. UI_EXPORT Rect ToNearestRect(const RectF& rect); +// Returns true if the Rect produced after snapping the corners of the RectF +// to an integer grid is withing |distance|. +UI_EXPORT bool IsNearestRectWithinDistance( + const gfx::RectF& rect, float distance); + // Returns a Rect obtained by flooring the values of the given RectF. // Please prefer the previous two functions in new code. UI_EXPORT Rect ToFlooredRectDeprecated(const RectF& rect); |