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/quads/texture_draw_quad.h"
12#include "cc/resources/shared_bitmap_manager.h"
13#include "cc/surfaces/surface.h"
14#include "cc/surfaces/surface_aggregator.h"
15#include "cc/surfaces/surface_aggregator_test_helpers.h"
16#include "cc/surfaces/surface_factory.h"
17#include "cc/surfaces/surface_factory_client.h"
18#include "cc/surfaces/surface_id_allocator.h"
19#include "cc/surfaces/surface_manager.h"
20#include "cc/test/fake_output_surface.h"
21#include "cc/test/fake_output_surface_client.h"
22#include "cc/test/render_pass_test_common.h"
23#include "cc/test/render_pass_test_utils.h"
24#include "cc/test/test_shared_bitmap_manager.h"
25#include "testing/gmock/include/gmock/gmock.h"
26#include "testing/gtest/include/gtest/gtest.h"
27#include "third_party/skia/include/core/SkColor.h"
28
29namespace cc {
30namespace {
31
32SurfaceId InvalidSurfaceId() {
33  static SurfaceId invalid;
34  invalid.id = static_cast<uint64_t>(-1);
35  return invalid;
36}
37
38gfx::Size SurfaceSize() {
39  static gfx::Size size(5, 5);
40  return size;
41}
42
43class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
44 public:
45  virtual void ReturnResources(
46      const ReturnedResourceArray& resources) OVERRIDE {}
47};
48
49class SurfaceAggregatorTest : public testing::Test {
50 public:
51  SurfaceAggregatorTest()
52      : factory_(&manager_, &empty_client_), aggregator_(&manager_, NULL) {}
53
54 protected:
55  SurfaceManager manager_;
56  EmptySurfaceFactoryClient empty_client_;
57  SurfaceFactory factory_;
58  SurfaceAggregator aggregator_;
59};
60
61TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) {
62  SurfaceId one_id(7);
63  factory_.Create(one_id, SurfaceSize());
64  scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(one_id);
65  EXPECT_FALSE(frame);
66  factory_.Destroy(one_id);
67}
68
69class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
70 public:
71  SurfaceAggregatorValidSurfaceTest() : allocator_(1u) {}
72
73  virtual void SetUp() {
74    SurfaceAggregatorTest::SetUp();
75    root_surface_id_ = allocator_.GenerateId();
76    factory_.Create(root_surface_id_, SurfaceSize());
77  }
78
79  virtual void TearDown() {
80    factory_.Destroy(root_surface_id_);
81    SurfaceAggregatorTest::TearDown();
82  }
83
84  void AggregateAndVerify(test::Pass* expected_passes,
85                          size_t expected_pass_count,
86                          SurfaceId* surface_ids,
87                          size_t expected_surface_count) {
88    scoped_ptr<CompositorFrame> aggregated_frame =
89        aggregator_.Aggregate(root_surface_id_);
90
91    ASSERT_TRUE(aggregated_frame);
92    ASSERT_TRUE(aggregated_frame->delegated_frame_data);
93
94    DelegatedFrameData* frame_data =
95        aggregated_frame->delegated_frame_data.get();
96
97    TestPassesMatchExpectations(
98        expected_passes, expected_pass_count, &frame_data->render_pass_list);
99
100    EXPECT_EQ(expected_surface_count,
101              aggregator_.previous_contained_surfaces().size());
102    for (size_t i = 0; i < expected_surface_count; i++) {
103      EXPECT_TRUE(
104          aggregator_.previous_contained_surfaces().find(surface_ids[i]) !=
105          aggregator_.previous_contained_surfaces().end());
106    }
107  }
108
109  void SubmitFrame(test::Pass* passes,
110                   size_t pass_count,
111                   SurfaceId surface_id) {
112    RenderPassList pass_list;
113    AddPasses(&pass_list, gfx::Rect(SurfaceSize()), passes, pass_count);
114
115    scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
116    pass_list.swap(frame_data->render_pass_list);
117
118    scoped_ptr<CompositorFrame> frame(new CompositorFrame);
119    frame->delegated_frame_data = frame_data.Pass();
120
121    factory_.SubmitFrame(surface_id, frame.Pass(), base::Closure());
122  }
123
124  void QueuePassAsFrame(scoped_ptr<RenderPass> pass, SurfaceId surface_id) {
125    scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
126    delegated_frame_data->render_pass_list.push_back(pass.Pass());
127
128    scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
129    child_frame->delegated_frame_data = delegated_frame_data.Pass();
130
131    factory_.SubmitFrame(surface_id, child_frame.Pass(), base::Closure());
132  }
133
134 protected:
135  SurfaceId root_surface_id_;
136  SurfaceIdAllocator allocator_;
137};
138
139// Tests that a very simple frame containing only two solid color quads makes it
140// through the aggregator correctly.
141TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleFrame) {
142  test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorRED),
143                        test::Quad::SolidColorQuad(SK_ColorBLUE)};
144  test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
145
146  SubmitFrame(passes, arraysize(passes), root_surface_id_);
147
148  SurfaceId ids[] = {root_surface_id_};
149  AggregateAndVerify(passes, arraysize(passes), ids, arraysize(ids));
150}
151
152TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) {
153  test::Quad quads[][2] = {{test::Quad::SolidColorQuad(SK_ColorWHITE),
154                            test::Quad::SolidColorQuad(SK_ColorLTGRAY)},
155                           {test::Quad::SolidColorQuad(SK_ColorGRAY),
156                            test::Quad::SolidColorQuad(SK_ColorDKGRAY)}};
157  test::Pass passes[] = {test::Pass(quads[0], arraysize(quads[0])),
158                         test::Pass(quads[1], arraysize(quads[1]))};
159
160  SubmitFrame(passes, arraysize(passes), root_surface_id_);
161
162  SurfaceId ids[] = {root_surface_id_};
163  AggregateAndVerify(passes, arraysize(passes), ids, arraysize(ids));
164}
165
166// This tests very simple embedding. root_surface has a frame containing a few
167// solid color quads and a surface quad referencing embedded_surface.
168// embedded_surface has a frame containing only a solid color quad. The solid
169// color quad should be aggregated into the final frame.
170TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
171  SurfaceId embedded_surface_id = allocator_.GenerateId();
172  factory_.Create(embedded_surface_id, SurfaceSize());
173
174  test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
175  test::Pass embedded_passes[] = {
176      test::Pass(embedded_quads, arraysize(embedded_quads))};
177
178  SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id);
179
180  test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
181                             test::Quad::SurfaceQuad(embedded_surface_id),
182                             test::Quad::SolidColorQuad(SK_ColorBLACK)};
183  test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
184
185  SubmitFrame(root_passes, arraysize(root_passes), root_surface_id_);
186
187  test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
188                                 test::Quad::SolidColorQuad(SK_ColorGREEN),
189                                 test::Quad::SolidColorQuad(SK_ColorBLACK)};
190  test::Pass expected_passes[] = {
191      test::Pass(expected_quads, arraysize(expected_quads))};
192  SurfaceId ids[] = {root_surface_id_, embedded_surface_id};
193  AggregateAndVerify(
194      expected_passes, arraysize(expected_passes), ids, arraysize(ids));
195
196  factory_.Destroy(embedded_surface_id);
197}
198
199TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
200  SurfaceId embedded_surface_id = allocator_.GenerateId();
201  factory_.Create(embedded_surface_id, SurfaceSize());
202
203  test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
204  test::Pass embedded_passes[] = {
205      test::Pass(embedded_quads, arraysize(embedded_quads))};
206
207  SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id);
208  scoped_ptr<CopyOutputRequest> copy_request(
209      CopyOutputRequest::CreateEmptyRequest());
210  CopyOutputRequest* copy_request_ptr = copy_request.get();
211  factory_.RequestCopyOfSurface(embedded_surface_id, copy_request.Pass());
212
213  test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
214                             test::Quad::SurfaceQuad(embedded_surface_id),
215                             test::Quad::SolidColorQuad(SK_ColorBLACK)};
216  test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
217
218  SubmitFrame(root_passes, arraysize(root_passes), root_surface_id_);
219
220  scoped_ptr<CompositorFrame> aggregated_frame =
221      aggregator_.Aggregate(root_surface_id_);
222
223  ASSERT_TRUE(aggregated_frame);
224  ASSERT_TRUE(aggregated_frame->delegated_frame_data);
225
226  DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
227
228  test::Quad expected_quads[] = {
229      test::Quad::SolidColorQuad(SK_ColorWHITE),
230      test::Quad::RenderPassQuad(frame_data->render_pass_list[0]->id),
231      test::Quad::SolidColorQuad(SK_ColorBLACK)};
232  test::Pass expected_passes[] = {
233      test::Pass(embedded_quads, arraysize(embedded_quads)),
234      test::Pass(expected_quads, arraysize(expected_quads))};
235  TestPassesMatchExpectations(expected_passes,
236                              arraysize(expected_passes),
237                              &frame_data->render_pass_list);
238  ASSERT_EQ(2u, frame_data->render_pass_list.size());
239  ASSERT_EQ(1u, frame_data->render_pass_list[0]->copy_requests.size());
240  DCHECK_EQ(copy_request_ptr,
241            frame_data->render_pass_list[0]->copy_requests[0]);
242
243  SurfaceId surface_ids[] = {root_surface_id_, embedded_surface_id};
244  EXPECT_EQ(arraysize(surface_ids),
245            aggregator_.previous_contained_surfaces().size());
246  for (size_t i = 0; i < arraysize(surface_ids); i++) {
247    EXPECT_TRUE(
248        aggregator_.previous_contained_surfaces().find(surface_ids[i]) !=
249        aggregator_.previous_contained_surfaces().end());
250  }
251
252  factory_.Destroy(embedded_surface_id);
253}
254
255// This tests referencing a surface that has multiple render passes.
256TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
257  SurfaceId embedded_surface_id = allocator_.GenerateId();
258  factory_.Create(embedded_surface_id, SurfaceSize());
259
260  RenderPassId pass_ids[] = {RenderPassId(1, 1), RenderPassId(1, 2),
261                             RenderPassId(1, 3)};
262
263  test::Quad embedded_quads[][2] = {
264      {test::Quad::SolidColorQuad(1), test::Quad::SolidColorQuad(2)},
265      {test::Quad::SolidColorQuad(3), test::Quad::RenderPassQuad(pass_ids[0])},
266      {test::Quad::SolidColorQuad(4), test::Quad::RenderPassQuad(pass_ids[1])}};
267  test::Pass embedded_passes[] = {
268      test::Pass(embedded_quads[0], arraysize(embedded_quads[0]), pass_ids[0]),
269      test::Pass(embedded_quads[1], arraysize(embedded_quads[1]), pass_ids[1]),
270      test::Pass(embedded_quads[2], arraysize(embedded_quads[2]), pass_ids[2])};
271
272  SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id);
273
274  test::Quad root_quads[][2] = {
275      {test::Quad::SolidColorQuad(5), test::Quad::SolidColorQuad(6)},
276      {test::Quad::SurfaceQuad(embedded_surface_id),
277       test::Quad::RenderPassQuad(pass_ids[0])},
278      {test::Quad::SolidColorQuad(7), test::Quad::RenderPassQuad(pass_ids[1])}};
279  test::Pass root_passes[] = {
280      test::Pass(root_quads[0], arraysize(root_quads[0]), pass_ids[0]),
281      test::Pass(root_quads[1], arraysize(root_quads[1]), pass_ids[1]),
282      test::Pass(root_quads[2], arraysize(root_quads[2]), pass_ids[2])};
283
284  SubmitFrame(root_passes, arraysize(root_passes), root_surface_id_);
285
286  scoped_ptr<CompositorFrame> aggregated_frame =
287      aggregator_.Aggregate(root_surface_id_);
288
289  ASSERT_TRUE(aggregated_frame);
290  ASSERT_TRUE(aggregated_frame->delegated_frame_data);
291
292  DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
293
294  const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
295
296  ASSERT_EQ(5u, aggregated_pass_list.size());
297  RenderPassId actual_pass_ids[] = {
298      aggregated_pass_list[0]->id, aggregated_pass_list[1]->id,
299      aggregated_pass_list[2]->id, aggregated_pass_list[3]->id,
300      aggregated_pass_list[4]->id};
301  for (size_t i = 0; i < 5; ++i) {
302    for (size_t j = 0; j < i; ++j) {
303      EXPECT_NE(actual_pass_ids[i], actual_pass_ids[j]);
304    }
305  }
306
307  {
308    SCOPED_TRACE("First pass");
309    // The first pass will just be the first pass from the root surfaces quad
310    // with no render pass quads to remap.
311    TestPassMatchesExpectations(root_passes[0], aggregated_pass_list[0]);
312  }
313
314  {
315    SCOPED_TRACE("Second pass");
316    // The next two passes will be from the embedded surface since we have to
317    // draw those passes before they are referenced from the render pass draw
318    // quad embedded into the root surface's second pass.
319    // First, there's the first embedded pass which doesn't reference anything
320    // else.
321    TestPassMatchesExpectations(embedded_passes[0], aggregated_pass_list[1]);
322  }
323
324  {
325    SCOPED_TRACE("Third pass");
326    const QuadList& third_pass_quad_list = aggregated_pass_list[2]->quad_list;
327    ASSERT_EQ(2u, third_pass_quad_list.size());
328    TestQuadMatchesExpectations(embedded_quads[1][0],
329                                third_pass_quad_list.ElementAt(0));
330
331    // This render pass pass quad will reference the first pass from the
332    // embedded surface, which is the second pass in the aggregated frame.
333    ASSERT_EQ(DrawQuad::RENDER_PASS,
334              third_pass_quad_list.ElementAt(1)->material);
335    const RenderPassDrawQuad* third_pass_render_pass_draw_quad =
336        RenderPassDrawQuad::MaterialCast(third_pass_quad_list.ElementAt(1));
337    EXPECT_EQ(actual_pass_ids[1],
338              third_pass_render_pass_draw_quad->render_pass_id);
339  }
340
341  {
342    SCOPED_TRACE("Fourth pass");
343    // The fourth pass will have aggregated quads from the root surface's second
344    // pass and the embedded surface's first pass.
345    const QuadList& fourth_pass_quad_list = aggregated_pass_list[3]->quad_list;
346    ASSERT_EQ(3u, fourth_pass_quad_list.size());
347
348    // The first quad will be the yellow quad from the embedded surface's last
349    // pass.
350    TestQuadMatchesExpectations(embedded_quads[2][0],
351                                fourth_pass_quad_list.ElementAt(0));
352
353    // The next quad will be a render pass quad referencing the second pass from
354    // the embedded surface, which is the third pass in the aggregated frame.
355    ASSERT_EQ(DrawQuad::RENDER_PASS,
356              fourth_pass_quad_list.ElementAt(1)->material);
357    const RenderPassDrawQuad* fourth_pass_first_render_pass_draw_quad =
358        RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.ElementAt(1));
359    EXPECT_EQ(actual_pass_ids[2],
360              fourth_pass_first_render_pass_draw_quad->render_pass_id);
361
362    // The last quad will be a render pass quad referencing the first pass from
363    // the root surface, which is the first pass overall.
364    ASSERT_EQ(DrawQuad::RENDER_PASS,
365              fourth_pass_quad_list.ElementAt(2)->material);
366    const RenderPassDrawQuad* fourth_pass_second_render_pass_draw_quad =
367        RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.ElementAt(2));
368    EXPECT_EQ(actual_pass_ids[0],
369              fourth_pass_second_render_pass_draw_quad->render_pass_id);
370  }
371
372  {
373    SCOPED_TRACE("Fifth pass");
374    const QuadList& fifth_pass_quad_list = aggregated_pass_list[4]->quad_list;
375    ASSERT_EQ(2u, fifth_pass_quad_list.size());
376
377    TestQuadMatchesExpectations(root_quads[2][0],
378                                fifth_pass_quad_list.ElementAt(0));
379
380    // The last quad in the last pass will reference the second pass from the
381    // root surface, which after aggregating is the fourth pass in the overall
382    // list.
383    ASSERT_EQ(DrawQuad::RENDER_PASS,
384              fifth_pass_quad_list.ElementAt(1)->material);
385    const RenderPassDrawQuad* fifth_pass_render_pass_draw_quad =
386        RenderPassDrawQuad::MaterialCast(fifth_pass_quad_list.ElementAt(1));
387    EXPECT_EQ(actual_pass_ids[3],
388              fifth_pass_render_pass_draw_quad->render_pass_id);
389  }
390  factory_.Destroy(embedded_surface_id);
391}
392
393// Tests an invalid surface reference in a frame. The surface quad should just
394// be dropped.
395TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) {
396  test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
397                        test::Quad::SurfaceQuad(InvalidSurfaceId()),
398                        test::Quad::SolidColorQuad(SK_ColorBLUE)};
399  test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
400
401  SubmitFrame(passes, arraysize(passes), root_surface_id_);
402
403  test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
404                                 test::Quad::SolidColorQuad(SK_ColorBLUE)};
405  test::Pass expected_passes[] = {
406      test::Pass(expected_quads, arraysize(expected_quads))};
407  SurfaceId ids[] = {root_surface_id_, InvalidSurfaceId()};
408  AggregateAndVerify(
409      expected_passes, arraysize(expected_passes), ids, arraysize(ids));
410}
411
412// Tests a reference to a valid surface with no submitted frame. This quad
413// should also just be dropped.
414TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) {
415  SurfaceId surface_with_no_frame_id = allocator_.GenerateId();
416  factory_.Create(surface_with_no_frame_id, gfx::Size(5, 5));
417  test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
418                        test::Quad::SurfaceQuad(surface_with_no_frame_id),
419                        test::Quad::SolidColorQuad(SK_ColorBLUE)};
420  test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
421
422  SubmitFrame(passes, arraysize(passes), root_surface_id_);
423
424  test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
425                                 test::Quad::SolidColorQuad(SK_ColorBLUE)};
426  test::Pass expected_passes[] = {
427      test::Pass(expected_quads, arraysize(expected_quads))};
428  SurfaceId ids[] = {root_surface_id_, surface_with_no_frame_id};
429  AggregateAndVerify(
430      expected_passes, arraysize(expected_passes), ids, arraysize(ids));
431  factory_.Destroy(surface_with_no_frame_id);
432}
433
434// Tests a surface quad referencing itself, generating a trivial cycle.
435// The quad creating the cycle should be dropped from the final frame.
436TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) {
437  test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_id_),
438                        test::Quad::SolidColorQuad(SK_ColorYELLOW)};
439  test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
440
441  SubmitFrame(passes, arraysize(passes), root_surface_id_);
442
443  test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorYELLOW)};
444  test::Pass expected_passes[] = {
445      test::Pass(expected_quads, arraysize(expected_quads))};
446  SurfaceId ids[] = {root_surface_id_};
447  AggregateAndVerify(
448      expected_passes, arraysize(expected_passes), ids, arraysize(ids));
449}
450
451// Tests a more complex cycle with one intermediate surface.
452TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) {
453  SurfaceId child_surface_id = allocator_.GenerateId();
454  factory_.Create(child_surface_id, SurfaceSize());
455
456  test::Quad parent_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE),
457                               test::Quad::SurfaceQuad(child_surface_id),
458                               test::Quad::SolidColorQuad(SK_ColorCYAN)};
459  test::Pass parent_passes[] = {
460      test::Pass(parent_quads, arraysize(parent_quads))};
461
462  SubmitFrame(parent_passes, arraysize(parent_passes), root_surface_id_);
463
464  test::Quad child_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
465                              test::Quad::SurfaceQuad(root_surface_id_),
466                              test::Quad::SolidColorQuad(SK_ColorMAGENTA)};
467  test::Pass child_passes[] = {test::Pass(child_quads, arraysize(child_quads))};
468
469  SubmitFrame(child_passes, arraysize(child_passes), child_surface_id);
470
471  // The child surface's reference to the root_surface_ will be dropped, so
472  // we'll end up with:
473  //   SK_ColorBLUE from the parent
474  //   SK_ColorGREEN from the child
475  //   SK_ColorMAGENTA from the child
476  //   SK_ColorCYAN from the parent
477  test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE),
478                                 test::Quad::SolidColorQuad(SK_ColorGREEN),
479                                 test::Quad::SolidColorQuad(SK_ColorMAGENTA),
480                                 test::Quad::SolidColorQuad(SK_ColorCYAN)};
481  test::Pass expected_passes[] = {
482      test::Pass(expected_quads, arraysize(expected_quads))};
483  SurfaceId ids[] = {root_surface_id_, child_surface_id};
484  AggregateAndVerify(
485      expected_passes, arraysize(expected_passes), ids, arraysize(ids));
486  factory_.Destroy(child_surface_id);
487}
488
489// Tests that we map render pass IDs from different surfaces into a unified
490// namespace and update RenderPassDrawQuad's id references to match.
491TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) {
492  SurfaceId child_surface_id = allocator_.GenerateId();
493  factory_.Create(child_surface_id, SurfaceSize());
494
495  RenderPassId child_pass_id[] = {RenderPassId(1, 1), RenderPassId(1, 2)};
496  test::Quad child_quad[][1] = {{test::Quad::SolidColorQuad(SK_ColorGREEN)},
497                                {test::Quad::RenderPassQuad(child_pass_id[0])}};
498  test::Pass surface_passes[] = {
499      test::Pass(child_quad[0], arraysize(child_quad[0]), child_pass_id[0]),
500      test::Pass(child_quad[1], arraysize(child_quad[1]), child_pass_id[1])};
501
502  SubmitFrame(surface_passes, arraysize(surface_passes), child_surface_id);
503
504  // Pass IDs from the parent surface may collide with ones from the child.
505  RenderPassId parent_pass_id[] = {RenderPassId(2, 1), RenderPassId(1, 2)};
506  test::Quad parent_quad[][1] = {
507      {test::Quad::SurfaceQuad(child_surface_id)},
508      {test::Quad::RenderPassQuad(parent_pass_id[0])}};
509  test::Pass parent_passes[] = {
510      test::Pass(parent_quad[0], arraysize(parent_quad[0]), parent_pass_id[0]),
511      test::Pass(parent_quad[1], arraysize(parent_quad[1]), parent_pass_id[1])};
512
513  SubmitFrame(parent_passes, arraysize(parent_passes), root_surface_id_);
514  scoped_ptr<CompositorFrame> aggregated_frame =
515      aggregator_.Aggregate(root_surface_id_);
516
517  ASSERT_TRUE(aggregated_frame);
518  ASSERT_TRUE(aggregated_frame->delegated_frame_data);
519
520  DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
521
522  const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
523
524  ASSERT_EQ(3u, aggregated_pass_list.size());
525  RenderPassId actual_pass_ids[] = {aggregated_pass_list[0]->id,
526                                    aggregated_pass_list[1]->id,
527                                    aggregated_pass_list[2]->id};
528  // Make sure the aggregated frame's pass IDs are all unique.
529  for (size_t i = 0; i < 3; ++i) {
530    for (size_t j = 0; j < i; ++j) {
531      EXPECT_NE(actual_pass_ids[j], actual_pass_ids[i]) << "pass ids " << i
532                                                        << " and " << j;
533    }
534  }
535
536  // Make sure the render pass quads reference the remapped pass IDs.
537  DrawQuad* render_pass_quads[] = {aggregated_pass_list[1]->quad_list.front(),
538                                   aggregated_pass_list[2]->quad_list.front()};
539  ASSERT_EQ(render_pass_quads[0]->material, DrawQuad::RENDER_PASS);
540  EXPECT_EQ(
541      actual_pass_ids[0],
542      RenderPassDrawQuad::MaterialCast(render_pass_quads[0])->render_pass_id);
543
544  ASSERT_EQ(render_pass_quads[1]->material, DrawQuad::RENDER_PASS);
545  EXPECT_EQ(
546      actual_pass_ids[1],
547      RenderPassDrawQuad::MaterialCast(render_pass_quads[1])->render_pass_id);
548  factory_.Destroy(child_surface_id);
549}
550
551void AddSolidColorQuadWithBlendMode(const gfx::Size& size,
552                                    RenderPass* pass,
553                                    const SkXfermode::Mode blend_mode) {
554  const gfx::Transform content_to_target_transform;
555  const gfx::Size content_bounds(size);
556  const gfx::Rect visible_content_rect(size);
557  const gfx::Rect clip_rect(size);
558
559  bool is_clipped = false;
560  float opacity = 1.f;
561
562  bool force_anti_aliasing_off = false;
563  SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
564  sqs->SetAll(content_to_target_transform,
565              content_bounds,
566              visible_content_rect,
567              clip_rect,
568              is_clipped,
569              opacity,
570              blend_mode,
571              0);
572
573  SolidColorDrawQuad* color_quad =
574      pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
575  color_quad->SetNew(pass->shared_quad_state_list.back(),
576                     visible_content_rect,
577                     visible_content_rect,
578                     SK_ColorGREEN,
579                     force_anti_aliasing_off);
580}
581
582// This tests that we update shared quad state pointers correctly within
583// aggregated passes.  The shared quad state list on the aggregated pass will
584// include the shared quad states from each pass in one list so the quads will
585// end up pointed to shared quad state objects at different offsets. This test
586// uses the blend_mode value stored on the shared quad state to track the shared
587// quad state, but anything saved on the shared quad state would work.
588//
589// This test has 4 surfaces in the following structure:
590// root_surface -> quad with kClear_Mode,
591//                 [child_one_surface],
592//                 quad with kDstOver_Mode,
593//                 [child_two_surface],
594//                 quad with kDstIn_Mode
595// child_one_surface -> quad with kSrc_Mode,
596//                      [grandchild_surface],
597//                      quad with kSrcOver_Mode
598// child_two_surface -> quad with kSrcIn_Mode
599// grandchild_surface -> quad with kDst_Mode
600//
601// Resulting in the following aggregated pass:
602//  quad_root_0       - blend_mode kClear_Mode
603//  quad_child_one_0  - blend_mode kSrc_Mode
604//  quad_grandchild_0 - blend_mode kDst_Mode
605//  quad_child_one_1  - blend_mode kSrcOver_Mode
606//  quad_root_1       - blend_mode kDstOver_Mode
607//  quad_child_two_0  - blend_mode kSrcIn_Mode
608//  quad_root_2       - blend_mode kDstIn_Mode
609TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
610  const SkXfermode::Mode blend_modes[] = {SkXfermode::kClear_Mode,    // 0
611                                          SkXfermode::kSrc_Mode,      // 1
612                                          SkXfermode::kDst_Mode,      // 2
613                                          SkXfermode::kSrcOver_Mode,  // 3
614                                          SkXfermode::kDstOver_Mode,  // 4
615                                          SkXfermode::kSrcIn_Mode,    // 5
616                                          SkXfermode::kDstIn_Mode,    // 6
617  };
618
619  RenderPassId pass_id(1, 1);
620  SurfaceId grandchild_surface_id = allocator_.GenerateId();
621  factory_.Create(grandchild_surface_id, SurfaceSize());
622  scoped_ptr<RenderPass> grandchild_pass = RenderPass::Create();
623  gfx::Rect output_rect(SurfaceSize());
624  gfx::Rect damage_rect(SurfaceSize());
625  gfx::Transform transform_to_root_target;
626  grandchild_pass->SetNew(
627      pass_id, output_rect, damage_rect, transform_to_root_target);
628  AddSolidColorQuadWithBlendMode(
629      SurfaceSize(), grandchild_pass.get(), blend_modes[2]);
630  QueuePassAsFrame(grandchild_pass.Pass(), grandchild_surface_id);
631
632  SurfaceId child_one_surface_id = allocator_.GenerateId();
633  factory_.Create(child_one_surface_id, SurfaceSize());
634
635  scoped_ptr<RenderPass> child_one_pass = RenderPass::Create();
636  child_one_pass->SetNew(
637      pass_id, output_rect, damage_rect, transform_to_root_target);
638  AddSolidColorQuadWithBlendMode(
639      SurfaceSize(), child_one_pass.get(), blend_modes[1]);
640  SurfaceDrawQuad* grandchild_surface_quad =
641      child_one_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
642  grandchild_surface_quad->SetNew(child_one_pass->shared_quad_state_list.back(),
643                                  gfx::Rect(SurfaceSize()),
644                                  gfx::Rect(SurfaceSize()),
645                                  grandchild_surface_id);
646  AddSolidColorQuadWithBlendMode(
647      SurfaceSize(), child_one_pass.get(), blend_modes[3]);
648  QueuePassAsFrame(child_one_pass.Pass(), child_one_surface_id);
649
650  SurfaceId child_two_surface_id = allocator_.GenerateId();
651  factory_.Create(child_two_surface_id, SurfaceSize());
652
653  scoped_ptr<RenderPass> child_two_pass = RenderPass::Create();
654  child_two_pass->SetNew(
655      pass_id, output_rect, damage_rect, transform_to_root_target);
656  AddSolidColorQuadWithBlendMode(
657      SurfaceSize(), child_two_pass.get(), blend_modes[5]);
658  QueuePassAsFrame(child_two_pass.Pass(), child_two_surface_id);
659
660  scoped_ptr<RenderPass> root_pass = RenderPass::Create();
661  root_pass->SetNew(
662      pass_id, output_rect, damage_rect, transform_to_root_target);
663
664  AddSolidColorQuadWithBlendMode(
665      SurfaceSize(), root_pass.get(), blend_modes[0]);
666  SurfaceDrawQuad* child_one_surface_quad =
667      root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
668  child_one_surface_quad->SetNew(root_pass->shared_quad_state_list.back(),
669                                 gfx::Rect(SurfaceSize()),
670                                 gfx::Rect(SurfaceSize()),
671                                 child_one_surface_id);
672  AddSolidColorQuadWithBlendMode(
673      SurfaceSize(), root_pass.get(), blend_modes[4]);
674  SurfaceDrawQuad* child_two_surface_quad =
675      root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
676  child_two_surface_quad->SetNew(root_pass->shared_quad_state_list.back(),
677                                 gfx::Rect(SurfaceSize()),
678                                 gfx::Rect(SurfaceSize()),
679                                 child_two_surface_id);
680  AddSolidColorQuadWithBlendMode(
681      SurfaceSize(), root_pass.get(), blend_modes[6]);
682
683  QueuePassAsFrame(root_pass.Pass(), root_surface_id_);
684
685  scoped_ptr<CompositorFrame> aggregated_frame =
686      aggregator_.Aggregate(root_surface_id_);
687
688  ASSERT_TRUE(aggregated_frame);
689  ASSERT_TRUE(aggregated_frame->delegated_frame_data);
690
691  DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
692
693  const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
694
695  ASSERT_EQ(1u, aggregated_pass_list.size());
696
697  const QuadList& aggregated_quad_list = aggregated_pass_list[0]->quad_list;
698
699  ASSERT_EQ(7u, aggregated_quad_list.size());
700
701  size_t i = 0;
702  for (QuadList::ConstIterator iter = aggregated_quad_list.begin();
703       iter != aggregated_quad_list.end();
704       ++iter) {
705    EXPECT_EQ(blend_modes[i], iter->shared_quad_state->blend_mode) << i;
706    ++i;
707  }
708  factory_.Destroy(child_one_surface_id);
709  factory_.Destroy(child_two_surface_id);
710  factory_.Destroy(grandchild_surface_id);
711}
712
713// This tests that when aggregating a frame with multiple render passes that we
714// map the transforms for the root pass but do not modify the transform on child
715// passes.
716//
717// The root surface has one pass with a surface quad transformed by +10 in the y
718// direction.
719//
720// The child surface has two passes. The first pass has a quad with a transform
721// of +5 in the x direction. The second pass has a reference to the first pass'
722// pass id and a transform of +8 in the x direction.
723//
724// After aggregation, the child surface's root pass quad should have both
725// transforms concatenated for a total transform of +8 x, +10 y. The
726// contributing render pass' transform in the aggregate frame should not be
727// affected.
728TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
729  SurfaceId child_surface_id = allocator_.GenerateId();
730  factory_.Create(child_surface_id, SurfaceSize());
731  RenderPassId child_pass_id[] = {RenderPassId(1, 1), RenderPassId(1, 2)};
732  test::Quad child_quads[][1] = {
733      {test::Quad::SolidColorQuad(SK_ColorGREEN)},
734      {test::Quad::RenderPassQuad(child_pass_id[0])}};
735  test::Pass child_passes[] = {
736      test::Pass(child_quads[0], arraysize(child_quads[0]), child_pass_id[0]),
737      test::Pass(child_quads[1], arraysize(child_quads[1]), child_pass_id[1])};
738
739  RenderPassList child_pass_list;
740  AddPasses(&child_pass_list,
741            gfx::Rect(SurfaceSize()),
742            child_passes,
743            arraysize(child_passes));
744
745  RenderPass* child_nonroot_pass = child_pass_list.at(0u);
746  child_nonroot_pass->transform_to_root_target.Translate(8, 0);
747  SharedQuadState* child_nonroot_pass_sqs =
748      child_nonroot_pass->shared_quad_state_list[0];
749  child_nonroot_pass_sqs->content_to_target_transform.Translate(5, 0);
750
751  RenderPass* child_root_pass = child_pass_list.at(1u);
752  SharedQuadState* child_root_pass_sqs =
753      child_root_pass->shared_quad_state_list[0];
754  child_root_pass_sqs->content_to_target_transform.Translate(8, 0);
755  child_root_pass_sqs->is_clipped = true;
756  child_root_pass_sqs->clip_rect = gfx::Rect(0, 0, 5, 5);
757
758  scoped_ptr<DelegatedFrameData> child_frame_data(new DelegatedFrameData);
759  child_pass_list.swap(child_frame_data->render_pass_list);
760
761  scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
762  child_frame->delegated_frame_data = child_frame_data.Pass();
763
764  factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
765
766  test::Quad root_quads[] = {test::Quad::SolidColorQuad(1),
767                             test::Quad::SurfaceQuad(child_surface_id)};
768  test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
769
770  RenderPassList root_pass_list;
771  AddPasses(&root_pass_list,
772            gfx::Rect(SurfaceSize()),
773            root_passes,
774            arraysize(root_passes));
775
776  root_pass_list.at(0)
777      ->shared_quad_state_list[0]
778      ->content_to_target_transform.Translate(0, 7);
779  root_pass_list.at(0)
780      ->shared_quad_state_list[1]
781      ->content_to_target_transform.Translate(0, 10);
782
783  scoped_ptr<DelegatedFrameData> root_frame_data(new DelegatedFrameData);
784  root_pass_list.swap(root_frame_data->render_pass_list);
785
786  scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
787  root_frame->delegated_frame_data = root_frame_data.Pass();
788
789  factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
790
791  scoped_ptr<CompositorFrame> aggregated_frame =
792      aggregator_.Aggregate(root_surface_id_);
793
794  ASSERT_TRUE(aggregated_frame);
795  ASSERT_TRUE(aggregated_frame->delegated_frame_data);
796
797  DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
798
799  const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
800
801  ASSERT_EQ(2u, aggregated_pass_list.size());
802
803  ASSERT_EQ(1u, aggregated_pass_list[0]->shared_quad_state_list.size());
804
805  // The first pass should have one shared quad state for the one solid color
806  // quad.
807  EXPECT_EQ(1u, aggregated_pass_list[0]->shared_quad_state_list.size());
808  // The second (root) pass should have just two shared quad states. We'll
809  // verify the properties through the quads.
810  EXPECT_EQ(2u, aggregated_pass_list[1]->shared_quad_state_list.size());
811
812  SharedQuadState* aggregated_first_pass_sqs =
813      aggregated_pass_list[0]->shared_quad_state_list.front();
814
815  // The first pass's transform should be unaffected by the embedding and still
816  // be a translation by +5 in the x direction.
817  gfx::Transform expected_aggregated_first_pass_sqs_transform;
818  expected_aggregated_first_pass_sqs_transform.Translate(5, 0);
819  EXPECT_EQ(expected_aggregated_first_pass_sqs_transform.ToString(),
820            aggregated_first_pass_sqs->content_to_target_transform.ToString());
821
822  // The first pass's transform to the root target should include the aggregated
823  // transform.
824  gfx::Transform expected_first_pass_transform_to_root_target;
825  expected_first_pass_transform_to_root_target.Translate(8, 10);
826  EXPECT_EQ(expected_first_pass_transform_to_root_target.ToString(),
827            aggregated_pass_list[0]->transform_to_root_target.ToString());
828
829  ASSERT_EQ(2u, aggregated_pass_list[1]->quad_list.size());
830
831  gfx::Transform expected_root_pass_quad_transforms[2];
832  // The first quad in the root pass is the solid color quad from the original
833  // root surface. Its transform should be unaffected by the aggregation and
834  // still be +7 in the y direction.
835  expected_root_pass_quad_transforms[0].Translate(0, 7);
836  // The second quad in the root pass is aggregated from the child surface so
837  // its transform should be the combination of its original translation (0, 10)
838  // and the child surface draw quad's translation (8, 0).
839  expected_root_pass_quad_transforms[1].Translate(8, 10);
840
841  size_t i = 0;
842  for (QuadList::Iterator iter = aggregated_pass_list[1]->quad_list.begin();
843       iter != aggregated_pass_list[1]->quad_list.end();
844       ++iter) {
845    EXPECT_EQ(expected_root_pass_quad_transforms[i].ToString(),
846              iter->quadTransform().ToString())
847        << i;
848    i++;
849  }
850
851  EXPECT_EQ(true,
852            aggregated_pass_list[1]->shared_quad_state_list[1]->is_clipped);
853
854  // The second quad in the root pass is aggregated from the child, so its
855  // clip rect must be transformed by the child's translation.
856  EXPECT_EQ(
857      gfx::Rect(0, 10, 5, 5).ToString(),
858      aggregated_pass_list[1]->shared_quad_state_list[1]->clip_rect.ToString());
859
860  factory_.Destroy(child_surface_id);
861}
862
863// Tests that damage rects are aggregated correctly when surfaces change.
864TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
865  SurfaceId child_surface_id = allocator_.GenerateId();
866  factory_.Create(child_surface_id, SurfaceSize());
867  RenderPassId child_pass_id = RenderPassId(1, 1);
868  test::Quad child_quads[] = {test::Quad::RenderPassQuad(child_pass_id)};
869  test::Pass child_passes[] = {
870      test::Pass(child_quads, arraysize(child_quads), child_pass_id)};
871
872  RenderPassList child_pass_list;
873  AddPasses(&child_pass_list,
874            gfx::Rect(SurfaceSize()),
875            child_passes,
876            arraysize(child_passes));
877
878  RenderPass* child_root_pass = child_pass_list.at(0u);
879  SharedQuadState* child_root_pass_sqs =
880      child_root_pass->shared_quad_state_list[0];
881  child_root_pass_sqs->content_to_target_transform.Translate(8, 0);
882
883  scoped_ptr<DelegatedFrameData> child_frame_data(new DelegatedFrameData);
884  child_pass_list.swap(child_frame_data->render_pass_list);
885
886  scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
887  child_frame->delegated_frame_data = child_frame_data.Pass();
888
889  factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
890
891  test::Quad root_quads[] = {test::Quad::SurfaceQuad(child_surface_id)};
892  test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
893
894  RenderPassList root_pass_list;
895  AddPasses(&root_pass_list,
896            gfx::Rect(SurfaceSize()),
897            root_passes,
898            arraysize(root_passes));
899
900  root_pass_list.at(0)
901      ->shared_quad_state_list[0]
902      ->content_to_target_transform.Translate(0, 10);
903  root_pass_list.at(0)->damage_rect = gfx::Rect(5, 5, 10, 10);
904
905  scoped_ptr<DelegatedFrameData> root_frame_data(new DelegatedFrameData);
906  root_pass_list.swap(root_frame_data->render_pass_list);
907
908  scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
909  root_frame->delegated_frame_data = root_frame_data.Pass();
910
911  factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
912
913  scoped_ptr<CompositorFrame> aggregated_frame =
914      aggregator_.Aggregate(root_surface_id_);
915
916  ASSERT_TRUE(aggregated_frame);
917  ASSERT_TRUE(aggregated_frame->delegated_frame_data);
918
919  DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
920
921  const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
922
923  ASSERT_EQ(1u, aggregated_pass_list.size());
924
925  // Damage rect for first aggregation should contain entire root surface.
926  EXPECT_TRUE(
927      aggregated_pass_list[0]->damage_rect.Contains(gfx::Rect(SurfaceSize())));
928
929  {
930    AddPasses(&child_pass_list,
931              gfx::Rect(SurfaceSize()),
932              child_passes,
933              arraysize(child_passes));
934
935    RenderPass* child_root_pass = child_pass_list.at(0u);
936    SharedQuadState* child_root_pass_sqs =
937        child_root_pass->shared_quad_state_list[0];
938    child_root_pass_sqs->content_to_target_transform.Translate(8, 0);
939    child_root_pass->damage_rect = gfx::Rect(10, 10, 10, 10);
940
941    scoped_ptr<DelegatedFrameData> child_frame_data(new DelegatedFrameData);
942    child_pass_list.swap(child_frame_data->render_pass_list);
943
944    scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
945    child_frame->delegated_frame_data = child_frame_data.Pass();
946
947    factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
948
949    scoped_ptr<CompositorFrame> aggregated_frame =
950        aggregator_.Aggregate(root_surface_id_);
951
952    ASSERT_TRUE(aggregated_frame);
953    ASSERT_TRUE(aggregated_frame->delegated_frame_data);
954
955    DelegatedFrameData* frame_data =
956        aggregated_frame->delegated_frame_data.get();
957
958    const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
959
960    ASSERT_EQ(1u, aggregated_pass_list.size());
961
962    // Outer surface didn't change, so transformed inner damage rect should be
963    // used.
964    EXPECT_EQ(gfx::Rect(10, 20, 10, 10).ToString(),
965              aggregated_pass_list[0]->damage_rect.ToString());
966  }
967
968  {
969    RenderPassList root_pass_list;
970    AddPasses(&root_pass_list,
971              gfx::Rect(SurfaceSize()),
972              root_passes,
973              arraysize(root_passes));
974
975    root_pass_list.at(0)
976        ->shared_quad_state_list[0]
977        ->content_to_target_transform.Translate(0, 10);
978    root_pass_list.at(0)->damage_rect = gfx::Rect(0, 0, 1, 1);
979
980    scoped_ptr<DelegatedFrameData> root_frame_data(new DelegatedFrameData);
981    root_pass_list.swap(root_frame_data->render_pass_list);
982
983    scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
984    root_frame->delegated_frame_data = root_frame_data.Pass();
985
986    factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
987  }
988
989  {
990    RenderPassList root_pass_list;
991    AddPasses(&root_pass_list,
992              gfx::Rect(SurfaceSize()),
993              root_passes,
994              arraysize(root_passes));
995
996    root_pass_list.at(0)
997        ->shared_quad_state_list[0]
998        ->content_to_target_transform.Translate(0, 10);
999    root_pass_list.at(0)->damage_rect = gfx::Rect(1, 1, 1, 1);
1000
1001    scoped_ptr<DelegatedFrameData> root_frame_data(new DelegatedFrameData);
1002    root_pass_list.swap(root_frame_data->render_pass_list);
1003
1004    scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
1005    root_frame->delegated_frame_data = root_frame_data.Pass();
1006
1007    factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
1008
1009    scoped_ptr<CompositorFrame> aggregated_frame =
1010        aggregator_.Aggregate(root_surface_id_);
1011
1012    ASSERT_TRUE(aggregated_frame);
1013    ASSERT_TRUE(aggregated_frame->delegated_frame_data);
1014
1015    DelegatedFrameData* frame_data =
1016        aggregated_frame->delegated_frame_data.get();
1017
1018    const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
1019
1020    ASSERT_EQ(1u, aggregated_pass_list.size());
1021
1022    // The root surface was enqueued without being aggregated once, so it should
1023    // be treated as completely damaged.
1024    EXPECT_TRUE(aggregated_pass_list[0]->damage_rect.Contains(
1025        gfx::Rect(SurfaceSize())));
1026  }
1027
1028  factory_.Destroy(child_surface_id);
1029}
1030
1031class SurfaceAggregatorWithResourcesTest : public testing::Test {
1032 public:
1033  virtual void SetUp() {
1034    output_surface_ = FakeOutputSurface::CreateSoftware(
1035        make_scoped_ptr(new SoftwareOutputDevice));
1036    output_surface_->BindToClient(&output_surface_client_);
1037    shared_bitmap_manager_.reset(new TestSharedBitmapManager);
1038
1039    resource_provider_ = ResourceProvider::Create(output_surface_.get(),
1040                                                  shared_bitmap_manager_.get(),
1041                                                  NULL,
1042                                                  0,
1043                                                  false,
1044                                                  1,
1045                                                  false);
1046
1047    aggregator_.reset(
1048        new SurfaceAggregator(&manager_, resource_provider_.get()));
1049  }
1050
1051 protected:
1052  SurfaceManager manager_;
1053  FakeOutputSurfaceClient output_surface_client_;
1054  scoped_ptr<OutputSurface> output_surface_;
1055  scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
1056  scoped_ptr<ResourceProvider> resource_provider_;
1057  scoped_ptr<SurfaceAggregator> aggregator_;
1058};
1059
1060class ResourceTrackingSurfaceFactoryClient : public SurfaceFactoryClient {
1061 public:
1062  ResourceTrackingSurfaceFactoryClient() {}
1063  virtual ~ResourceTrackingSurfaceFactoryClient() {}
1064
1065  virtual void ReturnResources(
1066      const ReturnedResourceArray& resources) OVERRIDE {
1067    returned_resources_ = resources;
1068  }
1069
1070  ReturnedResourceArray returned_resources() const {
1071    return returned_resources_;
1072  }
1073
1074 private:
1075  ReturnedResourceArray returned_resources_;
1076
1077  DISALLOW_COPY_AND_ASSIGN(ResourceTrackingSurfaceFactoryClient);
1078};
1079
1080void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids,
1081                              size_t num_resource_ids,
1082                              SurfaceFactory* factory,
1083                              SurfaceId surface_id) {
1084  scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
1085  scoped_ptr<RenderPass> pass = RenderPass::Create();
1086  pass->id = RenderPassId(1, 1);
1087  SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
1088  for (size_t i = 0u; i < num_resource_ids; ++i) {
1089    TransferableResource resource;
1090    resource.id = resource_ids[i];
1091    resource.is_software = true;
1092    frame_data->resource_list.push_back(resource);
1093    TextureDrawQuad* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
1094    const gfx::Rect rect;
1095    const gfx::Rect opaque_rect;
1096    const gfx::Rect visible_rect;
1097    bool needs_blending = false;
1098    bool premultiplied_alpha = false;
1099    const gfx::PointF uv_top_left;
1100    const gfx::PointF uv_bottom_right;
1101    SkColor background_color = SK_ColorGREEN;
1102    const float vertex_opacity[4] = {0.f, 0.f, 1.f, 1.f};
1103    bool flipped = false;
1104    quad->SetAll(sqs,
1105                 rect,
1106                 opaque_rect,
1107                 visible_rect,
1108                 needs_blending,
1109                 resource_ids[i],
1110                 premultiplied_alpha,
1111                 uv_top_left,
1112                 uv_bottom_right,
1113                 background_color,
1114                 vertex_opacity,
1115                 flipped);
1116
1117    quad->shared_quad_state = sqs;
1118  }
1119  frame_data->render_pass_list.push_back(pass.Pass());
1120  scoped_ptr<CompositorFrame> frame(new CompositorFrame);
1121  frame->delegated_frame_data = frame_data.Pass();
1122  factory->SubmitFrame(surface_id, frame.Pass(), base::Closure());
1123}
1124
1125TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) {
1126  ResourceTrackingSurfaceFactoryClient client;
1127  SurfaceFactory factory(&manager_, &client);
1128  SurfaceId surface_id(7u);
1129  factory.Create(surface_id, SurfaceSize());
1130
1131  ResourceProvider::ResourceId ids[] = {11, 12, 13};
1132  SubmitFrameWithResources(ids, arraysize(ids), &factory, surface_id);
1133
1134  scoped_ptr<CompositorFrame> frame = aggregator_->Aggregate(surface_id);
1135
1136  // Nothing should be available to be returned yet.
1137  EXPECT_TRUE(client.returned_resources().empty());
1138
1139  SubmitFrameWithResources(NULL, 0u, &factory, surface_id);
1140
1141  frame = aggregator_->Aggregate(surface_id);
1142
1143  ASSERT_EQ(3u, client.returned_resources().size());
1144  ResourceProvider::ResourceId returned_ids[3];
1145  for (size_t i = 0; i < 3; ++i) {
1146    returned_ids[i] = client.returned_resources()[i].id;
1147  }
1148  EXPECT_THAT(returned_ids,
1149              testing::WhenSorted(testing::ElementsAreArray(ids)));
1150  factory.Destroy(surface_id);
1151}
1152
1153}  // namespace
1154}  // namespace cc
1155
1156