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 14namespace { 15 16// Number of partial updates we allow. 17const size_t kPartialTextureUpdatesMax = 12; 18 19// Measured in seconds. 20const double kUploaderBusyTickRate = 0.001; 21 22// Number of blocking update intervals to allow. 23const size_t kMaxBlockingUpdateIntervals = 4; 24 25} // namespace 26 27namespace cc { 28 29size_t ResourceUpdateController::MaxPartialTextureUpdates() { 30 return kPartialTextureUpdatesMax; 31} 32 33size_t ResourceUpdateController::MaxFullUpdatesPerTick( 34 ResourceProvider* resource_provider) { 35 return resource_provider->EstimatedUploadsPerTick(); 36} 37 38ResourceUpdateController::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 52ResourceUpdateController::~ResourceUpdateController() {} 53 54void 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 81void ResourceUpdateController::DiscardUploadsToEvictedResources() { 82 queue_->ClearUploadsToEvictedResources(); 83} 84 85void 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 96void 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 106void ResourceUpdateController::OnTimerFired() { 107 task_posted_ = false; 108 if (!UpdateMoreTexturesIfEnoughTimeRemaining()) 109 client_->ReadyToFinalizeTextureUpdates(); 110} 111 112base::TimeTicks ResourceUpdateController::UpdateMoreTexturesCompletionTime() { 113 return resource_provider_->EstimatedUploadCompletionTime( 114 texture_updates_per_tick_); 115} 116 117size_t ResourceUpdateController::UpdateMoreTexturesSize() const { 118 return texture_updates_per_tick_; 119} 120 121size_t ResourceUpdateController::MaxBlockingUpdates() const { 122 return UpdateMoreTexturesSize() * kMaxBlockingUpdateIntervals; 123} 124 125bool 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 148void 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