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 // Contributing passes aggregated in to the pass list need to take the
103 // transform of the surface quad into account to update their transform to
105 // TODO(jamesr): Make sure this is sufficient for surfaces nested several
106 // levels deep and add tests.
107 copy_pass
->transform_to_root_target
.ConcatTransform(
108 surface_quad
->quadTransform());
110 CopyQuadsToPass(source
.quad_list
,
111 source
.shared_quad_state_list
,
116 dest_pass_list_
->push_back(copy_pass
.Pass());
119 // TODO(jamesr): Clean up last pass special casing.
120 const RenderPass
& last_pass
= *referenced_data
->render_pass_list
.back();
121 const QuadList
& quads
= last_pass
.quad_list
;
123 // TODO(jamesr): Make sure clipping is enforced.
124 CopyQuadsToPass(quads
,
125 last_pass
.shared_quad_state_list
,
126 surface_quad
->quadTransform(),
130 referenced_surfaces_
.erase(it
);
133 void SurfaceAggregator::CopySharedQuadState(
134 const SharedQuadState
& source_sqs
,
135 const gfx::Transform
& content_to_target_transform
,
136 SharedQuadStateList
* dest_sqs_list
) {
137 scoped_ptr
<SharedQuadState
> copy_shared_quad_state
= source_sqs
.Copy();
138 // content_to_target_transform contains any transformation that may exist
139 // between the context that these quads are being copied from (i.e. the
140 // surface's draw transform when aggregated from within a surface) to the
141 // target space of the pass. This will be identity except when copying the
142 // root draw pass from a surface into a pass when the surface draw quad's
143 // transform is not identity.
144 copy_shared_quad_state
->content_to_target_transform
.ConcatTransform(
145 content_to_target_transform
);
146 dest_sqs_list
->push_back(copy_shared_quad_state
.Pass());
149 void SurfaceAggregator::CopyQuadsToPass(
150 const QuadList
& source_quad_list
,
151 const SharedQuadStateList
& source_shared_quad_state_list
,
152 const gfx::Transform
& content_to_target_transform
,
153 RenderPass
* dest_pass
,
155 const SharedQuadState
* last_copied_source_shared_quad_state
= NULL
;
157 for (size_t i
= 0, sqs_i
= 0; i
< source_quad_list
.size(); ++i
) {
158 DrawQuad
* quad
= source_quad_list
[i
];
159 while (quad
->shared_quad_state
!= source_shared_quad_state_list
[sqs_i
]) {
161 DCHECK_LT(sqs_i
, source_shared_quad_state_list
.size());
163 DCHECK_EQ(quad
->shared_quad_state
, source_shared_quad_state_list
[sqs_i
]);
165 if (quad
->material
== DrawQuad::SURFACE_CONTENT
) {
166 const SurfaceDrawQuad
* surface_quad
= SurfaceDrawQuad::MaterialCast(quad
);
167 HandleSurfaceQuad(surface_quad
, dest_pass
);
169 if (quad
->shared_quad_state
!= last_copied_source_shared_quad_state
) {
170 CopySharedQuadState(*quad
->shared_quad_state
,
171 content_to_target_transform
,
172 &dest_pass
->shared_quad_state_list
);
173 last_copied_source_shared_quad_state
= quad
->shared_quad_state
;
175 if (quad
->material
== DrawQuad::RENDER_PASS
) {
176 const RenderPassDrawQuad
* pass_quad
=
177 RenderPassDrawQuad::MaterialCast(quad
);
178 RenderPass::Id original_pass_id
= pass_quad
->render_pass_id
;
179 RenderPass::Id remapped_pass_id
=
180 RemapPassId(original_pass_id
, surface_id
);
182 dest_pass
->quad_list
.push_back(
183 pass_quad
->Copy(dest_pass
->shared_quad_state_list
.back(),
184 remapped_pass_id
).PassAs
<DrawQuad
>());
186 dest_pass
->quad_list
.push_back(
187 quad
->Copy(dest_pass
->shared_quad_state_list
.back()));
193 void SurfaceAggregator::CopyPasses(const RenderPassList
& source_pass_list
,
195 for (size_t i
= 0; i
< source_pass_list
.size(); ++i
) {
196 const RenderPass
& source
= *source_pass_list
[i
];
198 scoped_ptr
<RenderPass
> copy_pass(RenderPass::Create());
200 RenderPass::Id remapped_pass_id
= RemapPassId(source
.id
, surface_id
);
202 copy_pass
->SetAll(remapped_pass_id
,
205 source
.transform_to_root_target
,
206 source
.has_transparent_background
);
208 CopyQuadsToPass(source
.quad_list
,
209 source
.shared_quad_state_list
,
214 dest_pass_list_
->push_back(copy_pass
.Pass());
218 scoped_ptr
<CompositorFrame
> SurfaceAggregator::Aggregate(int surface_id
) {
219 Surface
* surface
= manager_
->GetSurfaceForID(surface_id
);
221 return scoped_ptr
<CompositorFrame
>();
222 CompositorFrame
* root_surface_frame
= surface
->GetEligibleFrame();
223 if (!root_surface_frame
)
224 return scoped_ptr
<CompositorFrame
>();
226 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
227 frame
->delegated_frame_data
= make_scoped_ptr(new DelegatedFrameData
);
229 DCHECK(root_surface_frame
->delegated_frame_data
);
231 const RenderPassList
& source_pass_list
=
232 root_surface_frame
->delegated_frame_data
->render_pass_list
;
234 std::set
<int>::iterator it
= referenced_surfaces_
.insert(surface_id
).first
;
236 dest_pass_list_
= &frame
->delegated_frame_data
->render_pass_list
;
237 CopyPasses(source_pass_list
, surface_id
);
239 referenced_surfaces_
.erase(it
);
240 DCHECK(referenced_surfaces_
.empty());
242 dest_pass_list_
= NULL
;
244 // TODO(jamesr): Aggregate all resource references into the returned frame's