diff options
author | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-12-03 20:47:32 +0100 |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-12-03 20:47:32 +0100 |
commit | 6dcc29c938cb404d2473188e046cb2616b2bbf9b (patch) | |
tree | e76ee6148ecfdb7a7c3f97d1dc6f4e6a20b13ec3 | |
parent | c7350d331901cd95dc3eac69afd0efc7ca04155f (diff) |
Introduced threaded texture manager and make use of it in QxImage
-rw-r--r-- | src/adaptationlayers/adaptationlayer.cpp | 10 | ||||
-rw-r--r-- | src/adaptationlayers/adaptationlayer.h | 9 | ||||
-rw-r--r-- | src/adaptationlayers/adaptationlayers.pri | 4 | ||||
-rw-r--r-- | src/adaptationlayers/default/default_glyphnode_p.cpp | 2 | ||||
-rw-r--r-- | src/adaptationlayers/default/default_texturemanager.cpp | 53 | ||||
-rw-r--r-- | src/adaptationlayers/default/default_texturemanager.h | 55 | ||||
-rw-r--r-- | src/adaptationlayers/threadedtexturemanager.cpp | 124 | ||||
-rw-r--r-- | src/adaptationlayers/threadedtexturemanager.h | 19 | ||||
-rw-r--r-- | src/graphicsitems/qximage.cpp | 8 | ||||
-rw-r--r-- | src/graphicsitems/qximage_p_p.h | 3 | ||||
-rw-r--r-- | src/graphicsitems/qximagebase.cpp | 40 | ||||
-rw-r--r-- | src/graphicsitems/qximagebase_p.h | 4 | ||||
-rw-r--r-- | src/graphicsitems/qximagebase_p_p.h | 2 | ||||
-rw-r--r-- | src/scenegraph/coreapi/qsgcontext.cpp | 8 | ||||
-rw-r--r-- | tests/image-asynchronous.qml | 71 | ||||
-rw-r--r-- | tools/qmlscene/main.cpp | 2 |
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"); |