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 29 size_t ResourceUpdateController::MaxPartialTextureUpdates() { 30 return kPartialTextureUpdatesMax; 31 } 32 33 size_t ResourceUpdateController::MaxFullUpdatesPerTick( 34 ResourceProvider* resource_provider) { 35 return resource_provider->EstimatedUploadsPerTick(); 36 } 37 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 52 ResourceUpdateController::~ResourceUpdateController() {} 53 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 81 void ResourceUpdateController::DiscardUploadsToEvictedResources() { 82 queue_->ClearUploadsToEvictedResources(); 83 } 84 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 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 106 void ResourceUpdateController::OnTimerFired() { 107 task_posted_ = false; 108 if (!UpdateMoreTexturesIfEnoughTimeRemaining()) 109 client_->ReadyToFinalizeTextureUpdates(); 110 } 111 112 base::TimeTicks ResourceUpdateController::UpdateMoreTexturesCompletionTime() { 113 return resource_provider_->EstimatedUploadCompletionTime( 114 texture_updates_per_tick_); 115 } 116 117 size_t ResourceUpdateController::UpdateMoreTexturesSize() const { 118 return texture_updates_per_tick_; 119 } 120 121 size_t ResourceUpdateController::MaxBlockingUpdates() const { 122 return UpdateMoreTexturesSize() * kMaxBlockingUpdateIntervals; 123 } 124 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 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