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