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"
10 #include "base/containers/hash_tables.h"
11 #include "base/logging.h"
12 #include "base/trace_event/trace_event.h"
13 #include "cc/base/math_util.h"
14 #include "cc/output/compositor_frame.h"
15 #include "cc/output/delegated_frame_data.h"
16 #include "cc/quads/draw_quad.h"
17 #include "cc/quads/render_pass_draw_quad.h"
18 #include "cc/quads/shared_quad_state.h"
19 #include "cc/quads/surface_draw_quad.h"
20 #include "cc/surfaces/surface.h"
21 #include "cc/surfaces/surface_factory.h"
22 #include "cc/surfaces/surface_manager.h"
23 #include "cc/trees/blocking_task_runner.h"
28 void MoveMatchingRequests(
30 std::multimap
<RenderPassId
, CopyOutputRequest
*>* copy_requests
,
31 ScopedPtrVector
<CopyOutputRequest
>* output_requests
) {
32 auto request_range
= copy_requests
->equal_range(id
);
33 for (auto it
= request_range
.first
; it
!= request_range
.second
; ++it
) {
35 output_requests
->push_back(scoped_ptr
<CopyOutputRequest
>(it
->second
));
38 copy_requests
->erase(request_range
.first
, request_range
.second
);
43 SurfaceAggregator::SurfaceAggregator(SurfaceManager
* manager
,
44 ResourceProvider
* provider
,
45 bool aggregate_only_damaged
)
48 next_render_pass_id_(1),
49 aggregate_only_damaged_(aggregate_only_damaged
) {
53 SurfaceAggregator::~SurfaceAggregator() {}
55 // Create a clip rect for an aggregated quad from the original clip rect and
56 // the clip rect from the surface it's on.
57 SurfaceAggregator::ClipData
SurfaceAggregator::CalculateClipRect(
58 const ClipData
& surface_clip
,
59 const ClipData
& quad_clip
,
60 const gfx::Transform
& target_transform
) {
62 if (surface_clip
.is_clipped
)
63 out_clip
= surface_clip
;
65 if (quad_clip
.is_clipped
) {
66 // TODO(jamesr): This only works if target_transform maps integer
67 // rects to integer rects.
68 gfx::Rect final_clip
=
69 MathUtil::MapEnclosingClippedRect(target_transform
, quad_clip
.rect
);
70 if (out_clip
.is_clipped
)
71 out_clip
.rect
.Intersect(final_clip
);
73 out_clip
.rect
= final_clip
;
74 out_clip
.is_clipped
= true;
80 class SurfaceAggregator::RenderPassIdAllocator
{
82 explicit RenderPassIdAllocator(int* next_index
) : next_index_(next_index
) {}
83 ~RenderPassIdAllocator() {}
85 void AddKnownPass(RenderPassId id
) {
86 if (id_to_index_map_
.find(id
) != id_to_index_map_
.end())
88 id_to_index_map_
[id
] = (*next_index_
)++;
91 RenderPassId
Remap(RenderPassId id
) {
92 DCHECK(id_to_index_map_
.find(id
) != id_to_index_map_
.end());
93 return RenderPassId(1, id_to_index_map_
[id
]);
97 base::hash_map
<RenderPassId
, int> id_to_index_map_
;
100 DISALLOW_COPY_AND_ASSIGN(RenderPassIdAllocator
);
103 static void UnrefHelper(base::WeakPtr
<SurfaceFactory
> surface_factory
,
104 const ReturnedResourceArray
& resources
,
105 BlockingTaskRunner
* main_thread_task_runner
) {
107 surface_factory
->UnrefResources(resources
);
110 RenderPassId
SurfaceAggregator::RemapPassId(RenderPassId surface_local_pass_id
,
111 SurfaceId surface_id
) {
112 RenderPassIdAllocator
* allocator
= render_pass_allocator_map_
.get(surface_id
);
114 allocator
= new RenderPassIdAllocator(&next_render_pass_id_
);
115 render_pass_allocator_map_
.set(surface_id
, make_scoped_ptr(allocator
));
117 allocator
->AddKnownPass(surface_local_pass_id
);
118 return allocator
->Remap(surface_local_pass_id
);
121 int SurfaceAggregator::ChildIdForSurface(Surface
* surface
) {
122 SurfaceToResourceChildIdMap::iterator it
=
123 surface_id_to_resource_child_id_
.find(surface
->surface_id());
124 if (it
== surface_id_to_resource_child_id_
.end()) {
126 provider_
->CreateChild(base::Bind(&UnrefHelper
, surface
->factory()));
127 if (surface
->factory()) {
128 provider_
->SetChildNeedsSyncPoints(
129 child_id
, surface
->factory()->needs_sync_points());
131 surface_id_to_resource_child_id_
[surface
->surface_id()] = child_id
;
139 gfx::Rect
SurfaceAggregator::DamageRectForSurface(const Surface
* surface
,
140 const RenderPass
& source
,
141 const gfx::Rect
& full_rect
) {
142 int previous_index
= previous_contained_surfaces_
[surface
->surface_id()];
143 if (previous_index
== surface
->frame_index())
145 else if (previous_index
== surface
->frame_index() - 1)
146 return source
.damage_rect
;
150 void SurfaceAggregator::HandleSurfaceQuad(
151 const SurfaceDrawQuad
* surface_quad
,
152 const gfx::Transform
& target_transform
,
153 const ClipData
& clip_rect
,
154 RenderPass
* dest_pass
) {
155 SurfaceId surface_id
= surface_quad
->surface_id
;
156 // If this surface's id is already in our referenced set then it creates
157 // a cycle in the graph and should be dropped.
158 if (referenced_surfaces_
.count(surface_id
))
160 Surface
* surface
= manager_
->GetSurfaceForId(surface_id
);
163 const CompositorFrame
* frame
= surface
->GetEligibleFrame();
166 const DelegatedFrameData
* frame_data
= frame
->delegated_frame_data
.get();
170 std::multimap
<RenderPassId
, CopyOutputRequest
*> copy_requests
;
171 surface
->TakeCopyOutputRequests(©_requests
);
173 const RenderPassList
& render_pass_list
= frame_data
->render_pass_list
;
174 if (!valid_surfaces_
.count(surface
->surface_id())) {
175 for (auto& request
: copy_requests
) {
176 request
.second
->SendEmptyResult();
177 delete request
.second
;
182 SurfaceSet::iterator it
= referenced_surfaces_
.insert(surface_id
).first
;
183 // TODO(vmpstr): provider check is a hack for unittests that don't set up a
184 // resource provider.
185 ResourceProvider::ResourceIdMap empty_map
;
186 const ResourceProvider::ResourceIdMap
& child_to_parent_map
=
187 provider_
? provider_
->GetChildToParentMap(ChildIdForSurface(surface
))
190 surface_quad
->shared_quad_state
->opacity
== 1.f
&& copy_requests
.empty();
192 const RenderPassList
& referenced_passes
= render_pass_list
;
193 size_t passes_to_copy
=
194 merge_pass
? referenced_passes
.size() - 1 : referenced_passes
.size();
195 for (size_t j
= 0; j
< passes_to_copy
; ++j
) {
196 const RenderPass
& source
= *referenced_passes
[j
];
198 size_t sqs_size
= source
.shared_quad_state_list
.size();
199 size_t dq_size
= source
.quad_list
.size();
200 scoped_ptr
<RenderPass
> copy_pass(RenderPass::Create(sqs_size
, dq_size
));
202 RenderPassId remapped_pass_id
= RemapPassId(source
.id
, surface_id
);
204 copy_pass
->SetAll(remapped_pass_id
, source
.output_rect
, gfx::Rect(),
205 source
.transform_to_root_target
,
206 source
.has_transparent_background
);
208 MoveMatchingRequests(source
.id
, ©_requests
, ©_pass
->copy_requests
);
210 // Contributing passes aggregated in to the pass list need to take the
211 // transform of the surface quad into account to update their transform to
213 copy_pass
->transform_to_root_target
.ConcatTransform(
214 surface_quad
->shared_quad_state
->quad_to_target_transform
);
215 copy_pass
->transform_to_root_target
.ConcatTransform(target_transform
);
216 copy_pass
->transform_to_root_target
.ConcatTransform(
217 dest_pass
->transform_to_root_target
);
219 CopyQuadsToPass(source
.quad_list
, source
.shared_quad_state_list
,
220 child_to_parent_map
, gfx::Transform(), ClipData(),
221 copy_pass
.get(), surface_id
);
223 dest_pass_list_
->push_back(copy_pass
.Pass());
226 gfx::Transform surface_transform
=
227 surface_quad
->shared_quad_state
->quad_to_target_transform
;
228 surface_transform
.ConcatTransform(target_transform
);
230 const RenderPass
& last_pass
= *render_pass_list
.back();
232 // TODO(jamesr): Clean up last pass special casing.
233 const QuadList
& quads
= last_pass
.quad_list
;
235 // Intersect the transformed visible rect and the clip rect to create a
236 // smaller cliprect for the quad.
237 ClipData
surface_quad_clip_rect(
238 true, MathUtil::MapEnclosingClippedRect(
239 surface_quad
->shared_quad_state
->quad_to_target_transform
,
240 surface_quad
->visible_rect
));
241 if (surface_quad
->shared_quad_state
->is_clipped
) {
242 surface_quad_clip_rect
.rect
.Intersect(
243 surface_quad
->shared_quad_state
->clip_rect
);
246 ClipData quads_clip
=
247 CalculateClipRect(clip_rect
, surface_quad_clip_rect
, target_transform
);
249 CopyQuadsToPass(quads
, last_pass
.shared_quad_state_list
,
250 child_to_parent_map
, surface_transform
, quads_clip
,
251 dest_pass
, surface_id
);
253 RenderPassId remapped_pass_id
= RemapPassId(last_pass
.id
, surface_id
);
255 SharedQuadState
* shared_quad_state
=
256 CopySharedQuadState(surface_quad
->shared_quad_state
, target_transform
,
257 clip_rect
, dest_pass
);
259 RenderPassDrawQuad
* quad
=
260 dest_pass
->CreateAndAppendDrawQuad
<RenderPassDrawQuad
>();
261 quad
->SetNew(shared_quad_state
,
263 surface_quad
->visible_rect
,
273 referenced_surfaces_
.erase(it
);
276 SharedQuadState
* SurfaceAggregator::CopySharedQuadState(
277 const SharedQuadState
* source_sqs
,
278 const gfx::Transform
& target_transform
,
279 const ClipData
& clip_rect
,
280 RenderPass
* dest_render_pass
) {
281 SharedQuadState
* copy_shared_quad_state
=
282 dest_render_pass
->CreateAndAppendSharedQuadState();
283 copy_shared_quad_state
->CopyFrom(source_sqs
);
284 // target_transform contains any transformation that may exist
285 // between the context that these quads are being copied from (i.e. the
286 // surface's draw transform when aggregated from within a surface) to the
287 // target space of the pass. This will be identity except when copying the
288 // root draw pass from a surface into a pass when the surface draw quad's
289 // transform is not identity.
290 copy_shared_quad_state
->quad_to_target_transform
.ConcatTransform(
293 ClipData new_clip_rect
= CalculateClipRect(
294 clip_rect
, ClipData(source_sqs
->is_clipped
, source_sqs
->clip_rect
),
296 copy_shared_quad_state
->is_clipped
= new_clip_rect
.is_clipped
;
297 copy_shared_quad_state
->clip_rect
= new_clip_rect
.rect
;
298 return copy_shared_quad_state
;
301 static gfx::Rect
CalculateQuadSpaceDamageRect(
302 const gfx::Transform
& quad_to_target_transform
,
303 const gfx::Transform
& target_to_root_transform
,
304 const gfx::Rect
& root_damage_rect
) {
305 gfx::Transform
quad_to_root_transform(target_to_root_transform
,
306 quad_to_target_transform
);
307 gfx::Transform
inverse_transform(gfx::Transform::kSkipInitialization
);
308 bool inverse_valid
= quad_to_root_transform
.GetInverse(&inverse_transform
);
309 DCHECK(inverse_valid
);
311 return MathUtil::ProjectEnclosingClippedRect(inverse_transform
,
315 void SurfaceAggregator::CopyQuadsToPass(
316 const QuadList
& source_quad_list
,
317 const SharedQuadStateList
& source_shared_quad_state_list
,
318 const ResourceProvider::ResourceIdMap
& child_to_parent_map
,
319 const gfx::Transform
& target_transform
,
320 const ClipData
& clip_rect
,
321 RenderPass
* dest_pass
,
322 SurfaceId surface_id
) {
323 const SharedQuadState
* last_copied_source_shared_quad_state
= nullptr;
324 const SharedQuadState
* dest_shared_quad_state
= nullptr;
325 // If the current frame has copy requests then aggregate the entire
326 // thing, as otherwise parts of the copy requests may be ignored.
327 const bool ignore_undamaged
= aggregate_only_damaged_
&& !has_copy_requests_
;
328 // Damage rect in the quad space of the current shared quad state.
329 // TODO(jbauman): This rect may contain unnecessary area if
330 // transform isn't axis-aligned.
331 gfx::Rect damage_rect_in_quad_space
;
334 // If quads have come in with SharedQuadState out of order, or when quads have
335 // invalid SharedQuadState pointer, it should DCHECK.
336 SharedQuadStateList::ConstIterator sqs_iter
=
337 source_shared_quad_state_list
.begin();
338 for (const auto& quad
: source_quad_list
) {
339 while (sqs_iter
!= source_shared_quad_state_list
.end() &&
340 quad
->shared_quad_state
!= *sqs_iter
) {
343 DCHECK(sqs_iter
!= source_shared_quad_state_list
.end());
347 for (const auto& quad
: source_quad_list
) {
348 if (quad
->material
== DrawQuad::SURFACE_CONTENT
) {
349 const SurfaceDrawQuad
* surface_quad
= SurfaceDrawQuad::MaterialCast(quad
);
350 // HandleSurfaceQuad may add other shared quad state, so reset the
352 last_copied_source_shared_quad_state
= nullptr;
354 if (ignore_undamaged
) {
355 gfx::Transform
quad_to_target_transform(
357 quad
->shared_quad_state
->quad_to_target_transform
);
358 damage_rect_in_quad_space
= CalculateQuadSpaceDamageRect(
359 quad_to_target_transform
, dest_pass
->transform_to_root_target
,
361 if (!damage_rect_in_quad_space
.Intersects(quad
->visible_rect
))
364 HandleSurfaceQuad(surface_quad
, target_transform
, clip_rect
, dest_pass
);
366 if (quad
->shared_quad_state
!= last_copied_source_shared_quad_state
) {
367 dest_shared_quad_state
= CopySharedQuadState(
368 quad
->shared_quad_state
, target_transform
, clip_rect
, dest_pass
);
369 last_copied_source_shared_quad_state
= quad
->shared_quad_state
;
370 if (aggregate_only_damaged_
&& !has_copy_requests_
) {
371 damage_rect_in_quad_space
= CalculateQuadSpaceDamageRect(
372 dest_shared_quad_state
->quad_to_target_transform
,
373 dest_pass
->transform_to_root_target
, root_damage_rect_
);
377 if (ignore_undamaged
) {
378 if (!damage_rect_in_quad_space
.Intersects(quad
->visible_rect
))
383 if (quad
->material
== DrawQuad::RENDER_PASS
) {
384 const RenderPassDrawQuad
* pass_quad
=
385 RenderPassDrawQuad::MaterialCast(quad
);
386 RenderPassId original_pass_id
= pass_quad
->render_pass_id
;
387 RenderPassId remapped_pass_id
=
388 RemapPassId(original_pass_id
, surface_id
);
390 dest_quad
= dest_pass
->CopyFromAndAppendRenderPassDrawQuad(
391 pass_quad
, dest_shared_quad_state
, remapped_pass_id
);
394 dest_pass
->CopyFromAndAppendDrawQuad(quad
, dest_shared_quad_state
);
396 if (!child_to_parent_map
.empty()) {
397 for (ResourceId
& resource_id
: dest_quad
->resources
) {
398 ResourceProvider::ResourceIdMap::const_iterator it
=
399 child_to_parent_map
.find(resource_id
);
400 DCHECK(it
!= child_to_parent_map
.end());
402 DCHECK_EQ(it
->first
, resource_id
);
403 ResourceId remapped_id
= it
->second
;
404 resource_id
= remapped_id
;
411 void SurfaceAggregator::CopyPasses(const DelegatedFrameData
* frame_data
,
413 // The root surface is allowed to have copy output requests, so grab them
414 // off its render passes.
415 std::multimap
<RenderPassId
, CopyOutputRequest
*> copy_requests
;
416 surface
->TakeCopyOutputRequests(©_requests
);
418 const RenderPassList
& source_pass_list
= frame_data
->render_pass_list
;
419 DCHECK(valid_surfaces_
.count(surface
->surface_id()));
420 if (!valid_surfaces_
.count(surface
->surface_id()))
423 // TODO(vmpstr): provider check is a hack for unittests that don't set up a
424 // resource provider.
425 ResourceProvider::ResourceIdMap empty_map
;
426 const ResourceProvider::ResourceIdMap
& child_to_parent_map
=
427 provider_
? provider_
->GetChildToParentMap(ChildIdForSurface(surface
))
429 for (size_t i
= 0; i
< source_pass_list
.size(); ++i
) {
430 const RenderPass
& source
= *source_pass_list
[i
];
432 size_t sqs_size
= source
.shared_quad_state_list
.size();
433 size_t dq_size
= source
.quad_list
.size();
434 scoped_ptr
<RenderPass
> copy_pass(RenderPass::Create(sqs_size
, dq_size
));
436 MoveMatchingRequests(source
.id
, ©_requests
, ©_pass
->copy_requests
);
438 RenderPassId remapped_pass_id
=
439 RemapPassId(source
.id
, surface
->surface_id());
441 copy_pass
->SetAll(remapped_pass_id
, source
.output_rect
, gfx::Rect(),
442 source
.transform_to_root_target
,
443 source
.has_transparent_background
);
445 CopyQuadsToPass(source
.quad_list
, source
.shared_quad_state_list
,
446 child_to_parent_map
, gfx::Transform(), ClipData(),
447 copy_pass
.get(), surface
->surface_id());
449 dest_pass_list_
->push_back(copy_pass
.Pass());
453 void SurfaceAggregator::RemoveUnreferencedChildren() {
454 for (const auto& surface
: previous_contained_surfaces_
) {
455 if (!contained_surfaces_
.count(surface
.first
)) {
456 SurfaceToResourceChildIdMap::iterator it
=
457 surface_id_to_resource_child_id_
.find(surface
.first
);
458 if (it
!= surface_id_to_resource_child_id_
.end()) {
459 provider_
->DestroyChild(it
->second
);
460 surface_id_to_resource_child_id_
.erase(it
);
463 Surface
* surface_ptr
= manager_
->GetSurfaceForId(surface
.first
);
465 surface_ptr
->RunDrawCallbacks(SurfaceDrawStatus::DRAW_SKIPPED
);
470 // Walk the Surface tree from surface_id. Validate the resources of the current
471 // surface and its descendants, check if there are any copy requests, and
472 // return the combined damage rect.
473 gfx::Rect
SurfaceAggregator::PrewalkTree(SurfaceId surface_id
) {
474 if (referenced_surfaces_
.count(surface_id
))
476 Surface
* surface
= manager_
->GetSurfaceForId(surface_id
);
478 contained_surfaces_
[surface_id
] = 0;
481 contained_surfaces_
[surface_id
] = surface
->frame_index();
482 const CompositorFrame
* surface_frame
= surface
->GetEligibleFrame();
485 const DelegatedFrameData
* frame_data
=
486 surface_frame
->delegated_frame_data
.get();
490 // TODO(jbauman): hack for unit tests that don't set up rp
492 child_id
= ChildIdForSurface(surface
);
493 if (surface
->factory())
494 surface
->factory()->RefResources(frame_data
->resource_list
);
495 provider_
->ReceiveFromChild(child_id
, frame_data
->resource_list
);
498 ResourceProvider::ResourceIdSet referenced_resources
;
499 size_t reserve_size
= frame_data
->resource_list
.size();
500 #if defined(COMPILER_MSVC)
501 referenced_resources
.reserve(reserve_size
);
502 #elif defined(COMPILER_GCC)
503 // Pre-standard hash-tables only implement resize, which behaves similarly
504 // to reserve for these keys. Resizing to 0 may also be broken (particularly
506 // TODO(jbauman): Replace with reserve when C++11 is supported everywhere.
508 referenced_resources
.resize(reserve_size
);
511 bool invalid_frame
= false;
512 ResourceProvider::ResourceIdMap empty_map
;
513 const ResourceProvider::ResourceIdMap
& child_to_parent_map
=
514 provider_
? provider_
->GetChildToParentMap(child_id
) : empty_map
;
516 // Each pair in the vector is a child surface and the transform from its
517 // target to the root target of this surface.
518 std::vector
<std::pair
<SurfaceId
, gfx::Transform
>> child_surfaces
;
519 for (const auto& render_pass
: frame_data
->render_pass_list
) {
520 for (const auto& quad
: render_pass
->quad_list
) {
521 if (quad
->material
== DrawQuad::SURFACE_CONTENT
) {
522 const SurfaceDrawQuad
* surface_quad
=
523 SurfaceDrawQuad::MaterialCast(quad
);
524 gfx::Transform
target_to_surface_transform(
525 render_pass
->transform_to_root_target
,
526 surface_quad
->shared_quad_state
->quad_to_target_transform
);
527 child_surfaces
.push_back(std::make_pair(surface_quad
->surface_id
,
528 target_to_surface_transform
));
533 for (ResourceId resource_id
: quad
->resources
) {
534 if (!child_to_parent_map
.count(resource_id
)) {
535 invalid_frame
= true;
538 referenced_resources
.insert(resource_id
);
545 valid_surfaces_
.insert(surface
->surface_id());
548 provider_
->DeclareUsedResourcesFromChild(child_id
, referenced_resources
);
550 for (const auto& render_pass
: frame_data
->render_pass_list
)
551 has_copy_requests_
|= !render_pass
->copy_requests
.empty();
553 gfx::Rect damage_rect
;
554 if (!frame_data
->render_pass_list
.empty()) {
555 RenderPass
* last_pass
= frame_data
->render_pass_list
.back();
557 DamageRectForSurface(surface
, *last_pass
, last_pass
->output_rect
);
560 // Avoid infinite recursion by adding current surface to
561 // referenced_surfaces_.
562 SurfaceSet::iterator it
=
563 referenced_surfaces_
.insert(surface
->surface_id()).first
;
564 for (const auto& surface_info
: child_surfaces
) {
565 gfx::Rect surface_damage
= PrewalkTree(surface_info
.first
);
567 MathUtil::MapEnclosingClippedRect(surface_info
.second
, surface_damage
));
569 referenced_surfaces_
.erase(it
);
573 scoped_ptr
<CompositorFrame
> SurfaceAggregator::Aggregate(SurfaceId surface_id
) {
574 Surface
* surface
= manager_
->GetSurfaceForId(surface_id
);
576 contained_surfaces_
[surface_id
] = surface
->frame_index();
577 const CompositorFrame
* root_surface_frame
= surface
->GetEligibleFrame();
578 if (!root_surface_frame
)
580 TRACE_EVENT0("cc", "SurfaceAggregator::Aggregate");
582 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
583 frame
->delegated_frame_data
= make_scoped_ptr(new DelegatedFrameData
);
585 DCHECK(root_surface_frame
->delegated_frame_data
);
587 dest_resource_list_
= &frame
->delegated_frame_data
->resource_list
;
588 dest_pass_list_
= &frame
->delegated_frame_data
->render_pass_list
;
590 valid_surfaces_
.clear();
591 has_copy_requests_
= false;
592 root_damage_rect_
= PrewalkTree(surface_id
);
594 SurfaceSet::iterator it
= referenced_surfaces_
.insert(surface_id
).first
;
595 CopyPasses(root_surface_frame
->delegated_frame_data
.get(), surface
);
596 referenced_surfaces_
.erase(it
);
598 DCHECK(referenced_surfaces_
.empty());
600 if (dest_pass_list_
->empty())
602 dest_pass_list_
->back()->damage_rect
= root_damage_rect_
;
604 dest_pass_list_
= NULL
;
605 RemoveUnreferencedChildren();
606 contained_surfaces_
.swap(previous_contained_surfaces_
);
607 contained_surfaces_
.clear();
609 for (SurfaceIndexMap::iterator it
= previous_contained_surfaces_
.begin();
610 it
!= previous_contained_surfaces_
.end();
612 Surface
* surface
= manager_
->GetSurfaceForId(it
->first
);
614 surface
->TakeLatencyInfo(&frame
->metadata
.latency_info
);
617 // TODO(jamesr): Aggregate all resource references into the returned frame's
623 void SurfaceAggregator::ReleaseResources(SurfaceId surface_id
) {
624 SurfaceToResourceChildIdMap::iterator it
=
625 surface_id_to_resource_child_id_
.find(surface_id
);
626 if (it
!= surface_id_to_resource_child_id_
.end()) {
627 provider_
->DestroyChild(it
->second
);
628 surface_id_to_resource_child_id_
.erase(it
);
632 void SurfaceAggregator::SetFullDamageForSurface(SurfaceId surface_id
) {
633 auto it
= previous_contained_surfaces_
.find(surface_id
);
634 if (it
== previous_contained_surfaces_
.end())
636 // Set the last drawn index as 0 to ensure full damage next time it's drawn.