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 ready_to_finalize_(false), 51 weak_factory_(this) {} 52 53 ResourceUpdateController::~ResourceUpdateController() {} 54 55 void ResourceUpdateController::PerformMoreUpdates( 56 base::TimeTicks time_limit) { 57 time_limit_ = time_limit; 58 59 // Update already in progress or we are already done. 60 if (task_posted_ || ready_to_finalize_) 61 return; 62 63 // Call UpdateMoreTexturesNow() directly unless it's the first update 64 // attempt. This ensures that we empty the update queue in a finite 65 // amount of time. 66 if (!first_update_attempt_) 67 UpdateMoreTexturesNow(); 68 69 // Post a 0-delay task when no updates were left. When it runs, 70 // ReadyToFinalizeTextureUpdates() will be called. 71 if (!UpdateMoreTexturesIfEnoughTimeRemaining()) { 72 task_posted_ = true; 73 task_runner_->PostTask( 74 FROM_HERE, 75 base::Bind(&ResourceUpdateController::OnTimerFired, 76 weak_factory_.GetWeakPtr())); 77 } 78 79 first_update_attempt_ = false; 80 } 81 82 void ResourceUpdateController::DiscardUploadsToEvictedResources() { 83 queue_->ClearUploadsToEvictedResources(); 84 } 85 86 void ResourceUpdateController::UpdateTexture(ResourceUpdate update) { 87 update.bitmap->lockPixels(); 88 update.texture->SetPixels( 89 resource_provider_, 90 static_cast<const uint8_t*>(update.bitmap->getPixels()), 91 update.content_rect, 92 update.source_rect, 93 update.dest_offset); 94 update.bitmap->unlockPixels(); 95 } 96 97 void ResourceUpdateController::Finalize() { 98 while (queue_->FullUploadSize()) 99 UpdateTexture(queue_->TakeFirstFullUpload()); 100 101 while (queue_->PartialUploadSize()) 102 UpdateTexture(queue_->TakeFirstPartialUpload()); 103 104 resource_provider_->FlushUploads(); 105 } 106 107 void ResourceUpdateController::OnTimerFired() { 108 task_posted_ = false; 109 if (!UpdateMoreTexturesIfEnoughTimeRemaining()) { 110 ready_to_finalize_ = true; 111 client_->ReadyToFinalizeTextureUpdates(); 112 } 113 } 114 115 base::TimeTicks ResourceUpdateController::UpdateMoreTexturesCompletionTime() { 116 return resource_provider_->EstimatedUploadCompletionTime( 117 texture_updates_per_tick_); 118 } 119 120 size_t ResourceUpdateController::UpdateMoreTexturesSize() const { 121 return texture_updates_per_tick_; 122 } 123 124 size_t ResourceUpdateController::MaxBlockingUpdates() const { 125 return UpdateMoreTexturesSize() * kMaxBlockingUpdateIntervals; 126 } 127 128 bool ResourceUpdateController::UpdateMoreTexturesIfEnoughTimeRemaining() { 129 while (resource_provider_->NumBlockingUploads() < MaxBlockingUpdates()) { 130 if (!queue_->FullUploadSize()) 131 return false; 132 133 if (!time_limit_.is_null()) { 134 base::TimeTicks completion_time = UpdateMoreTexturesCompletionTime(); 135 if (completion_time > time_limit_) 136 return true; 137 } 138 139 UpdateMoreTexturesNow(); 140 } 141 142 task_posted_ = true; 143 task_runner_->PostDelayedTask( 144 FROM_HERE, 145 base::Bind(&ResourceUpdateController::OnTimerFired, 146 weak_factory_.GetWeakPtr()), 147 base::TimeDelta::FromMilliseconds(kUploaderBusyTickRate * 1000)); 148 return true; 149 } 150 151 void ResourceUpdateController::UpdateMoreTexturesNow() { 152 size_t uploads = std::min( 153 queue_->FullUploadSize(), UpdateMoreTexturesSize()); 154 155 if (!uploads) 156 return; 157 158 while (queue_->FullUploadSize() && uploads--) 159 UpdateTexture(queue_->TakeFirstFullUpload()); 160 161 resource_provider_->FlushUploads(); 162 } 163 164 } // namespace cc 165