}
unlock();
+
+ // Process any "deleteLater" objects...
+ QCoreApplication::processEvents();
}
#ifdef THREAD_DEBUG
#include "qsgimage_p.h"
#include "qsgimage_p_p.h"
+#include <private/qsgtextureprovider_p.h>
+
#include <private/qsgcontext_p.h>
#include <private/qsgadaptationlayer_p.h>
QT_BEGIN_NAMESPACE
+class QSGImageTextureProvider : public QSGTextureProvider
+{
+ Q_OBJECT
+public:
+ QSGImageTextureProvider(const QSGImage *imageItem)
+ : d((QSGImagePrivate *) QSGItemPrivate::get(imageItem))
+ , m_texture(0)
+ , m_smooth(false)
+ {
+ }
+
+ QSGTexture *texture() const {
+ if (m_texture) {
+ m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ m_texture->setMipmapFiltering(QSGTexture::Nearest);
+ m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ }
+ return m_texture;
+ }
+
+ friend class QSGImage;
+
+ QSGImagePrivate *d;
+ QSGTexture *m_texture;
+ bool m_smooth;
+};
+
+#include "qsgimage.moc"
+
QSGImagePrivate::QSGImagePrivate()
: fillMode(QSGImage::Stretch)
, paintedWidth(0)
, pixmapChanged(false)
, hAlign(QSGImage::AlignHCenter)
, vAlign(QSGImage::AlignVCenter)
+ , provider(0)
{
}
QSGImage::~QSGImage()
{
+ Q_D(QSGImage);
+ if (d->provider)
+ d->provider->deleteLater();
}
void QSGImagePrivate::setPixmap(const QPixmap &pixmap)
return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
}
-QSGTexture *QSGImage::texture() const
+QSGTextureProvider *QSGImage::textureProvider() const
{
Q_D(const QSGImage);
- QSGTexture *t = d->pix.texture(d->sceneGraphContext());
- if (t) {
- t->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
- t->setMipmapFiltering(QSGTexture::None);
- t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
- t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ if (!d->provider) {
+ Q_ASSERT(d->sceneGraphContext());
+ // Make sure it gets thread affinity on the rendering thread so deletion works properly..
+ Q_ASSERT_X(QThread::currentThread() == d->sceneGraphContext()->thread(),
+ "QSGImage::textureProvider",
+ "Cannot be used outside the GUI thread");
+ const_cast<QSGImagePrivate *>(d)->provider = new QSGImageTextureProvider(this);
}
- return t;
+
+ return d->provider;
}
QSGNode *QSGImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
QSGTexture *texture = d->pix.texture(d->sceneGraphContext());
+ // Copy over the current texture state into the texture provider...
+ if (d->provider) {
+ d->provider->m_smooth = d->smooth;
+ d->provider->m_texture = texture;
+ }
+
if (!texture || width() <= 0 || height() <= 0) {
delete oldNode;
return 0;
QT_MODULE(Declarative)
class QSGImagePrivate;
-class Q_AUTOTEST_EXPORT QSGImage : public QSGImageBase, public QSGTextureProvider
+class Q_AUTOTEST_EXPORT QSGImage : public QSGImageBase
{
Q_OBJECT
Q_ENUMS(FillMode)
Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedGeometryChanged)
Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedGeometryChanged)
- Q_PROPERTY(QSGTexture *texture READ texture)
Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment NOTIFY horizontalAlignmentChanged)
Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment NOTIFY verticalAlignmentChanged)
- Q_INTERFACES(QSGTextureProvider)
-
public:
QSGImage(QSGItem *parent=0);
~QSGImage();
QRectF boundingRect() const;
- virtual QSGTexture *texture() const;
-
HAlignment horizontalAlignment() const;
void setHorizontalAlignment(HAlignment align);
VAlignment verticalAlignment() const;
void setVerticalAlignment(VAlignment align);
+ QSGTextureProvider *textureProvider() const;
+
Q_SIGNALS:
void fillModeChanged();
void paintedGeometryChanged();
QT_BEGIN_NAMESPACE
-class QSGImagePrivate;
+class QSGImageTextureProvider;
class QSGImagePrivate : public QSGImageBasePrivate
{
bool pixmapChanged : 1;
QSGImage::HAlignment hAlign;
QSGImage::VAlignment vAlign;
+
+ QSGImageTextureProvider *provider;
};
QT_END_NAMESPACE
#include <private/qsgtextureprovider_p.h>
#include "qsgcanvas.h"
+#include <qsgimage_p.h>
+#include <qsgshadereffectsource_p.h>
+
#include <QtCore/qsignalmapper.h>
#include <QtOpenGL/qglframebufferobject.h>
SourceData &source = m_sources[index];
- source.item = 0;
+ source.sourceObject = 0;
if (var.isNull()) {
return;
} else if (!qVariantCanConvert<QObject *>(var)) {
}
QObject *obj = qVariantValue<QObject *>(var);
-
- QSGTextureProvider *int3rface = QSGTextureProvider::from(obj);
- if (!int3rface) {
- qWarning("Could not assign property '%s', did not implement QSGTextureProvider.", source.name.constData());
+ if (!QSGTextureProvider::from(obj)) {
+ qWarning("ShaderEffect: source uniform [%s] is not assigned a valid texture provider: %s [%s]",
+ qPrintable(source.name), qPrintable(obj->objectName()), obj->metaObject()->className());
+ return;
}
- source.item = qobject_cast<QSGItem *>(obj);
+ source.sourceObject = obj;
+
+ QSGItem *item = qobject_cast<QSGItem *>(obj);
// TODO: Find better solution.
- // 'source.item' needs a canvas to get a scenegraph node.
+ // 'item' needs a canvas to get a scenegraph node.
// The easiest way to make sure it gets a canvas is to
// make it a part of the same item tree as 'this'.
- if (source.item && source.item->parentItem() == 0) {
- source.item->setParentItem(this);
- source.item->setVisible(false);
+ if (item && item->parentItem() == 0) {
+ item->setParentItem(this);
+ item->setVisible(false);
}
}
for (int i = 0; i < m_sources.size(); ++i) {
const SourceData &source = m_sources.at(i);
delete source.mapper;
- if (source.item && source.item->parentItem() == this)
- source.item->setParentItem(0);
+ QSGItem *item = qobject_cast<QSGItem *>(source.sourceObject);
+ if (item && item->parentItem() == this)
+ item->setParentItem(0);
}
m_sources.clear();
SourceData d;
d.mapper = new QSignalMapper;
d.name = name;
- d.item = 0;
+ d.sourceObject = 0;
m_sources.append(d);
}
}
if (m_dirtyData) {
QVector<QPair<QByteArray, QVariant> > values;
- QVector<QPair<QByteArray, QPointer<QSGItem> > > textures;
- const QVector<QPair<QByteArray, QPointer<QSGItem> > > &oldTextures = material->textureProviders();
+ QVector<QPair<QByteArray, QSGTextureProvider *> > textures;
+ const QVector<QPair<QByteArray, QSGTextureProvider *> > &oldTextures = material->textureProviders();
for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin();
it != m_source.uniformNames.end(); ++it) {
values.append(qMakePair(*it, property(*it)));
}
for (int i = 0; i < oldTextures.size(); ++i) {
- QSGTextureProvider *oldSource = QSGTextureProvider::from(oldTextures.at(i).second);
- if (oldSource && oldSource->textureChangedSignal())
- disconnect(oldTextures.at(i).second, oldSource->textureChangedSignal(), node, SLOT(markDirtyTexture()));
+ QSGTextureProvider *t = oldTextures.at(i).second;
+ if (t)
+ disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
}
for (int i = 0; i < m_sources.size(); ++i) {
const SourceData &source = m_sources.at(i);
- textures.append(qMakePair(source.name, source.item));
- QSGTextureProvider *t = QSGTextureProvider::from(source.item);
- if (t && t->textureChangedSignal())
- connect(source.item, t->textureChangedSignal(), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+ QSGTextureProvider *t = QSGTextureProvider::from(source.sourceObject);
+ textures.append(qMakePair(source.name, t));
+ if (t)
+ connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
}
material->setUniforms(values);
material->setTextureProviders(textures);
struct SourceData
{
QSignalMapper *mapper;
- QPointer<QSGItem> item;
+ QPointer<QObject> sourceObject;
QByteArray name;
};
QVector<SourceData> m_sources;
QGLFunctions *functions = state.context()->functions();
for (int i = material->m_textures.size() - 1; i >= 0; --i) {
- QPointer<QSGItem> source = material->m_textures.at(i).second;
- QSGTextureProvider *provider = QSGTextureProvider::from(source);
- QSGTexture *texture = provider ? provider->texture() : 0;
- if (!source || !provider || !texture) {
- qWarning("ShaderEffectItem: source or provider missing when binding textures");
- continue;
- }
functions->glActiveTexture(GL_TEXTURE0 + i);
- provider->texture()->bind();
+ if (QSGTextureProvider *provider = material->m_textures.at(i).second) {
+ if (QSGTexture *texture = provider->texture()) {
+ texture->bind();
+ continue;
+ }
+ }
+ qWarning("ShaderEffectItem: source or provider missing when binding textures");
+ glBindTexture(GL_TEXTURE_2D, 0);
}
if (material->m_source.respectsOpacity)
m_uniformValues = uniformValues;
}
-void QSGShaderEffectMaterial::setTextureProviders(const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textures)
+void QSGShaderEffectMaterial::setTextureProviders(const QVector<QPair<QByteArray, QSGTextureProvider *> > &textures)
{
m_textures = textures;
}
-const QVector<QPair<QByteArray, QPointer<QSGItem> > > &QSGShaderEffectMaterial::textureProviders() const
+const QVector<QPair<QByteArray, QSGTextureProvider *> > &QSGShaderEffectMaterial::textureProviders() const
{
return m_textures;
}
void QSGShaderEffectMaterial::updateTextures() const
{
for (int i = 0; i < m_textures.size(); ++i) {
- QSGItem *item = m_textures.at(i).second;
- if (item) {
- QSGTextureProvider *provider = QSGTextureProvider::from(item);
- if (provider) {
- QSGTexture *texture = provider->texture();
- if (!texture) {
- qWarning("QSGShaderEffectMaterial: no texture from %s [%s]",
- qPrintable(item->objectName()),
- item->metaObject()->className());
- }
- if (QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(provider->texture())) {
- t->updateTexture();
- }
- }
+ if (QSGTextureProvider *provider = m_textures.at(i).second) {
+ if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(provider->texture()))
+ texture->updateTexture();
}
}
}
void setProgramSource(const QSGShaderEffectProgram &);
void setUniforms(const QVector<QPair<QByteArray, QVariant> > &uniformValues);
- void setTextureProviders(const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textures);
- const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textureProviders() const;
+ void setTextureProviders(const QVector<QPair<QByteArray, QSGTextureProvider *> > &textures);
+ const QVector<QPair<QByteArray, QSGTextureProvider *> > &textureProviders() const;
void updateTextures() const;
protected:
QSGShaderEffectProgram m_source;
QVector<QPair<QByteArray, QVariant> > m_uniformValues;
- QVector<QPair<QByteArray, QPointer<QSGItem> > > m_textures;
+ QVector<QPair<QByteArray, QSGTextureProvider *> > m_textures;
CullMode m_cullMode;
static QHash<QSGShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > materialMap;
private:
QSGShaderEffectMaterial m_material;
-
-
};
QT_END_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
+class QSGShaderEffectSourceTextureProvider : public QSGTextureProvider
+{
+ Q_OBJECT
+public:
+ QSGShaderEffectSourceTextureProvider()
+ : sourceTexture(0)
+ {
+ }
+
+ QSGTexture *texture() const {
+ sourceTexture->setMipmapFiltering(mipmapFiltering);
+ sourceTexture->setFiltering(filtering);
+ sourceTexture->setHorizontalWrapMode(horizontalWrap);
+ sourceTexture->setVerticalWrapMode(verticalWrap);
+ return sourceTexture;
+ }
+
+ QSGShaderEffectTexture *sourceTexture;
+
+ QSGTexture::Filtering mipmapFiltering;
+ QSGTexture::Filtering filtering;
+ QSGTexture::WrapMode horizontalWrap;
+ QSGTexture::WrapMode verticalWrap;
+};
+#include "qsgshadereffectsource.moc"
+
+
QSGShaderEffectSourceNode::QSGShaderEffectSourceNode()
{
setFlag(UsePreprocess, true);
QSGShaderEffectSource::QSGShaderEffectSource(QSGItem *parent)
: QSGItem(parent)
+ , m_provider(0)
, m_wrapMode(ClampToEdge)
, m_sourceItem(0)
, m_textureSize(0, 0)
{
setFlag(ItemHasContents);
m_texture = new QSGShaderEffectTexture(this);
- connect(m_texture, SIGNAL(textureChanged()), this, SIGNAL(textureChanged()), Qt::DirectConnection);
connect(m_texture, SIGNAL(textureChanged()), this, SLOT(update()));
}
{
m_texture->scheduleForCleanup();
+ if (m_provider)
+ m_provider->deleteLater();
+
if (m_sourceItem)
QSGItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
}
+QSGTextureProvider *QSGShaderEffectSource::textureProvider() const
+{
+ if (!m_provider) {
+ Q_ASSERT(QSGItemPrivate::get(this)->sceneGraphContext());
+ // Make sure it gets thread affinity on the rendering thread so deletion works properly..
+ Q_ASSERT_X(QThread::currentThread() == QSGItemPrivate::get(this)->sceneGraphContext()->thread(),
+ "QSGShaderEffectSource::textureProvider",
+ "Cannot be used outside the GUI thread");
+ const_cast<QSGShaderEffectSource *>(this)->m_provider = new QSGShaderEffectSourceTextureProvider();
+ connect(m_texture, SIGNAL(textureChanged()), m_provider, SIGNAL(textureChanged()), Qt::DirectConnection);
+ m_provider->sourceTexture = m_texture;
+ }
+ return m_provider;
+}
+
/*!
\qmlproperty enumeration ShaderEffectSource::wrapMode
}
-QSGTexture *QSGShaderEffectSource::texture() const
-{
- m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None);
- m_texture->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
- QSGTexture::WrapMode h, v;
- get_wrap_mode(m_wrapMode, &h, &v);
- m_texture->setHorizontalWrapMode(h);
- m_texture->setVerticalWrapMode(v);
- return m_texture;
-}
-
QSGNode *QSGShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
if (!m_sourceItem) {
return 0;
}
- QSGShaderEffectSourceNode *node = static_cast<QSGShaderEffectSourceNode *>(oldNode);
- if (!node) {
- node = new QSGShaderEffectSourceNode;
- node->setTexture(m_texture);
- connect(m_texture, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
- }
-
- // If live and recursive, update continuously.
- if (m_live && m_recursive)
- node->markDirty(QSGNode::DirtyMaterial);
-
QSGShaderEffectTexture *tex = qobject_cast<QSGShaderEffectTexture *>(m_texture);
-
tex->setLive(m_live);
tex->setItem(QSGItemPrivate::get(m_sourceItem)->itemNode());
QRectF sourceRect = m_sourceRect.isNull()
? QSGTexture::Linear
: QSGTexture::Nearest;
QSGTexture::Filtering mmFiltering = m_mipmap ? filtering : QSGTexture::None;
- node->setMipmapFiltering(mmFiltering);
- node->setFiltering(filtering);
-
QSGTexture::WrapMode hWrap, vWrap;
get_wrap_mode(m_wrapMode, &hWrap, &vWrap);
+ if (m_provider) {
+ m_provider->mipmapFiltering = mmFiltering;
+ m_provider->filtering = filtering;
+ m_provider->horizontalWrap = hWrap;
+ m_provider->verticalWrap = vWrap;
+ }
+
+ // Don't create the paint node if we're not spanning any area
+ if (width() == 0 || height() == 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGShaderEffectSourceNode *node = static_cast<QSGShaderEffectSourceNode *>(oldNode);
+ if (!node) {
+ node = new QSGShaderEffectSourceNode;
+ node->setTexture(m_texture);
+ connect(m_texture, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+ }
+
+ // If live and recursive, update continuously.
+ if (m_live && m_recursive)
+ node->markDirty(QSGNode::DirtyMaterial);
+
+ node->setMipmapFiltering(mmFiltering);
+ node->setFiltering(filtering);
node->setHorizontalWrapMode(hWrap);
node->setVerticalWrapMode(vWrap);
node->setTargetRect(QRectF(0, 0, width(), height()));
class UpdatePaintNodeData;
class QGLFramebufferObject;
+class QSGShaderEffectSourceTextureProvider;
+
class QSGShaderEffectSourceNode : public QObject, public QSGDefaultImageNode
{
Q_OBJECT
uint m_grab : 1;
};
-class QSGShaderEffectSource : public QSGItem, public QSGTextureProvider
+class QSGShaderEffectSource : public QSGItem
{
Q_OBJECT
Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
Q_PROPERTY(bool hideSource READ hideSource WRITE setHideSource NOTIFY hideSourceChanged)
Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged)
Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
- Q_INTERFACES(QSGTextureProvider)
+
Q_ENUMS(Format WrapMode)
public:
enum WrapMode {
bool recursive() const;
void setRecursive(bool enabled);
- QSGTexture *texture() const;
- const char *textureChangedSignal() const { return SIGNAL(textureChanged()); }
+ QSGTextureProvider *textureProvider() const;
Q_INVOKABLE void scheduleUpdate();
virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
private:
+ QSGShaderEffectSourceTextureProvider *m_provider;
QSGShaderEffectTexture *m_texture;
WrapMode m_wrapMode;
QPointer<QSGItem> m_sourceItem;
if (!m_rootNode)
return;
QVector<QPair<QByteArray, QVariant> > values;
- QVector<QPair<QByteArray, QPointer<QSGItem> > > textures;
- const QVector<QPair<QByteArray, QPointer<QSGItem> > > &oldTextures = m_material.textureProviders();
+ QVector<QPair<QByteArray, QSGTextureProvider *> > textures;
+ const QVector<QPair<QByteArray, QSGTextureProvider *> > &oldTextures = m_material.textureProviders();
for (int i = 0; i < oldTextures.size(); ++i) {
- QSGTextureProvider *oldSource = QSGTextureProvider::from(oldTextures.at(i).second);
- if (oldSource && oldSource->textureChangedSignal())
+ QSGTextureProvider *t = oldTextures.at(i).second;
+ if (t)
foreach (QSGShaderEffectNode* node, m_nodes)
- disconnect(oldTextures.at(i).second, oldSource->textureChangedSignal(), node, SLOT(markDirtyTexture()));
+ disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
}
for (int i = 0; i < m_sources.size(); ++i) {
const SourceData &source = m_sources.at(i);
- textures.append(qMakePair(source.name, source.item));
QSGTextureProvider *t = QSGTextureProvider::from(source.item);
- if (t && t->textureChangedSignal())
+ textures.append(qMakePair(source.name, t));
+ if (t)
foreach (QSGShaderEffectNode* node, m_nodes)
- connect(source.item, t->textureChangedSignal(), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+ connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
}
for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin();
it != m_source.uniformNames.end(); ++it) {
#include "qsgtextureprovider_p.h"
+#include <qsgimage_p.h>
+#include <qsgshadereffectsource_p.h>
+
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
/*!
\class QSGTextureProvider
\brief The QSGTextureProvider class encapsulates texture based entities in QML.
+
+ The QSGTextureProvider lives primarily in the scene graph rendering thread.
*/
*/
QSGTextureProvider *QSGTextureProvider::from(QObject *object)
{
- return object ? static_cast<QSGTextureProvider *>(object->qt_metacast("QSGTextureProvider")) : 0;
+ if (QSGImage *image = qobject_cast<QSGImage*>(object))
+ return image->textureProvider();
+ else if (QSGShaderEffectSource *source = qobject_cast<QSGShaderEffectSource *>(object))
+ return source->textureProvider();
+ else if (QSGTextureProvider *provider = qobject_cast<QSGTextureProvider *>(object))
+ return provider;
+
+ qDebug() << "QSGTextureProvider::from() not a texture provider" << object;
+ return 0;
}
#ifndef QSGTEXTUREPROVIDER_H
#define QSGTEXTUREPROVIDER_H
-#include <qgl.h>
-
#include "qsgtexture.h"
#include "qobject.h"
QT_MODULE(Declarative)
-class QSGTextureProvider
+class QSGTextureProvider : public QObject
{
+ Q_OBJECT
public:
virtual QSGTexture *texture() const = 0;
- virtual const char *textureChangedSignal() const { return 0; }
static QSGTextureProvider *from(QObject *object);
+
+Q_SIGNALS:
+ void textureChanged();
};
-Q_DECLARE_INTERFACE(QSGTextureProvider, "QSGTextureProvider")
QT_END_NAMESPACE