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>
This commit is contained in:
parent
6b31418a1b
commit
ee616b3905
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue