aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
authorMichael Brasser <michael.brasser@live.com>2014-04-22 21:19:50 -0500
committerMichael Brasser <michael.brasser@live.com>2014-08-07 21:36:14 +0200
commitee616b3905106a3eedef9ee964ab283ef45c7dbc (patch)
tree8cef0f09a44419e88acf21ad893bbbfadb5c8af1 /src/quick/items
parent6b31418a1b5d9be47df5ed61747e8a5fb225acfa (diff)
Allow simple ShaderEffects to be batched by the renderer.
Identical ShaderEffects that use the standard vertex shader with a single source texture, and that set supportsAtlasTextures, are now candidates for batching. Task-number: QTBUG-37914 Change-Id: Ib0ce58647a8c7c48e88bd84cf2645f1a8f28691f Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/qquickitemsmodule.cpp1
-rw-r--r--src/quick/items/qquickshadereffect.cpp121
-rw-r--r--src/quick/items/qquickshadereffect_p.h7
-rw-r--r--src/quick/items/qquickshadereffectmesh.cpp3
-rw-r--r--src/quick/items/qquickshadereffectmesh_p.h4
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp37
-rw-r--r--src/quick/items/qquickshadereffectnode_p.h3
7 files changed, 131 insertions, 45 deletions
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 22a6eeb4a5..2951fc70b9 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -271,6 +271,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickItem, 2>(uri, 2, 4, "Item");
qmlRegisterType<QQuickMouseArea, 1>(uri, 2, 4, "MouseArea");
+ qmlRegisterType<QQuickShaderEffect, 1>(uri, 2, 4, "ShaderEffect");
}
static void initResources()
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 8bcd2e64db..9dfce3fb28 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -565,7 +565,8 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
position (0, 0), the bottom-right (\l{Item::width}{width},
\l{Item::height}{height}).
\li attribute vec2 qt_MultiTexCoord0 - texture coordinate, the top-left
- coordinate is (0, 0), the bottom-right (1, 1).
+ coordinate is (0, 0), the bottom-right (1, 1). If \l supportsAtlasTextures
+ is true, coordinates will be based on position in the atlas instead.
\endlist
In addition, any property that can be mapped to an OpenGL Shading Language
@@ -594,7 +595,8 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
it is by default copied from the texture atlas into a stand-alone texture
so that the texture coordinates span from 0 to 1, and you get the expected
wrap modes. However, this will increase the memory usage. To avoid the
- texture copy, you can for each "uniform sampler2D <name>" declare a
+ texture copy, set \l supportsAtlasTextures for simple shaders using
+ qt_MultiTexCoord0, or for each "uniform sampler2D <name>" declare a
"uniform vec4 qt_SubRect_<name>" which will be assigned the texture's
normalized source rectangle. For stand-alone textures, the source rectangle
is [0, 1]x[0, 1]. For textures in an atlas, the source rectangle corresponds
@@ -665,6 +667,8 @@ QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
, m_dirtyParseLog(true)
, m_dirtyMesh(true)
, m_dirtyGeometry(true)
+ , m_customVertexShader(false)
+ , m_supportsAtlasTextures(false)
{
setFlag(QQuickItem::ItemHasContents);
}
@@ -718,6 +722,7 @@ void QQuickShaderEffect::setVertexShader(const QByteArray &code)
m_common.source.sourceCode[Key::VertexShader] = code;
m_dirtyProgram = true;
m_dirtyParseLog = true;
+ m_customVertexShader = true;
if (isComponentComplete())
m_common.updateShader(this, Key::VertexShader);
@@ -828,6 +833,31 @@ void QQuickShaderEffect::setCullMode(CullMode face)
emit cullModeChanged();
}
+/*!
+ \qmlproperty bool QtQuick::ShaderEffect::supportsAtlasTextures
+
+ Set this property true to indicate that the ShaderEffect is able to
+ use the default source texture without first removing it from an atlas.
+ In this case the range of qt_MultiTexCoord0 will based on the position of
+ the texture within the atlas, rather than (0,0) to (1,1).
+
+ Setting this to true may enable some optimizations.
+
+ The default value is false.
+
+ \since 5.4
+ \since QtQuick 2.4
+*/
+
+void QQuickShaderEffect::setSupportsAtlasTextures(bool supports)
+{
+ if (supports == m_supportsAtlasTextures)
+ return;
+ m_supportsAtlasTextures = supports;
+ updateGeometry();
+ emit supportsAtlasTexturesChanged();
+}
+
QString QQuickShaderEffect::parseLog()
{
if (m_dirtyParseLog) {
@@ -940,39 +970,6 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
connect(node, SIGNAL(logAndStatusChanged(QString,int)), this, SLOT(updateLogAndStatus(QString,int)));
}
- if (m_dirtyMesh) {
- node->setGeometry(0);
- m_dirtyMesh = false;
- m_dirtyGeometry = true;
- }
-
- if (m_dirtyGeometry) {
- node->setFlag(QSGNode::OwnsGeometry, false);
- QSGGeometry *geometry = node->geometry();
- QRectF rect(0, 0, width(), height());
- QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
-
- geometry = mesh->updateGeometry(geometry, m_common.attributes, rect);
- if (!geometry) {
- QString log = mesh->log();
- if (!log.isNull()) {
- m_log = parseLog();
- m_log += QLatin1String("*** Mesh ***\n");
- m_log += log;
- m_status = Error;
- emit logChanged();
- emit statusChanged();
- }
- delete node;
- return 0;
- }
-
- node->setGeometry(geometry);
- node->setFlag(QSGNode::OwnsGeometry, true);
-
- m_dirtyGeometry = false;
- }
-
QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(node->material());
// Update blending
@@ -1014,6 +1011,60 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
m_dirtyUniforms = m_dirtyUniformValues = m_dirtyTextureProviders = false;
}
+ int textureCount = material->textureProviders.size();
+ bool preventBatching = m_customVertexShader || textureCount > 1 || (textureCount > 0 && !m_supportsAtlasTextures);
+
+ QRectF srcRect(0, 0, 1, 1);
+ if (m_supportsAtlasTextures && textureCount != 0) {
+ if (QSGTextureProvider *provider = material->textureProviders.at(0)) {
+ if (provider->texture())
+ srcRect = provider->texture()->normalizedTextureSubRect();
+ }
+ }
+
+ if (bool(material->flags() & QSGMaterial::RequiresFullMatrix) != preventBatching) {
+ material->setFlag(QSGMaterial::RequiresFullMatrix, preventBatching);
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (material->supportsAtlasTextures != m_supportsAtlasTextures) {
+ material->supportsAtlasTextures = m_supportsAtlasTextures;
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (m_dirtyMesh) {
+ node->setGeometry(0);
+ m_dirtyMesh = false;
+ m_dirtyGeometry = true;
+ }
+
+ if (m_dirtyGeometry) {
+ node->setFlag(QSGNode::OwnsGeometry, false);
+ QSGGeometry *geometry = node->geometry();
+ QRectF rect(0, 0, width(), height());
+ QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
+
+ geometry = mesh->updateGeometry(geometry, m_common.attributes, srcRect, rect);
+ if (!geometry) {
+ QString log = mesh->log();
+ if (!log.isNull()) {
+ m_log = parseLog();
+ m_log += QLatin1String("*** Mesh ***\n");
+ m_log += log;
+ m_status = Error;
+ emit logChanged();
+ emit statusChanged();
+ }
+ delete node;
+ return 0;
+ }
+
+ node->setGeometry(geometry);
+ node->setFlag(QSGNode::OwnsGeometry, true);
+
+ m_dirtyGeometry = false;
+ }
+
return node;
}
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index 8b613b4ef0..14d11a7814 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -99,6 +99,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
Q_PROPERTY(CullMode cullMode READ cullMode WRITE setCullMode NOTIFY cullModeChanged)
Q_PROPERTY(QString log READ log NOTIFY logChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 1)
Q_ENUMS(CullMode)
Q_ENUMS(Status)
@@ -138,6 +139,9 @@ public:
QString log() const { return m_log; }
Status status() const { return m_status; }
+ bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
+ void setSupportsAtlasTextures(bool supports);
+
QString parseLog();
virtual bool event(QEvent *);
@@ -150,6 +154,7 @@ Q_SIGNALS:
void cullModeChanged();
void logChanged();
void statusChanged();
+ void supportsAtlasTexturesChanged();
protected:
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
@@ -187,6 +192,8 @@ private:
uint m_dirtyParseLog : 1;
uint m_dirtyMesh : 1;
uint m_dirtyGeometry : 1;
+ uint m_customVertexShader : 1;
+ uint m_supportsAtlasTextures : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffectmesh.cpp b/src/quick/items/qquickshadereffectmesh.cpp
index bc97a424f4..cf2f8faf5e 100644
--- a/src/quick/items/qquickshadereffectmesh.cpp
+++ b/src/quick/items/qquickshadereffectmesh.cpp
@@ -70,7 +70,7 @@ QQuickGridMesh::QQuickGridMesh(QObject *parent)
connect(this, SIGNAL(resolutionChanged()), this, SIGNAL(geometryChanged()));
}
-QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &dstRect)
+QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &dstRect)
{
int vmesh = m_resolution.height();
int hmesh = m_resolution.width();
@@ -125,7 +125,6 @@ QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector
QSGGeometry::Point2D *vdata = static_cast<QSGGeometry::Point2D *>(geometry->vertexData());
- QRectF srcRect(0, 0, 1, 1);
for (int iy = 0; iy <= vmesh; ++iy) {
float fy = iy / float(vmesh);
float y = float(dstRect.top()) + fy * float(dstRect.height());
diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h
index ea92490979..99dbacaa53 100644
--- a/src/quick/items/qquickshadereffectmesh_p.h
+++ b/src/quick/items/qquickshadereffectmesh_p.h
@@ -62,7 +62,7 @@ class QQuickShaderEffectMesh : public QObject
public:
QQuickShaderEffectMesh(QObject *parent = 0);
// If 'geometry' != 0, 'attributes' is the same as last time the function was called.
- virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &rect) = 0;
+ virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &rect) = 0;
// If updateGeometry() fails, the reason should appear in the log.
virtual QString log() const { return QString(); }
@@ -77,7 +77,7 @@ class QQuickGridMesh : public QQuickShaderEffectMesh
Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged)
public:
QQuickGridMesh(QObject *parent = 0);
- virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &rect);
+ virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &rect);
virtual QString log() const { return m_log; }
void setResolution(const QSize &res);
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index fcf5591d01..95d4d587a4 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -41,7 +41,6 @@
#include <private/qquickshadereffectnode_p.h>
-#include "qquickshadereffectmesh_p.h"
#include "qquickshadereffect_p.h"
#include <QtQuick/qsgtextureprovider.h>
#include <QtQuick/private/qsgrenderer_p.h>
@@ -67,7 +66,6 @@ protected:
const QQuickShaderEffectMaterialKey m_key;
QVector<const char *> m_attributeNames;
- const QVector<QByteArray> m_attributes;
QString m_log;
bool m_compiled;
@@ -77,7 +75,6 @@ protected:
QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
: m_key(key)
- , m_attributes(attributes)
, m_compiled(false)
, m_initialized(false)
{
@@ -146,7 +143,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
if (loc >= 0) {
QRectF r = texture->normalizedTextureSubRect();
program()->setUniformValue(loc, r.x(), r.y(), r.width(), r.height());
- } else if (texture->isAtlasTexture()) {
+ } else if (texture->isAtlasTexture() && (idx != 0 || !material->supportsAtlasTextures)) {
texture = texture->removedFromAtlas();
}
texture->bind();
@@ -346,6 +343,7 @@ QHash<QQuickShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > QQuickSha
QQuickShaderEffectMaterial::QQuickShaderEffectMaterial(QQuickShaderEffectNode *node)
: cullMode(NoCulling)
+ , supportsAtlasTextures(false)
, m_node(node)
, m_emittedLogChanged(false)
{
@@ -362,9 +360,36 @@ QSGMaterialShader *QQuickShaderEffectMaterial::createShader() const
return new QQuickCustomMaterialShader(m_source, attributes);
}
-int QQuickShaderEffectMaterial::compare(const QSGMaterial *other) const
+bool QQuickShaderEffectMaterial::UniformData::operator == (const UniformData &other) const
{
- return this - static_cast<const QQuickShaderEffectMaterial *>(other);
+ if (specialType != other.specialType)
+ return false;
+ if (name != other.name)
+ return false;
+
+ if (specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(value));
+ QQuickItem *otherSource = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(other.value));
+ if (!source || !otherSource || !source->isTextureProvider() || !otherSource->isTextureProvider())
+ return false;
+ return source->textureProvider()->texture()->textureId() == otherSource->textureProvider()->texture()->textureId();
+ } else {
+ return value == other.value;
+ }
+}
+
+int QQuickShaderEffectMaterial::compare(const QSGMaterial *o) const
+{
+ const QQuickShaderEffectMaterial *other = static_cast<const QQuickShaderEffectMaterial *>(o);
+ if (cullMode != other->cullMode)
+ return 1;
+ if (supportsAtlasTextures != other->supportsAtlasTextures)
+ return 1;
+ for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
+ if (uniforms[shaderType] != other->uniforms[shaderType])
+ return 1;
+ }
+ return 0;
}
void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectMaterialKey &source)
diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h
index 232dd86aa1..53c2cb9694 100644
--- a/src/quick/items/qquickshadereffectnode_p.h
+++ b/src/quick/items/qquickshadereffectnode_p.h
@@ -82,6 +82,8 @@ public:
QByteArray name;
QVariant value;
SpecialType specialType;
+
+ bool operator == (const UniformData &other) const;
};
enum CullMode
@@ -100,6 +102,7 @@ public:
QVector<UniformData> uniforms[QQuickShaderEffectMaterialKey::ShaderTypeCount];
QVector<QSGTextureProvider *> textureProviders;
CullMode cullMode;
+ bool supportsAtlasTextures;
void setProgramSource(const QQuickShaderEffectMaterialKey &source);
void updateTextures() const;