summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@nokia.com>2010-12-03 20:47:32 +0100
committerGunnar Sletta <gunnar.sletta@nokia.com>2010-12-03 20:47:32 +0100
commit6dcc29c938cb404d2473188e046cb2616b2bbf9b (patch)
treee76ee6148ecfdb7a7c3f97d1dc6f4e6a20b13ec3
parentc7350d331901cd95dc3eac69afd0efc7ca04155f (diff)
Introduced threaded texture manager and make use of it in QxImage
-rw-r--r--src/adaptationlayers/adaptationlayer.cpp10
-rw-r--r--src/adaptationlayers/adaptationlayer.h9
-rw-r--r--src/adaptationlayers/adaptationlayers.pri4
-rw-r--r--src/adaptationlayers/default/default_glyphnode_p.cpp2
-rw-r--r--src/adaptationlayers/default/default_texturemanager.cpp53
-rw-r--r--src/adaptationlayers/default/default_texturemanager.h55
-rw-r--r--src/adaptationlayers/threadedtexturemanager.cpp124
-rw-r--r--src/adaptationlayers/threadedtexturemanager.h19
-rw-r--r--src/graphicsitems/qximage.cpp8
-rw-r--r--src/graphicsitems/qximage_p_p.h3
-rw-r--r--src/graphicsitems/qximagebase.cpp40
-rw-r--r--src/graphicsitems/qximagebase_p.h4
-rw-r--r--src/graphicsitems/qximagebase_p_p.h2
-rw-r--r--src/scenegraph/coreapi/qsgcontext.cpp8
-rw-r--r--tests/image-asynchronous.qml71
-rw-r--r--tools/qmlscene/main.cpp2
16 files changed, 278 insertions, 136 deletions
diff --git a/src/adaptationlayers/adaptationlayer.cpp b/src/adaptationlayers/adaptationlayer.cpp
index 152156f..0fdddd9 100644
--- a/src/adaptationlayers/adaptationlayer.cpp
+++ b/src/adaptationlayers/adaptationlayer.cpp
@@ -65,7 +65,7 @@ void TextureReference::setStatus(Status s)
{
m_status = s;
- Q_ASSERT(s != Ready || (m_texture_id > 0 && !m_texture_size.isEmpty()));
+ Q_ASSERT(s != Uploaded || (m_texture_id > 0 && !m_texture_size.isEmpty()));
emit statusChanged(s);
}
@@ -75,7 +75,7 @@ void TextureReference::setStatus(Status s)
The upload is done using the QGLContext::bindTexture().
*/
-const TextureReference *TextureManager::uploadImage(const QImage &image, UploadHints hints)
+const TextureReference *TextureManager::requestUploadedTexture(const QImage &image, UploadHints hints, QObject *listener, const char *slot)
{
QGLContext *context = const_cast<QGLContext *>(QGLContext::currentContext());
@@ -89,11 +89,15 @@ const TextureReference *TextureManager::uploadImage(const QImage &image, UploadH
options);
TextureReference *ref = new TextureReference();
+
+ if (listener && slot)
+ QObject::connect(ref, SIGNAL(statusChanged(int)), listener, slot);
+
ref->setTextureId(id);
ref->setOwnsTexture(true);
ref->setAlphaChannel(image.hasAlphaChannel());
ref->setTextureSize(image.size());
- ref->setStatus(TextureReference::Ready);
+ ref->setStatus(TextureReference::Uploaded);
return ref;
}
diff --git a/src/adaptationlayers/adaptationlayer.h b/src/adaptationlayers/adaptationlayer.h
index fead7d9..aa89b71 100644
--- a/src/adaptationlayers/adaptationlayer.h
+++ b/src/adaptationlayers/adaptationlayer.h
@@ -132,8 +132,8 @@ class TextureReference : public QObject
public:
enum Status {
Null,
- Ready,
- Loading,
+ Uploaded,
+ Uploading,
Error
};
@@ -162,7 +162,7 @@ public:
Status status() const { return m_status; }
signals:
- void statusChanged(Status status);
+ void statusChanged(int status);
protected:
@@ -192,8 +192,7 @@ public:
virtual ~TextureManager() { };
- virtual const TextureReference *requestUploadedTexture(const QImage &image, UploadHints hints = DefaultUploadHints) = 0;
- const TextureReference *uploadImage(const QImage &image, UploadHints hints);
+ virtual const TextureReference *requestUploadedTexture(const QImage &image, UploadHints hints = DefaultUploadHints, QObject *listener = 0, const char *slot = 0);
};
diff --git a/src/adaptationlayers/adaptationlayers.pri b/src/adaptationlayers/adaptationlayers.pri
index b72c427..514e32d 100644
--- a/src/adaptationlayers/adaptationlayers.pri
+++ b/src/adaptationlayers/adaptationlayers.pri
@@ -6,7 +6,7 @@ HEADERS += \
$$PWD/default/default_rectanglenode.h \
$$PWD/default/default_glyphnode.h \
$$PWD/default/default_glyphnode_p.h \
- $$PWD/default/default_texturemanager.h \
+ $$PWD/adaptationlayers/threadedtexturemanager.h
SOURCES += \
$$PWD/adaptationlayer.cpp \
@@ -14,4 +14,4 @@ SOURCES += \
$$PWD/default/default_rectanglenode.cpp \
$$PWD/default/default_glyphnode.cpp \
$$PWD/default/default_glyphnode_p.cpp \
- $$PWD/default/default_texturemanager.cpp \
+ $$PWD/threadedtexturemanager.cpp
diff --git a/src/adaptationlayers/default/default_glyphnode_p.cpp b/src/adaptationlayers/default/default_glyphnode_p.cpp
index 8ea64c4..685e02b 100644
--- a/src/adaptationlayers/default/default_glyphnode_p.cpp
+++ b/src/adaptationlayers/default/default_glyphnode_p.cpp
@@ -317,7 +317,7 @@ bool TextMaskMaterial::ensureUpToDate()
m_texture->setTextureId(glyphCache()->texture());
m_texture->setTextureSize(QSize(glyphCache()->width(),
glyphCache()->height()));
- m_texture->setStatus(TextureReference::Ready);
+ m_texture->setStatus(TextureReference::Uploaded);
m_size = glyphCacheSize;
diff --git a/src/adaptationlayers/default/default_texturemanager.cpp b/src/adaptationlayers/default/default_texturemanager.cpp
deleted file mode 100644
index 5f3de1c..0000000
--- a/src/adaptationlayers/default/default_texturemanager.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the Qt scene graph research project.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "default_texturemanager.h"
-
-DefaultTextureManager::DefaultTextureManager()
-{
-}
-
-
-
-const TextureReference *DefaultTextureManager::requestUploadedTexture(const QImage &image, UploadHints hints)
-{
- return uploadImage(image, hints);
-}
diff --git a/src/adaptationlayers/default/default_texturemanager.h b/src/adaptationlayers/default/default_texturemanager.h
deleted file mode 100644
index aacc820..0000000
--- a/src/adaptationlayers/default/default_texturemanager.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the Qt scene graph research project.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef DEFAULTTEXTUREMANAGER_H
-#define DEFAULTTEXTUREMANAGER_H
-
-#include "adaptationlayer.h"
-
-class DefaultTextureManager : public TextureManager
-{
-public:
- DefaultTextureManager();
-
- const TextureReference *requestUploadedTexture(const QImage &image, UploadHints hints);
-};
-
-#endif // DEFAULTTEXTUREMANAGER_H
diff --git a/src/adaptationlayers/threadedtexturemanager.cpp b/src/adaptationlayers/threadedtexturemanager.cpp
new file mode 100644
index 0000000..a1af9cf
--- /dev/null
+++ b/src/adaptationlayers/threadedtexturemanager.cpp
@@ -0,0 +1,124 @@
+#include "threadedtexturemanager.h"
+
+#include <QWaitCondition>
+#include <QMutex>
+#include <QThread>
+
+#include <QQueue>
+#include <QPaintDevice>
+#include <QGLWidget>
+
+
+struct TextureToUpload
+{
+ QImage image;
+ TextureReference *texture;
+ TextureManager::UploadHints hints;
+};
+
+class QSGTTMUploadThread : public QThread
+{
+public:
+ QSGTTMUploadThread() {
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ // Getting the share widget from the current context is rather nasty and
+ // will not work for lighthouse based
+ Q_ASSERT(ctx->device() && ctx->device()->devType() == QInternal::Widget);
+
+ QGLWidget *share = static_cast<QGLWidget *>(ctx->device());
+
+ widget = new QGLWidget(0, share);
+ widget->resize(8, 8);
+
+ context = const_cast<QGLContext *>(widget->context());
+
+ widget->doneCurrent();
+
+ ctx->makeCurrent();
+
+ start();
+ }
+
+ void run() {
+
+ context->makeCurrent();
+
+ while (true) {
+
+ mutex.lock();
+ if (requests.isEmpty()) {
+ condition.wait(&mutex);
+ }
+
+ if (requests.isEmpty()) {
+ mutex.unlock();
+ continue;
+ }
+
+ TextureToUpload work = requests.dequeue();
+ mutex.unlock();
+
+ if (work.image.isNull())
+ continue;
+
+ GLuint id;
+ glGenTextures(1, &id);
+ glBindTexture(GL_TEXTURE_2D, id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, work.image.width(), work.image.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, work.image.constBits());
+
+ if (work.hints & TextureManager::GenerateMipmapUploadHint)
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ work.texture->setTextureId(id);
+ work.texture->setTextureSize(work.image.size());
+ work.texture->setMipmaps(work.hints & TextureManager::GenerateMipmapUploadHint);
+ work.texture->setStatus(TextureReference::Uploaded);
+ }
+ }
+
+ QGLWidget *widget;
+ QGLContext *context;
+
+ QWaitCondition condition;
+ QMutex mutex;
+
+ QQueue<TextureToUpload> requests;
+};
+
+class QSGThreadedTextureManagerPrivate
+{
+public:
+ QSGTTMUploadThread thread;
+};
+
+QSGThreadedTextureManager::QSGThreadedTextureManager()
+{
+ d = new QSGThreadedTextureManagerPrivate;
+}
+
+const TextureReference *QSGThreadedTextureManager::requestUploadedTexture(const QImage &image, UploadHints hints, QObject *listener, const char *slot)
+{
+ Q_ASSERT(!image.isNull());
+
+ if (hints & SynchronousUploadHint) {
+ return TextureManager::requestUploadedTexture(image, hints, listener, slot);
+ }
+
+ TextureToUpload work;
+ work.texture = new TextureReference;
+ work.image = image;
+ work.hints = hints;
+
+ QObject::connect(work.texture, SIGNAL(statusChanged(int)), listener, slot);
+
+ d->thread.mutex.lock();
+ d->thread.requests << work;
+ d->thread.condition.wakeOne();
+ d->thread.mutex.unlock();
+
+ return work.texture;
+}
+
+
+
+
diff --git a/src/adaptationlayers/threadedtexturemanager.h b/src/adaptationlayers/threadedtexturemanager.h
new file mode 100644
index 0000000..26abaf1
--- /dev/null
+++ b/src/adaptationlayers/threadedtexturemanager.h
@@ -0,0 +1,19 @@
+#ifndef THREADEDTEXTUREMANAGER_H
+#define THREADEDTEXTUREMANAGER_H
+
+#include "adaptationlayer.h"
+
+class QSGThreadedTextureManagerPrivate;
+
+class QSGThreadedTextureManager : public TextureManager
+{
+public:
+ QSGThreadedTextureManager();
+
+ const TextureReference *requestUploadedTexture(const QImage &image, UploadHints hints, QObject *listener, const char *slot);
+
+private:
+ QSGThreadedTextureManagerPrivate *d;
+};
+
+#endif // THREADEDTEXTUREMANAGER_H
diff --git a/src/graphicsitems/qximage.cpp b/src/graphicsitems/qximage.cpp
index 7a2afc4..68ceac0 100644
--- a/src/graphicsitems/qximage.cpp
+++ b/src/graphicsitems/qximage.cpp
@@ -61,7 +61,6 @@ QxImage::~QxImage()
{
Q_D(QxImage);
delete d->node;
- delete d->texture;
}
QPixmap QxImage::pixmap() const
@@ -197,11 +196,6 @@ void QxImagePrivate::update()
node = QSGContext::current->createTextureNode();
}
- if (!texture) {
- texture = QSGContext::current->textureManager()->requestUploadedTexture(pix.pixmap().toImage(),
- TextureManager::SynchronousUploadHint);
- }
-
node->setTexture(texture);
node->setRect(targetRect);
node->setSourceRect(sourceRect);
@@ -239,8 +233,6 @@ void QxImage::pixmapChange()
setImplicitWidth(d->pix.width());
setImplicitHeight(d->pix.height());
d->status = d->pix.isNull() ? QxImageBase::Null : QxImageBase::Ready;
- delete d->texture;
- d->texture = 0;
d->pixmapDirty = true;
d->update();
emit pixmapChanged();
diff --git a/src/graphicsitems/qximage_p_p.h b/src/graphicsitems/qximage_p_p.h
index b8469c4..9de93f2 100644
--- a/src/graphicsitems/qximage_p_p.h
+++ b/src/graphicsitems/qximage_p_p.h
@@ -63,7 +63,7 @@ class QxImagePrivate : public QxImageBasePrivate
public:
QxImagePrivate()
- : fillMode(QxImage::Stretch), paintedWidth(0), paintedHeight(0), pixmapDirty(false), node(0), texture(0)
+ : fillMode(QxImage::Stretch), paintedWidth(0), paintedHeight(0), pixmapDirty(false), node(0)
{
}
@@ -76,7 +76,6 @@ public:
void updateOpacity();
bool pixmapDirty;
TextureNodeInterface *node;
- const TextureReference *texture;
};
#endif // QXIMAGE_P_H
diff --git a/src/graphicsitems/qximagebase.cpp b/src/graphicsitems/qximagebase.cpp
index 285e14e..8bbae28 100644
--- a/src/graphicsitems/qximagebase.cpp
+++ b/src/graphicsitems/qximagebase.cpp
@@ -47,6 +47,7 @@
#include <private/qdeclarativepixmapcache_p.h>
#include <QtCore/qfile.h>
+#include <QTime>
QxImageBase::QxImageBase(QxImageBasePrivate &dd, QxItem *parent)
: QxItem(dd, parent)
@@ -174,7 +175,10 @@ void QxImageBase::requestFinished()
d->status = Error;
qmlInfo(this) << d->pix.error();
} else {
- d->status = Ready;
+ if (d->async)
+ d->status = Uploading;
+ else
+ d->status = Ready;
}
d->progress = 1.0;
@@ -186,7 +190,39 @@ void QxImageBase::requestFinished()
emit statusChanged(d->status);
if (d->progress != oldProgress)
emit progressChanged(d->progress);
- pixmapChange();
+
+
+ if (d->texture) {
+ delete d->texture;
+ }
+
+ TextureManager *tm = QSGContext::current->textureManager();
+
+ if (d->async) {
+ d->texture = tm->requestUploadedTexture(d->pix.pixmap().toImage(),
+ 0,
+ this,
+ SLOT(textureStatusChanged(int)));
+ if (d->texture->status() == TextureReference::Uploaded)
+ pixmapChange();
+ } else {
+ d->texture = tm->requestUploadedTexture(d->pix.pixmap().toImage(), TextureManager::SynchronousUploadHint);
+ pixmapChange();
+ }
+}
+
+void QxImageBase::textureStatusChanged(int status)
+{
+ Q_D(QxImageBase);
+
+ if (status == TextureReference::Uploaded) {
+ d->status = Ready;
+ emit statusChanged(d->status);
+ }
+
+ if (d->texture)
+ pixmapChange();
+
}
void QxImageBase::requestProgress(qint64 received, qint64 total)
diff --git a/src/graphicsitems/qximagebase_p.h b/src/graphicsitems/qximagebase_p.h
index 22808ee..d7a4030 100644
--- a/src/graphicsitems/qximagebase_p.h
+++ b/src/graphicsitems/qximagebase_p.h
@@ -43,6 +43,7 @@
#define QXIMAGEBASE_H
#include "qxitem.h"
+#include "adaptationlayer.h"
class QxImageBasePrivate;
class QxImageBase : public QxItem
@@ -59,7 +60,7 @@ class QxImageBase : public QxItem
public:
~QxImageBase();
- enum Status { Null, Ready, Loading, Error };
+ enum Status { Null, Ready, Loading, Uploading, Error };
Status status() const;
qreal progress() const;
@@ -88,6 +89,7 @@ protected:
private Q_SLOTS:
virtual void requestFinished();
void requestProgress(qint64,qint64);
+ void textureStatusChanged(int status);
private:
Q_DISABLE_COPY(QxImageBase)
diff --git a/src/graphicsitems/qximagebase_p_p.h b/src/graphicsitems/qximagebase_p_p.h
index bca583f..9e5f12a 100644
--- a/src/graphicsitems/qximagebase_p_p.h
+++ b/src/graphicsitems/qximagebase_p_p.h
@@ -78,7 +78,7 @@ public:
QUrl url;
qreal progress;
QSize sourcesize;
- TextureReference *texture;
+ const TextureReference *texture;
bool explicitSourceSize : 1;
bool async : 1;
};
diff --git a/src/scenegraph/coreapi/qsgcontext.cpp b/src/scenegraph/coreapi/qsgcontext.cpp
index f8fde55..68a65bb 100644
--- a/src/scenegraph/coreapi/qsgcontext.cpp
+++ b/src/scenegraph/coreapi/qsgcontext.cpp
@@ -5,8 +5,8 @@
#include "qmlrenderer.h"
#include "default/default_rectanglenode.h"
#include "default/default_texturenode.h"
-#include "default/default_texturemanager.h"
#include "default/default_glyphnode.h"
+#include "threadedtexturemanager.h"
#include <private/qobject_p.h>
@@ -159,5 +159,9 @@ Renderer *QSGContext::createRenderer()
*/
TextureManager *QSGContext::createTextureManager()
{
- return new DefaultTextureManager;
+#if defined (Q_WS_MAC) || defined (Q_WS_WIN)
+ return new QSGThreadedTextureManager;
+#else
+ return new TextureManager;
+#endif
}
diff --git a/tests/image-asynchronous.qml b/tests/image-asynchronous.qml
new file mode 100644
index 0000000..b1c441e
--- /dev/null
+++ b/tests/image-asynchronous.qml
@@ -0,0 +1,71 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 800
+ height: 600
+
+ color: "red"
+
+ Image {
+ id: image
+ source: state == 1 || state == 3 ? "/Users/gunnar/Pictures/big.jpg" : ""
+ width: 100
+ height: 100
+ asynchronous: true
+
+ opacity: source == "" ? 0.01 : 1
+
+ property int state: 0
+
+ Behavior on opacity {
+ NumberAnimation { duration: 250 }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ image.state = (image.state + 1) % 4;
+ }
+ }
+
+ }
+
+ Rectangle {
+ anchors.fill: text
+ anchors.margins: -10
+ color: "black"
+ radius: 5
+ }
+
+ Text {
+ id: text
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.margins: 20
+ color: "white"
+ text: image.asynchronous ? "Loading in a thread" : "Not loading in a thread"
+ }
+
+
+ Rectangle {
+
+ anchors.centerIn: parent
+
+ width: 200
+ height: 200
+
+ border.width: 4
+ border.color: "black"
+ color: "white"
+
+ NumberAnimation on rotation {
+ from: 0
+ to: 360
+ duration: 2500
+ loops: Animation.Infinite
+ }
+ }
+
+
+
+}
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
index b49f194..fe363d6 100644
--- a/tools/qmlscene/main.cpp
+++ b/tools/qmlscene/main.cpp
@@ -155,7 +155,7 @@ protected:
QxGraphicsView::paintEvent(e);
#ifdef QML_RUNTIME_TESTING
- RenderStatistics::updateStats();
+// RenderStatistics::updateStats();
#endif
static bool continuousUpdate = qApp->arguments().contains("--continuous-update");