summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@nokia.com>2010-12-08 09:04:06 +0100
committerGunnar Sletta <gunnar.sletta@nokia.com>2010-12-08 09:04:06 +0100
commit56bf92c816687942670cfd599b76f00705392d2e (patch)
tree4d0f21a3f414b0e7b853589ddb018cab48657dc0
parenta2e244eb4a958d3f8adc42d364def21ff8ea7f20 (diff)
Asynchronous texture loading on the rendering thread.
Split the textures up into 64x64 chunks and only process textures for a few ms prior to each frame...
-rw-r--r--src/adaptationlayers/default/default_texturenode.cpp2
-rw-r--r--src/canvas/qxgraphicsview.cpp4
-rw-r--r--src/graphicsitems/qximagebase.cpp7
-rw-r--r--src/scenegraph/coreapi/qsgcontext.cpp18
-rw-r--r--src/scenegraph/coreapi/qsgcontext.h4
-rw-r--r--src/scenegraph/coreapi/qsgtexturemanager.cpp126
-rw-r--r--src/scenegraph/coreapi/qsgtexturemanager.h13
7 files changed, 153 insertions, 21 deletions
diff --git a/src/adaptationlayers/default/default_texturenode.cpp b/src/adaptationlayers/default/default_texturenode.cpp
index 5dcbba5..077f7de 100644
--- a/src/adaptationlayers/default/default_texturenode.cpp
+++ b/src/adaptationlayers/default/default_texturenode.cpp
@@ -213,7 +213,7 @@ void DefaultTextureNode::updateGeometry()
v[0].tx = v[1].tx = src.left();
v[2].tx = v[3].tx = src.right();
v[0].ty = v[2].ty = src.top();
- v[1].ty = v[3].ty = src.bottom();
+ v[1].ty = v[3].ty = src.bottom();
v += 4;
}
}
diff --git a/src/canvas/qxgraphicsview.cpp b/src/canvas/qxgraphicsview.cpp
index b3fe658..1057900 100644
--- a/src/canvas/qxgraphicsview.cpp
+++ b/src/canvas/qxgraphicsview.cpp
@@ -233,7 +233,8 @@ void QxGraphicsView::paintEvent(QPaintEvent *e)
d->sg->renderer()->setDeviceRect(rect());
d->sg->renderer()->setProjectMatrixToDeviceRect();
- d->sg->renderer()->renderScene();
+
+ d->sg->renderNextFrame();
#ifndef Q_WS_QPA
// printf("QxGraphicsView: Swapping...\n");
@@ -605,7 +606,6 @@ void QxGraphicsView::showEvent(QShowEvent *e)
*/
void QxGraphicsView::initializeSceneGraph()
{
-
#ifdef Q_WS_QPA
QPlatformWindow *platformWindow = window()->platformWindow();
QPlatformGLContext *platformContext = const_cast<QPlatformGLContext *>(platformWindow->glContext());
diff --git a/src/graphicsitems/qximagebase.cpp b/src/graphicsitems/qximagebase.cpp
index 21bf956..185c291 100644
--- a/src/graphicsitems/qximagebase.cpp
+++ b/src/graphicsitems/qximagebase.cpp
@@ -215,12 +215,13 @@ void QxImageBase::textureStatusChanged(int status)
if (status == QSGTexture::Ready) {
d->status = Ready;
emit statusChanged(d->status);
- }
- if (!d->texture.isNull()) {
- pixmapChange();
+ if (!d->texture.isNull()) {
+ pixmapChange();
+ }
}
+
}
void QxImageBase::requestProgress(qint64 received, qint64 total)
diff --git a/src/scenegraph/coreapi/qsgcontext.cpp b/src/scenegraph/coreapi/qsgcontext.cpp
index a2fe816..152452c 100644
--- a/src/scenegraph/coreapi/qsgcontext.cpp
+++ b/src/scenegraph/coreapi/qsgcontext.cpp
@@ -130,6 +130,16 @@ bool QSGContext::isReady() const
return d->gl;
}
+
+void QSGContext::renderNextFrame()
+{
+ Q_D(QSGContext);
+
+ emit aboutToRenderNextFrame();
+
+ d->renderer->renderScene();
+}
+
/*!
Factory function for scene graph backends of the Rectangle element.
*/
@@ -172,9 +182,11 @@ QSGTextureManager *QSGContext::createTextureManager()
{
QStringList args = qApp->arguments();
+ QSGTextureManager *manager;
+
// if (args.contains("--basic-texture-manager")) {
// printf("QSGContext: Using basic texture manager\n");
- return new QSGTextureManager;
+ manager = new QSGTextureManager;
// } else if (args.contains("--threaded-texture-manager")) {
// printf("QSGContext: Using threaded texture manager\n");
// return new QSGThreadedTextureManager;
@@ -191,5 +203,7 @@ QSGTextureManager *QSGContext::createTextureManager()
// return new QSGEglFSThreadedTextureManager;
//#endif
-// return new TextureManager;
+ manager->setContext(this);
+
+ return manager;
}
diff --git a/src/scenegraph/coreapi/qsgcontext.h b/src/scenegraph/coreapi/qsgcontext.h
index 90f7451..afdb34b 100644
--- a/src/scenegraph/coreapi/qsgcontext.h
+++ b/src/scenegraph/coreapi/qsgcontext.h
@@ -38,6 +38,8 @@ public:
bool isReady() const;
+ virtual void renderNextFrame();
+
virtual RectangleNodeInterface *createRectangleNode();
virtual TextureNodeInterface *createTextureNode();
virtual GlyphNodeInterface *createGlyphNode();
@@ -46,6 +48,8 @@ public:
signals:
void ready();
+
+ void aboutToRenderNextFrame();
};
#endif // QSGCONTEXT_H
diff --git a/src/scenegraph/coreapi/qsgtexturemanager.cpp b/src/scenegraph/coreapi/qsgtexturemanager.cpp
index 89cbe19..5e468a0 100644
--- a/src/scenegraph/coreapi/qsgtexturemanager.cpp
+++ b/src/scenegraph/coreapi/qsgtexturemanager.cpp
@@ -45,6 +45,8 @@
#include <qgl.h>
#include <qhash.h>
+#include <qqueue.h>
+#include <qdatetime.h>
QSGTexture::QSGTexture()
: m_status(Null)
@@ -74,7 +76,6 @@ void QSGTexture::setStatus(Status s)
}
-
struct QSGTextureCacheKey {
quint64 cacheKey;
@@ -83,6 +84,12 @@ struct QSGTextureCacheKey {
}
};
+struct QSGTextureAsyncUpload {
+ QImage image;
+ int progress;
+ QSGTexture *texture;
+};
+
uint qHash(const QSGTextureCacheKey &key)
{
@@ -92,7 +99,19 @@ uint qHash(const QSGTextureCacheKey &key)
class QSGTextureManagerPrivate
{
public:
+ QSGTextureManagerPrivate()
+ : context(0)
+ , maxUploadTime(5)
+ , uploadChunkSize(64)
+ {
+ }
+
+ QSGContext *context;
QHash<QSGTextureCacheKey, QSGTexture *> cache;
+
+ QQueue<QSGTextureAsyncUpload> asyncUploads;
+ int maxUploadTime;
+ int uploadChunkSize;
};
@@ -103,18 +122,29 @@ QSGTextureManager::QSGTextureManager()
}
+void QSGTextureManager::setContext(QSGContext *context)
+{
+ Q_ASSERT(!d->context);
+
+ d->context = context;
+ connect(d->context, SIGNAL(aboutToRenderNextFrame()), this, SLOT(processAsyncTextures()));
+}
-QImage QSGTextureManager::swizzleBGGRAToRGBA(const QImage &image)
+QSGContext *QSGTextureManager::context() const
{
- QImage img = image.copy();
- const int width = img.width();
- const int height = img.height();
+ return d->context;
+}
+
+
+void QSGTextureManager::swizzleBGRAToRGBA(QImage *image)
+{
+ const int width = image->width();
+ const int height = image->height();
for (int i = 0; i < height; ++i) {
- uint *p = (uint *) img.scanLine(i);
+ uint *p = (uint *) image->scanLine(i);
for (int x = 0; x < width; ++x)
p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
}
- return img;
}
@@ -131,7 +161,8 @@ QSGTextureRef QSGTextureManager::upload(const QImage &image)
glBindTexture(GL_TEXTURE_2D, id);
#ifdef QT_OPENGL_ES
- QImage i = swizzleBGRAToRGBA(image);
+ QImage i = image;
+ swizzleBGRAToRGBA(&i);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, i.width(), i.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, i.constBits());
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
@@ -150,12 +181,85 @@ QSGTextureRef QSGTextureManager::upload(const QImage &image)
}
-
QSGTextureRef QSGTextureManager::requestUpload(const QImage &image,
const QObject *listener,
const char *slot)
{
- QSGTextureRef texture = upload(image);
- return texture;
+ QSGTexture *t = new QSGTexture();
+ connect(t, SIGNAL(statusChanged(int)), listener, slot);
+
+ QSGTextureAsyncUpload work;
+ work.image = image;
+ work.progress = 0;
+ work.texture = t;
+
+ d->asyncUploads << work;
+
+ return QSGTextureRef(t);
}
+void QSGTextureManager::processAsyncTextures()
+{
+ QTime time;
+ time.start();
+
+ while (!d->asyncUploads.isEmpty()) {
+
+ QSGTextureAsyncUpload &upload = d->asyncUploads.first();
+
+ int w = upload.image.width();
+ int h = upload.image.height();
+
+ int hChunkCount = (w + d->uploadChunkSize - 1) / d->uploadChunkSize;
+ int vChunkCount = (h + d->uploadChunkSize - 1) / d->uploadChunkSize;
+ int chunkCount = hChunkCount * vChunkCount;
+ QSGTexture *t = upload.texture;
+
+// printf("ASYNC: texture: %p, id=%d, size=(%dx%d), progress: %d / %d\n",
+// t,
+// t->textureId(),
+// w, h,
+// upload.progress, chunkCount);
+
+ // Create or bind the texture...
+ if (upload.texture->textureId() == 0) {
+ GLuint id;
+ glGenTextures(1, &id);
+ glBindTexture(GL_TEXTURE_2D, id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ t->setTextureId(id);
+ t->setTextureSize(QSize(w, h));
+ t->setAlphaChannel(upload.image.hasAlphaChannel());
+ t->setStatus(QSGTexture::Loading);
+// printf("ASYNC: created texture %p with id=%d\n", t, id);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, t->textureId());
+ }
+
+ if (time.elapsed() > d->maxUploadTime)
+ return;
+
+ 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);
+// 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());
+
+ ++upload.progress;
+ }
+
+ if (upload.progress == chunkCount) {
+ t->setStatus(QSGTexture::Ready);
+ d->asyncUploads.dequeue();
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
diff --git a/src/scenegraph/coreapi/qsgtexturemanager.h b/src/scenegraph/coreapi/qsgtexturemanager.h
index ef0c910..46979a2 100644
--- a/src/scenegraph/coreapi/qsgtexturemanager.h
+++ b/src/scenegraph/coreapi/qsgtexturemanager.h
@@ -43,6 +43,7 @@
#define QSGTEXTUREMANAGER_H
#include "qmlscene_global.h"
+#include "qsgcontext.h"
#include <QObject>
#include <QImage>
@@ -159,15 +160,23 @@ private:
};
-class QT_SCENEGRAPH_EXPORT QSGTextureManager
+class QT_SCENEGRAPH_EXPORT QSGTextureManager : public QObject
{
+ Q_OBJECT
+
public:
QSGTextureManager();
+ virtual void setContext(QSGContext *context);
+ QSGContext *context() const;
+
virtual QSGTextureRef upload(const QImage &image);
virtual QSGTextureRef requestUpload(const QImage &image, const QObject *listener, const char *slot);
- static QImage swizzleBGGRAToRGBA(const QImage &image);
+ static void swizzleBGRAToRGBA(QImage *image);
+
+private slots:
+ void processAsyncTextures();
private:
QSGTextureManagerPrivate *d;