Home | History | Annotate | Download | only in resources
      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