From 39d7613a229600e74604e429fa5c607930f6790c Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Wed, 8 Dec 2010 10:57:28 +0100 Subject: More work on async uploads If textures are deleted while pending upload, remove them from the queue. If no timers are running, upload regularily using a timer --- src/scenegraph/coreapi/qsgtexturemanager.cpp | 59 +++++++++++++++++++++++++--- src/scenegraph/coreapi/qsgtexturemanager.h | 4 ++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/scenegraph/coreapi/qsgtexturemanager.cpp b/src/scenegraph/coreapi/qsgtexturemanager.cpp index 5e468a0..218c1ea 100644 --- a/src/scenegraph/coreapi/qsgtexturemanager.cpp +++ b/src/scenegraph/coreapi/qsgtexturemanager.cpp @@ -103,6 +103,7 @@ public: : context(0) , maxUploadTime(5) , uploadChunkSize(64) + , uploadTimer(0) { } @@ -112,6 +113,9 @@ public: QQueue asyncUploads; int maxUploadTime; int uploadChunkSize; + + int uploadTimer; + QTime lastUpload; }; @@ -136,6 +140,17 @@ QSGContext *QSGTextureManager::context() const } +void QSGTextureManager::textureDestroyed(QObject *destroyed) +{ + for (int i=0; iasyncUploads.size(); ++i) { + if (destroyed == d->asyncUploads[i].texture) { + d->asyncUploads.removeAt(i); + break; + } + } +} + + void QSGTextureManager::swizzleBGRAToRGBA(QImage *image) { const int width = image->width(); @@ -174,6 +189,8 @@ QSGTextureRef QSGTextureManager::upload(const QImage &image) texture->setAlphaChannel(image.hasAlphaChannel()); texture->setStatus(QSGTexture::Ready); + connect(texture, SIGNAL(destroyed(QObject*)), this, SLOT(textureDestroyed(QObject*))); + d->cache.insert(key, texture); QSGTextureRef ref(texture); @@ -195,14 +212,38 @@ QSGTextureRef QSGTextureManager::requestUpload(const QImage &image, d->asyncUploads << work; + if (d->uploadTimer == 0) { + d->uploadTimer = startTimer(30); + } + return QSGTextureRef(t); } + +void QSGTextureManager::timerEvent(QTimerEvent *) +{ + // ### gunnar: + // In the future, I forsee us starting / stopping this timer based + // on wether the vsync animation driver is running or not. + // Then we can also skip the "time since last upload" logic which + // is currently kinda messy and unpredictable. + if (d->lastUpload.elapsed() > 50) { + // Its been a while since the last frame tick, so we are pausing... + // Upload a "big" chunk... + int old = d->maxUploadTime; + d->maxUploadTime = 50; + processAsyncTextures(); + d->maxUploadTime = old; + } +} + void QSGTextureManager::processAsyncTextures() { QTime time; time.start(); + d->lastUpload.restart(); + while (!d->asyncUploads.isEmpty()) { QSGTextureAsyncUpload &upload = d->asyncUploads.first(); @@ -215,11 +256,11 @@ void QSGTextureManager::processAsyncTextures() int chunkCount = hChunkCount * vChunkCount; QSGTexture *t = upload.texture; -// printf("ASYNC: texture: %p, id=%d, size=(%dx%d), progress: %d / %d\n", +// printf("\nASYNC: texture: %p, id=%d, size=(%dx%d), progress: %d / %d (%dx%d)\n", // t, // t->textureId(), // w, h, -// upload.progress, chunkCount); +// upload.progress, chunkCount, hChunkCount, vChunkCount); // Create or bind the texture... if (upload.texture->textureId() == 0) { @@ -239,25 +280,33 @@ void QSGTextureManager::processAsyncTextures() if (time.elapsed() > d->maxUploadTime) return; + int steps = 0; + while (upload.progress < chunkCount && time.elapsed() < d->maxUploadTime) { int x = (upload.progress % hChunkCount) * d->uploadChunkSize; int y = (upload.progress / hChunkCount) * d->uploadChunkSize; - QImage subImage = upload.image.copy(x, y, d->uploadChunkSize, d->uploadChunkSize); + QRect area = QRect(x, y, d->uploadChunkSize, d->uploadChunkSize) & upload.image.rect(); + + QImage subImage = upload.image.copy(area); // printf("ASYNC: - doing another batch: %d (x=%d, y=%d, w=%d, h=%d\n", // upload.progress, // x, y, subImage.width(), subImage.height()); swizzleBGRAToRGBA(&subImage); - - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, d->uploadChunkSize, d->uploadChunkSize, GL_RGBA, GL_UNSIGNED_BYTE, subImage.constBits()); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, subImage.width(), subImage.height(), GL_RGBA, GL_UNSIGNED_BYTE, subImage.constBits()); ++upload.progress; } if (upload.progress == chunkCount) { t->setStatus(QSGTexture::Ready); + disconnect(t, SIGNAL(destroyed(QObject*)), this, SLOT(textureDestroyed(QObject*))); d->asyncUploads.dequeue(); + if (d->asyncUploads.size() == 0) { + killTimer(d->uploadTimer); + d->uploadTimer = 0; + } } } diff --git a/src/scenegraph/coreapi/qsgtexturemanager.h b/src/scenegraph/coreapi/qsgtexturemanager.h index 46979a2..0bc08aa 100644 --- a/src/scenegraph/coreapi/qsgtexturemanager.h +++ b/src/scenegraph/coreapi/qsgtexturemanager.h @@ -175,8 +175,12 @@ public: static void swizzleBGRAToRGBA(QImage *image); +protected: + void timerEvent(QTimerEvent *); + private slots: void processAsyncTextures(); + void textureDestroyed(QObject *texture); private: QSGTextureManagerPrivate *d; -- cgit v1.2.3