summaryrefslogtreecommitdiffstats
path: root/cc/surfaces/surface_aggregator_unittest.cc
diff options
context:
space:
mode:
authorjamesr@chromium.org <jamesr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-29 02:34:21 +0000
committerjamesr@chromium.org <jamesr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-29 02:34:21 +0000
commit6a8b3390b17b96d8702b09ed66b569209902c85f (patch)
treed7636a92d1d4c528a37a250e421c16a206788d90 /cc/surfaces/surface_aggregator_unittest.cc
parentb23624b1286b39b81df10d82d4d2654ac4af3c39 (diff)
downloadchromium_src-6a8b3390b17b96d8702b09ed66b569209902c85f.zip
chromium_src-6a8b3390b17b96d8702b09ed66b569209902c85f.tar.gz
chromium_src-6a8b3390b17b96d8702b09ed66b569209902c85f.tar.bz2
Initial surface aggregator implementation
BUG=334876 Review URL: https://codereview.chromium.org/139763003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247598 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc/surfaces/surface_aggregator_unittest.cc')
-rw-r--r--cc/surfaces/surface_aggregator_unittest.cc410
1 files changed, 410 insertions, 0 deletions
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
new file mode 100644
index 0000000..22ce646
--- /dev/null
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -0,0 +1,410 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/output/compositor_frame.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/render_pass.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_aggregator.h"
+#include "cc/surfaces/surface_aggregator_test_helpers.h"
+#include "cc/surfaces/surface_manager.h"
+#include "cc/test/render_pass_test_common.h"
+#include "cc/test/render_pass_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace cc {
+namespace {
+const int kInvalidSurfaceId = -1;
+
+class SurfaceAggregatorTest : public testing::Test {
+ public:
+ SurfaceAggregatorTest() : aggregator_(&manager_) {}
+
+ protected:
+ SurfaceManager manager_;
+ SurfaceAggregator aggregator_;
+};
+
+TEST_F(SurfaceAggregatorTest, InvalidSurfaceId) {
+ scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(kInvalidSurfaceId);
+ EXPECT_FALSE(frame);
+}
+
+TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) {
+ Surface one(&manager_, NULL, gfx::Size(5, 5));
+ scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(one.surface_id());
+ EXPECT_FALSE(frame);
+}
+
+class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
+ public:
+ SurfaceAggregatorValidSurfaceTest()
+ : root_surface_(&manager_, NULL, gfx::Size(5, 5)) {}
+
+ void AggregateAndVerify(test::Pass* expected_passes,
+ size_t expected_pass_count) {
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_.surface_id());
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data =
+ aggregated_frame->delegated_frame_data.get();
+
+ TestPassesMatchExpectations(
+ expected_passes, expected_pass_count, &frame_data->render_pass_list);
+ }
+
+ protected:
+ Surface root_surface_;
+};
+
+// Tests that a very simple frame containing only two solid color quads makes it
+// through the aggregator correctly.
+TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleFrame) {
+ test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorRED),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ AggregateAndVerify(passes, arraysize(passes));
+}
+
+TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) {
+ test::Quad quads[][2] = {{test::Quad::SolidColorQuad(SK_ColorWHITE),
+ test::Quad::SolidColorQuad(SK_ColorLTGRAY)},
+ {test::Quad::SolidColorQuad(SK_ColorGRAY),
+ test::Quad::SolidColorQuad(SK_ColorDKGRAY)}};
+ test::Pass passes[] = {test::Pass(quads[0], arraysize(quads[0])),
+ test::Pass(quads[1], arraysize(quads[1]))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ AggregateAndVerify(passes, arraysize(passes));
+}
+
+// This tests very simple embedding. root_surface has a frame containing a few
+// solid color quads and a surface quad referencing embedded_surface.
+// embedded_surface has a frame containing only a solid color quad. The solid
+// color quad should be aggregated into the final frame.
+TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
+ gfx::Size surface_size(5, 5);
+
+ Surface embedded_surface(&manager_, NULL, surface_size);
+
+ test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
+ test::Pass embedded_passes[] = {
+ test::Pass(embedded_quads, arraysize(embedded_quads))};
+
+ SubmitFrame(embedded_passes, arraysize(embedded_passes), &embedded_surface);
+
+ test::Quad root_quads[] = {
+ test::Quad::SolidColorQuad(SK_ColorWHITE),
+ test::Quad::SurfaceQuad(embedded_surface.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorBLACK)};
+ test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
+
+ SubmitFrame(root_passes, arraysize(root_passes), &root_surface_);
+
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
+ test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SolidColorQuad(SK_ColorBLACK)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// This tests referencing a surface that has multiple render passes.
+TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
+ gfx::Size surface_size(5, 5);
+
+ Surface embedded_surface(&manager_, NULL, surface_size);
+
+ RenderPass::Id pass_ids[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2),
+ RenderPass::Id(1, 3)};
+
+ test::Quad embedded_quads[][2] = {
+ {test::Quad::SolidColorQuad(1), test::Quad::SolidColorQuad(2)},
+ {test::Quad::SolidColorQuad(3), test::Quad::RenderPassQuad(pass_ids[0])},
+ {test::Quad::SolidColorQuad(4), test::Quad::RenderPassQuad(pass_ids[1])}};
+ test::Pass embedded_passes[] = {
+ test::Pass(embedded_quads[0], arraysize(embedded_quads[0]), pass_ids[0]),
+ test::Pass(embedded_quads[1], arraysize(embedded_quads[1]), pass_ids[1]),
+ test::Pass(embedded_quads[2], arraysize(embedded_quads[2]), pass_ids[2])};
+
+ SubmitFrame(embedded_passes, arraysize(embedded_passes), &embedded_surface);
+
+ test::Quad root_quads[][2] = {
+ {test::Quad::SolidColorQuad(5), test::Quad::SolidColorQuad(6)},
+ {test::Quad::SurfaceQuad(embedded_surface.surface_id()),
+ test::Quad::RenderPassQuad(pass_ids[0])},
+ {test::Quad::SolidColorQuad(7), test::Quad::RenderPassQuad(pass_ids[1])}};
+ test::Pass root_passes[] = {
+ test::Pass(root_quads[0], arraysize(root_quads[0]), pass_ids[0]),
+ test::Pass(root_quads[1], arraysize(root_quads[1]), pass_ids[1]),
+ test::Pass(root_quads[2], arraysize(root_quads[2]), pass_ids[2])};
+
+ SubmitFrame(root_passes, arraysize(root_passes), &root_surface_);
+
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_.surface_id());
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
+
+ const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
+
+ ASSERT_EQ(5u, aggregated_pass_list.size());
+ RenderPass::Id actual_pass_ids[] = {
+ aggregated_pass_list[0]->id, aggregated_pass_list[1]->id,
+ aggregated_pass_list[2]->id, aggregated_pass_list[3]->id,
+ aggregated_pass_list[4]->id};
+ for (size_t i = 0; i < 5; ++i) {
+ for (size_t j = 0; j < i; ++j) {
+ EXPECT_NE(actual_pass_ids[i], actual_pass_ids[j]);
+ }
+ }
+
+ {
+ SCOPED_TRACE("First pass");
+ // The first pass will just be the first pass from the root surfaces quad
+ // with no render pass quads to remap.
+ TestPassMatchesExpectations(root_passes[0], aggregated_pass_list[0]);
+ }
+
+ {
+ SCOPED_TRACE("Second pass");
+ // The next two passes will be from the embedded surface since we have to
+ // draw those passes before they are referenced from the render pass draw
+ // quad embedded into the root surface's second pass.
+ // First, there's the first embedded pass which doesn't reference anything
+ // else.
+ TestPassMatchesExpectations(embedded_passes[0], aggregated_pass_list[1]);
+ }
+
+ {
+ SCOPED_TRACE("Third pass");
+ const QuadList& third_pass_quad_list = aggregated_pass_list[2]->quad_list;
+ ASSERT_EQ(2u, third_pass_quad_list.size());
+ TestQuadMatchesExpectations(embedded_quads[1][0],
+ third_pass_quad_list.at(0u));
+
+ // This render pass pass quad will reference the first pass from the
+ // embedded surface, which is the second pass in the aggregated frame.
+ ASSERT_EQ(DrawQuad::RENDER_PASS, third_pass_quad_list.at(1u)->material);
+ const RenderPassDrawQuad* third_pass_render_pass_draw_quad =
+ RenderPassDrawQuad::MaterialCast(third_pass_quad_list.at(1u));
+ EXPECT_EQ(actual_pass_ids[1],
+ third_pass_render_pass_draw_quad->render_pass_id);
+ }
+
+ {
+ SCOPED_TRACE("Fourth pass");
+ // The fourth pass will have aggregated quads from the root surface's second
+ // pass and the embedded surface's first pass.
+ const QuadList& fourth_pass_quad_list = aggregated_pass_list[3]->quad_list;
+ ASSERT_EQ(3u, fourth_pass_quad_list.size());
+
+ // The first quad will be the yellow quad from the embedded surface's last
+ // pass.
+ TestQuadMatchesExpectations(embedded_quads[2][0],
+ fourth_pass_quad_list.at(0u));
+
+ // The next quad will be a render pass quad referencing the second pass from
+ // the embedded surface, which is the third pass in the aggregated frame.
+ ASSERT_EQ(DrawQuad::RENDER_PASS, fourth_pass_quad_list.at(1u)->material);
+ const RenderPassDrawQuad* fourth_pass_first_render_pass_draw_quad =
+ RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.at(1u));
+ EXPECT_EQ(actual_pass_ids[2],
+ fourth_pass_first_render_pass_draw_quad->render_pass_id);
+
+ // The last quad will be a render pass quad referencing the first pass from
+ // the root surface, which is the first pass overall.
+ ASSERT_EQ(DrawQuad::RENDER_PASS, fourth_pass_quad_list.at(2u)->material);
+ const RenderPassDrawQuad* fourth_pass_second_render_pass_draw_quad =
+ RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.at(2u));
+ EXPECT_EQ(actual_pass_ids[0],
+ fourth_pass_second_render_pass_draw_quad->render_pass_id);
+ }
+
+ {
+ SCOPED_TRACE("Fifth pass");
+ const QuadList& fifth_pass_quad_list = aggregated_pass_list[4]->quad_list;
+ ASSERT_EQ(2u, fifth_pass_quad_list.size());
+
+ TestQuadMatchesExpectations(root_quads[2][0], fifth_pass_quad_list.at(0));
+
+ // The last quad in the last pass will reference the second pass from the
+ // root surface, which after aggregating is the fourth pass in the overall
+ // list.
+ ASSERT_EQ(DrawQuad::RENDER_PASS, fifth_pass_quad_list.at(1u)->material);
+ const RenderPassDrawQuad* fifth_pass_render_pass_draw_quad =
+ RenderPassDrawQuad::MaterialCast(fifth_pass_quad_list.at(1u));
+ EXPECT_EQ(actual_pass_ids[3],
+ fifth_pass_render_pass_draw_quad->render_pass_id);
+ }
+}
+
+// Tests an invalid surface reference in a frame. The surface quad should just
+// be dropped.
+TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) {
+ test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SurfaceQuad(kInvalidSurfaceId),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// Tests a reference to a valid surface with no submitted frame. This quad
+// should also just be dropped.
+TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) {
+ Surface surface_with_no_frame(&manager_, NULL, gfx::Size(5, 5));
+ test::Quad quads[] = {
+ test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SurfaceQuad(surface_with_no_frame.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// Tests a surface quad referencing itself, generating a trivial cycle.
+// The quad creating the cycle should be dropped from the final frame.
+TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) {
+ test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorYELLOW)};
+ test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorYELLOW)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// Tests a more complex cycle with one intermediate surface.
+TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) {
+ gfx::Size surface_size(5, 5);
+
+ Surface child_surface(&manager_, NULL, surface_size);
+
+ test::Quad parent_quads[] = {
+ test::Quad::SolidColorQuad(SK_ColorBLUE),
+ test::Quad::SurfaceQuad(child_surface.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorCYAN)};
+ test::Pass parent_passes[] = {
+ test::Pass(parent_quads, arraysize(parent_quads))};
+
+ SubmitFrame(parent_passes, arraysize(parent_passes), &root_surface_);
+
+ test::Quad child_quads[] = {
+ test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SurfaceQuad(root_surface_.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorMAGENTA)};
+ test::Pass child_passes[] = {test::Pass(child_quads, arraysize(child_quads))};
+
+ SubmitFrame(child_passes, arraysize(child_passes), &child_surface);
+
+ // The child surface's reference to the root_surface_ will be dropped, so
+ // we'll end up with:
+ // SK_ColorBLUE from the parent
+ // SK_ColorGREEN from the child
+ // SK_ColorMAGENTA from the child
+ // SK_ColorCYAN from the parent
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE),
+ test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SolidColorQuad(SK_ColorMAGENTA),
+ test::Quad::SolidColorQuad(SK_ColorCYAN)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// Tests that we map render pass IDs from different surfaces into a unified
+// namespace and update RenderPassDrawQuad's id references to match.
+TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) {
+ gfx::Size surface_size(5, 5);
+
+ Surface child_surface(&manager_, NULL, surface_size);
+
+ RenderPass::Id child_pass_id[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2)};
+ test::Quad child_quad[][1] = {{test::Quad::SolidColorQuad(SK_ColorGREEN)},
+ {test::Quad::RenderPassQuad(child_pass_id[0])}};
+ test::Pass surface_passes[] = {
+ test::Pass(child_quad[0], arraysize(child_quad[0]), child_pass_id[0]),
+ test::Pass(child_quad[1], arraysize(child_quad[1]), child_pass_id[1])};
+
+ SubmitFrame(surface_passes, arraysize(surface_passes), &child_surface);
+
+ // Pass IDs from the parent surface may collide with ones from the child.
+ RenderPass::Id parent_pass_id[] = {RenderPass::Id(2, 1),
+ RenderPass::Id(1, 2)};
+ test::Quad parent_quad[][1] = {
+ {test::Quad::SurfaceQuad(child_surface.surface_id())},
+ {test::Quad::RenderPassQuad(parent_pass_id[0])}};
+ test::Pass parent_passes[] = {
+ test::Pass(parent_quad[0], arraysize(parent_quad[0]), parent_pass_id[0]),
+ test::Pass(parent_quad[1], arraysize(parent_quad[1]), parent_pass_id[1])};
+
+ SubmitFrame(parent_passes, arraysize(parent_passes), &root_surface_);
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_.surface_id());
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
+
+ const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
+
+ ASSERT_EQ(3u, aggregated_pass_list.size());
+ RenderPass::Id actual_pass_ids[] = {aggregated_pass_list[0]->id,
+ aggregated_pass_list[1]->id,
+ aggregated_pass_list[2]->id};
+ // Make sure the aggregated frame's pass IDs are all unique.
+ for (size_t i = 0; i < 3; ++i) {
+ for (size_t j = 0; j < i; ++j) {
+ EXPECT_NE(actual_pass_ids[j], actual_pass_ids[i]) << "pass ids " << i
+ << " and " << j;
+ }
+ }
+
+ // Make sure the render pass quads reference the remapped pass IDs.
+ DrawQuad* render_pass_quads[] = {aggregated_pass_list[1]->quad_list[0],
+ aggregated_pass_list[2]->quad_list[0]};
+ ASSERT_EQ(render_pass_quads[0]->material, DrawQuad::RENDER_PASS);
+ EXPECT_EQ(
+ actual_pass_ids[0],
+ RenderPassDrawQuad::MaterialCast(render_pass_quads[0])->render_pass_id);
+
+ ASSERT_EQ(render_pass_quads[1]->material, DrawQuad::RENDER_PASS);
+ EXPECT_EQ(
+ actual_pass_ids[1],
+ RenderPassDrawQuad::MaterialCast(render_pass_quads[1])->render_pass_id);
+}
+
+} // namespace
+} // namespace cc