summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/output/gl_renderer.cc32
-rw-r--r--cc/output/gl_renderer_pixeltest.cc52
-rw-r--r--cc/output/gl_renderer_unittest.cc34
-rw-r--r--cc/test/render_pass_test_utils.cc16
-rw-r--r--cc/test/render_pass_test_utils.h6
-rw-r--r--ui/gfx/rect_conversions.cc18
-rw-r--r--ui/gfx/rect_conversions.h5
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);