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