[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / tiles / tile_manager.cc
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.
4
5 #include "cc/tiles/tile_manager.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <limits>
11 #include <string>
12
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"
40
41 namespace cc {
42 namespace {
43
44 // Flag to indicate whether we should try and detect that
45 // a tile is of solid color.
46 const bool kUseColorEstimator = true;
47
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 {
52  public:
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)) {
58   }
59   DispatchingImageProvider(const DispatchingImageProvider&) = delete;
60   ~DispatchingImageProvider() override = default;
61
62   DispatchingImageProvider& operator=(const DispatchingImageProvider&) = delete;
63
64   DispatchingImageProvider(DispatchingImageProvider&& other) = default;
65
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);
72   }
73
74  private:
75   PlaybackImageProvider playback_image_provider_;
76   PaintWorkletImageProvider paint_worklet_image_provider_;
77 };
78
79 class RasterTaskImpl : public TileTask {
80  public:
81   RasterTaskImpl(TileManager* tile_manager,
82                  Tile* tile,
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,
93                  GURL url)
94       : TileTask(
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,
100             dependencies),
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_;
120   }
121   RasterTaskImpl(const RasterTaskImpl&) = delete;
122   RasterTaskImpl& operator=(const RasterTaskImpl&) = delete;
123
124   // Overridden from Task:
125   void RunOnWorkerThread() override {
126     TRACE_EVENT1("cc", "RasterizerTaskImpl::RunOnWorkerThread",
127                  "source_prepare_tiles_id", source_prepare_tiles_id_);
128
129     DCHECK(raster_source_.get());
130     DCHECK(raster_buffer_);
131
132     frame_viewer_instrumentation::ScopedRasterTask raster_task(
133         tile_tracing_id_, tile_resolution_, source_frame_number_, layer_id_);
134
135     DCHECK(raster_source_);
136
137     raster_buffer_->Playback(raster_source_.get(), content_rect_,
138                              invalid_content_rect_, new_content_id_,
139                              raster_transform_, playback_settings_, url_);
140   }
141
142   // Overridden from TileTask:
143   void OnTaskCompleted() override {
144     DCHECK(origin_thread_checker_.CalledOnValidThread());
145
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());
152   }
153
154  protected:
155   ~RasterTaskImpl() override {
156     DCHECK(origin_thread_checker_.CalledOnValidThread());
157     DCHECK(!raster_buffer_);
158     DCHECK(!resource_);
159   }
160
161  private:
162   base::ThreadChecker origin_thread_checker_;
163
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_;
168   Tile::Id tile_id_;
169   ResourcePool::InUsePoolResource resource_;
170
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_;
178   int layer_id_;
179   uint64_t source_prepare_tiles_id_;
180   // TODO(crbug.com/1298696): views_unittests breaks with MTECheckedPtr
181   // enabled. Triage.
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_;
187   GURL url_;
188 };
189
190 TaskCategory TaskCategoryForTileTask(TileTask* task,
191                                      bool use_foreground_category) {
192   if (!task->supports_concurrent_execution())
193     return TASK_CATEGORY_NONCONCURRENT_FOREGROUND;
194
195   if (use_foreground_category)
196     return TASK_CATEGORY_FOREGROUND;
197
198   if (!task->supports_background_thread_priority())
199     return TASK_CATEGORY_BACKGROUND_WITH_NORMAL_THREAD_PRIORITY;
200
201   return TASK_CATEGORY_BACKGROUND;
202 }
203
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:
209       return true;
210     case TASK_CATEGORY_BACKGROUND:
211     case TASK_CATEGORY_BACKGROUND_WITH_NORMAL_THREAD_PRIORITY:
212       return false;
213   }
214
215   NOTREACHED();
216   return false;
217 }
218
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;
224
225 // For correctness, |kTileTaskPriorityBase| must be greater than
226 // all task set done task priorities.
227 size_t kTileTaskPriorityBase = 10u;
228
229 void InsertNodeForTask(TaskGraph* graph,
230                        TileTask* task,
231                        uint16_t category,
232                        uint16_t priority,
233                        size_t dependencies) {
234   DCHECK(!base::Contains(graph->nodes, task, &TaskGraph::Node::task));
235   graph->nodes.emplace_back(task, category, priority, dependencies);
236 }
237
238 void InsertNodeForDecodeTask(TaskGraph* graph,
239                              TileTask* task,
240                              bool use_foreground_category,
241                              uint16_t priority) {
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,
248                               priority);
249       graph->edges.emplace_back(dependency, task);
250       dependency_count = 1u;
251     }
252   }
253   InsertNodeForTask(graph, task,
254                     TaskCategoryForTileTask(task, use_foreground_category),
255                     priority, dependency_count);
256 }
257
258 void InsertNodesForRasterTask(TaskGraph* graph,
259                               TileTask* raster_task,
260                               const TileTask::Vector& decode_tasks,
261                               size_t priority,
262                               bool use_foreground_category) {
263   size_t dependencies = 0u;
264
265   // Insert image decode tasks.
266   for (auto it = decode_tasks.begin(); it != decode_tasks.end(); ++it) {
267     TileTask* decode_task = it->get();
268
269     // Skip if already decoded.
270     if (decode_task->HasCompleted())
271       continue;
272
273     dependencies++;
274
275     // Add decode task if it doesn't already exist in graph.
276     auto decode_it =
277         base::ranges::find(graph->nodes, decode_task, &TaskGraph::Node::task);
278
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.
283     // crbug.com/594851
284     // TODO(ericrk): This should handle dependencies recursively.
285     // crbug.com/605234
286     if (decode_it != graph->nodes.end() && use_foreground_category &&
287         !IsForegroundCategory(decode_it->category)) {
288       decode_it->category = TASK_CATEGORY_FOREGROUND;
289     }
290
291     if (decode_it == graph->nodes.end()) {
292       InsertNodeForDecodeTask(graph, decode_task, use_foreground_category,
293                               priority);
294     }
295
296     graph->edges.emplace_back(decode_task, raster_task);
297   }
298
299   InsertNodeForTask(
300       graph, raster_task,
301       TaskCategoryForTileTask(raster_task, use_foreground_category), priority,
302       dependencies);
303 }
304
305 class TaskSetFinishedTaskImpl : public TileTask {
306  public:
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;
317
318   // Overridden from Task:
319   void RunOnWorkerThread() override {
320     TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread");
321     TaskSetFinished();
322   }
323
324   // Overridden from TileTask:
325   void OnTaskCompleted() override {}
326
327  protected:
328   ~TaskSetFinishedTaskImpl() override = default;
329
330   void TaskSetFinished() {
331     task_runner_->PostTask(FROM_HERE, on_task_set_finished_callback_);
332   }
333
334  private:
335   raw_ptr<base::SequencedTaskRunner> task_runner_;
336   const base::RepeatingClosure on_task_set_finished_callback_;
337 };
338
339 class DidFinishRunningAllTilesTask : public TileTask {
340  public:
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)) {}
350
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();
357     }
358     task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(completion_cb_),
359                                                      has_pending_queries));
360   }
361
362   void OnTaskCompleted() override {}
363
364  protected:
365   ~DidFinishRunningAllTilesTask() override = default;
366
367  private:
368   raw_ptr<base::SequencedTaskRunner> task_runner_;
369   raw_ptr<RasterQueryQueue, DanglingUntriaged> pending_raster_queries_;
370   CompletionCb completion_cb_;
371 };
372
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();
379 }
380
381 }  // namespace
382
383 RasterTaskCompletionStats::RasterTaskCompletionStats()
384     : completed_count(0u), canceled_count(0u) {}
385
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);
395 }
396
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)
403     : client_(client),
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_,
417                              this,
418                              tile_manager_settings_.enable_checker_imaging,
419                              tile_manager_settings_.min_image_bytes_to_checker),
420       more_tiles_need_prepare_check_notifier_(
421           task_runner_,
422           base::BindRepeating(&TileManager::CheckIfMoreTilesNeedToBePrepared,
423                               base::Unretained(this))),
424       signals_check_notifier_(
425           task_runner_,
426           base::BindRepeating(&TileManager::FlushAndIssueSignals,
427                               base::Unretained(this))),
428       has_scheduled_tile_tasks_(false),
429       prepare_tiles_count_(0u),
430       next_tile_id_(0u) {}
431
432 TileManager::~TileManager() {
433   FinishTasksAndCleanUp();
434 }
435
436 void TileManager::FinishTasksAndCleanUp() {
437   if (!tile_task_manager_)
438     return;
439
440   global_state_ = GlobalStateThatImpactsTilePriority();
441
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();
446
447   // This cancels tasks if possible, finishes pending tasks, and release any
448   // uninitialized resources.
449   tile_task_manager_->Shutdown();
450
451   // Reset the signal since SetResources() might be called later.
452   shutdown_event_.Reset();
453
454   raster_buffer_provider_->Shutdown();
455
456   tile_task_manager_->CheckForCompletedTasks();
457
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;
467
468   // Ask the tracker to drop any locked decodes since we will be destroying the
469   // decode cache.
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();
474 }
475
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);
484
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;
491
492   raster_buffer_provider_->SetShutdownEvent(&shutdown_event_);
493 }
494
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);
499
500   FreeResourcesForTile(tile);
501   tiles_.erase(tile->id());
502 }
503
504 void TileManager::DidFinishRunningTileTasksRequiredForActivation() {
505   TRACE_EVENT0("cc",
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();
514 }
515
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();
525 }
526
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_);
532
533   has_scheduled_tile_tasks_ = false;
534   has_pending_queries_ = has_pending_queries;
535
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();
545     return;
546   }
547
548   more_tiles_need_prepare_check_notifier_.Schedule();
549 }
550
551 bool TileManager::PrepareTiles(
552     const GlobalStateThatImpactsTilePriority& state) {
553   ++prepare_tiles_count_;
554
555   TRACE_EVENT1("cc,benchmark", "TileManager::PrepareTiles", "prepare_tiles_id",
556                prepare_tiles_count_);
557
558   if (!tile_task_manager_) {
559     TRACE_EVENT_INSTANT0("cc", "PrepareTiles aborted",
560                          TRACE_EVENT_SCOPE_THREAD);
561     return false;
562   }
563
564   signals_ = Signals();
565   global_state_ = state;
566
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
570   // to the client.
571   checker_image_tracker_.SetNoDecodesAllowed();
572
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;
578   }
579
580   if (!ShouldRasterOccludedTiles())
581     FreeResourcesForOccludedTiles();
582
583   PrioritizedWorkToSchedule prioritized_work = AssignGpuMemoryToTiles();
584
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());
590
591   // Schedule tile tasks.
592   ScheduleTasks(std::move(prioritized_work));
593
594   TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
595                        "state", BasicStateAsValue());
596   return true;
597 }
598
599 void TileManager::CheckForCompletedTasks() {
600   TRACE_EVENT0("cc", "TileManager::CheckForCompletedTasks");
601
602   if (!tile_task_manager_) {
603     TRACE_EVENT_INSTANT0("cc", "TileManager::CheckForCompletedTasksAborted",
604                          TRACE_EVENT_SCOPE_THREAD);
605     return;
606   }
607
608   tile_task_manager_->CheckForCompletedTasks();
609   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
610
611   CheckPendingGpuWorkAndIssueSignals();
612
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();
618 }
619
620 void TileManager::DidModifyTilePriorities() {
621   pending_tile_requirements_dirty_ = true;
622 }
623
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);
630 }
631
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();
639 }
640
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);
650     }
651     if (eviction_priority_queue->IsEmpty())
652       break;
653
654     Tile* tile = eviction_priority_queue->Top().tile();
655     *usage -= MemoryUsage::FromTile(tile);
656     FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
657     eviction_priority_queue->Pop();
658   }
659   return eviction_priority_queue;
660 }
661
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);
672     }
673     if (eviction_priority_queue->IsEmpty())
674       break;
675
676     const PrioritizedTile& prioritized_tile = eviction_priority_queue->Top();
677     if (!other_priority.IsHigherPriorityThan(prioritized_tile.priority()))
678       break;
679
680     Tile* tile = prioritized_tile.tile();
681     *usage -= MemoryUsage::FromTile(tile);
682     FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
683     eviction_priority_queue->Pop();
684   }
685   return eviction_priority_queue;
686 }
687
688 bool TileManager::TilePriorityViolatesMemoryPolicy(
689     const TilePriority& priority) {
690   switch (global_state_.memory_limit_policy) {
691     case ALLOW_NOTHING:
692       return true;
693     case ALLOW_ABSOLUTE_MINIMUM:
694       return priority.priority_bin > TilePriority::NOW;
695     case ALLOW_PREPAINT_ONLY:
696       return priority.priority_bin > TilePriority::SOON;
697     case ALLOW_ANYTHING:
698       return priority.distance_to_visible ==
699              std::numeric_limits<float>::infinity();
700   }
701   NOTREACHED();
702   return true;
703 }
704
705 TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
706   TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
707
708   DCHECK(resource_pool_);
709   DCHECK(tile_task_manager_);
710
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;
716
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());
723
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();
734
735     if (TilePriorityViolatesMemoryPolicy(priority)) {
736       TRACE_EVENT_INSTANT0(
737           "cc", "TileManager::AssignGpuMemory tile violates memory policy",
738           TRACE_EVENT_SCOPE_THREAD);
739       break;
740     }
741
742     DCHECK(!prioritized_tile.is_occluded() || raster_occluded_tiles);
743
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);
757         continue;
758       }
759     }
760
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);
764       continue;
765     }
766
767     auto content_color_usage =
768         GetContentColorUsageForPrioritizedTile(prioritized_tile);
769     const auto target_color_params =
770         client_->GetTargetColorParams(content_color_usage);
771
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());
780
781       AddCheckeredImagesToDecodeQueue(
782           prioritized_tile, target_color_params,
783           CheckerImageTracker::DecodeType::kRaster,
784           &work_to_schedule.checker_image_decode_queue);
785       continue;
786     }
787
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;
792       break;
793     }
794
795     DCHECK(tile->draw_info().mode() == TileDrawInfo::OOM_MODE ||
796            !tile->draw_info().IsReadyToDraw());
797
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));
805     }
806
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;
812
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);
821
822     // If we couldn't fit the tile into our current memory limit, then we're
823     // done.
824     if (!memory_usage_is_within_limit) {
825       if (tile_is_needed_now) {
826         LOG(ERROR) << "WARNING: tile memory limits exceeded, some content may "
827                       "not draw";
828
829         had_enough_memory_to_schedule_tiles_needed_now = false;
830       }
831       all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
832       break;
833     }
834
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);
846       }
847     } else {
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,
851                                           &work_to_schedule);
852       if (!raster_task) {
853         continue;
854       }
855
856       tile->raster_task_ = std::move(raster_task);
857     }
858
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);
862   }
863
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);
869
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();
880
881       if (prioritized_tile.priority().priority_bin > TilePriority::NOW)
882         break;
883
884       if (!prioritized_tile.should_decode_checkered_images_for_tile())
885         continue;
886
887       auto content_color_usage =
888           GetContentColorUsageForPrioritizedTile(prioritized_tile);
889       const auto target_color_params =
890           client_->GetTargetColorParams(content_color_usage);
891
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);
899       }
900     }
901   }
902
903   did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
904
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;
911
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;
919 }
920
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());
927   }
928 }
929
930 void TileManager::FreeResourcesForTile(Tile* tile) {
931   TileDrawInfo& draw_info = tile->draw_info();
932
933   if (draw_info.is_checker_imaged())
934     num_of_tiles_with_checker_images_--;
935   DCHECK_GE(num_of_tiles_with_checker_images_, 0);
936
937   if (draw_info.has_resource()) {
938     resource_pool_->ReleaseResource(draw_info.TakeResource());
939     pending_gpu_work_tiles_.erase(tile);
940   }
941 }
942
943 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
944     Tile* tile) {
945   bool was_ready_to_draw = tile->draw_info().IsReadyToDraw();
946   FreeResourcesForTile(tile);
947   if (was_ready_to_draw)
948     client_->NotifyTileStateChanged(tile);
949 }
950
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)));
964   }
965   prioritized_tile.raster_source()->GetDiscardableImagesInRect(enclosing_rect,
966                                                                &images_in_tile);
967   WhichTree tree = tile->tiling()->tree();
968
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;
974
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());
979     else
980       sync_decoded_images->push_back(std::move(draw_image));
981   }
982 }
983
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);
1001     }
1002   }
1003 }
1004
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());
1010
1011   DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
1012
1013   if (!has_scheduled_tile_tasks_) {
1014     TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc", "ScheduledTasks",
1015                                       TRACE_ID_LOCAL(this));
1016   }
1017
1018   // Cancel existing OnTaskSetFinished callbacks.
1019   task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
1020
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;
1025
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;
1030
1031   size_t priority = kTileTaskPriorityBase;
1032
1033   graph_.Reset();
1034
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);
1041
1042   auto all_done_cb =
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));
1048
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();
1053
1054     DCHECK(tile->draw_info().requires_resource());
1055     DCHECK(!tile->draw_info().has_resource());
1056     DCHECK(tile->HasRasterTask());
1057
1058     TileTask* task = tile->raster_task_.get();
1059     task->set_frame_number(tile->source_frame_number());
1060
1061     DCHECK(!task->HasCompleted());
1062
1063     if (tile->required_for_activation()) {
1064       required_for_activate_count++;
1065       graph_.edges.emplace_back(task, required_for_activation_done_task.get());
1066     }
1067     if (tile->required_for_draw()) {
1068       required_for_draw_count++;
1069       graph_.edges.emplace_back(task, required_for_draw_done_task.get());
1070     }
1071     all_count++;
1072     graph_.edges.emplace_back(task, all_done_task.get());
1073
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);
1082   }
1083
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);
1092
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,
1097                                  nullptr);
1098
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()));
1105
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);
1110     }
1111   }
1112
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());
1116
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();
1129
1130   for (auto& task : new_locked_image_tasks) {
1131     auto decode_it =
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())
1135       continue;
1136
1137     InsertNodeForDecodeTask(&graph_, task.get(), false, priority++);
1138     all_count++;
1139     graph_.edges.emplace_back(task.get(), all_done_task.get());
1140   }
1141
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);
1148
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();
1153
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);
1167
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_);
1172
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));
1178
1179   did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
1180
1181   TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("cc", "ScheduledTasksState",
1182                                       TRACE_ID_LOCAL(this), "state",
1183                                       ScheduledTasksStateAsValue());
1184 }
1185
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());
1195
1196   const int msaa_sample_count = client_->GetMSAASampleCountForRaster(
1197       prioritized_tile.raster_source()->GetDisplayItemList());
1198
1199   // When possible, rasterize HDR content into F16.
1200   //
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;
1208   }
1209
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);
1220   }
1221
1222   bool partial_tile_decode = false;
1223   if (resource) {
1224     resource_content_id = tile->invalidated_id();
1225     DCHECK_EQ(format, resource.format());
1226     partial_tile_decode = true;
1227   } else {
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,
1232         debug_name);
1233     DCHECK(resource);
1234   }
1235
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();
1244
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;
1255   if (!skip_images) {
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);
1260   }
1261
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);
1276
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_++;
1281
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 */);
1292     return nullptr;
1293   }
1294
1295   PaintImageIdFlatSet images_to_skip;
1296   for (const auto& image : checkered_images) {
1297     DCHECK(!image.ShouldAnimate());
1298
1299     images_to_skip.insert(image.stable_id());
1300
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);
1308     }
1309   }
1310
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);
1316
1317   absl::optional<PlaybackImageProvider::Settings> settings;
1318   if (!skip_images) {
1319     settings.emplace();
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;
1325     }
1326   }
1327
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));
1339
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_);
1346 }
1347
1348 void TileManager::ResetSignalsForTesting() {
1349   signals_ = Signals();
1350 }
1351
1352 void TileManager::OnRasterTaskCompleted(
1353     Tile::Id tile_id,
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_--;
1366   }
1367
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);
1377
1378   if (was_canceled) {
1379     ++raster_task_completion_stats_.canceled_count;
1380     resource_pool_->ReleaseResource(std::move(resource));
1381     return;
1382   }
1383
1384   resource_pool_->OnContentReplaced(resource, tile_id);
1385   ++raster_task_completion_stats_.completed_count;
1386
1387   if (!tile) {
1388     resource_pool_->ReleaseResource(std::move(resource));
1389     return;
1390   }
1391
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);
1395
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) {
1400     is_ready_for_draw =
1401         raster_buffer_provider_->IsResourceReadyToDraw(resource);
1402   }
1403
1404   TileDrawInfo& draw_info = tile->draw_info();
1405   if (exported) {
1406     bool is_premultiplied = raster_buffer_provider_->IsResourcePremultiplied();
1407     draw_info.SetResource(std::move(resource),
1408                           raster_task_was_scheduled_with_checker_images,
1409                           is_premultiplied);
1410   } else {
1411     resource_pool_->ReleaseResource(std::move(resource));
1412     draw_info.set_oom();
1413   }
1414   if (raster_task_was_scheduled_with_checker_images)
1415     num_of_tiles_with_checker_images_++;
1416
1417   if (!is_ready_for_draw) {
1418     pending_gpu_work_tiles_.insert(tile);
1419   } else {
1420     draw_info.set_resource_ready_for_draw();
1421     client_->NotifyTileStateChanged(tile);
1422   }
1423 }
1424
1425 std::unique_ptr<Tile> TileManager::CreateTile(const Tile::CreateInfo& info,
1426                                               int layer_id,
1427                                               int source_frame_number,
1428                                               int flags) {
1429   // We need to have a tile task worker pool to do anything meaningful with
1430   // tiles.
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());
1435
1436   tiles_[tile->id()] = tile.get();
1437   return tile;
1438 }
1439
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
1448   // draw.
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())
1452       return false;
1453   }
1454
1455 #if DCHECK_IS_ON()
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());
1462   }
1463 #endif
1464   return true;
1465 }
1466
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);
1472 }
1473
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);
1479 }
1480
1481 void TileManager::ScheduleCheckRasterFinishedQueries() {
1482   DCHECK(has_pending_queries_);
1483
1484   if (!check_pending_tile_queries_callback_.IsCancelled())
1485     return;
1486
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));
1492 }
1493
1494 void TileManager::CheckRasterFinishedQueries() {
1495   check_pending_tile_queries_callback_.Cancel();
1496
1497   if (!has_pending_queries_)
1498     return;
1499
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)
1502     return;
1503
1504   has_pending_queries_ = false;
1505   if (pending_raster_queries_) {
1506     has_pending_queries_ =
1507         pending_raster_queries_->CheckRasterFinishedQueries();
1508   }
1509   if (has_pending_queries_)
1510     ScheduleCheckRasterFinishedQueries();
1511 }
1512
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;
1517
1518   raster_buffer_provider_->Flush();
1519   CheckPendingGpuWorkAndIssueSignals();
1520 }
1521
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();
1534     }
1535   }
1536
1537   // Ready to draw.
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();
1545     }
1546   }
1547
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");
1554
1555       if (has_pending_queries_)
1556         ScheduleCheckRasterFinishedQueries();
1557
1558       signals_.did_notify_all_tile_tasks_completed = true;
1559       client_->NotifyAllTileTasksCompleted();
1560     }
1561   }
1562
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;
1568
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);
1580   }
1581 }
1582
1583 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
1584   tile_task_manager_->CheckForCompletedTasks();
1585   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
1586
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();
1590
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());
1596
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));
1601     return;
1602   }
1603
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();
1610   }
1611
1612   resource_pool_->ReduceResourceUsage();
1613   image_controller_.ReduceMemoryUsage();
1614
1615   // TODO(vmpstr): Temporary check to debug crbug.com/642927.
1616   CHECK(tile_task_manager_);
1617
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();
1623
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;
1633
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)
1637     return;
1638
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));
1650
1651   // TODO(vmpstr): Temporary check to debug crbug.com/642927.
1652   CHECK(tile_task_manager_);
1653
1654   DCHECK(IsReadyToActivate());
1655   DCHECK(IsReadyToDraw());
1656 }
1657
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())
1664       continue;
1665     tile->draw_info().set_oom();
1666     client_->NotifyTileStateChanged(tile);
1667   }
1668 }
1669
1670 const PaintImageIdFlatSet& TileManager::TakeImagesToInvalidateOnSyncTree() {
1671   return checker_image_tracker_.TakeImagesToInvalidateOnSyncTree();
1672 }
1673
1674 void TileManager::DidActivateSyncTree() {
1675   checker_image_tracker_.DidActivateSyncTree();
1676 }
1677
1678 void TileManager::ClearCheckerImageTracking(
1679     bool can_clear_decode_policy_tracking) {
1680   checker_image_tracker_.ClearTracker(can_clear_decode_policy_tracking);
1681 }
1682
1683 void TileManager::SetCheckerImagingForceDisabled(bool force_disable) {
1684   checker_image_tracker_.set_force_disabled(force_disable);
1685 }
1686
1687 void TileManager::NeedsInvalidationForCheckerImagedTiles() {
1688   client_->RequestImplSideInvalidationForCheckerImagedTiles();
1689 }
1690
1691 viz::ResourceFormat TileManager::DetermineResourceFormat(
1692     const Tile* tile) const {
1693   return raster_buffer_provider_->GetResourceFormat();
1694 }
1695
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);
1709 }
1710
1711 bool TileManager::UsePartialRaster(int msaa_sample_count) const {
1712   // Partial raster doesn't support MSAA, as the MSAA resolve is unaware of clip
1713   // rects.
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;
1718 }
1719
1720 void TileManager::CheckPendingGpuWorkAndIssueSignals() {
1721   TRACE_EVENT2("cc", "TileManager::CheckPendingGpuWorkAndIssueSignals",
1722                "pending_gpu_work_tiles", pending_gpu_work_tiles_.size(),
1723                "tree_priority",
1724                TreePriorityToString(global_state_.tree_priority));
1725
1726   std::vector<const ResourcePool::InUsePoolResource*> required_for_activation;
1727   std::vector<const ResourcePool::InUsePoolResource*> required_for_draw;
1728
1729   for (auto it = pending_gpu_work_tiles_.begin();
1730        it != pending_gpu_work_tiles_.end();) {
1731     Tile* tile = *it;
1732     DCHECK(tile->draw_info().has_resource());
1733     const ResourcePool::InUsePoolResource& resource =
1734         tile->draw_info().GetResource();
1735
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);
1740
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);
1746       continue;
1747     }
1748
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);
1756
1757     ++it;
1758   }
1759
1760   if (required_for_activation.empty()) {
1761     pending_required_for_activation_callback_id_ = 0;
1762   } else {
1763     pending_required_for_activation_callback_id_ =
1764         raster_buffer_provider_->SetReadyToDrawCallback(
1765             required_for_activation,
1766             base::BindOnce(
1767                 &TileManager::CheckPendingGpuWorkAndIssueSignals,
1768                 ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
1769             pending_required_for_activation_callback_id_);
1770   }
1771
1772   if (required_for_draw.empty()) {
1773     pending_required_for_draw_callback_id_ = 0;
1774   } else {
1775     pending_required_for_draw_callback_id_ =
1776         raster_buffer_provider_->SetReadyToDrawCallback(
1777             required_for_draw,
1778             base::BindOnce(
1779                 &TileManager::CheckPendingGpuWorkAndIssueSignals,
1780                 ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
1781             pending_required_for_draw_callback_id_);
1782   }
1783
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);
1789
1790   // We've just updated all pending tile requirements if necessary.
1791   pending_tile_requirements_dirty_ = false;
1792
1793   IssueSignals();
1794 }
1795
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>(
1801       task_runner_,
1802       base::BindRepeating(callback,
1803                           task_set_finished_weak_ptr_factory_.GetWeakPtr()));
1804 }
1805
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);
1811 }
1812
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());
1826
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();
1833
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());
1845   };
1846
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();
1855   }
1856   state->EndArray();
1857
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();
1867   }
1868   state->EndArray();
1869 }
1870
1871 bool TileManager::ShouldRasterOccludedTiles() const {
1872   return (global_state_.memory_limit_policy != ALLOW_NOTHING &&
1873           global_state_.memory_limit_policy != ALLOW_ABSOLUTE_MINIMUM);
1874 }
1875
1876 TileManager::MemoryUsage::MemoryUsage()
1877     : memory_bytes_(0), resource_count_(0) {}
1878
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()));
1891 }
1892
1893 // static
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
1899   // size).
1900   return MemoryUsage(
1901       viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format), 1);
1902 }
1903
1904 // static
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);
1909   }
1910   return MemoryUsage();
1911 }
1912
1913 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
1914     const MemoryUsage& other) {
1915   memory_bytes_ += other.memory_bytes_;
1916   resource_count_ += other.resource_count_;
1917   return *this;
1918 }
1919
1920 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
1921     const MemoryUsage& other) {
1922   memory_bytes_ -= other.memory_bytes_;
1923   resource_count_ -= other.resource_count_;
1924   return *this;
1925 }
1926
1927 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
1928     const MemoryUsage& other) {
1929   MemoryUsage result = *this;
1930   result -= other;
1931   return result;
1932 }
1933
1934 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
1935   return memory_bytes_ > limit.memory_bytes_ ||
1936          resource_count_ > limit.resource_count_;
1937 }
1938
1939 TileManager::PrioritizedWorkToSchedule::PrioritizedWorkToSchedule() = default;
1940 TileManager::PrioritizedWorkToSchedule::PrioritizedWorkToSchedule(
1941     PrioritizedWorkToSchedule&& other) = default;
1942 TileManager::PrioritizedWorkToSchedule::~PrioritizedWorkToSchedule() = default;
1943
1944 }  // namespace cc