#include "config.h"
#include "CCTextureUpdateController.h"
#include "GraphicsContext3D.h"
#include "TextureCopier.h"
#include "TextureUploader.h"
#include "TraceEvent.h"
#include <limits>
#include <wtf/CurrentTime.h>
namespace {
static const size_t partialTextureUpdatesMax = 12;
static const double textureUpdateTickRate = 0.004;
static const double uploaderBusyTickRate = 0.001;
static const int textureUploadFlushPeriod = 4;
}
namespace cc {
size_t CCTextureUpdateController::maxPartialTextureUpdates()
{
return partialTextureUpdatesMax;
}
size_t CCTextureUpdateController::maxFullUpdatesPerTick(TextureUploader* uploader)
{
double texturesPerSecond = uploader->estimatedTexturesPerSecond();
size_t texturesPerTick = floor(textureUpdateTickRate * texturesPerSecond);
return texturesPerTick ? texturesPerTick : 1;
}
CCTextureUpdateController::CCTextureUpdateController(CCTextureUpdateControllerClient* client, CCThread* thread, PassOwnPtr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureUploader* uploader)
: m_client(client)
, m_timer(adoptPtr(new CCTimer(thread, this)))
, m_queue(queue)
, m_resourceProvider(resourceProvider)
, m_uploader(uploader)
, m_monotonicTimeLimit(0)
, m_textureUpdatesPerTick(maxFullUpdatesPerTick(uploader))
, m_firstUpdateAttempt(true)
{
}
CCTextureUpdateController::~CCTextureUpdateController()
{
}
void CCTextureUpdateController::performMoreUpdates(
double monotonicTimeLimit)
{
ASSERT(monotonicTimeLimit >= m_monotonicTimeLimit);
m_monotonicTimeLimit = monotonicTimeLimit;
if (m_timer->isActive())
return;
if (m_firstUpdateAttempt) {
if (!updateMoreTexturesIfEnoughTimeRemaining())
m_timer->startOneShot(0);
m_firstUpdateAttempt = false;
} else
updateMoreTexturesNow();
}
void CCTextureUpdateController::discardUploadsToEvictedResources()
{
m_queue->clearUploadsToEvictedResources();
}
void CCTextureUpdateController::finalize()
{
size_t uploadCount = 0;
while (m_queue->fullUploadSize()) {
if (!(uploadCount % textureUploadFlushPeriod) && uploadCount)
m_resourceProvider->shallowFlushIfSupported();
m_uploader->uploadTexture(
m_resourceProvider, m_queue->takeFirstFullUpload());
uploadCount++;
}
while (m_queue->partialUploadSize()) {
if (!(uploadCount % textureUploadFlushPeriod) && uploadCount)
m_resourceProvider->shallowFlushIfSupported();
m_uploader->uploadTexture(
m_resourceProvider, m_queue->takeFirstPartialUpload());
uploadCount++;
}
if (uploadCount)
m_resourceProvider->shallowFlushIfSupported();
if (m_queue->copySize()) {
TextureCopier* copier = m_resourceProvider->textureCopier();
while (m_queue->copySize())
copier->copyTexture(m_queue->takeFirstCopy());
copier->flush();
}
}
void CCTextureUpdateController::onTimerFired()
{
if (!updateMoreTexturesIfEnoughTimeRemaining())
m_client->readyToFinalizeTextureUpdates();
}
double CCTextureUpdateController::monotonicTimeNow() const
{
return monotonicallyIncreasingTime();
}
double CCTextureUpdateController::updateMoreTexturesTime() const
{
return textureUpdateTickRate;
}
size_t CCTextureUpdateController::updateMoreTexturesSize() const
{
return m_textureUpdatesPerTick;
}
bool CCTextureUpdateController::updateMoreTexturesIfEnoughTimeRemaining()
{
if (m_uploader->isBusy()) {
m_timer->startOneShot(uploaderBusyTickRate);
return true;
}
if (!m_queue->fullUploadSize())
return false;
bool hasTimeRemaining = monotonicTimeNow() < m_monotonicTimeLimit - updateMoreTexturesTime();
if (hasTimeRemaining)
updateMoreTexturesNow();
return true;
}
void CCTextureUpdateController::updateMoreTexturesNow()
{
size_t uploads = std::min(
m_queue->fullUploadSize(), updateMoreTexturesSize());
m_timer->startOneShot(
updateMoreTexturesTime() / updateMoreTexturesSize() * uploads);
if (!uploads)
return;
size_t uploadCount = 0;
m_uploader->beginUploads();
while (m_queue->fullUploadSize() && uploadCount < uploads) {
if (!(uploadCount % textureUploadFlushPeriod) && uploadCount)
m_resourceProvider->shallowFlushIfSupported();
m_uploader->uploadTexture(m_resourceProvider, m_queue->takeFirstFullUpload());
uploadCount++;
}
m_uploader->endUploads();
m_resourceProvider->shallowFlushIfSupported();
}
}