1 // Copyright 2012 The Chromium Authors
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/tiles/tile_manager.h"
13 #include "base/bind.h"
14 #include "base/containers/contains.h"
15 #include "base/json/json_writer.h"
16 #include "base/logging.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/metrics/histogram.h"
19 #include "base/notreached.h"
20 #include "base/numerics/safe_conversions.h"
21 #include "base/ranges/algorithm.h"
22 #include "base/synchronization/waitable_event.h"
23 #include "base/threading/thread_checker.h"
24 #include "base/trace_event/traced_value.h"
25 #include "cc/base/devtools_instrumentation.h"
26 #include "cc/base/histograms.h"
27 #include "cc/layers/picture_layer_impl.h"
28 #include "cc/paint/display_item_list.h"
29 #include "cc/raster/paint_worklet_image_provider.h"
30 #include "cc/raster/playback_image_provider.h"
31 #include "cc/raster/raster_buffer.h"
32 #include "cc/raster/task_category.h"
33 #include "cc/tiles/frame_viewer_instrumentation.h"
34 #include "cc/tiles/tile.h"
35 #include "cc/tiles/tiles_with_resource_iterator.h"
36 #include "components/viz/common/resources/resource_sizes.h"
37 #include "third_party/abseil-cpp/absl/types/optional.h"
38 #include "ui/gfx/geometry/axis_transform2d.h"
39 #include "ui/gfx/geometry/rect_conversions.h"
44 // Flag to indicate whether we should try and detect that
45 // a tile is of solid color.
46 const bool kUseColorEstimator = true;
48 // This class is wrapper for both ImageProvider and PaintWorkletImageProvider,
49 // which is used in RasterSource::PlaybackSettings. It looks at the draw image
50 // and decides which one of the two providers to dispatch the request to.
51 class DispatchingImageProvider : public ImageProvider {
53 DispatchingImageProvider(
54 PlaybackImageProvider playback_image_provider,
55 PaintWorkletImageProvider paint_worklet_image_provider)
56 : playback_image_provider_(std::move(playback_image_provider)),
57 paint_worklet_image_provider_(std::move(paint_worklet_image_provider)) {
59 DispatchingImageProvider(const DispatchingImageProvider&) = delete;
60 ~DispatchingImageProvider() override = default;
62 DispatchingImageProvider& operator=(const DispatchingImageProvider&) = delete;
64 DispatchingImageProvider(DispatchingImageProvider&& other) = default;
66 ImageProvider::ScopedResult GetRasterContent(
67 const DrawImage& draw_image) override {
68 return draw_image.paint_image().IsPaintWorklet()
69 ? paint_worklet_image_provider_.GetPaintRecordResult(
70 draw_image.paint_image().paint_worklet_input())
71 : playback_image_provider_.GetRasterContent(draw_image);
75 PlaybackImageProvider playback_image_provider_;
76 PaintWorkletImageProvider paint_worklet_image_provider_;
79 class RasterTaskImpl : public TileTask {
81 RasterTaskImpl(TileManager* tile_manager,
83 ResourcePool::InUsePoolResource resource,
84 scoped_refptr<RasterSource> raster_source,
85 const RasterSource::PlaybackSettings& playback_settings,
86 TileResolution tile_resolution,
87 gfx::Rect invalidated_rect,
88 uint64_t source_prepare_tiles_id,
89 std::unique_ptr<RasterBuffer> raster_buffer,
90 TileTask::Vector* dependencies,
91 bool is_gpu_rasterization,
92 DispatchingImageProvider image_provider,
95 is_gpu_rasterization ? TileTask::SupportsConcurrentExecution::kNo
96 : TileTask::SupportsConcurrentExecution::kYes,
97 raster_buffer && raster_buffer->SupportsBackgroundThreadPriority()
98 ? TileTask::SupportsBackgroundThreadPriority::kYes
99 : TileTask::SupportsBackgroundThreadPriority::kNo,
101 tile_manager_(tile_manager),
102 tile_id_(tile->id()),
103 resource_(std::move(resource)),
104 raster_source_(std::move(raster_source)),
105 content_rect_(tile->content_rect()),
106 invalid_content_rect_(invalidated_rect),
107 raster_transform_(tile->raster_transform()),
108 playback_settings_(playback_settings),
109 tile_resolution_(tile_resolution),
110 layer_id_(tile->layer_id()),
111 source_prepare_tiles_id_(source_prepare_tiles_id),
112 tile_tracing_id_(static_cast<void*>(tile)),
113 new_content_id_(tile->id()),
114 source_frame_number_(tile->source_frame_number()),
115 raster_buffer_(std::move(raster_buffer)),
116 image_provider_(std::move(image_provider)),
117 url_(std::move(url)) {
118 DCHECK(origin_thread_checker_.CalledOnValidThread());
119 playback_settings_.image_provider = &image_provider_;
121 RasterTaskImpl(const RasterTaskImpl&) = delete;
122 RasterTaskImpl& operator=(const RasterTaskImpl&) = delete;
124 // Overridden from Task:
125 void RunOnWorkerThread() override {
126 TRACE_EVENT1("cc", "RasterizerTaskImpl::RunOnWorkerThread",
127 "source_prepare_tiles_id", source_prepare_tiles_id_);
129 DCHECK(raster_source_.get());
130 DCHECK(raster_buffer_);
132 frame_viewer_instrumentation::ScopedRasterTask raster_task(
133 tile_tracing_id_, tile_resolution_, source_frame_number_, layer_id_);
135 DCHECK(raster_source_);
137 raster_buffer_->Playback(raster_source_.get(), content_rect_,
138 invalid_content_rect_, new_content_id_,
139 raster_transform_, playback_settings_, url_);
142 // Overridden from TileTask:
143 void OnTaskCompleted() override {
144 DCHECK(origin_thread_checker_.CalledOnValidThread());
146 // Here calling state().IsCanceled() is thread-safe, because this task is
147 // already concluded as FINISHED or CANCELLED and no longer will be worked
148 // upon by task graph runner.
149 raster_buffer_ = nullptr;
150 tile_manager_->OnRasterTaskCompleted(tile_id_, std::move(resource_),
151 state().IsCanceled());
155 ~RasterTaskImpl() override {
156 DCHECK(origin_thread_checker_.CalledOnValidThread());
157 DCHECK(!raster_buffer_);
162 base::ThreadChecker origin_thread_checker_;
164 // The following members are needed for processing completion of this task on
165 // origin thread. These are not thread-safe and should be accessed only in
166 // origin thread. Ensure their access by checking CalledOnValidThread().
167 raw_ptr<TileManager> tile_manager_;
169 ResourcePool::InUsePoolResource resource_;
171 // The following members should be used for running the task.
172 scoped_refptr<RasterSource> raster_source_;
173 gfx::Rect content_rect_;
174 gfx::Rect invalid_content_rect_;
175 gfx::AxisTransform2d raster_transform_;
176 RasterSource::PlaybackSettings playback_settings_;
177 TileResolution tile_resolution_;
179 uint64_t source_prepare_tiles_id_;
180 // TODO(crbug.com/1298696): views_unittests breaks with MTECheckedPtr
182 raw_ptr<void, DanglingUntriagedDegradeToNoOpWhenMTE> tile_tracing_id_;
183 uint64_t new_content_id_;
184 int source_frame_number_;
185 std::unique_ptr<RasterBuffer> raster_buffer_;
186 DispatchingImageProvider image_provider_;
190 TaskCategory TaskCategoryForTileTask(TileTask* task,
191 bool use_foreground_category) {
192 if (!task->supports_concurrent_execution())
193 return TASK_CATEGORY_NONCONCURRENT_FOREGROUND;
195 if (use_foreground_category)
196 return TASK_CATEGORY_FOREGROUND;
198 if (!task->supports_background_thread_priority())
199 return TASK_CATEGORY_BACKGROUND_WITH_NORMAL_THREAD_PRIORITY;
201 return TASK_CATEGORY_BACKGROUND;
204 bool IsForegroundCategory(uint16_t category) {
205 TaskCategory enum_category = static_cast<TaskCategory>(category);
206 switch (enum_category) {
207 case TASK_CATEGORY_NONCONCURRENT_FOREGROUND:
208 case TASK_CATEGORY_FOREGROUND:
210 case TASK_CATEGORY_BACKGROUND:
211 case TASK_CATEGORY_BACKGROUND_WITH_NORMAL_THREAD_PRIORITY:
219 // Task priorities that make sure that the task set done tasks run before any
220 // other remaining tasks.
221 const size_t kRequiredForActivationDoneTaskPriority = 1u;
222 const size_t kRequiredForDrawDoneTaskPriority = 2u;
223 const size_t kAllDoneTaskPriority = 3u;
225 // For correctness, |kTileTaskPriorityBase| must be greater than
226 // all task set done task priorities.
227 size_t kTileTaskPriorityBase = 10u;
229 void InsertNodeForTask(TaskGraph* graph,
233 size_t dependencies) {
234 DCHECK(!base::Contains(graph->nodes, task, &TaskGraph::Node::task));
235 graph->nodes.emplace_back(task, category, priority, dependencies);
238 void InsertNodeForDecodeTask(TaskGraph* graph,
240 bool use_foreground_category,
242 uint32_t dependency_count = 0u;
243 if (task->dependencies().size()) {
244 DCHECK_EQ(task->dependencies().size(), 1u);
245 auto* dependency = task->dependencies()[0].get();
246 if (!dependency->HasCompleted()) {
247 InsertNodeForDecodeTask(graph, dependency, use_foreground_category,
249 graph->edges.emplace_back(dependency, task);
250 dependency_count = 1u;
253 InsertNodeForTask(graph, task,
254 TaskCategoryForTileTask(task, use_foreground_category),
255 priority, dependency_count);
258 void InsertNodesForRasterTask(TaskGraph* graph,
259 TileTask* raster_task,
260 const TileTask::Vector& decode_tasks,
262 bool use_foreground_category) {
263 size_t dependencies = 0u;
265 // Insert image decode tasks.
266 for (auto it = decode_tasks.begin(); it != decode_tasks.end(); ++it) {
267 TileTask* decode_task = it->get();
269 // Skip if already decoded.
270 if (decode_task->HasCompleted())
275 // Add decode task if it doesn't already exist in graph.
277 base::ranges::find(graph->nodes, decode_task, &TaskGraph::Node::task);
279 // In rare circumstances, a background category task may come in before a
280 // foreground category task. In these cases, upgrade any background category
281 // dependencies of the current task.
282 // TODO(ericrk): Task iterators should be updated to avoid this.
284 // TODO(ericrk): This should handle dependencies recursively.
286 if (decode_it != graph->nodes.end() && use_foreground_category &&
287 !IsForegroundCategory(decode_it->category)) {
288 decode_it->category = TASK_CATEGORY_FOREGROUND;
291 if (decode_it == graph->nodes.end()) {
292 InsertNodeForDecodeTask(graph, decode_task, use_foreground_category,
296 graph->edges.emplace_back(decode_task, raster_task);
301 TaskCategoryForTileTask(raster_task, use_foreground_category), priority,
305 class TaskSetFinishedTaskImpl : public TileTask {
307 explicit TaskSetFinishedTaskImpl(
308 base::SequencedTaskRunner* task_runner,
309 base::RepeatingClosure on_task_set_finished_callback)
310 : TileTask(TileTask::SupportsConcurrentExecution::kYes,
311 TileTask::SupportsBackgroundThreadPriority::kYes),
312 task_runner_(task_runner),
313 on_task_set_finished_callback_(
314 std::move(on_task_set_finished_callback)) {}
315 TaskSetFinishedTaskImpl(const TaskSetFinishedTaskImpl&) = delete;
316 TaskSetFinishedTaskImpl& operator=(const TaskSetFinishedTaskImpl&) = delete;
318 // Overridden from Task:
319 void RunOnWorkerThread() override {
320 TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread");
324 // Overridden from TileTask:
325 void OnTaskCompleted() override {}
328 ~TaskSetFinishedTaskImpl() override = default;
330 void TaskSetFinished() {
331 task_runner_->PostTask(FROM_HERE, on_task_set_finished_callback_);
335 raw_ptr<base::SequencedTaskRunner> task_runner_;
336 const base::RepeatingClosure on_task_set_finished_callback_;
339 class DidFinishRunningAllTilesTask : public TileTask {
341 using CompletionCb = base::OnceCallback<void(bool has_pending_queries)>;
342 DidFinishRunningAllTilesTask(base::SequencedTaskRunner* task_runner,
343 RasterQueryQueue* pending_raster_queries,
344 CompletionCb completion_cb)
345 : TileTask(TileTask::SupportsConcurrentExecution::kNo,
346 TileTask::SupportsBackgroundThreadPriority::kYes),
347 task_runner_(task_runner),
348 pending_raster_queries_(pending_raster_queries),
349 completion_cb_(std::move(completion_cb)) {}
351 void RunOnWorkerThread() override {
352 TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread");
353 bool has_pending_queries = false;
354 if (pending_raster_queries_) {
355 has_pending_queries =
356 pending_raster_queries_->CheckRasterFinishedQueries();
358 task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(completion_cb_),
359 has_pending_queries));
362 void OnTaskCompleted() override {}
365 ~DidFinishRunningAllTilesTask() override = default;
368 raw_ptr<base::SequencedTaskRunner> task_runner_;
369 raw_ptr<RasterQueryQueue, DanglingUntriaged> pending_raster_queries_;
370 CompletionCb completion_cb_;
373 gfx::ContentColorUsage GetContentColorUsageForPrioritizedTile(
374 const PrioritizedTile& prioritized_tile) {
375 return prioritized_tile.raster_source()
376 ->GetDisplayItemList()
377 ->discardable_image_map()
378 .content_color_usage();
383 RasterTaskCompletionStats::RasterTaskCompletionStats()
384 : completed_count(0u), canceled_count(0u) {}
386 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
387 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
388 std::unique_ptr<base::trace_event::TracedValue> state(
389 new base::trace_event::TracedValue());
390 state->SetInteger("completed_count",
391 base::saturated_cast<int>(stats.completed_count));
392 state->SetInteger("canceled_count",
393 base::saturated_cast<int>(stats.canceled_count));
394 return std::move(state);
397 TileManager::TileManager(
398 TileManagerClient* client,
399 base::SequencedTaskRunner* origin_task_runner,
400 scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner,
401 size_t scheduled_raster_task_limit,
402 const TileManagerSettings& tile_manager_settings)
404 task_runner_(origin_task_runner),
405 resource_pool_(nullptr),
406 tile_task_manager_(nullptr),
407 scheduled_raster_task_limit_(scheduled_raster_task_limit),
408 tile_manager_settings_(tile_manager_settings),
409 use_gpu_rasterization_(false),
410 all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
411 did_check_for_completed_tasks_since_last_schedule_tasks_(true),
412 did_oom_on_last_assign_(false),
413 image_controller_(origin_task_runner,
414 std::move(image_worker_task_runner)),
415 decoded_image_tracker_(&image_controller_, origin_task_runner),
416 checker_image_tracker_(&image_controller_,
418 tile_manager_settings_.enable_checker_imaging,
419 tile_manager_settings_.min_image_bytes_to_checker),
420 more_tiles_need_prepare_check_notifier_(
422 base::BindRepeating(&TileManager::CheckIfMoreTilesNeedToBePrepared,
423 base::Unretained(this))),
424 signals_check_notifier_(
426 base::BindRepeating(&TileManager::FlushAndIssueSignals,
427 base::Unretained(this))),
428 has_scheduled_tile_tasks_(false),
429 prepare_tiles_count_(0u),
432 TileManager::~TileManager() {
433 FinishTasksAndCleanUp();
436 void TileManager::FinishTasksAndCleanUp() {
437 if (!tile_task_manager_)
440 global_state_ = GlobalStateThatImpactsTilePriority();
442 // This must be signalled before the Shutdown call below so that if there are
443 // any pending tasks on the worker thread that might be waiting on tasks
444 // posted to this thread they are cancelled.
445 shutdown_event_.Signal();
447 // This cancels tasks if possible, finishes pending tasks, and release any
448 // uninitialized resources.
449 tile_task_manager_->Shutdown();
451 // Reset the signal since SetResources() might be called later.
452 shutdown_event_.Reset();
454 raster_buffer_provider_->Shutdown();
456 tile_task_manager_->CheckForCompletedTasks();
458 tile_task_manager_ = nullptr;
459 resource_pool_ = nullptr;
460 pending_raster_queries_ = nullptr;
461 more_tiles_need_prepare_check_notifier_.Cancel();
462 signals_check_notifier_.Cancel();
463 task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
464 ready_to_draw_callback_weak_ptr_factory_.InvalidateWeakPtrs();
465 check_pending_tile_queries_callback_.Cancel();
466 raster_buffer_provider_ = nullptr;
468 // Ask the tracker to drop any locked decodes since we will be destroying the
470 bool can_clear_decode_policy_tracking = false;
471 checker_image_tracker_.ClearTracker(can_clear_decode_policy_tracking);
472 image_controller_.SetImageDecodeCache(nullptr);
473 locked_image_tasks_.clear();
476 void TileManager::SetResources(ResourcePool* resource_pool,
477 ImageDecodeCache* image_decode_cache,
478 TaskGraphRunner* task_graph_runner,
479 RasterBufferProvider* raster_buffer_provider,
480 bool use_gpu_rasterization,
481 RasterQueryQueue* pending_raster_queries) {
482 DCHECK(!tile_task_manager_);
483 DCHECK(task_graph_runner);
485 use_gpu_rasterization_ = use_gpu_rasterization;
486 pending_raster_queries_ = pending_raster_queries;
487 resource_pool_ = resource_pool;
488 image_controller_.SetImageDecodeCache(image_decode_cache);
489 tile_task_manager_ = TileTaskManagerImpl::Create(task_graph_runner);
490 raster_buffer_provider_ = raster_buffer_provider;
492 raster_buffer_provider_->SetShutdownEvent(&shutdown_event_);
495 void TileManager::Release(Tile* tile) {
496 if (tile->raster_task_scheduled_with_checker_images())
497 num_of_tiles_with_checker_images_--;
498 DCHECK_GE(num_of_tiles_with_checker_images_, 0);
500 FreeResourcesForTile(tile);
501 tiles_.erase(tile->id());
504 void TileManager::DidFinishRunningTileTasksRequiredForActivation() {
506 "TileManager::DidFinishRunningTileTasksRequiredForActivation");
507 TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("cc", "ScheduledTasksState",
508 TRACE_ID_LOCAL(this), "state",
509 ScheduledTasksStateAsValue());
510 // TODO(vmpstr): Temporary check to debug crbug.com/642927.
511 CHECK(tile_task_manager_);
512 signals_.activate_tile_tasks_completed = true;
513 signals_check_notifier_.Schedule();
516 void TileManager::DidFinishRunningTileTasksRequiredForDraw() {
517 TRACE_EVENT0("cc", "TileManager::DidFinishRunningTileTasksRequiredForDraw");
518 TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("cc", "ScheduledTasksState",
519 TRACE_ID_LOCAL(this), "state",
520 ScheduledTasksStateAsValue());
521 // TODO(vmpstr): Temporary check to debug crbug.com/642927.
522 CHECK(tile_task_manager_);
523 signals_.draw_tile_tasks_completed = true;
524 signals_check_notifier_.Schedule();
527 void TileManager::DidFinishRunningAllTileTasks(bool has_pending_queries) {
528 TRACE_EVENT0("cc", "TileManager::DidFinishRunningAllTileTasks");
529 TRACE_EVENT_NESTABLE_ASYNC_END0("cc", "ScheduledTasks", TRACE_ID_LOCAL(this));
530 DCHECK(resource_pool_);
531 DCHECK(tile_task_manager_);
533 has_scheduled_tile_tasks_ = false;
534 has_pending_queries_ = has_pending_queries;
536 if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
537 !resource_pool_->ResourceUsageTooHigh()) {
538 // TODO(ericrk): We should find a better way to safely handle re-entrant
539 // notifications than always having to schedule a new task.
540 // http://crbug.com/498439
541 // TODO(vmpstr): Temporary check to debug crbug.com/642927.
542 CHECK(tile_task_manager_);
543 signals_.all_tile_tasks_completed = true;
544 signals_check_notifier_.Schedule();
548 more_tiles_need_prepare_check_notifier_.Schedule();
551 bool TileManager::PrepareTiles(
552 const GlobalStateThatImpactsTilePriority& state) {
553 ++prepare_tiles_count_;
555 TRACE_EVENT1("cc,benchmark", "TileManager::PrepareTiles", "prepare_tiles_id",
556 prepare_tiles_count_);
558 if (!tile_task_manager_) {
559 TRACE_EVENT_INSTANT0("cc", "PrepareTiles aborted",
560 TRACE_EVENT_SCOPE_THREAD);
564 signals_ = Signals();
565 global_state_ = state;
567 // Ensure that we don't schedule any decode work for checkered images until
568 // the raster work for visible tiles is complete. This is done in
569 // FlushAndIssueSignals when the ready to activate/draw signals are dispatched
571 checker_image_tracker_.SetNoDecodesAllowed();
573 // We need to call CheckForCompletedTasks() once in-between each call
574 // to ScheduleTasks() to prevent canceled tasks from being scheduled.
575 if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
576 tile_task_manager_->CheckForCompletedTasks();
577 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
580 if (!ShouldRasterOccludedTiles())
581 FreeResourcesForOccludedTiles();
583 PrioritizedWorkToSchedule prioritized_work = AssignGpuMemoryToTiles();
585 // Inform the client that will likely require a draw if the highest priority
586 // tile that will be rasterized is required for draw.
587 client_->SetIsLikelyToRequireADraw(
588 !prioritized_work.tiles_to_raster.empty() &&
589 prioritized_work.tiles_to_raster.front().tile()->required_for_draw());
591 // Schedule tile tasks.
592 ScheduleTasks(std::move(prioritized_work));
594 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
595 "state", BasicStateAsValue());
599 void TileManager::CheckForCompletedTasks() {
600 TRACE_EVENT0("cc", "TileManager::CheckForCompletedTasks");
602 if (!tile_task_manager_) {
603 TRACE_EVENT_INSTANT0("cc", "TileManager::CheckForCompletedTasksAborted",
604 TRACE_EVENT_SCOPE_THREAD);
608 tile_task_manager_->CheckForCompletedTasks();
609 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
611 CheckPendingGpuWorkAndIssueSignals();
613 TRACE_EVENT_INSTANT1(
614 "cc", "TileManager::CheckForCompletedTasksFinished",
615 TRACE_EVENT_SCOPE_THREAD, "stats",
616 RasterTaskCompletionStatsAsValue(raster_task_completion_stats_));
617 raster_task_completion_stats_ = RasterTaskCompletionStats();
620 void TileManager::DidModifyTilePriorities() {
621 pending_tile_requirements_dirty_ = true;
624 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
625 TileManager::BasicStateAsValue() const {
626 std::unique_ptr<base::trace_event::TracedValue> value(
627 new base::trace_event::TracedValue());
628 BasicStateAsValueInto(value.get());
629 return std::move(value);
632 void TileManager::BasicStateAsValueInto(
633 base::trace_event::TracedValue* state) const {
634 state->SetInteger("tile_count", base::saturated_cast<int>(tiles_.size()));
635 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
636 state->BeginDictionary("global_state");
637 global_state_.AsValueInto(state);
638 state->EndDictionary();
641 std::unique_ptr<EvictionTilePriorityQueue>
642 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
643 std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
644 const MemoryUsage& limit,
645 MemoryUsage* usage) {
646 while (usage->Exceeds(limit)) {
647 if (!eviction_priority_queue) {
648 eviction_priority_queue =
649 client_->BuildEvictionQueue(global_state_.tree_priority);
651 if (eviction_priority_queue->IsEmpty())
654 Tile* tile = eviction_priority_queue->Top().tile();
655 *usage -= MemoryUsage::FromTile(tile);
656 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
657 eviction_priority_queue->Pop();
659 return eviction_priority_queue;
662 std::unique_ptr<EvictionTilePriorityQueue>
663 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
664 std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
665 const MemoryUsage& limit,
666 const TilePriority& other_priority,
667 MemoryUsage* usage) {
668 while (usage->Exceeds(limit)) {
669 if (!eviction_priority_queue) {
670 eviction_priority_queue =
671 client_->BuildEvictionQueue(global_state_.tree_priority);
673 if (eviction_priority_queue->IsEmpty())
676 const PrioritizedTile& prioritized_tile = eviction_priority_queue->Top();
677 if (!other_priority.IsHigherPriorityThan(prioritized_tile.priority()))
680 Tile* tile = prioritized_tile.tile();
681 *usage -= MemoryUsage::FromTile(tile);
682 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
683 eviction_priority_queue->Pop();
685 return eviction_priority_queue;
688 bool TileManager::TilePriorityViolatesMemoryPolicy(
689 const TilePriority& priority) {
690 switch (global_state_.memory_limit_policy) {
693 case ALLOW_ABSOLUTE_MINIMUM:
694 return priority.priority_bin > TilePriority::NOW;
695 case ALLOW_PREPAINT_ONLY:
696 return priority.priority_bin > TilePriority::SOON;
698 return priority.distance_to_visible ==
699 std::numeric_limits<float>::infinity();
705 TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
706 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
708 DCHECK(resource_pool_);
709 DCHECK(tile_task_manager_);
711 // Now give memory out to the tiles until we're out, and build
712 // the needs-to-be-rasterized queue.
713 unsigned schedule_priority = 1u;
714 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
715 bool had_enough_memory_to_schedule_tiles_needed_now = true;
717 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
718 global_state_.num_resources_limit);
719 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
720 global_state_.num_resources_limit);
721 MemoryUsage memory_usage(resource_pool_->memory_usage_bytes(),
722 resource_pool_->resource_count());
724 std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue(
725 client_->BuildRasterQueue(global_state_.tree_priority,
726 RasterTilePriorityQueue::Type::ALL));
727 std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue;
728 PrioritizedWorkToSchedule work_to_schedule;
729 const bool raster_occluded_tiles = ShouldRasterOccludedTiles();
730 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
731 const PrioritizedTile& prioritized_tile = raster_priority_queue->Top();
732 Tile* tile = prioritized_tile.tile();
733 TilePriority priority = prioritized_tile.priority();
735 if (TilePriorityViolatesMemoryPolicy(priority)) {
736 TRACE_EVENT_INSTANT0(
737 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
738 TRACE_EVENT_SCOPE_THREAD);
742 DCHECK(!prioritized_tile.is_occluded() || raster_occluded_tiles);
744 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
745 if (!tile->is_solid_color_analysis_performed() &&
746 tile->use_picture_analysis() && kUseColorEstimator) {
747 // We analyze for solid color here, to decide to continue
748 // or drop the tile for scheduling and raster.
749 tile->set_solid_color_analysis_performed(true);
750 SkColor4f color = SkColors::kTransparent;
751 bool is_solid_color =
752 prioritized_tile.raster_source()->PerformSolidColorAnalysis(
753 tile->enclosing_layer_rect(), &color);
754 if (is_solid_color) {
755 tile->draw_info().set_solid_color(color);
756 client_->NotifyTileStateChanged(tile);
761 // Prepaint tiles that are far away are only processed for images.
762 if (tile->is_prepaint() && prioritized_tile.is_process_for_images_only()) {
763 work_to_schedule.tiles_to_process_for_images.push_back(prioritized_tile);
767 auto content_color_usage =
768 GetContentColorUsageForPrioritizedTile(prioritized_tile);
769 const auto target_color_params =
770 client_->GetTargetColorParams(content_color_usage);
772 // Tiles in the raster queue should either require raster or decode for
773 // checker-images. If this tile does not need raster, process it only to
774 // build the decode queue for checkered images.
775 // Note that performing this check after the solid color analysis is not
776 // necessary for correctness.
777 if (!tile->draw_info().NeedsRaster()) {
778 DCHECK(tile->draw_info().is_checker_imaged());
779 DCHECK(prioritized_tile.should_decode_checkered_images_for_tile());
781 AddCheckeredImagesToDecodeQueue(
782 prioritized_tile, target_color_params,
783 CheckerImageTracker::DecodeType::kRaster,
784 &work_to_schedule.checker_image_decode_queue);
788 // We won't be able to schedule this tile, so break out early.
789 if (work_to_schedule.tiles_to_raster.size() >=
790 scheduled_raster_task_limit_) {
791 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
795 DCHECK(tile->draw_info().mode() == TileDrawInfo::OOM_MODE ||
796 !tile->draw_info().IsReadyToDraw());
798 // If the tile already has a raster_task, then the memory used by it is
799 // already accounted for in memory_usage. Otherwise, we'll have to acquire
800 // more memory to create a raster task.
801 MemoryUsage memory_required_by_tile_to_be_scheduled;
802 if (!tile->raster_task_.get()) {
803 memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
804 tile->desired_texture_size(), DetermineResourceFormat(tile));
807 // This is the memory limit that will be used by this tile. Depending on
808 // the tile priority, it will be one of hard_memory_limit or
809 // soft_memory_limit.
810 MemoryUsage& tile_memory_limit =
811 tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
813 const MemoryUsage& scheduled_tile_memory_limit =
814 tile_memory_limit - memory_required_by_tile_to_be_scheduled;
815 eviction_priority_queue =
816 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
817 std::move(eviction_priority_queue), scheduled_tile_memory_limit,
818 priority, &memory_usage);
819 bool memory_usage_is_within_limit =
820 !memory_usage.Exceeds(scheduled_tile_memory_limit);
822 // If we couldn't fit the tile into our current memory limit, then we're
824 if (!memory_usage_is_within_limit) {
825 if (tile_is_needed_now) {
826 LOG(ERROR) << "WARNING: tile memory limits exceeded, some content may "
829 had_enough_memory_to_schedule_tiles_needed_now = false;
831 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
835 // If the tile has a scheduled task that will rasterize a resource with
836 // checker-imaged content, add those images to the decode queue. Note that
837 // we add all images as we process the raster priority queue to ensure that
838 // images are added to the decode queue in raster priority order.
839 if (tile->HasRasterTask()) {
840 if (tile->raster_task_scheduled_with_checker_images() &&
841 prioritized_tile.should_decode_checkered_images_for_tile()) {
842 AddCheckeredImagesToDecodeQueue(
843 prioritized_tile, target_color_params,
844 CheckerImageTracker::DecodeType::kRaster,
845 &work_to_schedule.checker_image_decode_queue);
848 // Creating the raster task here will acquire resources, but
849 // this resource usage has already been accounted for above.
850 auto raster_task = CreateRasterTask(prioritized_tile, target_color_params,
856 tile->raster_task_ = std::move(raster_task);
859 tile->scheduled_priority_ = schedule_priority++;
860 memory_usage += memory_required_by_tile_to_be_scheduled;
861 work_to_schedule.tiles_to_raster.push_back(prioritized_tile);
864 // Note that we should try and further reduce memory in case the above loop
865 // didn't reduce memory. This ensures that we always release as many resources
866 // as possible to stay within the memory limit.
867 eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
868 std::move(eviction_priority_queue), hard_memory_limit, &memory_usage);
870 // At this point, if we ran out of memory when allocating resources and we
871 // couldn't go past even the NOW bin, this means we have evicted resources
872 // from all tiles with a lower priority while we still might have resources
873 // holding checker-imaged content. The invalidations for these resources will
874 // be generated only if the skipped images are decoded. So we must schedule
875 // decodes for these tiles to update their content.
876 if (!had_enough_memory_to_schedule_tiles_needed_now &&
877 num_of_tiles_with_checker_images_ > 0) {
878 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
879 const PrioritizedTile& prioritized_tile = raster_priority_queue->Top();
881 if (prioritized_tile.priority().priority_bin > TilePriority::NOW)
884 if (!prioritized_tile.should_decode_checkered_images_for_tile())
887 auto content_color_usage =
888 GetContentColorUsageForPrioritizedTile(prioritized_tile);
889 const auto target_color_params =
890 client_->GetTargetColorParams(content_color_usage);
892 Tile* tile = prioritized_tile.tile();
893 if (tile->draw_info().is_checker_imaged() ||
894 tile->raster_task_scheduled_with_checker_images()) {
895 AddCheckeredImagesToDecodeQueue(
896 prioritized_tile, target_color_params,
897 CheckerImageTracker::DecodeType::kRaster,
898 &work_to_schedule.checker_image_decode_queue);
903 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
905 memory_stats_from_last_assign_.total_budget_in_bytes =
906 global_state_.hard_memory_limit_in_bytes;
907 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
908 DCHECK_GE(memory_stats_from_last_assign_.total_bytes_used, 0);
909 memory_stats_from_last_assign_.had_enough_memory =
910 had_enough_memory_to_schedule_tiles_needed_now;
912 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
913 "all_tiles_that_need_to_be_rasterized_are_scheduled",
914 all_tiles_that_need_to_be_rasterized_are_scheduled_,
915 "had_enough_memory_to_schedule_tiles_needed_now",
916 had_enough_memory_to_schedule_tiles_needed_now);
917 image_controller_.cache()->RecordStats();
918 return work_to_schedule;
921 void TileManager::FreeResourcesForOccludedTiles() {
922 std::unique_ptr<TilesWithResourceIterator> iterator =
923 client_->CreateTilesWithResourceIterator();
924 for (; !iterator->AtEnd(); iterator->Next()) {
925 if (iterator->IsCurrentTileOccluded())
926 FreeResourcesForTile(iterator->GetCurrent());
930 void TileManager::FreeResourcesForTile(Tile* tile) {
931 TileDrawInfo& draw_info = tile->draw_info();
933 if (draw_info.is_checker_imaged())
934 num_of_tiles_with_checker_images_--;
935 DCHECK_GE(num_of_tiles_with_checker_images_, 0);
937 if (draw_info.has_resource()) {
938 resource_pool_->ReleaseResource(draw_info.TakeResource());
939 pending_gpu_work_tiles_.erase(tile);
943 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
945 bool was_ready_to_draw = tile->draw_info().IsReadyToDraw();
946 FreeResourcesForTile(tile);
947 if (was_ready_to_draw)
948 client_->NotifyTileStateChanged(tile);
951 void TileManager::PartitionImagesForCheckering(
952 const PrioritizedTile& prioritized_tile,
953 const TargetColorParams& target_color_params,
954 std::vector<DrawImage>* sync_decoded_images,
955 std::vector<PaintImage>* checkered_images,
956 const gfx::Rect* invalidated_rect,
957 base::flat_map<PaintImage::Id, size_t>* image_to_frame_index) {
958 Tile* tile = prioritized_tile.tile();
959 std::vector<const DrawImage*> images_in_tile;
960 gfx::Rect enclosing_rect = tile->enclosing_layer_rect();
961 if (invalidated_rect) {
962 enclosing_rect = ToEnclosingRect(
963 tile->raster_transform().InverseMapRect(gfx::RectF(*invalidated_rect)));
965 prioritized_tile.raster_source()->GetDiscardableImagesInRect(enclosing_rect,
967 WhichTree tree = tile->tiling()->tree();
969 for (const auto* original_draw_image : images_in_tile) {
970 const auto& image = original_draw_image->paint_image();
971 size_t frame_index = client_->GetFrameIndexForImage(image, tree);
972 if (image_to_frame_index)
973 (*image_to_frame_index)[image.stable_id()] = frame_index;
975 DrawImage draw_image(*original_draw_image, tile->contents_scale_key(),
976 frame_index, target_color_params);
977 if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree))
978 checkered_images->push_back(draw_image.paint_image());
980 sync_decoded_images->push_back(std::move(draw_image));
984 void TileManager::AddCheckeredImagesToDecodeQueue(
985 const PrioritizedTile& prioritized_tile,
986 const TargetColorParams& target_color_params,
987 CheckerImageTracker::DecodeType decode_type,
988 CheckerImageTracker::ImageDecodeQueue* image_decode_queue) {
989 Tile* tile = prioritized_tile.tile();
990 std::vector<const DrawImage*> images_in_tile;
991 prioritized_tile.raster_source()->GetDiscardableImagesInRect(
992 tile->enclosing_layer_rect(), &images_in_tile);
993 WhichTree tree = tile->tiling()->tree();
994 for (const auto* original_draw_image : images_in_tile) {
995 size_t frame_index = client_->GetFrameIndexForImage(
996 original_draw_image->paint_image(), tree);
997 DrawImage draw_image(*original_draw_image, tile->contents_scale_key(),
998 frame_index, target_color_params);
999 if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree)) {
1000 image_decode_queue->emplace_back(draw_image.paint_image(), decode_type);
1005 void TileManager::ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule) {
1006 const std::vector<PrioritizedTile>& tiles_that_need_to_be_rasterized =
1007 work_to_schedule.tiles_to_raster;
1008 TRACE_EVENT1("cc", "TileManager::ScheduleTasks", "count",
1009 tiles_that_need_to_be_rasterized.size());
1011 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
1013 if (!has_scheduled_tile_tasks_) {
1014 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc", "ScheduledTasks",
1015 TRACE_ID_LOCAL(this));
1018 // Cancel existing OnTaskSetFinished callbacks.
1019 task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
1021 // Even when scheduling an empty set of tiles, the TTWP does some work, and
1022 // will always trigger a DidFinishRunningTileTasks notification. Because of
1023 // this we unconditionally set |has_scheduled_tile_tasks_| to true.
1024 has_scheduled_tile_tasks_ = true;
1026 // Track the number of dependents for each *_done task.
1027 size_t required_for_activate_count = 0;
1028 size_t required_for_draw_count = 0;
1029 size_t all_count = 0;
1031 size_t priority = kTileTaskPriorityBase;
1035 scoped_refptr<TileTask> required_for_activation_done_task =
1036 CreateTaskSetFinishedTask(
1037 &TileManager::DidFinishRunningTileTasksRequiredForActivation);
1038 scoped_refptr<TileTask> required_for_draw_done_task =
1039 CreateTaskSetFinishedTask(
1040 &TileManager::DidFinishRunningTileTasksRequiredForDraw);
1043 base::BindOnce(&TileManager::DidFinishRunningAllTileTasks,
1044 task_set_finished_weak_ptr_factory_.GetWeakPtr());
1045 scoped_refptr<TileTask> all_done_task =
1046 base::MakeRefCounted<DidFinishRunningAllTilesTask>(
1047 task_runner_, pending_raster_queries_, std::move(all_done_cb));
1049 // Build a new task queue containing all task currently needed. Tasks
1050 // are added in order of priority, highest priority task first.
1051 for (auto& prioritized_tile : tiles_that_need_to_be_rasterized) {
1052 Tile* tile = prioritized_tile.tile();
1054 DCHECK(tile->draw_info().requires_resource());
1055 DCHECK(!tile->draw_info().has_resource());
1056 DCHECK(tile->HasRasterTask());
1058 TileTask* task = tile->raster_task_.get();
1059 task->set_frame_number(tile->source_frame_number());
1061 DCHECK(!task->HasCompleted());
1063 if (tile->required_for_activation()) {
1064 required_for_activate_count++;
1065 graph_.edges.emplace_back(task, required_for_activation_done_task.get());
1067 if (tile->required_for_draw()) {
1068 required_for_draw_count++;
1069 graph_.edges.emplace_back(task, required_for_draw_done_task.get());
1072 graph_.edges.emplace_back(task, all_done_task.get());
1074 // A tile should use a foreground task cateogry if it is either blocking
1075 // future compositing (required for draw or required for activation), or if
1076 // it has a priority bin of NOW for another reason (low resolution tiles).
1077 bool use_foreground_category =
1078 tile->required_for_draw() || tile->required_for_activation() ||
1079 prioritized_tile.priority().priority_bin == TilePriority::NOW;
1080 InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++,
1081 use_foreground_category);
1084 const std::vector<PrioritizedTile>& tiles_to_process_for_images =
1085 work_to_schedule.tiles_to_process_for_images;
1086 std::vector<DrawImage> new_locked_images;
1087 for (const PrioritizedTile& prioritized_tile : tiles_to_process_for_images) {
1088 auto content_color_usage =
1089 GetContentColorUsageForPrioritizedTile(prioritized_tile);
1090 const auto target_color_params =
1091 client_->GetTargetColorParams(content_color_usage);
1093 std::vector<DrawImage> sync_decoded_images;
1094 std::vector<PaintImage> checkered_images;
1095 PartitionImagesForCheckering(prioritized_tile, target_color_params,
1096 &sync_decoded_images, &checkered_images,
1099 // Add the sync decoded images to |new_locked_images| so they can be added
1100 // to the task graph.
1101 new_locked_images.insert(
1102 new_locked_images.end(),
1103 std::make_move_iterator(sync_decoded_images.begin()),
1104 std::make_move_iterator(sync_decoded_images.end()));
1106 // For checkered-images, send them to the decode service.
1107 for (auto& image : checkered_images) {
1108 work_to_schedule.checker_image_decode_queue.emplace_back(
1109 std::move(image), CheckerImageTracker::DecodeType::kPreDecode);
1113 new_locked_images.insert(new_locked_images.end(),
1114 work_to_schedule.extra_prepaint_images.begin(),
1115 work_to_schedule.extra_prepaint_images.end());
1117 // TODO(vmpstr): SOON is misleading here, but these images can come from
1118 // several diffent tiles. Rethink what we actually want to trace here. Note
1119 // that I'm using SOON, since it can't be NOW (these are prepaint).
1120 ImageDecodeCache::TracingInfo tracing_info(
1121 prepare_tiles_count_, TilePriority::SOON,
1122 ImageDecodeCache::TaskType::kInRaster);
1123 std::vector<scoped_refptr<TileTask>> new_locked_image_tasks =
1124 image_controller_.SetPredecodeImages(new_locked_images, tracing_info);
1125 // Notify |decoded_image_tracker_| after |image_controller_| to ensure we've
1126 // taken new refs on the images before releasing the predecode API refs.
1127 decoded_image_tracker_.OnImagesUsedInDraw(new_locked_images);
1128 work_to_schedule.extra_prepaint_images.clear();
1130 for (auto& task : new_locked_image_tasks) {
1132 base::ranges::find(graph_.nodes, task.get(), &TaskGraph::Node::task);
1133 // If this task is already in the graph, then we don't have to insert it.
1134 if (decode_it != graph_.nodes.end())
1137 InsertNodeForDecodeTask(&graph_, task.get(), false, priority++);
1139 graph_.edges.emplace_back(task.get(), all_done_task.get());
1142 // The old locked images tasks have to stay around until past the
1143 // ScheduleTasks call below, so we do a swap instead of a move.
1144 // TODO(crbug.com/647402): Have the tile_task_manager keep a ref on the tasks,
1145 // since it makes it awkward for the callers to keep refs on tasks that only
1146 // exist within the task graph runner.
1147 locked_image_tasks_.swap(new_locked_image_tasks);
1149 // We must reduce the amount of unused resources before calling
1150 // ScheduleTasks to prevent usage from rising above limits.
1151 resource_pool_->ReduceResourceUsage();
1152 image_controller_.ReduceMemoryUsage();
1154 // Insert nodes for our task completion tasks. We enqueue these using
1155 // NONCONCURRENT_FOREGROUND category this is the highest priority category and
1156 // we'd like to run these tasks as soon as possible.
1157 InsertNodeForTask(&graph_, required_for_activation_done_task.get(),
1158 TASK_CATEGORY_NONCONCURRENT_FOREGROUND,
1159 kRequiredForActivationDoneTaskPriority,
1160 required_for_activate_count);
1161 InsertNodeForTask(&graph_, required_for_draw_done_task.get(),
1162 TASK_CATEGORY_NONCONCURRENT_FOREGROUND,
1163 kRequiredForDrawDoneTaskPriority, required_for_draw_count);
1164 InsertNodeForTask(&graph_, all_done_task.get(),
1165 TASK_CATEGORY_NONCONCURRENT_FOREGROUND,
1166 kAllDoneTaskPriority, all_count);
1168 // Schedule running of |raster_queue_|. This replaces any previously
1169 // scheduled tasks and effectively cancels all tasks not present
1170 // in |raster_queue_|.
1171 tile_task_manager_->ScheduleTasks(&graph_);
1173 // Schedule running of the checker-image decode queue. This replaces the
1174 // previously scheduled queue and effectively cancels image decodes from the
1175 // previous queue, if not already started.
1176 checker_image_tracker_.ScheduleImageDecodeQueue(
1177 std::move(work_to_schedule.checker_image_decode_queue));
1179 did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
1181 TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("cc", "ScheduledTasksState",
1182 TRACE_ID_LOCAL(this), "state",
1183 ScheduledTasksStateAsValue());
1186 scoped_refptr<TileTask> TileManager::CreateRasterTask(
1187 const PrioritizedTile& prioritized_tile,
1188 const TargetColorParams& target_color_params,
1189 PrioritizedWorkToSchedule* work_to_schedule) {
1190 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1191 "TileManager::CreateRasterTask");
1192 Tile* tile = prioritized_tile.tile();
1193 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1194 "TileManager::CreateRasterTask", "Tile", tile->id());
1196 const int msaa_sample_count = client_->GetMSAASampleCountForRaster(
1197 prioritized_tile.raster_source()->GetDisplayItemList());
1199 // When possible, rasterize HDR content into F16.
1201 // TODO(crbug.com/1076568): Once we have access to the display's buffer format
1202 // via gfx::DisplayColorSpaces, we should also do this for HBD images.
1203 auto format = DetermineResourceFormat(tile);
1204 if (target_color_params.color_space.IsHDR() &&
1205 GetContentColorUsageForPrioritizedTile(prioritized_tile) ==
1206 gfx::ContentColorUsage::kHDR) {
1207 format = viz::ResourceFormat::RGBA_F16;
1210 // Get the resource.
1211 ResourcePool::InUsePoolResource resource;
1212 uint64_t resource_content_id = 0;
1213 gfx::Rect invalidated_rect = tile->invalidated_content_rect();
1214 if (UsePartialRaster(msaa_sample_count) && tile->invalidated_id()) {
1215 const std::string& debug_name =
1216 prioritized_tile.source_tiling()->raster_source()->debug_name();
1217 resource = resource_pool_->TryAcquireResourceForPartialRaster(
1218 tile->id(), tile->invalidated_content_rect(), tile->invalidated_id(),
1219 &invalidated_rect, target_color_params.color_space, debug_name);
1222 bool partial_tile_decode = false;
1224 resource_content_id = tile->invalidated_id();
1225 DCHECK_EQ(format, resource.format());
1226 partial_tile_decode = true;
1228 const std::string& debug_name =
1229 prioritized_tile.source_tiling()->raster_source()->debug_name();
1230 resource = resource_pool_->AcquireResource(
1231 tile->desired_texture_size(), format, target_color_params.color_space,
1236 // For LOW_RESOLUTION tiles, we don't draw or predecode images.
1237 RasterSource::PlaybackSettings playback_settings;
1238 const bool skip_images =
1239 prioritized_tile.priority().resolution == LOW_RESOLUTION;
1240 playback_settings.use_lcd_text = tile->can_use_lcd_text();
1241 playback_settings.msaa_sample_count = msaa_sample_count;
1242 playback_settings.visible =
1243 tile->required_for_activation() || tile->required_for_draw();
1245 // Create and queue all image decode tasks that this tile depends on. Note
1246 // that we need to store the images for decode tasks in
1247 // |scheduled_draw_images_| since the tile might have been destroyed by the
1248 // time the raster task finishes.
1249 TileTask::Vector decode_tasks;
1250 std::vector<DrawImage>& sync_decoded_images =
1251 scheduled_draw_images_[tile->id()];
1252 sync_decoded_images.clear();
1253 std::vector<PaintImage> checkered_images;
1254 base::flat_map<PaintImage::Id, size_t> image_id_to_current_frame_index;
1256 PartitionImagesForCheckering(
1257 prioritized_tile, target_color_params, &sync_decoded_images,
1258 &checkered_images, partial_tile_decode ? &invalidated_rect : nullptr,
1259 &image_id_to_current_frame_index);
1262 // Get the tasks for the required images.
1263 ImageDecodeCache::TracingInfo tracing_info(
1264 prepare_tiles_count_, prioritized_tile.priority().priority_bin,
1265 ImageDecodeCache::TaskType::kInRaster);
1266 bool has_at_raster_images = false;
1267 bool has_hardware_accelerated_jpeg_candidates = false;
1268 bool has_hardware_accelerated_webp_candidates = false;
1269 image_controller_.ConvertImagesToTasks(
1270 &sync_decoded_images, &decode_tasks, &has_at_raster_images,
1271 &has_hardware_accelerated_jpeg_candidates,
1272 &has_hardware_accelerated_webp_candidates, tracing_info);
1273 // Notify |decoded_image_tracker_| after |image_controller_| to ensure we've
1274 // taken new refs on the images before releasing the predecode API refs.
1275 decoded_image_tracker_.OnImagesUsedInDraw(sync_decoded_images);
1277 const bool has_checker_images = !checkered_images.empty();
1278 tile->set_raster_task_scheduled_with_checker_images(has_checker_images);
1279 if (has_checker_images)
1280 num_of_tiles_with_checker_images_++;
1282 // Don't allow at-raster prepaint tiles, because they could be very slow
1283 // and block high-priority tasks.
1284 if (has_at_raster_images && tile->is_prepaint()) {
1285 work_to_schedule->extra_prepaint_images.insert(
1286 work_to_schedule->extra_prepaint_images.end(),
1287 sync_decoded_images.begin(), sync_decoded_images.end());
1288 // This will unref the images, but ScheduleTasks will schedule them
1289 // right away anyway.
1290 OnRasterTaskCompleted(tile->id(), std::move(resource),
1291 true /* was_canceled */);
1295 PaintImageIdFlatSet images_to_skip;
1296 for (const auto& image : checkered_images) {
1297 DCHECK(!image.ShouldAnimate());
1299 images_to_skip.insert(image.stable_id());
1301 // This can be the case for tiles on the active tree that will be replaced
1302 // or are occluded on the pending tree. While we still need to continue
1303 // skipping images for these tiles, we don't need to decode them since
1304 // they will not be required on the next active tree.
1305 if (prioritized_tile.should_decode_checkered_images_for_tile()) {
1306 work_to_schedule->checker_image_decode_queue.emplace_back(
1307 image, CheckerImageTracker::DecodeType::kRaster);
1311 std::unique_ptr<RasterBuffer> raster_buffer =
1312 raster_buffer_provider_->AcquireBufferForRaster(
1313 resource, resource_content_id, tile->invalidated_id(),
1314 has_at_raster_images, has_hardware_accelerated_jpeg_candidates,
1315 has_hardware_accelerated_webp_candidates);
1317 absl::optional<PlaybackImageProvider::Settings> settings;
1320 settings->images_to_skip = std::move(images_to_skip);
1321 settings->image_to_current_frame_index =
1322 std::move(image_id_to_current_frame_index);
1323 if (use_gpu_rasterization_) {
1324 settings->raster_mode = PlaybackImageProvider::RasterMode::kOop;
1328 PlaybackImageProvider image_provider(
1329 image_controller_.cache(), target_color_params, std::move(settings));
1330 // We make a deliberate copy of the PaintWorklet map here, as the
1331 // PictureLayerImpl's map could be mutated or destroyed whilst raster from an
1332 // earlier snapshot is still ongoing on the raster worker threads.
1333 PaintWorkletRecordMap paint_worklet_records =
1334 prioritized_tile.GetPaintWorkletRecords();
1335 PaintWorkletImageProvider paint_worklet_image_provider(
1336 std::move(paint_worklet_records));
1337 DispatchingImageProvider dispatching_image_provider(
1338 std::move(image_provider), std::move(paint_worklet_image_provider));
1340 return base::MakeRefCounted<RasterTaskImpl>(
1341 this, tile, std::move(resource), prioritized_tile.raster_source(),
1342 playback_settings, prioritized_tile.priority().resolution,
1343 invalidated_rect, prepare_tiles_count_, std::move(raster_buffer),
1344 &decode_tasks, use_gpu_rasterization_,
1345 std::move(dispatching_image_provider), active_url_);
1348 void TileManager::ResetSignalsForTesting() {
1349 signals_ = Signals();
1352 void TileManager::OnRasterTaskCompleted(
1354 ResourcePool::InUsePoolResource resource,
1355 bool was_canceled) {
1356 auto found = tiles_.find(tile_id);
1357 Tile* tile = nullptr;
1358 bool raster_task_was_scheduled_with_checker_images = false;
1359 if (found != tiles_.end()) {
1360 tile = found->second;
1361 tile->raster_task_ = nullptr;
1362 raster_task_was_scheduled_with_checker_images =
1363 tile->set_raster_task_scheduled_with_checker_images(false);
1364 if (raster_task_was_scheduled_with_checker_images)
1365 num_of_tiles_with_checker_images_--;
1368 // Unref all the images.
1369 auto images_it = scheduled_draw_images_.find(tile_id);
1370 // Every raster task unconditionally creates sync_decoded_images_ entry in
1371 // CreateRasterTask. This is the only place it's cleared. So we should have
1372 // the images_it here that doesn't point to end. This check is here to debug
1373 // crbug.com/757049.
1374 CHECK(images_it != scheduled_draw_images_.end());
1375 image_controller_.UnrefImages(images_it->second);
1376 scheduled_draw_images_.erase(images_it);
1379 ++raster_task_completion_stats_.canceled_count;
1380 resource_pool_->ReleaseResource(std::move(resource));
1384 resource_pool_->OnContentReplaced(resource, tile_id);
1385 ++raster_task_completion_stats_.completed_count;
1388 resource_pool_->ReleaseResource(std::move(resource));
1392 // Once raster is done, allow the resource to be exported to the display
1393 // compositor, by giving it a ResourceId.
1394 bool exported = resource_pool_->PrepareForExport(resource);
1396 // In SMOOTHNESS_TAKES_PRIORITY mode, we wait for GPU work to complete for a
1397 // tile before setting it as ready to draw.
1398 bool is_ready_for_draw = true;
1399 if (global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY) {
1401 raster_buffer_provider_->IsResourceReadyToDraw(resource);
1404 TileDrawInfo& draw_info = tile->draw_info();
1406 bool is_premultiplied = raster_buffer_provider_->IsResourcePremultiplied();
1407 draw_info.SetResource(std::move(resource),
1408 raster_task_was_scheduled_with_checker_images,
1411 resource_pool_->ReleaseResource(std::move(resource));
1412 draw_info.set_oom();
1414 if (raster_task_was_scheduled_with_checker_images)
1415 num_of_tiles_with_checker_images_++;
1417 if (!is_ready_for_draw) {
1418 pending_gpu_work_tiles_.insert(tile);
1420 draw_info.set_resource_ready_for_draw();
1421 client_->NotifyTileStateChanged(tile);
1425 std::unique_ptr<Tile> TileManager::CreateTile(const Tile::CreateInfo& info,
1427 int source_frame_number,
1429 // We need to have a tile task worker pool to do anything meaningful with
1431 DCHECK(tile_task_manager_);
1432 std::unique_ptr<Tile> tile(
1433 new Tile(this, info, layer_id, source_frame_number, flags));
1434 DCHECK(tiles_.find(tile->id()) == tiles_.end());
1436 tiles_[tile->id()] = tile.get();
1440 bool TileManager::AreRequiredTilesReadyToDraw(
1441 RasterTilePriorityQueue::Type type) const {
1442 std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue(
1443 client_->BuildRasterQueue(global_state_.tree_priority, type));
1444 // It is insufficient to check whether the raster queue we constructed is
1445 // empty. The reason for this is that there are situations (rasterize on
1446 // demand) when the tile both needs raster and it's ready to draw. Hence, we
1447 // have to iterate the queue to check whether the required tiles are ready to
1449 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
1450 const auto& prioritized_tile = raster_priority_queue->Top();
1451 if (!prioritized_tile.tile()->draw_info().IsReadyToDraw())
1456 std::unique_ptr<RasterTilePriorityQueue> all_queue(
1457 client_->BuildRasterQueue(global_state_.tree_priority, type));
1458 for (; !all_queue->IsEmpty(); all_queue->Pop()) {
1459 Tile* tile = all_queue->Top().tile();
1460 DCHECK(!tile->required_for_activation() ||
1461 tile->draw_info().IsReadyToDraw());
1467 bool TileManager::IsReadyToActivate() const {
1468 TRACE_EVENT0("cc,benchmark", "TileManager::IsReadyToActivate");
1469 return pending_required_for_activation_callback_id_ == 0 &&
1470 AreRequiredTilesReadyToDraw(
1471 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
1474 bool TileManager::IsReadyToDraw() const {
1475 TRACE_EVENT0("cc,benchmark", "TileManager::IsReadyToDraw");
1476 return pending_required_for_draw_callback_id_ == 0 &&
1477 AreRequiredTilesReadyToDraw(
1478 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
1481 void TileManager::ScheduleCheckRasterFinishedQueries() {
1482 DCHECK(has_pending_queries_);
1484 if (!check_pending_tile_queries_callback_.IsCancelled())
1487 check_pending_tile_queries_callback_.Reset(base::BindOnce(
1488 &TileManager::CheckRasterFinishedQueries, base::Unretained(this)));
1489 task_runner_->PostDelayedTask(FROM_HERE,
1490 check_pending_tile_queries_callback_.callback(),
1491 base::Milliseconds(100));
1494 void TileManager::CheckRasterFinishedQueries() {
1495 check_pending_tile_queries_callback_.Cancel();
1497 if (!has_pending_queries_)
1500 // Raster tasks are in progress. The queries will be polled once they finish.
1501 if (has_scheduled_tile_tasks_ || !signals_.all_tile_tasks_completed)
1504 has_pending_queries_ = false;
1505 if (pending_raster_queries_) {
1506 has_pending_queries_ =
1507 pending_raster_queries_->CheckRasterFinishedQueries();
1509 if (has_pending_queries_)
1510 ScheduleCheckRasterFinishedQueries();
1513 void TileManager::FlushAndIssueSignals() {
1514 TRACE_EVENT0("cc", "TileManager::FlushAndIssueSignals");
1515 tile_task_manager_->CheckForCompletedTasks();
1516 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
1518 raster_buffer_provider_->Flush();
1519 CheckPendingGpuWorkAndIssueSignals();
1522 void TileManager::IssueSignals() {
1523 // Ready to activate.
1524 if (signals_.activate_tile_tasks_completed &&
1525 signals_.activate_gpu_work_completed &&
1526 !signals_.did_notify_ready_to_activate) {
1527 // If commit_to_active_tree is true(no pending tree), NotifyReadyToActivate
1528 // isn't sent to client, so don't call IsReadyToActivate() to save CPU time
1529 if (client_->HasPendingTree() && IsReadyToActivate()) {
1530 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1531 "TileManager::IssueSignals - ready to activate");
1532 signals_.did_notify_ready_to_activate = true;
1533 client_->NotifyReadyToActivate();
1538 if (signals_.draw_tile_tasks_completed && signals_.draw_gpu_work_completed &&
1539 !signals_.did_notify_ready_to_draw) {
1540 if (tile_manager_settings_.needs_notify_ready_to_draw && IsReadyToDraw()) {
1541 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1542 "TileManager::IssueSignals - ready to draw");
1543 signals_.did_notify_ready_to_draw = true;
1544 client_->NotifyReadyToDraw();
1548 // All tile tasks completed.
1549 if (signals_.all_tile_tasks_completed &&
1550 !signals_.did_notify_all_tile_tasks_completed) {
1551 if (!has_scheduled_tile_tasks_) {
1552 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1553 "TileManager::IssueSignals - all tile tasks completed");
1555 if (has_pending_queries_)
1556 ScheduleCheckRasterFinishedQueries();
1558 signals_.did_notify_all_tile_tasks_completed = true;
1559 client_->NotifyAllTileTasksCompleted();
1563 bool notify_ready_to_activate_pending =
1564 client_->HasPendingTree() && !signals_.did_notify_ready_to_activate;
1565 bool notify_ready_to_draw_pending =
1566 tile_manager_settings_.needs_notify_ready_to_draw &&
1567 !signals_.did_notify_ready_to_draw;
1569 // Allow decodes for rasterized tiles if all required for draw/activate tiles
1570 // are done. And pre-decode tiles once all tile tasks are done.
1571 // Note that the order is important here, since all signals could have become
1572 // true and in that case we want to allow the most decodes.
1573 if (signals_.did_notify_all_tile_tasks_completed) {
1574 checker_image_tracker_.SetMaxDecodePriorityAllowed(
1575 CheckerImageTracker::DecodeType::kPreDecode);
1576 } else if (!notify_ready_to_activate_pending &&
1577 !notify_ready_to_draw_pending) {
1578 checker_image_tracker_.SetMaxDecodePriorityAllowed(
1579 CheckerImageTracker::DecodeType::kRaster);
1583 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
1584 tile_task_manager_->CheckForCompletedTasks();
1585 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
1587 // When OOM, keep re-assigning memory until we reach a steady state
1588 // where top-priority tiles are initialized.
1589 PrioritizedWorkToSchedule work_to_schedule = AssignGpuMemoryToTiles();
1591 // Inform the client that will likely require a draw if the highest priority
1592 // tile that will be rasterized is required for draw.
1593 client_->SetIsLikelyToRequireADraw(
1594 !work_to_schedule.tiles_to_raster.empty() &&
1595 work_to_schedule.tiles_to_raster.front().tile()->required_for_draw());
1597 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
1598 // steady memory state. Keep scheduling tasks until we reach this state.
1599 if (!work_to_schedule.tiles_to_raster.empty()) {
1600 ScheduleTasks(std::move(work_to_schedule));
1604 // If we're not in SMOOTHNESS_TAKES_PRIORITY mode, we should unlock all
1605 // images since we're technically going idle here at least for this frame.
1606 if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY) {
1607 image_controller_.SetPredecodeImages(std::vector<DrawImage>(),
1608 ImageDecodeCache::TracingInfo());
1609 locked_image_tasks_.clear();
1612 resource_pool_->ReduceResourceUsage();
1613 image_controller_.ReduceMemoryUsage();
1615 // TODO(vmpstr): Temporary check to debug crbug.com/642927.
1616 CHECK(tile_task_manager_);
1618 // Schedule all checks in case we're left with solid color tiles only.
1619 signals_.activate_tile_tasks_completed = true;
1620 signals_.draw_tile_tasks_completed = true;
1621 signals_.all_tile_tasks_completed = true;
1622 signals_check_notifier_.Schedule();
1624 // We don't reserve memory for required-for-activation tiles during
1625 // accelerated gestures, so we just postpone activation when we don't
1626 // have these tiles, and activate after the accelerated gesture.
1627 // Likewise if we don't allow any tiles (as is the case when we're
1628 // invisible), if we have tiles that aren't ready, then we shouldn't
1629 // activate as activation can cause checkerboards.
1630 bool wait_for_all_required_tiles =
1631 global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
1632 global_state_.memory_limit_policy == ALLOW_NOTHING;
1634 // If we have tiles left to raster for activation, and we don't allow
1635 // activating without them, then skip activation and return early.
1636 if (wait_for_all_required_tiles)
1639 // Mark any required tiles that have not been been assigned memory after
1640 // reaching a steady memory state as OOM. This ensures that we activate/draw
1641 // even when OOM. Note that we can't reuse the queue we used for
1642 // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
1643 // evicted some tiles that would not be picked up by the old raster queue.
1644 MarkTilesOutOfMemory(client_->BuildRasterQueue(
1645 global_state_.tree_priority,
1646 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
1647 MarkTilesOutOfMemory(client_->BuildRasterQueue(
1648 global_state_.tree_priority,
1649 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW));
1651 // TODO(vmpstr): Temporary check to debug crbug.com/642927.
1652 CHECK(tile_task_manager_);
1654 DCHECK(IsReadyToActivate());
1655 DCHECK(IsReadyToDraw());
1658 void TileManager::MarkTilesOutOfMemory(
1659 std::unique_ptr<RasterTilePriorityQueue> queue) const {
1660 // Mark required tiles as OOM so that we can activate/draw without them.
1661 for (; !queue->IsEmpty(); queue->Pop()) {
1662 Tile* tile = queue->Top().tile();
1663 if (tile->draw_info().IsReadyToDraw())
1665 tile->draw_info().set_oom();
1666 client_->NotifyTileStateChanged(tile);
1670 const PaintImageIdFlatSet& TileManager::TakeImagesToInvalidateOnSyncTree() {
1671 return checker_image_tracker_.TakeImagesToInvalidateOnSyncTree();
1674 void TileManager::DidActivateSyncTree() {
1675 checker_image_tracker_.DidActivateSyncTree();
1678 void TileManager::ClearCheckerImageTracking(
1679 bool can_clear_decode_policy_tracking) {
1680 checker_image_tracker_.ClearTracker(can_clear_decode_policy_tracking);
1683 void TileManager::SetCheckerImagingForceDisabled(bool force_disable) {
1684 checker_image_tracker_.set_force_disabled(force_disable);
1687 void TileManager::NeedsInvalidationForCheckerImagedTiles() {
1688 client_->RequestImplSideInvalidationForCheckerImagedTiles();
1691 viz::ResourceFormat TileManager::DetermineResourceFormat(
1692 const Tile* tile) const {
1693 return raster_buffer_provider_->GetResourceFormat();
1696 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
1697 TileManager::ScheduledTasksStateAsValue() const {
1698 std::unique_ptr<base::trace_event::TracedValue> state(
1699 new base::trace_event::TracedValue());
1700 state->BeginDictionary("tasks_pending");
1701 state->SetBoolean("activate_tile_tasks_completed",
1702 signals_.activate_tile_tasks_completed);
1703 state->SetBoolean("draw_tile_tasks_completed",
1704 signals_.draw_tile_tasks_completed);
1705 state->SetBoolean("all_tile_tasks_completed",
1706 signals_.all_tile_tasks_completed);
1707 state->EndDictionary();
1708 return std::move(state);
1711 bool TileManager::UsePartialRaster(int msaa_sample_count) const {
1712 // Partial raster doesn't support MSAA, as the MSAA resolve is unaware of clip
1714 // TODO(crbug.com/629683): See if we can work around this limitation.
1715 return tile_manager_settings_.use_partial_raster &&
1716 raster_buffer_provider_->CanPartialRasterIntoProvidedResource() &&
1717 msaa_sample_count == 0;
1720 void TileManager::CheckPendingGpuWorkAndIssueSignals() {
1721 TRACE_EVENT2("cc", "TileManager::CheckPendingGpuWorkAndIssueSignals",
1722 "pending_gpu_work_tiles", pending_gpu_work_tiles_.size(),
1724 TreePriorityToString(global_state_.tree_priority));
1726 std::vector<const ResourcePool::InUsePoolResource*> required_for_activation;
1727 std::vector<const ResourcePool::InUsePoolResource*> required_for_draw;
1729 for (auto it = pending_gpu_work_tiles_.begin();
1730 it != pending_gpu_work_tiles_.end();) {
1732 DCHECK(tile->draw_info().has_resource());
1733 const ResourcePool::InUsePoolResource& resource =
1734 tile->draw_info().GetResource();
1736 // Update requirements first so that if the tile has become required
1737 // it will force a redraw.
1738 if (pending_tile_requirements_dirty_)
1739 tile->tiling()->UpdateRequiredStatesOnTile(tile);
1741 if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY ||
1742 raster_buffer_provider_->IsResourceReadyToDraw(resource)) {
1743 tile->draw_info().set_resource_ready_for_draw();
1744 client_->NotifyTileStateChanged(tile);
1745 it = pending_gpu_work_tiles_.erase(it);
1749 // TODO(ericrk): If a tile in our list no longer has valid tile priorities,
1750 // it may still report that it is required, and unnecessarily delay
1751 // activation. crbug.com/687265
1752 if (tile->required_for_activation())
1753 required_for_activation.push_back(&resource);
1754 if (tile->required_for_draw())
1755 required_for_draw.push_back(&resource);
1760 if (required_for_activation.empty()) {
1761 pending_required_for_activation_callback_id_ = 0;
1763 pending_required_for_activation_callback_id_ =
1764 raster_buffer_provider_->SetReadyToDrawCallback(
1765 required_for_activation,
1767 &TileManager::CheckPendingGpuWorkAndIssueSignals,
1768 ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
1769 pending_required_for_activation_callback_id_);
1772 if (required_for_draw.empty()) {
1773 pending_required_for_draw_callback_id_ = 0;
1775 pending_required_for_draw_callback_id_ =
1776 raster_buffer_provider_->SetReadyToDrawCallback(
1779 &TileManager::CheckPendingGpuWorkAndIssueSignals,
1780 ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
1781 pending_required_for_draw_callback_id_);
1784 // Update our signals now that we know whether we have pending resources.
1785 signals_.activate_gpu_work_completed =
1786 (pending_required_for_activation_callback_id_ == 0);
1787 signals_.draw_gpu_work_completed =
1788 (pending_required_for_draw_callback_id_ == 0);
1790 // We've just updated all pending tile requirements if necessary.
1791 pending_tile_requirements_dirty_ = false;
1796 // Utility function that can be used to create a "Task set finished" task that
1797 // posts |callback| to |task_runner| when run.
1798 scoped_refptr<TileTask> TileManager::CreateTaskSetFinishedTask(
1799 void (TileManager::*callback)()) {
1800 return base::MakeRefCounted<TaskSetFinishedTaskImpl>(
1802 base::BindRepeating(callback,
1803 task_set_finished_weak_ptr_factory_.GetWeakPtr()));
1806 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
1807 TileManager::ActivationStateAsValue() {
1808 auto state = std::make_unique<base::trace_event::TracedValue>();
1809 ActivationStateAsValueInto(state.get());
1810 return std::move(state);
1813 void TileManager::ActivationStateAsValueInto(
1814 base::trace_event::TracedValue* state) {
1815 state->SetString("tree_priority",
1816 TreePriorityToString(global_state_.tree_priority));
1817 state->SetInteger("soft_memory_limit",
1818 global_state_.soft_memory_limit_in_bytes);
1819 state->SetInteger("hard_memory_limit",
1820 global_state_.soft_memory_limit_in_bytes);
1821 state->SetInteger("pending_required_for_activation_callback_id",
1822 pending_required_for_activation_callback_id_);
1823 state->SetInteger("current_memory_usage",
1824 resource_pool_->memory_usage_bytes());
1825 state->SetInteger("current_resource_usage", resource_pool_->resource_count());
1827 // Use a custom tile_as_value, instead of Tile::AsValueInto, since we don't
1828 // need all of the state that would be captured by other functions.
1829 auto tile_as_value = [](const PrioritizedTile& prioritized_tile,
1830 base::trace_event::TracedValue* value) {
1831 Tile* tile = prioritized_tile.tile();
1832 TilePriority priority = prioritized_tile.priority();
1834 value->SetInteger("id", tile->id());
1835 value->SetString("content_rect", tile->content_rect().ToString());
1836 value->SetDouble("contents_scale", tile->contents_scale_key());
1837 value->SetBoolean("is_ready_to_draw", tile->draw_info().IsReadyToDraw());
1838 value->SetString("resolution", TileResolutionToString(priority.resolution));
1839 value->SetString("priority_bin",
1840 TilePriorityBinToString(priority.priority_bin));
1841 value->SetDouble("distance_to_visible", priority.distance_to_visible);
1842 value->SetBoolean("required_for_activation",
1843 tile->required_for_activation());
1844 value->SetBoolean("required_for_draw", tile->required_for_draw());
1847 std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue(
1848 client_->BuildRasterQueue(global_state_.tree_priority,
1849 RasterTilePriorityQueue::Type::ALL));
1850 state->BeginArray("raster_tiles");
1851 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
1852 state->BeginDictionary();
1853 tile_as_value(raster_priority_queue->Top(), state);
1854 state->EndDictionary();
1858 std::unique_ptr<RasterTilePriorityQueue> required_priority_queue(
1859 client_->BuildRasterQueue(
1860 global_state_.tree_priority,
1861 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
1862 state->BeginArray("activation_tiles");
1863 for (; !required_priority_queue->IsEmpty(); required_priority_queue->Pop()) {
1864 state->BeginDictionary();
1865 tile_as_value(required_priority_queue->Top(), state);
1866 state->EndDictionary();
1871 bool TileManager::ShouldRasterOccludedTiles() const {
1872 return (global_state_.memory_limit_policy != ALLOW_NOTHING &&
1873 global_state_.memory_limit_policy != ALLOW_ABSOLUTE_MINIMUM);
1876 TileManager::MemoryUsage::MemoryUsage()
1877 : memory_bytes_(0), resource_count_(0) {}
1879 TileManager::MemoryUsage::MemoryUsage(size_t memory_bytes,
1880 size_t resource_count)
1881 : memory_bytes_(static_cast<int64_t>(memory_bytes)),
1882 resource_count_(static_cast<int>(resource_count)) {
1883 // MemoryUsage is constructed using size_ts, since it deals with memory and
1884 // the inputs are typically size_t. However, during the course of usage (in
1885 // particular operator-=) can cause internal values to become negative.
1886 // Thus, member variables are signed.
1887 DCHECK_LE(memory_bytes,
1888 static_cast<size_t>(std::numeric_limits<int64_t>::max()));
1889 DCHECK_LE(resource_count,
1890 static_cast<size_t>(std::numeric_limits<int>::max()));
1894 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
1895 const gfx::Size& size,
1896 viz::ResourceFormat format) {
1897 // We can use UncheckedSizeInBytes here since this is used with a tile
1898 // size which is determined by the compositor (it's at most max texture
1901 viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format), 1);
1905 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
1906 const TileDrawInfo& draw_info = tile->draw_info();
1907 if (draw_info.has_resource()) {
1908 return MemoryUsage(draw_info.GetResource().memory_usage(), 1);
1910 return MemoryUsage();
1913 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
1914 const MemoryUsage& other) {
1915 memory_bytes_ += other.memory_bytes_;
1916 resource_count_ += other.resource_count_;
1920 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
1921 const MemoryUsage& other) {
1922 memory_bytes_ -= other.memory_bytes_;
1923 resource_count_ -= other.resource_count_;
1927 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
1928 const MemoryUsage& other) {
1929 MemoryUsage result = *this;
1934 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
1935 return memory_bytes_ > limit.memory_bytes_ ||
1936 resource_count_ > limit.resource_count_;
1939 TileManager::PrioritizedWorkToSchedule::PrioritizedWorkToSchedule() = default;
1940 TileManager::PrioritizedWorkToSchedule::PrioritizedWorkToSchedule(
1941 PrioritizedWorkToSchedule&& other) = default;
1942 TileManager::PrioritizedWorkToSchedule::~PrioritizedWorkToSchedule() = default;