// 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 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), ready_to_finalize_(false), weak_factory_(this) {} ResourceUpdateController::~ResourceUpdateController() {} void ResourceUpdateController::PerformMoreUpdates( base::TimeTicks time_limit) { time_limit_ = time_limit; // Update already in progress or we are already done. if (task_posted_ || ready_to_finalize_) 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(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()) { ready_to_finalize_ = true; 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