| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "cc/output/compositor_frame.h" |
| 6 #include "cc/output/delegated_frame_data.h" |
| 7 #include "cc/quads/render_pass.h" |
| 8 #include "cc/quads/render_pass_draw_quad.h" |
| 9 #include "cc/quads/solid_color_draw_quad.h" |
| 10 #include "cc/quads/surface_draw_quad.h" |
| 11 #include "cc/surfaces/surface.h" |
| 12 #include "cc/surfaces/surface_aggregator.h" |
| 13 #include "cc/surfaces/surface_aggregator_test_helpers.h" |
| 14 #include "cc/surfaces/surface_manager.h" |
| 15 #include "cc/test/render_pass_test_common.h" |
| 16 #include "cc/test/render_pass_test_utils.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 #include "third_party/skia/include/core/SkColor.h" |
| 19 |
| 20 namespace cc { |
| 21 namespace { |
| 22 const int kInvalidSurfaceId = -1; |
| 23 |
| 24 class SurfaceAggregatorTest : public testing::Test { |
| 25 public: |
| 26 SurfaceAggregatorTest() : aggregator_(&manager_) {} |
| 27 |
| 28 protected: |
| 29 SurfaceManager manager_; |
| 30 SurfaceAggregator aggregator_; |
| 31 }; |
| 32 |
| 33 TEST_F(SurfaceAggregatorTest, InvalidSurfaceId) { |
| 34 scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(kInvalidSurfaceId); |
| 35 EXPECT_FALSE(frame); |
| 36 } |
| 37 |
| 38 TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) { |
| 39 Surface one(&manager_, NULL, gfx::Size(5, 5)); |
| 40 scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(one.surface_id()); |
| 41 EXPECT_FALSE(frame); |
| 42 } |
| 43 |
| 44 class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest { |
| 45 public: |
| 46 SurfaceAggregatorValidSurfaceTest() |
| 47 : root_surface_(&manager_, NULL, gfx::Size(5, 5)) {} |
| 48 |
| 49 void AggregateAndVerify(test::Pass* expected_passes, |
| 50 size_t expected_pass_count) { |
| 51 scoped_ptr<CompositorFrame> aggregated_frame = |
| 52 aggregator_.Aggregate(root_surface_.surface_id()); |
| 53 |
| 54 ASSERT_TRUE(aggregated_frame); |
| 55 ASSERT_TRUE(aggregated_frame->delegated_frame_data); |
| 56 |
| 57 DelegatedFrameData* frame_data = |
| 58 aggregated_frame->delegated_frame_data.get(); |
| 59 |
| 60 TestPassesMatchExpectations( |
| 61 expected_passes, expected_pass_count, &frame_data->render_pass_list); |
| 62 } |
| 63 |
| 64 protected: |
| 65 Surface root_surface_; |
| 66 }; |
| 67 |
| 68 // Tests that a very simple frame containing only two solid color quads makes it |
| 69 // through the aggregator correctly. |
| 70 TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleFrame) { |
| 71 test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorRED), |
| 72 test::Quad::SolidColorQuad(SK_ColorBLUE)}; |
| 73 test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; |
| 74 |
| 75 SubmitFrame(passes, arraysize(passes), &root_surface_); |
| 76 |
| 77 AggregateAndVerify(passes, arraysize(passes)); |
| 78 } |
| 79 |
| 80 TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) { |
| 81 test::Quad quads[][2] = {{test::Quad::SolidColorQuad(SK_ColorWHITE), |
| 82 test::Quad::SolidColorQuad(SK_ColorLTGRAY)}, |
| 83 {test::Quad::SolidColorQuad(SK_ColorGRAY), |
| 84 test::Quad::SolidColorQuad(SK_ColorDKGRAY)}}; |
| 85 test::Pass passes[] = {test::Pass(quads[0], arraysize(quads[0])), |
| 86 test::Pass(quads[1], arraysize(quads[1]))}; |
| 87 |
| 88 SubmitFrame(passes, arraysize(passes), &root_surface_); |
| 89 |
| 90 AggregateAndVerify(passes, arraysize(passes)); |
| 91 } |
| 92 |
| 93 // This tests very simple embedding. root_surface has a frame containing a few |
| 94 // solid color quads and a surface quad referencing embedded_surface. |
| 95 // embedded_surface has a frame containing only a solid color quad. The solid |
| 96 // color quad should be aggregated into the final frame. |
| 97 TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) { |
| 98 gfx::Size surface_size(5, 5); |
| 99 |
| 100 Surface embedded_surface(&manager_, NULL, surface_size); |
| 101 |
| 102 test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)}; |
| 103 test::Pass embedded_passes[] = { |
| 104 test::Pass(embedded_quads, arraysize(embedded_quads))}; |
| 105 |
| 106 SubmitFrame(embedded_passes, arraysize(embedded_passes), &embedded_surface); |
| 107 |
| 108 test::Quad root_quads[] = { |
| 109 test::Quad::SolidColorQuad(SK_ColorWHITE), |
| 110 test::Quad::SurfaceQuad(embedded_surface.surface_id()), |
| 111 test::Quad::SolidColorQuad(SK_ColorBLACK)}; |
| 112 test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; |
| 113 |
| 114 SubmitFrame(root_passes, arraysize(root_passes), &root_surface_); |
| 115 |
| 116 test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE), |
| 117 test::Quad::SolidColorQuad(SK_ColorGREEN), |
| 118 test::Quad::SolidColorQuad(SK_ColorBLACK)}; |
| 119 test::Pass expected_passes[] = { |
| 120 test::Pass(expected_quads, arraysize(expected_quads))}; |
| 121 AggregateAndVerify(expected_passes, arraysize(expected_passes)); |
| 122 } |
| 123 |
| 124 // This tests referencing a surface that has multiple render passes. |
| 125 TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) { |
| 126 gfx::Size surface_size(5, 5); |
| 127 |
| 128 Surface embedded_surface(&manager_, NULL, surface_size); |
| 129 |
| 130 RenderPass::Id pass_ids[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2), |
| 131 RenderPass::Id(1, 3)}; |
| 132 |
| 133 test::Quad embedded_quads[][2] = { |
| 134 {test::Quad::SolidColorQuad(1), test::Quad::SolidColorQuad(2)}, |
| 135 {test::Quad::SolidColorQuad(3), test::Quad::RenderPassQuad(pass_ids[0])}, |
| 136 {test::Quad::SolidColorQuad(4), test::Quad::RenderPassQuad(pass_ids[1])}}; |
| 137 test::Pass embedded_passes[] = { |
| 138 test::Pass(embedded_quads[0], arraysize(embedded_quads[0]), pass_ids[0]), |
| 139 test::Pass(embedded_quads[1], arraysize(embedded_quads[1]), pass_ids[1]), |
| 140 test::Pass(embedded_quads[2], arraysize(embedded_quads[2]), pass_ids[2])}; |
| 141 |
| 142 SubmitFrame(embedded_passes, arraysize(embedded_passes), &embedded_surface); |
| 143 |
| 144 test::Quad root_quads[][2] = { |
| 145 {test::Quad::SolidColorQuad(5), test::Quad::SolidColorQuad(6)}, |
| 146 {test::Quad::SurfaceQuad(embedded_surface.surface_id()), |
| 147 test::Quad::RenderPassQuad(pass_ids[0])}, |
| 148 {test::Quad::SolidColorQuad(7), test::Quad::RenderPassQuad(pass_ids[1])}}; |
| 149 test::Pass root_passes[] = { |
| 150 test::Pass(root_quads[0], arraysize(root_quads[0]), pass_ids[0]), |
| 151 test::Pass(root_quads[1], arraysize(root_quads[1]), pass_ids[1]), |
| 152 test::Pass(root_quads[2], arraysize(root_quads[2]), pass_ids[2])}; |
| 153 |
| 154 SubmitFrame(root_passes, arraysize(root_passes), &root_surface_); |
| 155 |
| 156 scoped_ptr<CompositorFrame> aggregated_frame = |
| 157 aggregator_.Aggregate(root_surface_.surface_id()); |
| 158 |
| 159 ASSERT_TRUE(aggregated_frame); |
| 160 ASSERT_TRUE(aggregated_frame->delegated_frame_data); |
| 161 |
| 162 DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get(); |
| 163 |
| 164 const RenderPassList& aggregated_pass_list = frame_data->render_pass_list; |
| 165 |
| 166 ASSERT_EQ(5u, aggregated_pass_list.size()); |
| 167 RenderPass::Id actual_pass_ids[] = { |
| 168 aggregated_pass_list[0]->id, aggregated_pass_list[1]->id, |
| 169 aggregated_pass_list[2]->id, aggregated_pass_list[3]->id, |
| 170 aggregated_pass_list[4]->id}; |
| 171 for (size_t i = 0; i < 5; ++i) { |
| 172 for (size_t j = 0; j < i; ++j) { |
| 173 EXPECT_NE(actual_pass_ids[i], actual_pass_ids[j]); |
| 174 } |
| 175 } |
| 176 |
| 177 { |
| 178 SCOPED_TRACE("First pass"); |
| 179 // The first pass will just be the first pass from the root surfaces quad |
| 180 // with no render pass quads to remap. |
| 181 TestPassMatchesExpectations(root_passes[0], aggregated_pass_list[0]); |
| 182 } |
| 183 |
| 184 { |
| 185 SCOPED_TRACE("Second pass"); |
| 186 // The next two passes will be from the embedded surface since we have to |
| 187 // draw those passes before they are referenced from the render pass draw |
| 188 // quad embedded into the root surface's second pass. |
| 189 // First, there's the first embedded pass which doesn't reference anything |
| 190 // else. |
| 191 TestPassMatchesExpectations(embedded_passes[0], aggregated_pass_list[1]); |
| 192 } |
| 193 |
| 194 { |
| 195 SCOPED_TRACE("Third pass"); |
| 196 const QuadList& third_pass_quad_list = aggregated_pass_list[2]->quad_list; |
| 197 ASSERT_EQ(2u, third_pass_quad_list.size()); |
| 198 TestQuadMatchesExpectations(embedded_quads[1][0], |
| 199 third_pass_quad_list.at(0u)); |
| 200 |
| 201 // This render pass pass quad will reference the first pass from the |
| 202 // embedded surface, which is the second pass in the aggregated frame. |
| 203 ASSERT_EQ(DrawQuad::RENDER_PASS, third_pass_quad_list.at(1u)->material); |
| 204 const RenderPassDrawQuad* third_pass_render_pass_draw_quad = |
| 205 RenderPassDrawQuad::MaterialCast(third_pass_quad_list.at(1u)); |
| 206 EXPECT_EQ(actual_pass_ids[1], |
| 207 third_pass_render_pass_draw_quad->render_pass_id); |
| 208 } |
| 209 |
| 210 { |
| 211 SCOPED_TRACE("Fourth pass"); |
| 212 // The fourth pass will have aggregated quads from the root surface's second |
| 213 // pass and the embedded surface's first pass. |
| 214 const QuadList& fourth_pass_quad_list = aggregated_pass_list[3]->quad_list; |
| 215 ASSERT_EQ(3u, fourth_pass_quad_list.size()); |
| 216 |
| 217 // The first quad will be the yellow quad from the embedded surface's last |
| 218 // pass. |
| 219 TestQuadMatchesExpectations(embedded_quads[2][0], |
| 220 fourth_pass_quad_list.at(0u)); |
| 221 |
| 222 // The next quad will be a render pass quad referencing the second pass from |
| 223 // the embedded surface, which is the third pass in the aggregated frame. |
| 224 ASSERT_EQ(DrawQuad::RENDER_PASS, fourth_pass_quad_list.at(1u)->material); |
| 225 const RenderPassDrawQuad* fourth_pass_first_render_pass_draw_quad = |
| 226 RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.at(1u)); |
| 227 EXPECT_EQ(actual_pass_ids[2], |
| 228 fourth_pass_first_render_pass_draw_quad->render_pass_id); |
| 229 |
| 230 // The last quad will be a render pass quad referencing the first pass from |
| 231 // the root surface, which is the first pass overall. |
| 232 ASSERT_EQ(DrawQuad::RENDER_PASS, fourth_pass_quad_list.at(2u)->material); |
| 233 const RenderPassDrawQuad* fourth_pass_second_render_pass_draw_quad = |
| 234 RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.at(2u)); |
| 235 EXPECT_EQ(actual_pass_ids[0], |
| 236 fourth_pass_second_render_pass_draw_quad->render_pass_id); |
| 237 } |
| 238 |
| 239 { |
| 240 SCOPED_TRACE("Fifth pass"); |
| 241 const QuadList& fifth_pass_quad_list = aggregated_pass_list[4]->quad_list; |
| 242 ASSERT_EQ(2u, fifth_pass_quad_list.size()); |
| 243 |
| 244 TestQuadMatchesExpectations(root_quads[2][0], fifth_pass_quad_list.at(0)); |
| 245 |
| 246 // The last quad in the last pass will reference the second pass from the |
| 247 // root surface, which after aggregating is the fourth pass in the overall |
| 248 // list. |
| 249 ASSERT_EQ(DrawQuad::RENDER_PASS, fifth_pass_quad_list.at(1u)->material); |
| 250 const RenderPassDrawQuad* fifth_pass_render_pass_draw_quad = |
| 251 RenderPassDrawQuad::MaterialCast(fifth_pass_quad_list.at(1u)); |
| 252 EXPECT_EQ(actual_pass_ids[3], |
| 253 fifth_pass_render_pass_draw_quad->render_pass_id); |
| 254 } |
| 255 } |
| 256 |
| 257 // Tests an invalid surface reference in a frame. The surface quad should just |
| 258 // be dropped. |
| 259 TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) { |
| 260 test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), |
| 261 test::Quad::SurfaceQuad(kInvalidSurfaceId), |
| 262 test::Quad::SolidColorQuad(SK_ColorBLUE)}; |
| 263 test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; |
| 264 |
| 265 SubmitFrame(passes, arraysize(passes), &root_surface_); |
| 266 |
| 267 test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), |
| 268 test::Quad::SolidColorQuad(SK_ColorBLUE)}; |
| 269 test::Pass expected_passes[] = { |
| 270 test::Pass(expected_quads, arraysize(expected_quads))}; |
| 271 AggregateAndVerify(expected_passes, arraysize(expected_passes)); |
| 272 } |
| 273 |
| 274 // Tests a reference to a valid surface with no submitted frame. This quad |
| 275 // should also just be dropped. |
| 276 TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) { |
| 277 Surface surface_with_no_frame(&manager_, NULL, gfx::Size(5, 5)); |
| 278 test::Quad quads[] = { |
| 279 test::Quad::SolidColorQuad(SK_ColorGREEN), |
| 280 test::Quad::SurfaceQuad(surface_with_no_frame.surface_id()), |
| 281 test::Quad::SolidColorQuad(SK_ColorBLUE)}; |
| 282 test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; |
| 283 |
| 284 SubmitFrame(passes, arraysize(passes), &root_surface_); |
| 285 |
| 286 test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), |
| 287 test::Quad::SolidColorQuad(SK_ColorBLUE)}; |
| 288 test::Pass expected_passes[] = { |
| 289 test::Pass(expected_quads, arraysize(expected_quads))}; |
| 290 AggregateAndVerify(expected_passes, arraysize(expected_passes)); |
| 291 } |
| 292 |
| 293 // Tests a surface quad referencing itself, generating a trivial cycle. |
| 294 // The quad creating the cycle should be dropped from the final frame. |
| 295 TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) { |
| 296 test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_.surface_id()), |
| 297 test::Quad::SolidColorQuad(SK_ColorYELLOW)}; |
| 298 test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; |
| 299 |
| 300 SubmitFrame(passes, arraysize(passes), &root_surface_); |
| 301 |
| 302 test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorYELLOW)}; |
| 303 test::Pass expected_passes[] = { |
| 304 test::Pass(expected_quads, arraysize(expected_quads))}; |
| 305 AggregateAndVerify(expected_passes, arraysize(expected_passes)); |
| 306 } |
| 307 |
| 308 // Tests a more complex cycle with one intermediate surface. |
| 309 TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) { |
| 310 gfx::Size surface_size(5, 5); |
| 311 |
| 312 Surface child_surface(&manager_, NULL, surface_size); |
| 313 |
| 314 test::Quad parent_quads[] = { |
| 315 test::Quad::SolidColorQuad(SK_ColorBLUE), |
| 316 test::Quad::SurfaceQuad(child_surface.surface_id()), |
| 317 test::Quad::SolidColorQuad(SK_ColorCYAN)}; |
| 318 test::Pass parent_passes[] = { |
| 319 test::Pass(parent_quads, arraysize(parent_quads))}; |
| 320 |
| 321 SubmitFrame(parent_passes, arraysize(parent_passes), &root_surface_); |
| 322 |
| 323 test::Quad child_quads[] = { |
| 324 test::Quad::SolidColorQuad(SK_ColorGREEN), |
| 325 test::Quad::SurfaceQuad(root_surface_.surface_id()), |
| 326 test::Quad::SolidColorQuad(SK_ColorMAGENTA)}; |
| 327 test::Pass child_passes[] = {test::Pass(child_quads, arraysize(child_quads))}; |
| 328 |
| 329 SubmitFrame(child_passes, arraysize(child_passes), &child_surface); |
| 330 |
| 331 // The child surface's reference to the root_surface_ will be dropped, so |
| 332 // we'll end up with: |
| 333 // SK_ColorBLUE from the parent |
| 334 // SK_ColorGREEN from the child |
| 335 // SK_ColorMAGENTA from the child |
| 336 // SK_ColorCYAN from the parent |
| 337 test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE), |
| 338 test::Quad::SolidColorQuad(SK_ColorGREEN), |
| 339 test::Quad::SolidColorQuad(SK_ColorMAGENTA), |
| 340 test::Quad::SolidColorQuad(SK_ColorCYAN)}; |
| 341 test::Pass expected_passes[] = { |
| 342 test::Pass(expected_quads, arraysize(expected_quads))}; |
| 343 AggregateAndVerify(expected_passes, arraysize(expected_passes)); |
| 344 } |
| 345 |
| 346 // Tests that we map render pass IDs from different surfaces into a unified |
| 347 // namespace and update RenderPassDrawQuad's id references to match. |
| 348 TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) { |
| 349 gfx::Size surface_size(5, 5); |
| 350 |
| 351 Surface child_surface(&manager_, NULL, surface_size); |
| 352 |
| 353 RenderPass::Id child_pass_id[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2)}; |
| 354 test::Quad child_quad[][1] = {{test::Quad::SolidColorQuad(SK_ColorGREEN)}, |
| 355 {test::Quad::RenderPassQuad(child_pass_id[0])}}; |
| 356 test::Pass surface_passes[] = { |
| 357 test::Pass(child_quad[0], arraysize(child_quad[0]), child_pass_id[0]), |
| 358 test::Pass(child_quad[1], arraysize(child_quad[1]), child_pass_id[1])}; |
| 359 |
| 360 SubmitFrame(surface_passes, arraysize(surface_passes), &child_surface); |
| 361 |
| 362 // Pass IDs from the parent surface may collide with ones from the child. |
| 363 RenderPass::Id parent_pass_id[] = {RenderPass::Id(2, 1), |
| 364 RenderPass::Id(1, 2)}; |
| 365 test::Quad parent_quad[][1] = { |
| 366 {test::Quad::SurfaceQuad(child_surface.surface_id())}, |
| 367 {test::Quad::RenderPassQuad(parent_pass_id[0])}}; |
| 368 test::Pass parent_passes[] = { |
| 369 test::Pass(parent_quad[0], arraysize(parent_quad[0]), parent_pass_id[0]), |
| 370 test::Pass(parent_quad[1], arraysize(parent_quad[1]), parent_pass_id[1])}; |
| 371 |
| 372 SubmitFrame(parent_passes, arraysize(parent_passes), &root_surface_); |
| 373 scoped_ptr<CompositorFrame> aggregated_frame = |
| 374 aggregator_.Aggregate(root_surface_.surface_id()); |
| 375 |
| 376 ASSERT_TRUE(aggregated_frame); |
| 377 ASSERT_TRUE(aggregated_frame->delegated_frame_data); |
| 378 |
| 379 DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get(); |
| 380 |
| 381 const RenderPassList& aggregated_pass_list = frame_data->render_pass_list; |
| 382 |
| 383 ASSERT_EQ(3u, aggregated_pass_list.size()); |
| 384 RenderPass::Id actual_pass_ids[] = {aggregated_pass_list[0]->id, |
| 385 aggregated_pass_list[1]->id, |
| 386 aggregated_pass_list[2]->id}; |
| 387 // Make sure the aggregated frame's pass IDs are all unique. |
| 388 for (size_t i = 0; i < 3; ++i) { |
| 389 for (size_t j = 0; j < i; ++j) { |
| 390 EXPECT_NE(actual_pass_ids[j], actual_pass_ids[i]) << "pass ids " << i |
| 391 << " and " << j; |
| 392 } |
| 393 } |
| 394 |
| 395 // Make sure the render pass quads reference the remapped pass IDs. |
| 396 DrawQuad* render_pass_quads[] = {aggregated_pass_list[1]->quad_list[0], |
| 397 aggregated_pass_list[2]->quad_list[0]}; |
| 398 ASSERT_EQ(render_pass_quads[0]->material, DrawQuad::RENDER_PASS); |
| 399 EXPECT_EQ( |
| 400 actual_pass_ids[0], |
| 401 RenderPassDrawQuad::MaterialCast(render_pass_quads[0])->render_pass_id); |
| 402 |
| 403 ASSERT_EQ(render_pass_quads[1]->material, DrawQuad::RENDER_PASS); |
| 404 EXPECT_EQ( |
| 405 actual_pass_ids[1], |
| 406 RenderPassDrawQuad::MaterialCast(render_pass_quads[1])->render_pass_id); |
| 407 } |
| 408 |
| 409 } // namespace |
| 410 } // namespace cc |
| OLD | NEW |