1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "cc/tiles/tile_manager.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <algorithm>
11 #include <limits>
12 #include <string>
13 
14 #include "base/bind.h"
15 #include "base/json/json_writer.h"
16 #include "base/logging.h"
17 #include "base/metrics/histogram.h"
18 #include "base/numerics/safe_conversions.h"
19 #include "base/optional.h"
20 #include "base/threading/thread_checker.h"
21 #include "base/trace_event/traced_value.h"
22 #include "cc/base/devtools_instrumentation.h"
23 #include "cc/base/histograms.h"
24 #include "cc/layers/picture_layer_impl.h"
25 #include "cc/paint/display_item_list.h"
26 #include "cc/raster/paint_worklet_image_provider.h"
27 #include "cc/raster/playback_image_provider.h"
28 #include "cc/raster/raster_buffer.h"
29 #include "cc/raster/task_category.h"
30 #include "cc/tiles/frame_viewer_instrumentation.h"
31 #include "cc/tiles/tile.h"
32 #include "components/viz/common/resources/resource_sizes.h"
33 #include "ui/gfx/geometry/axis_transform2d.h"
34 #include "ui/gfx/geometry/rect_conversions.h"
35 
36 namespace cc {
37 namespace {
38 
39 // Flag to indicate whether we should try and detect that
40 // a tile is of solid color.
41 const bool kUseColorEstimator = true;
42 
43 // This class is wrapper for both ImageProvider and PaintWorkletImageProvider,
44 // which is used in RasterSource::PlaybackSettings. It looks at the draw image
45 // and decides which one of the two providers to dispatch the request to.
46 class DispatchingImageProvider : public ImageProvider {
47  public:
DispatchingImageProvider(PlaybackImageProvider playback_image_provider,PaintWorkletImageProvider paint_worklet_image_provider)48   DispatchingImageProvider(
49       PlaybackImageProvider playback_image_provider,
50       PaintWorkletImageProvider paint_worklet_image_provider)
51       : playback_image_provider_(std::move(playback_image_provider)),
52         paint_worklet_image_provider_(std::move(paint_worklet_image_provider)) {
53   }
54   DispatchingImageProvider(const DispatchingImageProvider&) = delete;
55   ~DispatchingImageProvider() override = default;
56 
57   DispatchingImageProvider& operator=(const DispatchingImageProvider&) = delete;
58 
59   DispatchingImageProvider(DispatchingImageProvider&& other) = default;
60 
GetRasterContent(const DrawImage & draw_image)61   ImageProvider::ScopedResult GetRasterContent(
62       const DrawImage& draw_image) override {
63     return draw_image.paint_image().IsPaintWorklet()
64                ? paint_worklet_image_provider_.GetPaintRecordResult(
65                      draw_image.paint_image().paint_worklet_input())
66                : playback_image_provider_.GetRasterContent(draw_image);
67   }
68 
69  private:
70   PlaybackImageProvider playback_image_provider_;
71   PaintWorkletImageProvider paint_worklet_image_provider_;
72 };
73 
74 class RasterTaskImpl : public TileTask {
75  public:
RasterTaskImpl(TileManager * tile_manager,Tile * tile,ResourcePool::InUsePoolResource resource,scoped_refptr<RasterSource> raster_source,const RasterSource::PlaybackSettings & playback_settings,TileResolution tile_resolution,gfx::Rect invalidated_rect,uint64_t source_prepare_tiles_id,std::unique_ptr<RasterBuffer> raster_buffer,TileTask::Vector * dependencies,bool is_gpu_rasterization,DispatchingImageProvider image_provider,GURL url)76   RasterTaskImpl(TileManager* tile_manager,
77                  Tile* tile,
78                  ResourcePool::InUsePoolResource resource,
79                  scoped_refptr<RasterSource> raster_source,
80                  const RasterSource::PlaybackSettings& playback_settings,
81                  TileResolution tile_resolution,
82                  gfx::Rect invalidated_rect,
83                  uint64_t source_prepare_tiles_id,
84                  std::unique_ptr<RasterBuffer> raster_buffer,
85                  TileTask::Vector* dependencies,
86                  bool is_gpu_rasterization,
87                  DispatchingImageProvider image_provider,
88                  GURL url)
89       : TileTask(!is_gpu_rasterization, dependencies),
90         tile_manager_(tile_manager),
91         tile_id_(tile->id()),
92         resource_(std::move(resource)),
93         raster_source_(std::move(raster_source)),
94         content_rect_(tile->content_rect()),
95         invalid_content_rect_(invalidated_rect),
96         raster_transform_(tile->raster_transform()),
97         playback_settings_(playback_settings),
98         tile_resolution_(tile_resolution),
99         layer_id_(tile->layer_id()),
100         source_prepare_tiles_id_(source_prepare_tiles_id),
101         tile_tracing_id_(static_cast<void*>(tile)),
102         new_content_id_(tile->id()),
103         source_frame_number_(tile->source_frame_number()),
104         raster_buffer_(std::move(raster_buffer)),
105         image_provider_(std::move(image_provider)),
106         url_(std::move(url)) {
107     DCHECK(origin_thread_checker_.CalledOnValidThread());
108     playback_settings_.image_provider = &image_provider_;
109   }
110   RasterTaskImpl(const RasterTaskImpl&) = delete;
111   RasterTaskImpl& operator=(const RasterTaskImpl&) = delete;
112 
113   // Overridden from Task:
RunOnWorkerThread()114   void RunOnWorkerThread() override {
115     TRACE_EVENT1("cc", "RasterizerTaskImpl::RunOnWorkerThread",
116                  "source_prepare_tiles_id", source_prepare_tiles_id_);
117 
118     DCHECK(raster_source_.get());
119     DCHECK(raster_buffer_);
120 
121     frame_viewer_instrumentation::ScopedRasterTask raster_task(
122         tile_tracing_id_, tile_resolution_, source_frame_number_, layer_id_);
123 
124     DCHECK(raster_source_);
125 
126     raster_buffer_->Playback(raster_source_.get(), content_rect_,
127                              invalid_content_rect_, new_content_id_,
128                              raster_transform_, playback_settings_, url_);
129   }
130 
131   // Overridden from TileTask:
OnTaskCompleted()132   void OnTaskCompleted() override {
133     DCHECK(origin_thread_checker_.CalledOnValidThread());
134 
135     // Here calling state().IsCanceled() is thread-safe, because this task is
136     // already concluded as FINISHED or CANCELLED and no longer will be worked
137     // upon by task graph runner.
138     raster_buffer_ = nullptr;
139     tile_manager_->OnRasterTaskCompleted(tile_id_, std::move(resource_),
140                                          state().IsCanceled());
141   }
142 
143  protected:
~RasterTaskImpl()144   ~RasterTaskImpl() override {
145     DCHECK(origin_thread_checker_.CalledOnValidThread());
146     DCHECK(!raster_buffer_);
147     DCHECK(!resource_);
148   }
149 
150  private:
151   base::ThreadChecker origin_thread_checker_;
152 
153   // The following members are needed for processing completion of this task on
154   // origin thread. These are not thread-safe and should be accessed only in
155   // origin thread. Ensure their access by checking CalledOnValidThread().
156   TileManager* tile_manager_;
157   Tile::Id tile_id_;
158   ResourcePool::InUsePoolResource resource_;
159 
160   // The following members should be used for running the task.
161   scoped_refptr<RasterSource> raster_source_;
162   gfx::Rect content_rect_;
163   gfx::Rect invalid_content_rect_;
164   gfx::AxisTransform2d raster_transform_;
165   RasterSource::PlaybackSettings playback_settings_;
166   TileResolution tile_resolution_;
167   int layer_id_;
168   uint64_t source_prepare_tiles_id_;
169   void* tile_tracing_id_;
170   uint64_t new_content_id_;
171   int source_frame_number_;
172   std::unique_ptr<RasterBuffer> raster_buffer_;
173   DispatchingImageProvider image_provider_;
174   GURL url_;
175 };
176 
TaskCategoryForTileTask(TileTask * task,bool use_foreground_category)177 TaskCategory TaskCategoryForTileTask(TileTask* task,
178                                      bool use_foreground_category) {
179   if (!task->supports_concurrent_execution())
180     return TASK_CATEGORY_NONCONCURRENT_FOREGROUND;
181 
182   if (use_foreground_category)
183     return TASK_CATEGORY_FOREGROUND;
184 
185   return TASK_CATEGORY_BACKGROUND;
186 }
187 
IsForegroundCategory(uint16_t category)188 bool IsForegroundCategory(uint16_t category) {
189   TaskCategory enum_category = static_cast<TaskCategory>(category);
190   switch (enum_category) {
191     case TASK_CATEGORY_NONCONCURRENT_FOREGROUND:
192     case TASK_CATEGORY_FOREGROUND:
193       return true;
194     case TASK_CATEGORY_BACKGROUND:
195       return false;
196   }
197 
198   DCHECK(false);
199   return false;
200 }
201 
202 // Task priorities that make sure that the task set done tasks run before any
203 // other remaining tasks.
204 const size_t kRequiredForActivationDoneTaskPriority = 1u;
205 const size_t kRequiredForDrawDoneTaskPriority = 2u;
206 const size_t kAllDoneTaskPriority = 3u;
207 
208 // For correctness, |kTileTaskPriorityBase| must be greater than
209 // all task set done task priorities.
210 size_t kTileTaskPriorityBase = 10u;
211 
InsertNodeForTask(TaskGraph * graph,TileTask * task,uint16_t category,uint16_t priority,size_t dependencies)212 void InsertNodeForTask(TaskGraph* graph,
213                        TileTask* task,
214                        uint16_t category,
215                        uint16_t priority,
216                        size_t dependencies) {
217   DCHECK(std::find_if(graph->nodes.begin(), graph->nodes.end(),
218                       [&task](const TaskGraph::Node& node) {
219                         return node.task == task;
220                       }) == graph->nodes.end());
221   graph->nodes.emplace_back(task, category, priority, dependencies);
222 }
223 
InsertNodeForDecodeTask(TaskGraph * graph,TileTask * task,bool use_foreground_category,uint16_t priority)224 void InsertNodeForDecodeTask(TaskGraph* graph,
225                              TileTask* task,
226                              bool use_foreground_category,
227                              uint16_t priority) {
228   uint32_t dependency_count = 0u;
229   if (task->dependencies().size()) {
230     DCHECK_EQ(task->dependencies().size(), 1u);
231     auto* dependency = task->dependencies()[0].get();
232     if (!dependency->HasCompleted()) {
233       InsertNodeForDecodeTask(graph, dependency, use_foreground_category,
234                               priority);
235       graph->edges.emplace_back(dependency, task);
236       dependency_count = 1u;
237     }
238   }
239   InsertNodeForTask(graph, task,
240                     TaskCategoryForTileTask(task, use_foreground_category),
241                     priority, dependency_count);
242 }
243 
InsertNodesForRasterTask(TaskGraph * graph,TileTask * raster_task,const TileTask::Vector & decode_tasks,size_t priority,bool use_foreground_category)244 void InsertNodesForRasterTask(TaskGraph* graph,
245                               TileTask* raster_task,
246                               const TileTask::Vector& decode_tasks,
247                               size_t priority,
248                               bool use_foreground_category) {
249   size_t dependencies = 0u;
250 
251   // Insert image decode tasks.
252   for (auto it = decode_tasks.begin(); it != decode_tasks.end(); ++it) {
253     TileTask* decode_task = it->get();
254 
255     // Skip if already decoded.
256     if (decode_task->HasCompleted())
257       continue;
258 
259     dependencies++;
260 
261     // Add decode task if it doesn't already exist in graph.
262     auto decode_it = std::find_if(graph->nodes.begin(), graph->nodes.end(),
263                                   [decode_task](const TaskGraph::Node& node) {
264                                     return node.task == decode_task;
265                                   });
266 
267     // In rare circumstances, a background category task may come in before a
268     // foreground category task. In these cases, upgrade any background category
269     // dependencies of the current task.
270     // TODO(ericrk): Task iterators should be updated to avoid this.
271     // crbug.com/594851
272     // TODO(ericrk): This should handle dependencies recursively.
273     // crbug.com/605234
274     if (decode_it != graph->nodes.end() && use_foreground_category &&
275         !IsForegroundCategory(decode_it->category)) {
276       decode_it->category = TASK_CATEGORY_FOREGROUND;
277     }
278 
279     if (decode_it == graph->nodes.end()) {
280       InsertNodeForDecodeTask(graph, decode_task, use_foreground_category,
281                               priority);
282     }
283 
284     graph->edges.emplace_back(decode_task, raster_task);
285   }
286 
287   InsertNodeForTask(
288       graph, raster_task,
289       TaskCategoryForTileTask(raster_task, use_foreground_category), priority,
290       dependencies);
291 }
292 
293 class TaskSetFinishedTaskImpl : public TileTask {
294  public:
TaskSetFinishedTaskImpl(base::SequencedTaskRunner * task_runner,base::RepeatingClosure on_task_set_finished_callback)295   explicit TaskSetFinishedTaskImpl(
296       base::SequencedTaskRunner* task_runner,
297       base::RepeatingClosure on_task_set_finished_callback)
298       : TileTask(true),
299         task_runner_(task_runner),
300         on_task_set_finished_callback_(
301             std::move(on_task_set_finished_callback)) {}
302   TaskSetFinishedTaskImpl(const TaskSetFinishedTaskImpl&) = delete;
303   TaskSetFinishedTaskImpl& operator=(const TaskSetFinishedTaskImpl&) = delete;
304 
305   // Overridden from Task:
RunOnWorkerThread()306   void RunOnWorkerThread() override {
307     TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread");
308     TaskSetFinished();
309   }
310 
311   // Overridden from TileTask:
OnTaskCompleted()312   void OnTaskCompleted() override {}
313 
314  protected:
315   ~TaskSetFinishedTaskImpl() override = default;
316 
TaskSetFinished()317   void TaskSetFinished() {
318     task_runner_->PostTask(FROM_HERE, on_task_set_finished_callback_);
319   }
320 
321  private:
322   base::SequencedTaskRunner* task_runner_;
323   const base::RepeatingClosure on_task_set_finished_callback_;
324 };
325 
326 class DidFinishRunningAllTilesTask : public TileTask {
327  public:
328   using CompletionCb = base::OnceCallback<void(bool has_pending_queries)>;
DidFinishRunningAllTilesTask(base::SequencedTaskRunner * task_runner,RasterBufferProvider * raster_buffer_provider,CompletionCb completion_cb)329   DidFinishRunningAllTilesTask(base::SequencedTaskRunner* task_runner,
330                                RasterBufferProvider* raster_buffer_provider,
331                                CompletionCb completion_cb)
332       : TileTask(false /* supports_concurrent_execution */),
333         task_runner_(task_runner),
334         raster_buffer_provider_(raster_buffer_provider),
335         completion_cb_(std::move(completion_cb)) {}
336 
RunOnWorkerThread()337   void RunOnWorkerThread() override {
338     TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread");
339     bool has_pending_queries =
340         raster_buffer_provider_->CheckRasterFinishedQueries();
341     task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(completion_cb_),
342                                                      has_pending_queries));
343   }
344 
OnTaskCompleted()345   void OnTaskCompleted() override {}
346 
347  protected:
348   ~DidFinishRunningAllTilesTask() override = default;
349 
350  private:
351   base::SequencedTaskRunner* task_runner_;
352   RasterBufferProvider* raster_buffer_provider_;
353   CompletionCb completion_cb_;
354 };
355 
GetContentColorUsageForPrioritizedTile(const PrioritizedTile & prioritized_tile)356 gfx::ContentColorUsage GetContentColorUsageForPrioritizedTile(
357     const PrioritizedTile& prioritized_tile) {
358   // TODO(cblume,ccameron): Add support for HDR.
359   bool contains_only_srgb_images = prioritized_tile.raster_source()
360                                        ->GetDisplayItemList()
361                                        ->discardable_image_map()
362                                        .contains_only_srgb_images();
363   return contains_only_srgb_images ? gfx::ContentColorUsage::kSRGB
364                                    : gfx::ContentColorUsage::kWideColorGamut;
365 }
366 
367 }  // namespace
368 
RasterTaskCompletionStats()369 RasterTaskCompletionStats::RasterTaskCompletionStats()
370     : completed_count(0u), canceled_count(0u) {}
371 
372 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats & stats)373 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
374   std::unique_ptr<base::trace_event::TracedValue> state(
375       new base::trace_event::TracedValue());
376   state->SetInteger("completed_count",
377                     base::saturated_cast<int>(stats.completed_count));
378   state->SetInteger("canceled_count",
379                     base::saturated_cast<int>(stats.canceled_count));
380   return std::move(state);
381 }
382 
TileManager(TileManagerClient * client,base::SequencedTaskRunner * origin_task_runner,scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner,size_t scheduled_raster_task_limit,const TileManagerSettings & tile_manager_settings)383 TileManager::TileManager(
384     TileManagerClient* client,
385     base::SequencedTaskRunner* origin_task_runner,
386     scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner,
387     size_t scheduled_raster_task_limit,
388     const TileManagerSettings& tile_manager_settings)
389     : client_(client),
390       task_runner_(origin_task_runner),
391       resource_pool_(nullptr),
392       tile_task_manager_(nullptr),
393       scheduled_raster_task_limit_(scheduled_raster_task_limit),
394       tile_manager_settings_(tile_manager_settings),
395       use_gpu_rasterization_(false),
396       all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
397       did_check_for_completed_tasks_since_last_schedule_tasks_(true),
398       did_oom_on_last_assign_(false),
399       image_controller_(origin_task_runner,
400                         std::move(image_worker_task_runner)),
401       decoded_image_tracker_(&image_controller_, origin_task_runner),
402       checker_image_tracker_(&image_controller_,
403                              this,
404                              tile_manager_settings_.enable_checker_imaging,
405                              tile_manager_settings_.min_image_bytes_to_checker),
406       more_tiles_need_prepare_check_notifier_(
407           task_runner_,
408           base::BindRepeating(&TileManager::CheckIfMoreTilesNeedToBePrepared,
409                               base::Unretained(this))),
410       signals_check_notifier_(
411           task_runner_,
412           base::BindRepeating(&TileManager::FlushAndIssueSignals,
413                               base::Unretained(this))),
414       has_scheduled_tile_tasks_(false),
415       prepare_tiles_count_(0u),
416       next_tile_id_(0u) {}
417 
~TileManager()418 TileManager::~TileManager() {
419   FinishTasksAndCleanUp();
420 }
421 
FinishTasksAndCleanUp()422 void TileManager::FinishTasksAndCleanUp() {
423   if (!tile_task_manager_)
424     return;
425 
426   global_state_ = GlobalStateThatImpactsTilePriority();
427 
428   // This cancels tasks if possible, finishes pending tasks, and release any
429   // uninitialized resources.
430   tile_task_manager_->Shutdown();
431 
432   raster_buffer_provider_->Shutdown();
433 
434   tile_task_manager_->CheckForCompletedTasks();
435 
436   tile_task_manager_ = nullptr;
437   resource_pool_ = nullptr;
438   more_tiles_need_prepare_check_notifier_.Cancel();
439   signals_check_notifier_.Cancel();
440   task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
441   ready_to_draw_callback_weak_ptr_factory_.InvalidateWeakPtrs();
442   check_pending_tile_queries_callback_.Cancel();
443   raster_buffer_provider_ = nullptr;
444 
445   // Ask the tracker to drop any locked decodes since we will be destroying the
446   // decode cache.
447   bool can_clear_decode_policy_tracking = false;
448   checker_image_tracker_.ClearTracker(can_clear_decode_policy_tracking);
449   image_controller_.SetImageDecodeCache(nullptr);
450   locked_image_tasks_.clear();
451 }
452 
SetResources(ResourcePool * resource_pool,ImageDecodeCache * image_decode_cache,TaskGraphRunner * task_graph_runner,RasterBufferProvider * raster_buffer_provider,bool use_gpu_rasterization)453 void TileManager::SetResources(ResourcePool* resource_pool,
454                                ImageDecodeCache* image_decode_cache,
455                                TaskGraphRunner* task_graph_runner,
456                                RasterBufferProvider* raster_buffer_provider,
457                                bool use_gpu_rasterization) {
458   DCHECK(!tile_task_manager_);
459   DCHECK(task_graph_runner);
460 
461   use_gpu_rasterization_ = use_gpu_rasterization;
462   resource_pool_ = resource_pool;
463   image_controller_.SetImageDecodeCache(image_decode_cache);
464   tile_task_manager_ = TileTaskManagerImpl::Create(task_graph_runner);
465   raster_buffer_provider_ = raster_buffer_provider;
466 }
467 
Release(Tile * tile)468 void TileManager::Release(Tile* tile) {
469   if (tile->raster_task_scheduled_with_checker_images())
470     num_of_tiles_with_checker_images_--;
471   DCHECK_GE(num_of_tiles_with_checker_images_, 0);
472 
473   FreeResourcesForTile(tile);
474   tiles_.erase(tile->id());
475 }
476 
DidFinishRunningTileTasksRequiredForActivation()477 void TileManager::DidFinishRunningTileTasksRequiredForActivation() {
478   TRACE_EVENT0("cc",
479                "TileManager::DidFinishRunningTileTasksRequiredForActivation");
480   TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("cc", "ScheduledTasksState",
481                                       TRACE_ID_LOCAL(this), "state",
482                                       ScheduledTasksStateAsValue());
483   // TODO(vmpstr): Temporary check to debug crbug.com/642927.
484   CHECK(tile_task_manager_);
485   signals_.activate_tile_tasks_completed = true;
486   signals_check_notifier_.Schedule();
487 }
488 
DidFinishRunningTileTasksRequiredForDraw()489 void TileManager::DidFinishRunningTileTasksRequiredForDraw() {
490   TRACE_EVENT0("cc", "TileManager::DidFinishRunningTileTasksRequiredForDraw");
491   TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("cc", "ScheduledTasksState",
492                                       TRACE_ID_LOCAL(this), "state",
493                                       ScheduledTasksStateAsValue());
494   // TODO(vmpstr): Temporary check to debug crbug.com/642927.
495   CHECK(tile_task_manager_);
496   signals_.draw_tile_tasks_completed = true;
497   signals_check_notifier_.Schedule();
498 }
499 
DidFinishRunningAllTileTasks(bool has_pending_queries)500 void TileManager::DidFinishRunningAllTileTasks(bool has_pending_queries) {
501   TRACE_EVENT0("cc", "TileManager::DidFinishRunningAllTileTasks");
502   TRACE_EVENT_NESTABLE_ASYNC_END0("cc", "ScheduledTasks", TRACE_ID_LOCAL(this));
503   DCHECK(resource_pool_);
504   DCHECK(tile_task_manager_);
505 
506   has_scheduled_tile_tasks_ = false;
507   has_pending_queries_ = has_pending_queries;
508 
509   if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
510       !resource_pool_->ResourceUsageTooHigh()) {
511     // TODO(ericrk): We should find a better way to safely handle re-entrant
512     // notifications than always having to schedule a new task.
513     // http://crbug.com/498439
514     // TODO(vmpstr): Temporary check to debug crbug.com/642927.
515     CHECK(tile_task_manager_);
516     signals_.all_tile_tasks_completed = true;
517     signals_check_notifier_.Schedule();
518     return;
519   }
520 
521   more_tiles_need_prepare_check_notifier_.Schedule();
522 }
523 
PrepareTiles(const GlobalStateThatImpactsTilePriority & state)524 bool TileManager::PrepareTiles(
525     const GlobalStateThatImpactsTilePriority& state) {
526   ++prepare_tiles_count_;
527 
528   TRACE_EVENT1("cc,benchmark", "TileManager::PrepareTiles", "prepare_tiles_id",
529                prepare_tiles_count_);
530 
531   if (!tile_task_manager_) {
532     TRACE_EVENT_INSTANT0("cc", "PrepareTiles aborted",
533                          TRACE_EVENT_SCOPE_THREAD);
534     return false;
535   }
536 
537   signals_ = Signals();
538   global_state_ = state;
539 
540   // Ensure that we don't schedule any decode work for checkered images until
541   // the raster work for visible tiles is complete. This is done in
542   // FlushAndIssueSignals when the ready to activate/draw signals are dispatched
543   // to the client.
544   checker_image_tracker_.SetNoDecodesAllowed();
545 
546   // We need to call CheckForCompletedTasks() once in-between each call
547   // to ScheduleTasks() to prevent canceled tasks from being scheduled.
548   if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
549     tile_task_manager_->CheckForCompletedTasks();
550     did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
551   }
552 
553   PrioritizedWorkToSchedule prioritized_work = AssignGpuMemoryToTiles();
554 
555   // Inform the client that will likely require a draw if the highest priority
556   // tile that will be rasterized is required for draw.
557   client_->SetIsLikelyToRequireADraw(
558       !prioritized_work.tiles_to_raster.empty() &&
559       prioritized_work.tiles_to_raster.front().tile()->required_for_draw());
560 
561   // Schedule tile tasks.
562   ScheduleTasks(std::move(prioritized_work));
563 
564   TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
565                        "state", BasicStateAsValue());
566   return true;
567 }
568 
CheckForCompletedTasks()569 void TileManager::CheckForCompletedTasks() {
570   TRACE_EVENT0("cc", "TileManager::CheckForCompletedTasks");
571 
572   if (!tile_task_manager_) {
573     TRACE_EVENT_INSTANT0("cc", "TileManager::CheckForCompletedTasksAborted",
574                          TRACE_EVENT_SCOPE_THREAD);
575     return;
576   }
577 
578   tile_task_manager_->CheckForCompletedTasks();
579   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
580 
581   CheckPendingGpuWorkAndIssueSignals();
582 
583   TRACE_EVENT_INSTANT1(
584       "cc", "TileManager::CheckForCompletedTasksFinished",
585       TRACE_EVENT_SCOPE_THREAD, "stats",
586       RasterTaskCompletionStatsAsValue(raster_task_completion_stats_));
587   raster_task_completion_stats_ = RasterTaskCompletionStats();
588 }
589 
DidModifyTilePriorities()590 void TileManager::DidModifyTilePriorities() {
591   pending_tile_requirements_dirty_ = true;
592 }
593 
594 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
BasicStateAsValue() const595 TileManager::BasicStateAsValue() const {
596   std::unique_ptr<base::trace_event::TracedValue> value(
597       new base::trace_event::TracedValue());
598   BasicStateAsValueInto(value.get());
599   return std::move(value);
600 }
601 
BasicStateAsValueInto(base::trace_event::TracedValue * state) const602 void TileManager::BasicStateAsValueInto(
603     base::trace_event::TracedValue* state) const {
604   state->SetInteger("tile_count", base::saturated_cast<int>(tiles_.size()));
605   state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
606   state->BeginDictionary("global_state");
607   global_state_.AsValueInto(state);
608   state->EndDictionary();
609 }
610 
611 std::unique_ptr<EvictionTilePriorityQueue>
FreeTileResourcesUntilUsageIsWithinLimit(std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue,const MemoryUsage & limit,MemoryUsage * usage)612 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
613     std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
614     const MemoryUsage& limit,
615     MemoryUsage* usage) {
616   while (usage->Exceeds(limit)) {
617     if (!eviction_priority_queue) {
618       eviction_priority_queue =
619           client_->BuildEvictionQueue(global_state_.tree_priority);
620     }
621     if (eviction_priority_queue->IsEmpty())
622       break;
623 
624     Tile* tile = eviction_priority_queue->Top().tile();
625     *usage -= MemoryUsage::FromTile(tile);
626     FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
627     eviction_priority_queue->Pop();
628   }
629   return eviction_priority_queue;
630 }
631 
632 std::unique_ptr<EvictionTilePriorityQueue>
FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue,const MemoryUsage & limit,const TilePriority & other_priority,MemoryUsage * usage)633 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
634     std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
635     const MemoryUsage& limit,
636     const TilePriority& other_priority,
637     MemoryUsage* usage) {
638   while (usage->Exceeds(limit)) {
639     if (!eviction_priority_queue) {
640       eviction_priority_queue =
641           client_->BuildEvictionQueue(global_state_.tree_priority);
642     }
643     if (eviction_priority_queue->IsEmpty())
644       break;
645 
646     const PrioritizedTile& prioritized_tile = eviction_priority_queue->Top();
647     if (!other_priority.IsHigherPriorityThan(prioritized_tile.priority()))
648       break;
649 
650     Tile* tile = prioritized_tile.tile();
651     *usage -= MemoryUsage::FromTile(tile);
652     FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
653     eviction_priority_queue->Pop();
654   }
655   return eviction_priority_queue;
656 }
657 
TilePriorityViolatesMemoryPolicy(const TilePriority & priority)658 bool TileManager::TilePriorityViolatesMemoryPolicy(
659     const TilePriority& priority) {
660   switch (global_state_.memory_limit_policy) {
661     case ALLOW_NOTHING:
662       return true;
663     case ALLOW_ABSOLUTE_MINIMUM:
664       return priority.priority_bin > TilePriority::NOW;
665     case ALLOW_PREPAINT_ONLY:
666       return priority.priority_bin > TilePriority::SOON;
667     case ALLOW_ANYTHING:
668       return priority.distance_to_visible ==
669              std::numeric_limits<float>::infinity();
670   }
671   NOTREACHED();
672   return true;
673 }
674 
AssignGpuMemoryToTiles()675 TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
676   TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
677 
678   DCHECK(resource_pool_);
679   DCHECK(tile_task_manager_);
680 
681   // Now give memory out to the tiles until we're out, and build
682   // the needs-to-be-rasterized queue.
683   unsigned schedule_priority = 1u;
684   all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
685   bool had_enough_memory_to_schedule_tiles_needed_now = true;
686 
687   MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
688                                 global_state_.num_resources_limit);
689   MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
690                                 global_state_.num_resources_limit);
691   MemoryUsage memory_usage(resource_pool_->memory_usage_bytes(),
692                            resource_pool_->resource_count());
693 
694   std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue(
695       client_->BuildRasterQueue(global_state_.tree_priority,
696                                 RasterTilePriorityQueue::Type::ALL));
697   std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue;
698   PrioritizedWorkToSchedule work_to_schedule;
699   for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
700     const PrioritizedTile& prioritized_tile = raster_priority_queue->Top();
701     Tile* tile = prioritized_tile.tile();
702     TilePriority priority = prioritized_tile.priority();
703 
704     if (TilePriorityViolatesMemoryPolicy(priority)) {
705       TRACE_EVENT_INSTANT0(
706           "cc", "TileManager::AssignGpuMemory tile violates memory policy",
707           TRACE_EVENT_SCOPE_THREAD);
708       break;
709     }
710 
711     bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
712     if (!tile->is_solid_color_analysis_performed() &&
713         tile->use_picture_analysis() && kUseColorEstimator) {
714       // We analyze for solid color here, to decide to continue
715       // or drop the tile for scheduling and raster.
716       tile->set_solid_color_analysis_performed(true);
717       SkColor color = SK_ColorTRANSPARENT;
718       bool is_solid_color =
719           prioritized_tile.raster_source()->PerformSolidColorAnalysis(
720               tile->enclosing_layer_rect(), &color);
721       if (is_solid_color) {
722         tile->draw_info().set_solid_color(color);
723         client_->NotifyTileStateChanged(tile);
724         continue;
725       }
726     }
727 
728     // Prepaint tiles that are far away are only processed for images.
729     if (tile->is_prepaint() && prioritized_tile.is_process_for_images_only()) {
730       work_to_schedule.tiles_to_process_for_images.push_back(prioritized_tile);
731       continue;
732     }
733 
734     auto content_color_usage =
735         GetContentColorUsageForPrioritizedTile(prioritized_tile);
736     const gfx::ColorSpace raster_color_space =
737         client_->GetRasterColorSpace(content_color_usage);
738 
739     // Tiles in the raster queue should either require raster or decode for
740     // checker-images. If this tile does not need raster, process it only to
741     // build the decode queue for checkered images.
742     // Note that performing this check after the solid color analysis is not
743     // necessary for correctness.
744     if (!tile->draw_info().NeedsRaster()) {
745       DCHECK(tile->draw_info().is_checker_imaged());
746       DCHECK(prioritized_tile.should_decode_checkered_images_for_tile());
747 
748       AddCheckeredImagesToDecodeQueue(
749           prioritized_tile, raster_color_space,
750           CheckerImageTracker::DecodeType::kRaster,
751           &work_to_schedule.checker_image_decode_queue);
752       continue;
753     }
754 
755     // We won't be able to schedule this tile, so break out early.
756     if (work_to_schedule.tiles_to_raster.size() >=
757         scheduled_raster_task_limit_) {
758       all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
759       break;
760     }
761 
762     DCHECK(tile->draw_info().mode() == TileDrawInfo::OOM_MODE ||
763            !tile->draw_info().IsReadyToDraw());
764 
765     // If the tile already has a raster_task, then the memory used by it is
766     // already accounted for in memory_usage. Otherwise, we'll have to acquire
767     // more memory to create a raster task.
768     MemoryUsage memory_required_by_tile_to_be_scheduled;
769     if (!tile->raster_task_.get()) {
770       memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
771           tile->desired_texture_size(), DetermineResourceFormat(tile));
772     }
773 
774     // This is the memory limit that will be used by this tile. Depending on
775     // the tile priority, it will be one of hard_memory_limit or
776     // soft_memory_limit.
777     MemoryUsage& tile_memory_limit =
778         tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
779 
780     const MemoryUsage& scheduled_tile_memory_limit =
781         tile_memory_limit - memory_required_by_tile_to_be_scheduled;
782     eviction_priority_queue =
783         FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
784             std::move(eviction_priority_queue), scheduled_tile_memory_limit,
785             priority, &memory_usage);
786     bool memory_usage_is_within_limit =
787         !memory_usage.Exceeds(scheduled_tile_memory_limit);
788 
789     // If we couldn't fit the tile into our current memory limit, then we're
790     // done.
791     if (!memory_usage_is_within_limit) {
792       if (tile_is_needed_now) {
793         LOG(ERROR) << "WARNING: tile memory limits exceeded, some content may "
794                       "not draw";
795 
796         had_enough_memory_to_schedule_tiles_needed_now = false;
797       }
798       all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
799       break;
800     }
801 
802     // If the tile has a scheduled task that will rasterize a resource with
803     // checker-imaged content, add those images to the decode queue. Note that
804     // we add all images as we process the raster priority queue to ensure that
805     // images are added to the decode queue in raster priority order.
806     if (tile->HasRasterTask()) {
807       if (tile->raster_task_scheduled_with_checker_images() &&
808           prioritized_tile.should_decode_checkered_images_for_tile()) {
809         AddCheckeredImagesToDecodeQueue(
810             prioritized_tile, raster_color_space,
811             CheckerImageTracker::DecodeType::kRaster,
812             &work_to_schedule.checker_image_decode_queue);
813       }
814     } else {
815       // Creating the raster task here will acquire resources, but
816       // this resource usage has already been accounted for above.
817       auto raster_task = CreateRasterTask(prioritized_tile, raster_color_space,
818                                           &work_to_schedule);
819       if (!raster_task) {
820         continue;
821       }
822 
823       tile->raster_task_ = std::move(raster_task);
824     }
825 
826     tile->scheduled_priority_ = schedule_priority++;
827     memory_usage += memory_required_by_tile_to_be_scheduled;
828     work_to_schedule.tiles_to_raster.push_back(prioritized_tile);
829   }
830 
831   // Note that we should try and further reduce memory in case the above loop
832   // didn't reduce memory. This ensures that we always release as many resources
833   // as possible to stay within the memory limit.
834   eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
835       std::move(eviction_priority_queue), hard_memory_limit, &memory_usage);
836 
837   // At this point, if we ran out of memory when allocating resources and we
838   // couldn't go past even the NOW bin, this means we have evicted resources
839   // from all tiles with a lower priority while we still might have resources
840   // holding checker-imaged content. The invalidations for these resources will
841   // be generated only if the skipped images are decoded. So we must schedule
842   // decodes for these tiles to update their content.
843   if (!had_enough_memory_to_schedule_tiles_needed_now &&
844       num_of_tiles_with_checker_images_ > 0) {
845     for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
846       const PrioritizedTile& prioritized_tile = raster_priority_queue->Top();
847 
848       if (prioritized_tile.priority().priority_bin > TilePriority::NOW)
849         break;
850 
851       if (!prioritized_tile.should_decode_checkered_images_for_tile())
852         continue;
853 
854       auto content_color_usage =
855           GetContentColorUsageForPrioritizedTile(prioritized_tile);
856       gfx::ColorSpace raster_color_space =
857           client_->GetRasterColorSpace(content_color_usage);
858 
859       Tile* tile = prioritized_tile.tile();
860       if (tile->draw_info().is_checker_imaged() ||
861           tile->raster_task_scheduled_with_checker_images()) {
862         AddCheckeredImagesToDecodeQueue(
863             prioritized_tile, raster_color_space,
864             CheckerImageTracker::DecodeType::kRaster,
865             &work_to_schedule.checker_image_decode_queue);
866       }
867     }
868   }
869 
870   UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
871                         !had_enough_memory_to_schedule_tiles_needed_now);
872   did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
873 
874   memory_stats_from_last_assign_.total_budget_in_bytes =
875       global_state_.hard_memory_limit_in_bytes;
876   memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
877   DCHECK_GE(memory_stats_from_last_assign_.total_bytes_used, 0);
878   memory_stats_from_last_assign_.had_enough_memory =
879       had_enough_memory_to_schedule_tiles_needed_now;
880 
881   TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
882                    "all_tiles_that_need_to_be_rasterized_are_scheduled",
883                    all_tiles_that_need_to_be_rasterized_are_scheduled_,
884                    "had_enough_memory_to_schedule_tiles_needed_now",
885                    had_enough_memory_to_schedule_tiles_needed_now);
886   image_controller_.cache()->RecordStats();
887   return work_to_schedule;
888 }
889 
FreeResourcesForTile(Tile * tile)890 void TileManager::FreeResourcesForTile(Tile* tile) {
891   TileDrawInfo& draw_info = tile->draw_info();
892 
893   if (draw_info.is_checker_imaged())
894     num_of_tiles_with_checker_images_--;
895   DCHECK_GE(num_of_tiles_with_checker_images_, 0);
896 
897   if (draw_info.has_resource()) {
898     resource_pool_->ReleaseResource(draw_info.TakeResource());
899     pending_gpu_work_tiles_.erase(tile);
900   }
901 }
902 
FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(Tile * tile)903 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
904     Tile* tile) {
905   bool was_ready_to_draw = tile->draw_info().IsReadyToDraw();
906   FreeResourcesForTile(tile);
907   if (was_ready_to_draw)
908     client_->NotifyTileStateChanged(tile);
909 }
910 
PartitionImagesForCheckering(const PrioritizedTile & prioritized_tile,const gfx::ColorSpace & raster_color_space,std::vector<DrawImage> * sync_decoded_images,std::vector<PaintImage> * checkered_images,const gfx::Rect * invalidated_rect,base::flat_map<PaintImage::Id,size_t> * image_to_frame_index)911 void TileManager::PartitionImagesForCheckering(
912     const PrioritizedTile& prioritized_tile,
913     const gfx::ColorSpace& raster_color_space,
914     std::vector<DrawImage>* sync_decoded_images,
915     std::vector<PaintImage>* checkered_images,
916     const gfx::Rect* invalidated_rect,
917     base::flat_map<PaintImage::Id, size_t>* image_to_frame_index) {
918   Tile* tile = prioritized_tile.tile();
919   std::vector<const DrawImage*> images_in_tile;
920   gfx::Rect enclosing_rect = tile->enclosing_layer_rect();
921   if (invalidated_rect) {
922     enclosing_rect = ToEnclosingRect(
923         tile->raster_transform().InverseMapRect(gfx::RectF(*invalidated_rect)));
924   }
925   prioritized_tile.raster_source()->GetDiscardableImagesInRect(enclosing_rect,
926                                                                &images_in_tile);
927   WhichTree tree = tile->tiling()->tree();
928 
929   for (const auto* original_draw_image : images_in_tile) {
930     const auto& image = original_draw_image->paint_image();
931     size_t frame_index = client_->GetFrameIndexForImage(image, tree);
932     if (image_to_frame_index)
933       (*image_to_frame_index)[image.stable_id()] = frame_index;
934 
935     DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(),
936                          frame_index, raster_color_space);
937     if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree))
938       checkered_images->push_back(draw_image.paint_image());
939     else
940       sync_decoded_images->push_back(std::move(draw_image));
941   }
942 }
943 
AddCheckeredImagesToDecodeQueue(const PrioritizedTile & prioritized_tile,const gfx::ColorSpace & raster_color_space,CheckerImageTracker::DecodeType decode_type,CheckerImageTracker::ImageDecodeQueue * image_decode_queue)944 void TileManager::AddCheckeredImagesToDecodeQueue(
945     const PrioritizedTile& prioritized_tile,
946     const gfx::ColorSpace& raster_color_space,
947     CheckerImageTracker::DecodeType decode_type,
948     CheckerImageTracker::ImageDecodeQueue* image_decode_queue) {
949   Tile* tile = prioritized_tile.tile();
950   std::vector<const DrawImage*> images_in_tile;
951   prioritized_tile.raster_source()->GetDiscardableImagesInRect(
952       tile->enclosing_layer_rect(), &images_in_tile);
953   WhichTree tree = tile->tiling()->tree();
954 
955   for (const auto* original_draw_image : images_in_tile) {
956     size_t frame_index = client_->GetFrameIndexForImage(
957         original_draw_image->paint_image(), tree);
958     DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(),
959                          frame_index, raster_color_space);
960     if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree)) {
961       image_decode_queue->emplace_back(draw_image.paint_image(), decode_type);
962     }
963   }
964 }
965 
ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule)966 void TileManager::ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule) {
967   const std::vector<PrioritizedTile>& tiles_that_need_to_be_rasterized =
968       work_to_schedule.tiles_to_raster;
969   TRACE_EVENT1("cc", "TileManager::ScheduleTasks", "count",
970                tiles_that_need_to_be_rasterized.size());
971 
972   DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
973 
974   if (!has_scheduled_tile_tasks_) {
975     TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc", "ScheduledTasks",
976                                       TRACE_ID_LOCAL(this));
977   }
978 
979   // Cancel existing OnTaskSetFinished callbacks.
980   task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
981 
982   // Even when scheduling an empty set of tiles, the TTWP does some work, and
983   // will always trigger a DidFinishRunningTileTasks notification. Because of
984   // this we unconditionally set |has_scheduled_tile_tasks_| to true.
985   has_scheduled_tile_tasks_ = true;
986 
987   // Track the number of dependents for each *_done task.
988   size_t required_for_activate_count = 0;
989   size_t required_for_draw_count = 0;
990   size_t all_count = 0;
991 
992   size_t priority = kTileTaskPriorityBase;
993 
994   graph_.Reset();
995 
996   scoped_refptr<TileTask> required_for_activation_done_task =
997       CreateTaskSetFinishedTask(
998           &TileManager::DidFinishRunningTileTasksRequiredForActivation);
999   scoped_refptr<TileTask> required_for_draw_done_task =
1000       CreateTaskSetFinishedTask(
1001           &TileManager::DidFinishRunningTileTasksRequiredForDraw);
1002 
1003   auto all_done_cb =
1004       base::BindOnce(&TileManager::DidFinishRunningAllTileTasks,
1005                      task_set_finished_weak_ptr_factory_.GetWeakPtr());
1006   scoped_refptr<TileTask> all_done_task =
1007       base::MakeRefCounted<DidFinishRunningAllTilesTask>(
1008           task_runner_, raster_buffer_provider_, std::move(all_done_cb));
1009 
1010   // Build a new task queue containing all task currently needed. Tasks
1011   // are added in order of priority, highest priority task first.
1012   for (auto& prioritized_tile : tiles_that_need_to_be_rasterized) {
1013     Tile* tile = prioritized_tile.tile();
1014 
1015     DCHECK(tile->draw_info().requires_resource());
1016     DCHECK(!tile->draw_info().has_resource());
1017     DCHECK(tile->HasRasterTask());
1018 
1019     TileTask* task = tile->raster_task_.get();
1020     task->set_frame_number(tile->source_frame_number());
1021 
1022     DCHECK(!task->HasCompleted());
1023 
1024     if (tile->required_for_activation()) {
1025       required_for_activate_count++;
1026       graph_.edges.emplace_back(task, required_for_activation_done_task.get());
1027     }
1028     if (tile->required_for_draw()) {
1029       required_for_draw_count++;
1030       graph_.edges.emplace_back(task, required_for_draw_done_task.get());
1031     }
1032     all_count++;
1033     graph_.edges.emplace_back(task, all_done_task.get());
1034 
1035     // A tile should use a foreground task cateogry if it is either blocking
1036     // future compositing (required for draw or required for activation), or if
1037     // it has a priority bin of NOW for another reason (low resolution tiles).
1038     bool use_foreground_category =
1039         tile->required_for_draw() || tile->required_for_activation() ||
1040         prioritized_tile.priority().priority_bin == TilePriority::NOW;
1041     InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++,
1042                              use_foreground_category);
1043   }
1044 
1045   const std::vector<PrioritizedTile>& tiles_to_process_for_images =
1046       work_to_schedule.tiles_to_process_for_images;
1047   std::vector<DrawImage> new_locked_images;
1048   for (const PrioritizedTile& prioritized_tile : tiles_to_process_for_images) {
1049     auto content_color_usage =
1050         GetContentColorUsageForPrioritizedTile(prioritized_tile);
1051     gfx::ColorSpace raster_color_space =
1052         client_->GetRasterColorSpace(content_color_usage);
1053 
1054     std::vector<DrawImage> sync_decoded_images;
1055     std::vector<PaintImage> checkered_images;
1056     PartitionImagesForCheckering(prioritized_tile, raster_color_space,
1057                                  &sync_decoded_images, &checkered_images,
1058                                  nullptr);
1059 
1060     // Add the sync decoded images to |new_locked_images| so they can be added
1061     // to the task graph.
1062     new_locked_images.insert(
1063         new_locked_images.end(),
1064         std::make_move_iterator(sync_decoded_images.begin()),
1065         std::make_move_iterator(sync_decoded_images.end()));
1066 
1067     // For checkered-images, send them to the decode service.
1068     for (auto& image : checkered_images) {
1069       work_to_schedule.checker_image_decode_queue.emplace_back(
1070           std::move(image), CheckerImageTracker::DecodeType::kPreDecode);
1071     }
1072   }
1073 
1074   new_locked_images.insert(new_locked_images.end(),
1075                            work_to_schedule.extra_prepaint_images.begin(),
1076                            work_to_schedule.extra_prepaint_images.end());
1077 
1078   // TODO(vmpstr): SOON is misleading here, but these images can come from
1079   // several diffent tiles. Rethink what we actually want to trace here. Note
1080   // that I'm using SOON, since it can't be NOW (these are prepaint).
1081   ImageDecodeCache::TracingInfo tracing_info(
1082       prepare_tiles_count_, TilePriority::SOON,
1083       ImageDecodeCache::TaskType::kInRaster);
1084   std::vector<scoped_refptr<TileTask>> new_locked_image_tasks =
1085       image_controller_.SetPredecodeImages(new_locked_images, tracing_info);
1086   // Notify |decoded_image_tracker_| after |image_controller_| to ensure we've
1087   // taken new refs on the images before releasing the predecode API refs.
1088   decoded_image_tracker_.OnImagesUsedInDraw(new_locked_images);
1089   work_to_schedule.extra_prepaint_images.clear();
1090 
1091   for (auto& task : new_locked_image_tasks) {
1092     auto decode_it = std::find_if(graph_.nodes.begin(), graph_.nodes.end(),
1093                                   [&task](const TaskGraph::Node& node) {
1094                                     return node.task == task.get();
1095                                   });
1096     // If this task is already in the graph, then we don't have to insert it.
1097     if (decode_it != graph_.nodes.end())
1098       continue;
1099 
1100     InsertNodeForDecodeTask(&graph_, task.get(), false, priority++);
1101     all_count++;
1102     graph_.edges.emplace_back(task.get(), all_done_task.get());
1103   }
1104 
1105   // The old locked images tasks have to stay around until past the
1106   // ScheduleTasks call below, so we do a swap instead of a move.
1107   // TODO(crbug.com/647402): Have the tile_task_manager keep a ref on the tasks,
1108   // since it makes it awkward for the callers to keep refs on tasks that only
1109   // exist within the task graph runner.
1110   locked_image_tasks_.swap(new_locked_image_tasks);
1111 
1112   // We must reduce the amount of unused resources before calling
1113   // ScheduleTasks to prevent usage from rising above limits.
1114   resource_pool_->ReduceResourceUsage();
1115   image_controller_.ReduceMemoryUsage();
1116 
1117   // Insert nodes for our task completion tasks. We enqueue these using
1118   // NONCONCURRENT_FOREGROUND category this is the highest prioirty category and
1119   // we'd like to run these tasks as soon as possible.
1120   InsertNodeForTask(&graph_, required_for_activation_done_task.get(),
1121                     TASK_CATEGORY_NONCONCURRENT_FOREGROUND,
1122                     kRequiredForActivationDoneTaskPriority,
1123                     required_for_activate_count);
1124   InsertNodeForTask(&graph_, required_for_draw_done_task.get(),
1125                     TASK_CATEGORY_NONCONCURRENT_FOREGROUND,
1126                     kRequiredForDrawDoneTaskPriority, required_for_draw_count);
1127   InsertNodeForTask(&graph_, all_done_task.get(),
1128                     TASK_CATEGORY_NONCONCURRENT_FOREGROUND,
1129                     kAllDoneTaskPriority, all_count);
1130 
1131   // Schedule running of |raster_queue_|. This replaces any previously
1132   // scheduled tasks and effectively cancels all tasks not present
1133   // in |raster_queue_|.
1134   tile_task_manager_->ScheduleTasks(&graph_);
1135 
1136   // Schedule running of the checker-image decode queue. This replaces the
1137   // previously scheduled queue and effectively cancels image decodes from the
1138   // previous queue, if not already started.
1139   checker_image_tracker_.ScheduleImageDecodeQueue(
1140       std::move(work_to_schedule.checker_image_decode_queue));
1141 
1142   did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
1143 
1144   TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("cc", "ScheduledTasksState",
1145                                       TRACE_ID_LOCAL(this), "state",
1146                                       ScheduledTasksStateAsValue());
1147 }
1148 
CreateRasterTask(const PrioritizedTile & prioritized_tile,const gfx::ColorSpace & raster_color_space,PrioritizedWorkToSchedule * work_to_schedule)1149 scoped_refptr<TileTask> TileManager::CreateRasterTask(
1150     const PrioritizedTile& prioritized_tile,
1151     const gfx::ColorSpace& raster_color_space,
1152     PrioritizedWorkToSchedule* work_to_schedule) {
1153   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1154                "TileManager::CreateRasterTask");
1155   Tile* tile = prioritized_tile.tile();
1156   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1157                "TileManager::CreateRasterTask", "Tile", tile->id());
1158 
1159   const int msaa_sample_count = client_->GetMSAASampleCountForRaster(
1160       prioritized_tile.raster_source()->GetDisplayItemList());
1161 
1162   // Get the resource.
1163   ResourcePool::InUsePoolResource resource;
1164   uint64_t resource_content_id = 0;
1165   gfx::Rect invalidated_rect = tile->invalidated_content_rect();
1166   if (UsePartialRaster(msaa_sample_count) && tile->invalidated_id()) {
1167     resource = resource_pool_->TryAcquireResourceForPartialRaster(
1168         tile->id(), tile->invalidated_content_rect(), tile->invalidated_id(),
1169         &invalidated_rect, raster_color_space);
1170   }
1171 
1172   bool partial_tile_decode = false;
1173   if (resource) {
1174     resource_content_id = tile->invalidated_id();
1175     DCHECK_EQ(DetermineResourceFormat(tile), resource.format());
1176     partial_tile_decode = true;
1177   } else {
1178     resource = resource_pool_->AcquireResource(tile->desired_texture_size(),
1179                                                DetermineResourceFormat(tile),
1180                                                raster_color_space);
1181     DCHECK(resource);
1182   }
1183 
1184   // For LOW_RESOLUTION tiles, we don't draw or predecode images.
1185   RasterSource::PlaybackSettings playback_settings;
1186   const bool skip_images =
1187       prioritized_tile.priority().resolution == LOW_RESOLUTION;
1188   playback_settings.use_lcd_text = tile->can_use_lcd_text();
1189   playback_settings.msaa_sample_count = msaa_sample_count;
1190 
1191   // Create and queue all image decode tasks that this tile depends on. Note
1192   // that we need to store the images for decode tasks in
1193   // |scheduled_draw_images_| since the tile might have been destroyed by the
1194   // time the raster task finishes.
1195   TileTask::Vector decode_tasks;
1196   std::vector<DrawImage>& sync_decoded_images =
1197       scheduled_draw_images_[tile->id()];
1198   sync_decoded_images.clear();
1199   std::vector<PaintImage> checkered_images;
1200   base::flat_map<PaintImage::Id, size_t> image_id_to_current_frame_index;
1201   if (!skip_images) {
1202     PartitionImagesForCheckering(
1203         prioritized_tile, raster_color_space, &sync_decoded_images,
1204         &checkered_images, partial_tile_decode ? &invalidated_rect : nullptr,
1205         &image_id_to_current_frame_index);
1206   }
1207 
1208   // Get the tasks for the required images.
1209   ImageDecodeCache::TracingInfo tracing_info(
1210       prepare_tiles_count_, prioritized_tile.priority().priority_bin,
1211       ImageDecodeCache::TaskType::kInRaster);
1212   bool has_at_raster_images = false;
1213   bool has_hardware_accelerated_jpeg_candidates = false;
1214   bool has_hardware_accelerated_webp_candidates = false;
1215   image_controller_.ConvertImagesToTasks(
1216       &sync_decoded_images, &decode_tasks, &has_at_raster_images,
1217       &has_hardware_accelerated_jpeg_candidates,
1218       &has_hardware_accelerated_webp_candidates, tracing_info);
1219   // Notify |decoded_image_tracker_| after |image_controller_| to ensure we've
1220   // taken new refs on the images before releasing the predecode API refs.
1221   decoded_image_tracker_.OnImagesUsedInDraw(sync_decoded_images);
1222 
1223   const bool has_checker_images = !checkered_images.empty();
1224   tile->set_raster_task_scheduled_with_checker_images(has_checker_images);
1225   if (has_checker_images)
1226     num_of_tiles_with_checker_images_++;
1227 
1228   // Don't allow at-raster prepaint tiles, because they could be very slow
1229   // and block high-priority tasks.
1230   if (has_at_raster_images && tile->is_prepaint()) {
1231     work_to_schedule->extra_prepaint_images.insert(
1232         work_to_schedule->extra_prepaint_images.end(),
1233         sync_decoded_images.begin(), sync_decoded_images.end());
1234     // This will unref the images, but ScheduleTasks will schedule them
1235     // right away anyway.
1236     OnRasterTaskCompleted(tile->id(), std::move(resource),
1237                           true /* was_canceled */);
1238     return nullptr;
1239   }
1240 
1241   PaintImageIdFlatSet images_to_skip;
1242   for (const auto& image : checkered_images) {
1243     DCHECK(!image.ShouldAnimate());
1244 
1245     images_to_skip.insert(image.stable_id());
1246 
1247     // This can be the case for tiles on the active tree that will be replaced
1248     // or are occluded on the pending tree. While we still need to continue
1249     // skipping images for these tiles, we don't need to decode them since
1250     // they will not be required on the next active tree.
1251     if (prioritized_tile.should_decode_checkered_images_for_tile()) {
1252       work_to_schedule->checker_image_decode_queue.emplace_back(
1253           image, CheckerImageTracker::DecodeType::kRaster);
1254     }
1255   }
1256 
1257   std::unique_ptr<RasterBuffer> raster_buffer =
1258       raster_buffer_provider_->AcquireBufferForRaster(
1259           resource, resource_content_id, tile->invalidated_id(),
1260           has_at_raster_images, has_hardware_accelerated_jpeg_candidates,
1261           has_hardware_accelerated_webp_candidates);
1262 
1263   base::Optional<PlaybackImageProvider::Settings> settings;
1264   if (!skip_images) {
1265     settings.emplace();
1266     settings->images_to_skip = std::move(images_to_skip);
1267     settings->image_to_current_frame_index =
1268         std::move(image_id_to_current_frame_index);
1269   }
1270 
1271   PlaybackImageProvider image_provider(image_controller_.cache(),
1272                                        raster_color_space, std::move(settings));
1273   // We make a deliberate copy of the PaintWorklet map here, as the
1274   // PictureLayerImpl's map could be mutated or destroyed whilst raster from an
1275   // earlier snapshot is still ongoing on the raster worker threads.
1276   PaintWorkletRecordMap paint_worklet_records =
1277       prioritized_tile.GetPaintWorkletRecords();
1278   PaintWorkletImageProvider paint_worklet_image_provider(
1279       std::move(paint_worklet_records));
1280   DispatchingImageProvider dispatching_image_provider(
1281       std::move(image_provider), std::move(paint_worklet_image_provider));
1282 
1283   return base::MakeRefCounted<RasterTaskImpl>(
1284       this, tile, std::move(resource), prioritized_tile.raster_source(),
1285       playback_settings, prioritized_tile.priority().resolution,
1286       invalidated_rect, prepare_tiles_count_, std::move(raster_buffer),
1287       &decode_tasks, use_gpu_rasterization_,
1288       std::move(dispatching_image_provider), active_url_);
1289 }
1290 
ResetSignalsForTesting()1291 void TileManager::ResetSignalsForTesting() {
1292   signals_ = Signals();
1293 }
1294 
OnRasterTaskCompleted(Tile::Id tile_id,ResourcePool::InUsePoolResource resource,bool was_canceled)1295 void TileManager::OnRasterTaskCompleted(
1296     Tile::Id tile_id,
1297     ResourcePool::InUsePoolResource resource,
1298     bool was_canceled) {
1299   auto found = tiles_.find(tile_id);
1300   Tile* tile = nullptr;
1301   bool raster_task_was_scheduled_with_checker_images = false;
1302   if (found != tiles_.end()) {
1303     tile = found->second;
1304     tile->raster_task_ = nullptr;
1305     raster_task_was_scheduled_with_checker_images =
1306         tile->set_raster_task_scheduled_with_checker_images(false);
1307     if (raster_task_was_scheduled_with_checker_images)
1308       num_of_tiles_with_checker_images_--;
1309   }
1310 
1311   // Unref all the images.
1312   auto images_it = scheduled_draw_images_.find(tile_id);
1313   // Every raster task unconditionally creates sync_decoded_images_ entry in
1314   // CreateRasterTask. This is the only place it's cleared. So we should have
1315   // the images_it here that doesn't point to end. This check is here to debug
1316   // crbug.com/757049.
1317   CHECK(images_it != scheduled_draw_images_.end());
1318   image_controller_.UnrefImages(images_it->second);
1319   scheduled_draw_images_.erase(images_it);
1320 
1321   if (was_canceled) {
1322     ++raster_task_completion_stats_.canceled_count;
1323     resource_pool_->ReleaseResource(std::move(resource));
1324     return;
1325   }
1326 
1327   resource_pool_->OnContentReplaced(resource, tile_id);
1328   ++raster_task_completion_stats_.completed_count;
1329 
1330   if (!tile) {
1331     resource_pool_->ReleaseResource(std::move(resource));
1332     return;
1333   }
1334 
1335   // Once raster is done, allow the resource to be exported to the display
1336   // compositor, by giving it a ResourceId.
1337   bool exported = resource_pool_->PrepareForExport(resource);
1338 
1339   // In SMOOTHNESS_TAKES_PRIORITY mode, we wait for GPU work to complete for a
1340   // tile before setting it as ready to draw.
1341   bool is_ready_for_draw = true;
1342   if (global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY) {
1343     is_ready_for_draw =
1344         raster_buffer_provider_->IsResourceReadyToDraw(resource);
1345   }
1346 
1347   TileDrawInfo& draw_info = tile->draw_info();
1348   if (exported) {
1349     bool is_premultiplied = raster_buffer_provider_->IsResourcePremultiplied();
1350     draw_info.SetResource(std::move(resource),
1351                           raster_task_was_scheduled_with_checker_images,
1352                           is_premultiplied);
1353   } else {
1354     resource_pool_->ReleaseResource(std::move(resource));
1355     draw_info.set_oom();
1356   }
1357   if (raster_task_was_scheduled_with_checker_images)
1358     num_of_tiles_with_checker_images_++;
1359 
1360   if (!is_ready_for_draw) {
1361     pending_gpu_work_tiles_.insert(tile);
1362   } else {
1363     draw_info.set_resource_ready_for_draw();
1364     client_->NotifyTileStateChanged(tile);
1365   }
1366 }
1367 
CreateTile(const Tile::CreateInfo & info,int layer_id,int source_frame_number,int flags,bool can_use_lcd_text)1368 std::unique_ptr<Tile> TileManager::CreateTile(const Tile::CreateInfo& info,
1369                                               int layer_id,
1370                                               int source_frame_number,
1371                                               int flags,
1372                                               bool can_use_lcd_text) {
1373   // We need to have a tile task worker pool to do anything meaningful with
1374   // tiles.
1375   DCHECK(tile_task_manager_);
1376   std::unique_ptr<Tile> tile(new Tile(this, info, layer_id, source_frame_number,
1377                                       flags, can_use_lcd_text));
1378   DCHECK(tiles_.find(tile->id()) == tiles_.end());
1379 
1380   tiles_[tile->id()] = tile.get();
1381   return tile;
1382 }
1383 
AreRequiredTilesReadyToDraw(RasterTilePriorityQueue::Type type) const1384 bool TileManager::AreRequiredTilesReadyToDraw(
1385     RasterTilePriorityQueue::Type type) const {
1386   std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue(
1387       client_->BuildRasterQueue(global_state_.tree_priority, type));
1388   // It is insufficient to check whether the raster queue we constructed is
1389   // empty. The reason for this is that there are situations (rasterize on
1390   // demand) when the tile both needs raster and it's ready to draw. Hence, we
1391   // have to iterate the queue to check whether the required tiles are ready to
1392   // draw.
1393   for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
1394     const auto& prioritized_tile = raster_priority_queue->Top();
1395     // TODO(vmpstr): Check to debug crbug.com/622080. Remove when fixed.
1396     CHECK_EQ(prioritized_tile.priority().priority_bin, TilePriority::NOW);
1397     if (!prioritized_tile.tile()->draw_info().IsReadyToDraw())
1398       return false;
1399   }
1400 
1401 #if DCHECK_IS_ON()
1402   std::unique_ptr<RasterTilePriorityQueue> all_queue(
1403       client_->BuildRasterQueue(global_state_.tree_priority, type));
1404   for (; !all_queue->IsEmpty(); all_queue->Pop()) {
1405     Tile* tile = all_queue->Top().tile();
1406     DCHECK(!tile->required_for_activation() ||
1407            tile->draw_info().IsReadyToDraw());
1408   }
1409 #endif
1410   return true;
1411 }
1412 
IsReadyToActivate() const1413 bool TileManager::IsReadyToActivate() const {
1414   TRACE_EVENT0("cc,benchmark", "TileManager::IsReadyToActivate");
1415   return pending_required_for_activation_callback_id_ == 0 &&
1416          AreRequiredTilesReadyToDraw(
1417              RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
1418 }
1419 
IsReadyToDraw() const1420 bool TileManager::IsReadyToDraw() const {
1421   TRACE_EVENT0("cc,benchmark", "TileManager::IsReadyToDraw");
1422   return pending_required_for_draw_callback_id_ == 0 &&
1423          AreRequiredTilesReadyToDraw(
1424              RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
1425 }
1426 
ScheduleCheckRasterFinishedQueries()1427 void TileManager::ScheduleCheckRasterFinishedQueries() {
1428   DCHECK(has_pending_queries_);
1429 
1430   if (!check_pending_tile_queries_callback_.IsCancelled())
1431     return;
1432 
1433   check_pending_tile_queries_callback_.Reset(base::BindOnce(
1434       &TileManager::CheckRasterFinishedQueries, base::Unretained(this)));
1435   task_runner_->PostDelayedTask(FROM_HERE,
1436                                 check_pending_tile_queries_callback_.callback(),
1437                                 base::TimeDelta::FromMilliseconds(100));
1438 }
1439 
CheckRasterFinishedQueries()1440 void TileManager::CheckRasterFinishedQueries() {
1441   check_pending_tile_queries_callback_.Cancel();
1442 
1443   if (!has_pending_queries_)
1444     return;
1445 
1446   // Raster tasks are in progress. The queries will be polled once they finish.
1447   if (has_scheduled_tile_tasks_ || !signals_.all_tile_tasks_completed)
1448     return;
1449 
1450   has_pending_queries_ = raster_buffer_provider_->CheckRasterFinishedQueries();
1451   if (has_pending_queries_)
1452     ScheduleCheckRasterFinishedQueries();
1453 }
1454 
FlushAndIssueSignals()1455 void TileManager::FlushAndIssueSignals() {
1456   TRACE_EVENT0("cc", "TileManager::FlushAndIssueSignals");
1457   tile_task_manager_->CheckForCompletedTasks();
1458   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
1459 
1460   raster_buffer_provider_->Flush();
1461   CheckPendingGpuWorkAndIssueSignals();
1462 }
1463 
IssueSignals()1464 void TileManager::IssueSignals() {
1465   // Ready to activate.
1466   if (signals_.activate_tile_tasks_completed &&
1467       signals_.activate_gpu_work_completed &&
1468       !signals_.did_notify_ready_to_activate) {
1469     if (IsReadyToActivate()) {
1470       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1471                    "TileManager::IssueSignals - ready to activate");
1472       signals_.did_notify_ready_to_activate = true;
1473       client_->NotifyReadyToActivate();
1474     }
1475   }
1476 
1477   // Ready to draw.
1478   if (signals_.draw_tile_tasks_completed && signals_.draw_gpu_work_completed &&
1479       !signals_.did_notify_ready_to_draw) {
1480     if (IsReadyToDraw()) {
1481       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1482                    "TileManager::IssueSignals - ready to draw");
1483       signals_.did_notify_ready_to_draw = true;
1484       client_->NotifyReadyToDraw();
1485     }
1486   }
1487 
1488   // All tile tasks completed.
1489   if (signals_.all_tile_tasks_completed &&
1490       !signals_.did_notify_all_tile_tasks_completed) {
1491     if (!has_scheduled_tile_tasks_) {
1492       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1493                    "TileManager::IssueSignals - all tile tasks completed");
1494 
1495       if (has_pending_queries_)
1496         ScheduleCheckRasterFinishedQueries();
1497 
1498       signals_.did_notify_all_tile_tasks_completed = true;
1499       client_->NotifyAllTileTasksCompleted();
1500     }
1501   }
1502 
1503   // Allow decodes for rasterized tiles if all required for draw/activate tiles
1504   // are done. And pre-decode tiles once all tile tasks are done.
1505   // Note that the order is important here, since all signals could have become
1506   // true and in that case we want to allow the most decodes.
1507   if (signals_.did_notify_all_tile_tasks_completed) {
1508     checker_image_tracker_.SetMaxDecodePriorityAllowed(
1509         CheckerImageTracker::DecodeType::kPreDecode);
1510   } else if (signals_.did_notify_ready_to_activate &&
1511              signals_.did_notify_ready_to_draw) {
1512     checker_image_tracker_.SetMaxDecodePriorityAllowed(
1513         CheckerImageTracker::DecodeType::kRaster);
1514   }
1515 }
1516 
CheckIfMoreTilesNeedToBePrepared()1517 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
1518   tile_task_manager_->CheckForCompletedTasks();
1519   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
1520 
1521   // When OOM, keep re-assigning memory until we reach a steady state
1522   // where top-priority tiles are initialized.
1523   PrioritizedWorkToSchedule work_to_schedule = AssignGpuMemoryToTiles();
1524 
1525   // Inform the client that will likely require a draw if the highest priority
1526   // tile that will be rasterized is required for draw.
1527   client_->SetIsLikelyToRequireADraw(
1528       !work_to_schedule.tiles_to_raster.empty() &&
1529       work_to_schedule.tiles_to_raster.front().tile()->required_for_draw());
1530 
1531   // |tiles_that_need_to_be_rasterized| will be empty when we reach a
1532   // steady memory state. Keep scheduling tasks until we reach this state.
1533   if (!work_to_schedule.tiles_to_raster.empty()) {
1534     ScheduleTasks(std::move(work_to_schedule));
1535     return;
1536   }
1537 
1538   // If we're not in SMOOTHNESS_TAKES_PRIORITY  mode, we should unlock all
1539   // images since we're technically going idle here at least for this frame.
1540   if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY) {
1541     image_controller_.SetPredecodeImages(std::vector<DrawImage>(),
1542                                          ImageDecodeCache::TracingInfo());
1543     locked_image_tasks_.clear();
1544   }
1545 
1546   resource_pool_->ReduceResourceUsage();
1547   image_controller_.ReduceMemoryUsage();
1548 
1549   // TODO(vmpstr): Temporary check to debug crbug.com/642927.
1550   CHECK(tile_task_manager_);
1551 
1552   // Schedule all checks in case we're left with solid color tiles only.
1553   signals_.activate_tile_tasks_completed = true;
1554   signals_.draw_tile_tasks_completed = true;
1555   signals_.all_tile_tasks_completed = true;
1556   signals_check_notifier_.Schedule();
1557 
1558   // We don't reserve memory for required-for-activation tiles during
1559   // accelerated gestures, so we just postpone activation when we don't
1560   // have these tiles, and activate after the accelerated gesture.
1561   // Likewise if we don't allow any tiles (as is the case when we're
1562   // invisible), if we have tiles that aren't ready, then we shouldn't
1563   // activate as activation can cause checkerboards.
1564   bool wait_for_all_required_tiles =
1565       global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
1566       global_state_.memory_limit_policy == ALLOW_NOTHING;
1567 
1568   // If we have tiles left to raster for activation, and we don't allow
1569   // activating without them, then skip activation and return early.
1570   if (wait_for_all_required_tiles)
1571     return;
1572 
1573   // Mark any required tiles that have not been been assigned memory after
1574   // reaching a steady memory state as OOM. This ensures that we activate/draw
1575   // even when OOM. Note that we can't reuse the queue we used for
1576   // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
1577   // evicted some tiles that would not be picked up by the old raster queue.
1578   MarkTilesOutOfMemory(client_->BuildRasterQueue(
1579       global_state_.tree_priority,
1580       RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
1581   MarkTilesOutOfMemory(client_->BuildRasterQueue(
1582       global_state_.tree_priority,
1583       RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW));
1584 
1585   // TODO(vmpstr): Temporary check to debug crbug.com/642927.
1586   CHECK(tile_task_manager_);
1587 
1588   DCHECK(IsReadyToActivate());
1589   DCHECK(IsReadyToDraw());
1590 }
1591 
MarkTilesOutOfMemory(std::unique_ptr<RasterTilePriorityQueue> queue) const1592 void TileManager::MarkTilesOutOfMemory(
1593     std::unique_ptr<RasterTilePriorityQueue> queue) const {
1594   // Mark required tiles as OOM so that we can activate/draw without them.
1595   for (; !queue->IsEmpty(); queue->Pop()) {
1596     Tile* tile = queue->Top().tile();
1597     if (tile->draw_info().IsReadyToDraw())
1598       continue;
1599     tile->draw_info().set_oom();
1600     client_->NotifyTileStateChanged(tile);
1601   }
1602 }
1603 
TakeImagesToInvalidateOnSyncTree()1604 const PaintImageIdFlatSet& TileManager::TakeImagesToInvalidateOnSyncTree() {
1605   return checker_image_tracker_.TakeImagesToInvalidateOnSyncTree();
1606 }
1607 
DidActivateSyncTree()1608 void TileManager::DidActivateSyncTree() {
1609   checker_image_tracker_.DidActivateSyncTree();
1610 }
1611 
ClearCheckerImageTracking(bool can_clear_decode_policy_tracking)1612 void TileManager::ClearCheckerImageTracking(
1613     bool can_clear_decode_policy_tracking) {
1614   checker_image_tracker_.ClearTracker(can_clear_decode_policy_tracking);
1615 }
1616 
SetCheckerImagingForceDisabled(bool force_disable)1617 void TileManager::SetCheckerImagingForceDisabled(bool force_disable) {
1618   checker_image_tracker_.set_force_disabled(force_disable);
1619 }
1620 
NeedsInvalidationForCheckerImagedTiles()1621 void TileManager::NeedsInvalidationForCheckerImagedTiles() {
1622   client_->RequestImplSideInvalidationForCheckerImagedTiles();
1623 }
1624 
DetermineResourceFormat(const Tile * tile) const1625 viz::ResourceFormat TileManager::DetermineResourceFormat(
1626     const Tile* tile) const {
1627   return raster_buffer_provider_->GetResourceFormat();
1628 }
1629 
1630 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
ScheduledTasksStateAsValue() const1631 TileManager::ScheduledTasksStateAsValue() const {
1632   std::unique_ptr<base::trace_event::TracedValue> state(
1633       new base::trace_event::TracedValue());
1634   state->BeginDictionary("tasks_pending");
1635   state->SetBoolean("activate_tile_tasks_completed",
1636                     signals_.activate_tile_tasks_completed);
1637   state->SetBoolean("draw_tile_tasks_completed",
1638                     signals_.draw_tile_tasks_completed);
1639   state->SetBoolean("all_tile_tasks_completed",
1640                     signals_.all_tile_tasks_completed);
1641   state->EndDictionary();
1642   return std::move(state);
1643 }
1644 
UsePartialRaster(int msaa_sample_count) const1645 bool TileManager::UsePartialRaster(int msaa_sample_count) const {
1646   // Partial raster doesn't support MSAA, as the MSAA resolve is unaware of clip
1647   // rects.
1648   // TODO(crbug.com/629683): See if we can work around this limitation.
1649   return tile_manager_settings_.use_partial_raster &&
1650          raster_buffer_provider_->CanPartialRasterIntoProvidedResource() &&
1651          msaa_sample_count == 0;
1652 }
1653 
CheckPendingGpuWorkAndIssueSignals()1654 void TileManager::CheckPendingGpuWorkAndIssueSignals() {
1655   TRACE_EVENT2("cc", "TileManager::CheckPendingGpuWorkAndIssueSignals",
1656                "pending_gpu_work_tiles", pending_gpu_work_tiles_.size(),
1657                "tree_priority",
1658                TreePriorityToString(global_state_.tree_priority));
1659 
1660   std::vector<const ResourcePool::InUsePoolResource*> required_for_activation;
1661   std::vector<const ResourcePool::InUsePoolResource*> required_for_draw;
1662 
1663   for (auto it = pending_gpu_work_tiles_.begin();
1664        it != pending_gpu_work_tiles_.end();) {
1665     Tile* tile = *it;
1666     DCHECK(tile->draw_info().has_resource());
1667     const ResourcePool::InUsePoolResource& resource =
1668         tile->draw_info().GetResource();
1669 
1670     // Update requirements first so that if the tile has become required
1671     // it will force a redraw.
1672     if (pending_tile_requirements_dirty_)
1673       tile->tiling()->UpdateRequiredStatesOnTile(tile);
1674 
1675     if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY ||
1676         raster_buffer_provider_->IsResourceReadyToDraw(resource)) {
1677       tile->draw_info().set_resource_ready_for_draw();
1678       client_->NotifyTileStateChanged(tile);
1679       it = pending_gpu_work_tiles_.erase(it);
1680       continue;
1681     }
1682 
1683     // TODO(ericrk): If a tile in our list no longer has valid tile priorities,
1684     // it may still report that it is required, and unnecessarily delay
1685     // activation. crbug.com/687265
1686     if (tile->required_for_activation())
1687       required_for_activation.push_back(&resource);
1688     if (tile->required_for_draw())
1689       required_for_draw.push_back(&resource);
1690 
1691     ++it;
1692   }
1693 
1694   if (required_for_activation.empty()) {
1695     pending_required_for_activation_callback_id_ = 0;
1696   } else {
1697     pending_required_for_activation_callback_id_ =
1698         raster_buffer_provider_->SetReadyToDrawCallback(
1699             required_for_activation,
1700             base::BindOnce(
1701                 &TileManager::CheckPendingGpuWorkAndIssueSignals,
1702                 ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
1703             pending_required_for_activation_callback_id_);
1704   }
1705 
1706   if (required_for_draw.empty()) {
1707     pending_required_for_draw_callback_id_ = 0;
1708   } else {
1709     pending_required_for_draw_callback_id_ =
1710         raster_buffer_provider_->SetReadyToDrawCallback(
1711             required_for_draw,
1712             base::BindOnce(
1713                 &TileManager::CheckPendingGpuWorkAndIssueSignals,
1714                 ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
1715             pending_required_for_draw_callback_id_);
1716   }
1717 
1718   // Update our signals now that we know whether we have pending resources.
1719   signals_.activate_gpu_work_completed =
1720       (pending_required_for_activation_callback_id_ == 0);
1721   signals_.draw_gpu_work_completed =
1722       (pending_required_for_draw_callback_id_ == 0);
1723 
1724   // We've just updated all pending tile requirements if necessary.
1725   pending_tile_requirements_dirty_ = false;
1726 
1727   IssueSignals();
1728 }
1729 
1730 // Utility function that can be used to create a "Task set finished" task that
1731 // posts |callback| to |task_runner| when run.
CreateTaskSetFinishedTask(void (TileManager::* callback)())1732 scoped_refptr<TileTask> TileManager::CreateTaskSetFinishedTask(
1733     void (TileManager::*callback)()) {
1734   return base::MakeRefCounted<TaskSetFinishedTaskImpl>(
1735       task_runner_,
1736       base::BindRepeating(callback,
1737                           task_set_finished_weak_ptr_factory_.GetWeakPtr()));
1738 }
1739 
1740 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
ActivationStateAsValue()1741 TileManager::ActivationStateAsValue() {
1742   auto state = std::make_unique<base::trace_event::TracedValue>();
1743   ActivationStateAsValueInto(state.get());
1744   return std::move(state);
1745 }
1746 
ActivationStateAsValueInto(base::trace_event::TracedValue * state)1747 void TileManager::ActivationStateAsValueInto(
1748     base::trace_event::TracedValue* state) {
1749   state->SetString("tree_priority",
1750                    TreePriorityToString(global_state_.tree_priority));
1751   state->SetInteger("soft_memory_limit",
1752                     global_state_.soft_memory_limit_in_bytes);
1753   state->SetInteger("hard_memory_limit",
1754                     global_state_.soft_memory_limit_in_bytes);
1755   state->SetInteger("pending_required_for_activation_callback_id",
1756                     pending_required_for_activation_callback_id_);
1757   state->SetInteger("current_memory_usage",
1758                     resource_pool_->memory_usage_bytes());
1759   state->SetInteger("current_resource_usage", resource_pool_->resource_count());
1760 
1761   // Use a custom tile_as_value, instead of Tile::AsValueInto, since we don't
1762   // need all of the state that would be captured by other functions.
1763   auto tile_as_value = [](const PrioritizedTile& prioritized_tile,
1764                           base::trace_event::TracedValue* value) {
1765     Tile* tile = prioritized_tile.tile();
1766     TilePriority priority = prioritized_tile.priority();
1767 
1768     value->SetInteger("id", tile->id());
1769     value->SetString("content_rect", tile->content_rect().ToString());
1770     value->SetDouble("contents_scale", tile->contents_scale_key());
1771     value->SetBoolean("is_ready_to_draw", tile->draw_info().IsReadyToDraw());
1772     value->SetString("resolution", TileResolutionToString(priority.resolution));
1773     value->SetString("priority_bin",
1774                      TilePriorityBinToString(priority.priority_bin));
1775     value->SetDouble("distance_to_visible", priority.distance_to_visible);
1776     value->SetBoolean("required_for_activation",
1777                       tile->required_for_activation());
1778     value->SetBoolean("required_for_draw", tile->required_for_draw());
1779   };
1780 
1781   std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue(
1782       client_->BuildRasterQueue(global_state_.tree_priority,
1783                                 RasterTilePriorityQueue::Type::ALL));
1784   state->BeginArray("raster_tiles");
1785   for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
1786     state->BeginDictionary();
1787     tile_as_value(raster_priority_queue->Top(), state);
1788     state->EndDictionary();
1789   }
1790   state->EndArray();
1791 
1792   std::unique_ptr<RasterTilePriorityQueue> required_priority_queue(
1793       client_->BuildRasterQueue(
1794           global_state_.tree_priority,
1795           RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
1796   state->BeginArray("activation_tiles");
1797   for (; !required_priority_queue->IsEmpty(); required_priority_queue->Pop()) {
1798     state->BeginDictionary();
1799     tile_as_value(required_priority_queue->Top(), state);
1800     state->EndDictionary();
1801   }
1802   state->EndArray();
1803 }
1804 
MemoryUsage()1805 TileManager::MemoryUsage::MemoryUsage()
1806     : memory_bytes_(0), resource_count_(0) {}
1807 
MemoryUsage(size_t memory_bytes,size_t resource_count)1808 TileManager::MemoryUsage::MemoryUsage(size_t memory_bytes,
1809                                       size_t resource_count)
1810     : memory_bytes_(static_cast<int64_t>(memory_bytes)),
1811       resource_count_(static_cast<int>(resource_count)) {
1812   // MemoryUsage is constructed using size_ts, since it deals with memory and
1813   // the inputs are typically size_t. However, during the course of usage (in
1814   // particular operator-=) can cause internal values to become negative.
1815   // Thus, member variables are signed.
1816   DCHECK_LE(memory_bytes,
1817             static_cast<size_t>(std::numeric_limits<int64_t>::max()));
1818   DCHECK_LE(resource_count,
1819             static_cast<size_t>(std::numeric_limits<int>::max()));
1820 }
1821 
1822 // static
FromConfig(const gfx::Size & size,viz::ResourceFormat format)1823 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
1824     const gfx::Size& size,
1825     viz::ResourceFormat format) {
1826   // We can use UncheckedSizeInBytes here since this is used with a tile
1827   // size which is determined by the compositor (it's at most max texture
1828   // size).
1829   return MemoryUsage(
1830       viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format), 1);
1831 }
1832 
1833 // static
FromTile(const Tile * tile)1834 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
1835   const TileDrawInfo& draw_info = tile->draw_info();
1836   if (draw_info.has_resource()) {
1837     return MemoryUsage::FromConfig(draw_info.resource_size(),
1838                                    draw_info.resource_format());
1839   }
1840   return MemoryUsage();
1841 }
1842 
operator +=(const MemoryUsage & other)1843 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
1844     const MemoryUsage& other) {
1845   memory_bytes_ += other.memory_bytes_;
1846   resource_count_ += other.resource_count_;
1847   return *this;
1848 }
1849 
operator -=(const MemoryUsage & other)1850 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
1851     const MemoryUsage& other) {
1852   memory_bytes_ -= other.memory_bytes_;
1853   resource_count_ -= other.resource_count_;
1854   return *this;
1855 }
1856 
operator -(const MemoryUsage & other)1857 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
1858     const MemoryUsage& other) {
1859   MemoryUsage result = *this;
1860   result -= other;
1861   return result;
1862 }
1863 
Exceeds(const MemoryUsage & limit) const1864 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
1865   return memory_bytes_ > limit.memory_bytes_ ||
1866          resource_count_ > limit.resource_count_;
1867 }
1868 
1869 TileManager::PrioritizedWorkToSchedule::PrioritizedWorkToSchedule() = default;
1870 TileManager::PrioritizedWorkToSchedule::PrioritizedWorkToSchedule(
1871     PrioritizedWorkToSchedule&& other) = default;
1872 TileManager::PrioritizedWorkToSchedule::~PrioritizedWorkToSchedule() = default;
1873 
1874 }  // namespace cc
1875