普通文本  |  162行  |  4.57 KB

// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/resources/resource_update_controller.h"

#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/resource_provider.h"
#include "ui/gfx/frame_time.h"

namespace {

// Number of partial updates we allow.
const size_t kPartialTextureUpdatesMax = 12;

// Measured in seconds.
const double kUploaderBusyTickRate = 0.001;

// Number of blocking update intervals to allow.
const size_t kMaxBlockingUpdateIntervals = 4;

}  // namespace

namespace cc {

size_t ResourceUpdateController::MaxPartialTextureUpdates() {
  return kPartialTextureUpdatesMax;
}

size_t ResourceUpdateController::MaxFullUpdatesPerTick(
    ResourceProvider* resource_provider) {
  return resource_provider->EstimatedUploadsPerTick();
}

ResourceUpdateController::ResourceUpdateController(
    ResourceUpdateControllerClient* client,
    base::SingleThreadTaskRunner* task_runner,
    scoped_ptr<ResourceUpdateQueue> queue,
    ResourceProvider* resource_provider)
    : client_(client),
      queue_(queue.Pass()),
      resource_provider_(resource_provider),
      texture_updates_per_tick_(MaxFullUpdatesPerTick(resource_provider)),
      first_update_attempt_(true),
      task_runner_(task_runner),
      task_posted_(false),
      weak_factory_(this) {}

ResourceUpdateController::~ResourceUpdateController() {}

void ResourceUpdateController::PerformMoreUpdates(
    base::TimeTicks time_limit) {
  time_limit_ = time_limit;

  // Update already in progress.
  if (task_posted_)
    return;

  // Call UpdateMoreTexturesNow() directly unless it's the first update
  // attempt. This ensures that we empty the update queue in a finite
  // amount of time.
  if (!first_update_attempt_)
    UpdateMoreTexturesNow();

  // Post a 0-delay task when no updates were left. When it runs,
  // ReadyToFinalizeTextureUpdates() will be called.
  if (!UpdateMoreTexturesIfEnoughTimeRemaining()) {
    task_posted_ = true;
    task_runner_->PostTask(
        FROM_HERE,
        base::Bind(&ResourceUpdateController::OnTimerFired,
                   weak_factory_.GetWeakPtr()));
  }

  first_update_attempt_ = false;
}

void ResourceUpdateController::DiscardUploadsToEvictedResources() {
  queue_->ClearUploadsToEvictedResources();
}

void ResourceUpdateController::UpdateTexture(ResourceUpdate update) {
  update.bitmap->lockPixels();
  update.texture->SetPixels(
      resource_provider_,
      static_cast<const uint8_t*>(update.bitmap->getPixels()),
      update.content_rect,
      update.source_rect,
      update.dest_offset);
  update.bitmap->unlockPixels();
}

void ResourceUpdateController::Finalize() {
  while (queue_->FullUploadSize())
    UpdateTexture(queue_->TakeFirstFullUpload());

  while (queue_->PartialUploadSize())
    UpdateTexture(queue_->TakeFirstPartialUpload());

  resource_provider_->FlushUploads();
}

void ResourceUpdateController::OnTimerFired() {
  task_posted_ = false;
  if (!UpdateMoreTexturesIfEnoughTimeRemaining())
    client_->ReadyToFinalizeTextureUpdates();
}

base::TimeTicks ResourceUpdateController::UpdateMoreTexturesCompletionTime() {
  return resource_provider_->EstimatedUploadCompletionTime(
      texture_updates_per_tick_);
}

size_t ResourceUpdateController::UpdateMoreTexturesSize() const {
  return texture_updates_per_tick_;
}

size_t ResourceUpdateController::MaxBlockingUpdates() const {
  return UpdateMoreTexturesSize() * kMaxBlockingUpdateIntervals;
}

bool ResourceUpdateController::UpdateMoreTexturesIfEnoughTimeRemaining() {
  while (resource_provider_->NumBlockingUploads() < MaxBlockingUpdates()) {
    if (!queue_->FullUploadSize())
      return false;

    if (!time_limit_.is_null()) {
      base::TimeTicks completion_time = UpdateMoreTexturesCompletionTime();
      if (completion_time > time_limit_)
        return true;
    }

    UpdateMoreTexturesNow();
  }

  task_posted_ = true;
  task_runner_->PostDelayedTask(
      FROM_HERE,
      base::Bind(&ResourceUpdateController::OnTimerFired,
                 weak_factory_.GetWeakPtr()),
      base::TimeDelta::FromMilliseconds(kUploaderBusyTickRate * 1000));
  return true;
}

void ResourceUpdateController::UpdateMoreTexturesNow() {
  size_t uploads = std::min(
      queue_->FullUploadSize(), UpdateMoreTexturesSize());

  if (!uploads)
    return;

  while (queue_->FullUploadSize() && uploads--)
    UpdateTexture(queue_->TakeFirstFullUpload());

  resource_provider_->FlushUploads();
}

}  // namespace cc