// 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 "config.h" #include "CCTextureUpdateController.h" #include "GraphicsContext3D.h" #include "TextureCopier.h" #include "TextureUploader.h" #include <wtf/CurrentTime.h> namespace { // Number of textures to update with each call to updateMoreTexturesIfEnoughTimeRemaining(). static const size_t textureUpdatesPerTick = 12; // Measured in seconds. static const double textureUpdateTickRate = 0.004; // Flush interval when performing texture uploads. static const int textureUploadFlushPeriod = 4; } // anonymous namespace namespace WebCore { size_t CCTextureUpdateController::maxPartialTextureUpdates() { return textureUpdatesPerTick; } void CCTextureUpdateController::updateTextures(CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader, CCTextureUpdateQueue* queue, size_t count) { if (queue->fullUploadSize() || queue->partialUploadSize()) { if (uploader->isBusy()) return; uploader->beginUploads(); size_t fullUploadCount = 0; while (queue->fullUploadSize() && fullUploadCount < count) { uploader->uploadTexture(resourceProvider, queue->takeFirstFullUpload()); fullUploadCount++; if (!(fullUploadCount % textureUploadFlushPeriod)) resourceProvider->shallowFlushIfSupported(); } // Make sure there are no dangling uploads without a flush. if (fullUploadCount % textureUploadFlushPeriod) resourceProvider->shallowFlushIfSupported(); bool moreUploads = queue->fullUploadSize(); ASSERT(queue->partialUploadSize() <= count); // We need another update batch if the number of updates remaining // in |count| is greater than the remaining partial entries. if ((count - fullUploadCount) < queue->partialUploadSize()) moreUploads = true; if (moreUploads) { uploader->endUploads(); return; } size_t partialUploadCount = 0; while (queue->partialUploadSize()) { uploader->uploadTexture(resourceProvider, queue->takeFirstPartialUpload()); partialUploadCount++; if (!(partialUploadCount % textureUploadFlushPeriod)) resourceProvider->shallowFlushIfSupported(); } // Make sure there are no dangling partial uploads without a flush. if (partialUploadCount % textureUploadFlushPeriod) resourceProvider->shallowFlushIfSupported(); uploader->endUploads(); } size_t copyCount = 0; while (queue->copySize()) { copier->copyTexture(queue->takeFirstCopy()); copyCount++; } // If we've performed any texture copies, we need to insert a flush here into the compositor context // before letting the main thread proceed as it may make draw calls to the source texture of one of // our copy operations. if (copyCount) copier->flush(); } CCTextureUpdateController::CCTextureUpdateController(CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader) : m_timer(adoptPtr(new CCTimer(thread, this))) , m_queue(queue) , m_resourceProvider(resourceProvider) , m_copier(copier) , m_uploader(uploader) , m_monotonicTimeLimit(0) , m_firstUpdateAttempt(true) { } CCTextureUpdateController::~CCTextureUpdateController() { } bool CCTextureUpdateController::hasMoreUpdates() const { return m_queue->hasMoreUpdates(); } void CCTextureUpdateController::updateMoreTextures(double monotonicTimeLimit) { m_monotonicTimeLimit = monotonicTimeLimit; if (!m_queue->hasMoreUpdates()) 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 (m_firstUpdateAttempt) { updateMoreTexturesIfEnoughTimeRemaining(); m_firstUpdateAttempt = false; } else updateMoreTexturesNow(); } void CCTextureUpdateController::onTimerFired() { if (!m_queue->hasMoreUpdates()) return; updateMoreTexturesIfEnoughTimeRemaining(); } double CCTextureUpdateController::monotonicTimeNow() const { return monotonicallyIncreasingTime(); } double CCTextureUpdateController::updateMoreTexturesTime() const { return textureUpdateTickRate; } size_t CCTextureUpdateController::updateMoreTexturesSize() const { return textureUpdatesPerTick; } void CCTextureUpdateController::updateMoreTexturesIfEnoughTimeRemaining() { bool hasTimeRemaining = monotonicTimeNow() < m_monotonicTimeLimit - updateMoreTexturesTime(); if (hasTimeRemaining) updateMoreTexturesNow(); } void CCTextureUpdateController::updateMoreTexturesNow() { m_timer->startOneShot(updateMoreTexturesTime()); updateTextures(m_resourceProvider, m_copier, m_uploader, m_queue.get(), updateMoreTexturesSize()); } }