qmlRegisterType<QQuickItem, 2>(uri, 2, 4, "Item");
qmlRegisterType<QQuickMouseArea, 1>(uri, 2, 4, "MouseArea");
+ qmlRegisterType<QQuickShaderEffect, 1>(uri, 2, 4, "ShaderEffect");
}
static void initResources()
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
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
, m_dirtyParseLog(true)
, m_dirtyMesh(true)
, m_dirtyGeometry(true)
+ , m_customVertexShader(false)
+ , m_supportsAtlasTextures(false)
{
setFlag(QQuickItem::ItemHasContents);
}
m_common.source.sourceCode[Key::VertexShader] = code;
m_dirtyProgram = true;
m_dirtyParseLog = true;
+ m_customVertexShader = true;
if (isComponentComplete())
m_common.updateShader(this, Key::VertexShader);
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) {
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
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;
}
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)
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 *);
void cullModeChanged();
void logChanged();
void statusChanged();
+ void supportsAtlasTexturesChanged();
protected:
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
uint m_dirtyParseLog : 1;
uint m_dirtyMesh : 1;
uint m_dirtyGeometry : 1;
+ uint m_customVertexShader : 1;
+ uint m_supportsAtlasTextures : 1;
};
QT_END_NAMESPACE
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();
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());
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(); }
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);
#include <private/qquickshadereffectnode_p.h>
-#include "qquickshadereffectmesh_p.h"
#include "qquickshadereffect_p.h"
#include <QtQuick/qsgtextureprovider.h>
#include <QtQuick/private/qsgrenderer_p.h>
const QQuickShaderEffectMaterialKey m_key;
QVector<const char *> m_attributeNames;
- const QVector<QByteArray> m_attributes;
QString m_log;
bool m_compiled;
QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
: m_key(key)
- , m_attributes(attributes)
, m_compiled(false)
, m_initialized(false)
{
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();
QQuickShaderEffectMaterial::QQuickShaderEffectMaterial(QQuickShaderEffectNode *node)
: cullMode(NoCulling)
+ , supportsAtlasTextures(false)
, m_node(node)
, m_emittedLogChanged(false)
{
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)
QByteArray name;
QVariant value;
SpecialType specialType;
+
+ bool operator == (const UniformData &other) const;
};
enum CullMode
QVector<UniformData> uniforms[QQuickShaderEffectMaterialKey::ShaderTypeCount];
QVector<QSGTextureProvider *> textureProviders;
CullMode cullMode;
+ bool supportsAtlasTextures;
void setProgramSource(const QQuickShaderEffectMaterialKey &source);
void updateTextures() const;