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.
5 #include "cc/surfaces/surface_aggregator.h"
7 #include "base/containers/hash_tables.h"
8 #include "base/logging.h"
9 #include "cc/output/compositor_frame.h"
10 #include "cc/output/delegated_frame_data.h"
11 #include "cc/quads/draw_quad.h"
12 #include "cc/quads/render_pass_draw_quad.h"
13 #include "cc/quads/shared_quad_state.h"
14 #include "cc/quads/surface_draw_quad.h"
15 #include "cc/surfaces/surface.h"
16 #include "cc/surfaces/surface_manager.h"
20 SurfaceAggregator::SurfaceAggregator(SurfaceManager
* manager
)
25 SurfaceAggregator::~SurfaceAggregator() {}
27 DelegatedFrameData
* SurfaceAggregator::GetReferencedDataForSurfaceID(
29 Surface
* referenced_surface
= manager_
->GetSurfaceForID(surface_id
);
30 if (!referenced_surface
)
31 return NULL
; // Invalid surface id, skip this quad.
32 CompositorFrame
* referenced_frame
= referenced_surface
->GetEligibleFrame();
33 if (!referenced_frame
)
35 return referenced_frame
->delegated_frame_data
.get();
38 class SurfaceAggregator::RenderPassIdAllocator
{
40 explicit RenderPassIdAllocator(int surface_id
)
41 : surface_id_(surface_id
), next_index_(1) {}
42 ~RenderPassIdAllocator() {}
44 void AddKnownPass(RenderPass::Id id
) {
45 if (id_to_index_map_
.find(id
) != id_to_index_map_
.end())
47 id_to_index_map_
[id
] = next_index_
++;
50 RenderPass::Id
Remap(RenderPass::Id id
) {
51 DCHECK(id_to_index_map_
.find(id
) != id_to_index_map_
.end());
52 return RenderPass::Id(surface_id_
, id_to_index_map_
[id
]);
56 base::hash_map
<RenderPass::Id
, int> id_to_index_map_
;
60 DISALLOW_COPY_AND_ASSIGN(RenderPassIdAllocator
);
63 RenderPass::Id
SurfaceAggregator::RemapPassId(
64 RenderPass::Id surface_local_pass_id
,
66 RenderPassIdAllocator
* allocator
= render_pass_allocator_map_
.get(surface_id
);
68 allocator
= new RenderPassIdAllocator(surface_id
);
69 render_pass_allocator_map_
.set(surface_id
, make_scoped_ptr(allocator
));
71 allocator
->AddKnownPass(surface_local_pass_id
);
72 return allocator
->Remap(surface_local_pass_id
);
75 void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad
* surface_quad
,
76 RenderPass
* dest_pass
) {
77 int surface_id
= surface_quad
->surface_id
;
78 // If this surface's id is already in our referenced set then it creates
79 // a cycle in the graph and should be dropped.
80 if (referenced_surfaces_
.count(surface_id
))
82 DelegatedFrameData
* referenced_data
=
83 GetReferencedDataForSurfaceID(surface_id
);
86 std::set
<int>::iterator it
= referenced_surfaces_
.insert(surface_id
).first
;
88 const RenderPassList
& referenced_passes
= referenced_data
->render_pass_list
;
89 for (size_t j
= 0; j
+ 1 < referenced_passes
.size(); ++j
) {
90 const RenderPass
& source
= *referenced_passes
[j
];
92 scoped_ptr
<RenderPass
> copy_pass(RenderPass::Create());
94 RenderPass::Id remapped_pass_id
= RemapPassId(source
.id
, surface_id
);
96 copy_pass
->SetAll(remapped_pass_id
,
99 source
.transform_to_root_target
,
100 source
.has_transparent_background
);
102 CopyQuadsToPass(source
.quad_list
,
103 source
.shared_quad_state_list
,
107 dest_pass_list_
->push_back(copy_pass
.Pass());
110 // TODO(jamesr): Clean up last pass special casing.
111 const RenderPass
& last_pass
= *referenced_data
->render_pass_list
.back();
112 const QuadList
& quads
= last_pass
.quad_list
;
114 for (size_t j
= 0; j
< last_pass
.shared_quad_state_list
.size(); ++j
) {
115 dest_pass
->shared_quad_state_list
.push_back(
116 last_pass
.shared_quad_state_list
[j
]->Copy());
118 // TODO(jamesr): Map transform correctly for quads in the referenced
119 // surface into this pass's space.
120 // TODO(jamesr): Make sure clipping is enforced.
122 quads
, last_pass
.shared_quad_state_list
, dest_pass
, surface_id
);
124 referenced_surfaces_
.erase(it
);
127 void SurfaceAggregator::CopyQuadsToPass(
128 const QuadList
& source_quad_list
,
129 const SharedQuadStateList
& source_shared_quad_state_list
,
130 RenderPass
* dest_pass
,
132 for (size_t j
= 0; j
< source_shared_quad_state_list
.size(); ++j
) {
133 dest_pass
->shared_quad_state_list
.push_back(
134 source_shared_quad_state_list
[j
]->Copy());
137 for (size_t i
= 0, sqs_i
= 0; i
< source_quad_list
.size(); ++i
) {
138 DrawQuad
* quad
= source_quad_list
[i
];
140 while (quad
->shared_quad_state
!= source_shared_quad_state_list
[sqs_i
]) {
142 DCHECK_LT(sqs_i
, source_shared_quad_state_list
.size());
143 DCHECK_LT(sqs_i
, dest_pass
->shared_quad_state_list
.size());
145 DCHECK_EQ(quad
->shared_quad_state
, source_shared_quad_state_list
[sqs_i
]);
147 if (quad
->material
== DrawQuad::SURFACE_CONTENT
) {
148 const SurfaceDrawQuad
* surface_quad
= SurfaceDrawQuad::MaterialCast(quad
);
149 HandleSurfaceQuad(surface_quad
, dest_pass
);
150 } else if (quad
->material
== DrawQuad::RENDER_PASS
) {
151 const RenderPassDrawQuad
* pass_quad
=
152 RenderPassDrawQuad::MaterialCast(quad
);
153 RenderPass::Id original_pass_id
= pass_quad
->render_pass_id
;
154 RenderPass::Id remapped_pass_id
=
155 RemapPassId(original_pass_id
, surface_id
);
157 dest_pass
->quad_list
.push_back(
158 pass_quad
->Copy(dest_pass
->shared_quad_state_list
[sqs_i
],
159 remapped_pass_id
).PassAs
<DrawQuad
>());
161 dest_pass
->quad_list
.push_back(
162 quad
->Copy(dest_pass
->shared_quad_state_list
[sqs_i
]));
167 void SurfaceAggregator::CopyPasses(const RenderPassList
& source_pass_list
,
169 for (size_t i
= 0; i
< source_pass_list
.size(); ++i
) {
170 const RenderPass
& source
= *source_pass_list
[i
];
172 scoped_ptr
<RenderPass
> copy_pass(RenderPass::Create());
174 RenderPass::Id remapped_pass_id
= RemapPassId(source
.id
, surface_id
);
176 copy_pass
->SetAll(remapped_pass_id
,
179 source
.transform_to_root_target
,
180 source
.has_transparent_background
);
182 CopyQuadsToPass(source
.quad_list
,
183 source
.shared_quad_state_list
,
187 dest_pass_list_
->push_back(copy_pass
.Pass());
191 scoped_ptr
<CompositorFrame
> SurfaceAggregator::Aggregate(int surface_id
) {
192 Surface
* surface
= manager_
->GetSurfaceForID(surface_id
);
194 return scoped_ptr
<CompositorFrame
>();
195 CompositorFrame
* root_surface_frame
= surface
->GetEligibleFrame();
196 if (!root_surface_frame
)
197 return scoped_ptr
<CompositorFrame
>();
199 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
200 frame
->delegated_frame_data
= make_scoped_ptr(new DelegatedFrameData
);
202 DCHECK(root_surface_frame
->delegated_frame_data
);
204 const RenderPassList
& source_pass_list
=
205 root_surface_frame
->delegated_frame_data
->render_pass_list
;
207 referenced_surfaces_
.insert(surface_id
);
209 dest_pass_list_
= &frame
->delegated_frame_data
->render_pass_list
;
210 CopyPasses(source_pass_list
, surface_id
);
212 referenced_surfaces_
.clear();
213 dest_pass_list_
= NULL
;
215 // TODO(jamesr): Aggregate all resource references into the returned frame's