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/resources/resource_update_controller.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "cc/resources/prioritized_resource.h"
11 #include "cc/resources/resource_provider.h"
12 #include "ui/gfx/frame_time.h"
13
14 namespace {
15
16 // Number of partial updates we allow.
17 const size_t kPartialTextureUpdatesMax = 12;
18
19 // Measured in seconds.
20 const double kUploaderBusyTickRate = 0.001;
21
22 // Number of blocking update intervals to allow.
23 const size_t kMaxBlockingUpdateIntervals = 4;
24
25 } // namespace
26
27 namespace cc {
28
MaxPartialTextureUpdates()29 size_t ResourceUpdateController::MaxPartialTextureUpdates() {
30 return kPartialTextureUpdatesMax;
31 }
32
MaxFullUpdatesPerTick(ResourceProvider * resource_provider)33 size_t ResourceUpdateController::MaxFullUpdatesPerTick(
34 ResourceProvider* resource_provider) {
35 return resource_provider->EstimatedUploadsPerTick();
36 }
37
ResourceUpdateController(ResourceUpdateControllerClient * client,base::SingleThreadTaskRunner * task_runner,scoped_ptr<ResourceUpdateQueue> queue,ResourceProvider * resource_provider)38 ResourceUpdateController::ResourceUpdateController(
39 ResourceUpdateControllerClient* client,
40 base::SingleThreadTaskRunner* task_runner,
41 scoped_ptr<ResourceUpdateQueue> queue,
42 ResourceProvider* resource_provider)
43 : client_(client),
44 queue_(queue.Pass()),
45 resource_provider_(resource_provider),
46 texture_updates_per_tick_(MaxFullUpdatesPerTick(resource_provider)),
47 first_update_attempt_(true),
48 task_runner_(task_runner),
49 task_posted_(false),
50 weak_factory_(this) {}
51
~ResourceUpdateController()52 ResourceUpdateController::~ResourceUpdateController() {}
53
PerformMoreUpdates(base::TimeTicks time_limit)54 void ResourceUpdateController::PerformMoreUpdates(
55 base::TimeTicks time_limit) {
56 time_limit_ = time_limit;
57
58 // Update already in progress.
59 if (task_posted_)
60 return;
61
62 // Call UpdateMoreTexturesNow() directly unless it's the first update
63 // attempt. This ensures that we empty the update queue in a finite
64 // amount of time.
65 if (!first_update_attempt_)
66 UpdateMoreTexturesNow();
67
68 // Post a 0-delay task when no updates were left. When it runs,
69 // ReadyToFinalizeTextureUpdates() will be called.
70 if (!UpdateMoreTexturesIfEnoughTimeRemaining()) {
71 task_posted_ = true;
72 task_runner_->PostTask(
73 FROM_HERE,
74 base::Bind(&ResourceUpdateController::OnTimerFired,
75 weak_factory_.GetWeakPtr()));
76 }
77
78 first_update_attempt_ = false;
79 }
80
DiscardUploadsToEvictedResources()81 void ResourceUpdateController::DiscardUploadsToEvictedResources() {
82 queue_->ClearUploadsToEvictedResources();
83 }
84
UpdateTexture(ResourceUpdate update)85 void ResourceUpdateController::UpdateTexture(ResourceUpdate update) {
86 update.bitmap->lockPixels();
87 update.texture->SetPixels(
88 resource_provider_,
89 static_cast<const uint8_t*>(update.bitmap->getPixels()),
90 update.content_rect,
91 update.source_rect,
92 update.dest_offset);
93 update.bitmap->unlockPixels();
94 }
95
Finalize()96 void ResourceUpdateController::Finalize() {
97 while (queue_->FullUploadSize())
98 UpdateTexture(queue_->TakeFirstFullUpload());
99
100 while (queue_->PartialUploadSize())
101 UpdateTexture(queue_->TakeFirstPartialUpload());
102
103 resource_provider_->FlushUploads();
104 }
105
OnTimerFired()106 void ResourceUpdateController::OnTimerFired() {
107 task_posted_ = false;
108 if (!UpdateMoreTexturesIfEnoughTimeRemaining())
109 client_->ReadyToFinalizeTextureUpdates();
110 }
111
UpdateMoreTexturesCompletionTime()112 base::TimeTicks ResourceUpdateController::UpdateMoreTexturesCompletionTime() {
113 return resource_provider_->EstimatedUploadCompletionTime(
114 texture_updates_per_tick_);
115 }
116
UpdateMoreTexturesSize() const117 size_t ResourceUpdateController::UpdateMoreTexturesSize() const {
118 return texture_updates_per_tick_;
119 }
120
MaxBlockingUpdates() const121 size_t ResourceUpdateController::MaxBlockingUpdates() const {
122 return UpdateMoreTexturesSize() * kMaxBlockingUpdateIntervals;
123 }
124
UpdateMoreTexturesIfEnoughTimeRemaining()125 bool ResourceUpdateController::UpdateMoreTexturesIfEnoughTimeRemaining() {
126 while (resource_provider_->NumBlockingUploads() < MaxBlockingUpdates()) {
127 if (!queue_->FullUploadSize())
128 return false;
129
130 if (!time_limit_.is_null()) {
131 base::TimeTicks completion_time = UpdateMoreTexturesCompletionTime();
132 if (completion_time > time_limit_)
133 return true;
134 }
135
136 UpdateMoreTexturesNow();
137 }
138
139 task_posted_ = true;
140 task_runner_->PostDelayedTask(
141 FROM_HERE,
142 base::Bind(&ResourceUpdateController::OnTimerFired,
143 weak_factory_.GetWeakPtr()),
144 base::TimeDelta::FromMilliseconds(kUploaderBusyTickRate * 1000));
145 return true;
146 }
147
UpdateMoreTexturesNow()148 void ResourceUpdateController::UpdateMoreTexturesNow() {
149 size_t uploads = std::min(
150 queue_->FullUploadSize(), UpdateMoreTexturesSize());
151
152 if (!uploads)
153 return;
154
155 while (queue_->FullUploadSize() && uploads--)
156 UpdateTexture(queue_->TakeFirstFullUpload());
157
158 resource_provider_->FlushUploads();
159 }
160
161 } // namespace cc
162