aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/items
diff options
context:
space:
mode:
authorKim Motoyoshi Kalland <kim.kalland@nokia.com>2011-11-01 18:11:38 +0100
committerQt by Nokia <qt-info@nokia.com>2011-11-14 14:19:34 +0100
commitfd58c5fc9fa5dc1aa975cf40a5a58945671e22ee (patch)
tree91a198e029aee1343cd3c67aef33b305c191cd13 /src/declarative/items
parent7dc37bc9b580efb5916144c00df128dd24e67faa (diff)
Improved QQuickShaderEffect::lookThroughShaderCode() performance.
Removed use of regexp. Skip comments and compiler directives in the shader code. Don't look through default shader code. Task-number: QTBUG-22423 Change-Id: Ie08cd8288ba7d7a33f1e3b0dc2ab5f2bedad04dd Reviewed-by: Yoann Lopes <yoann.lopes@nokia.com>
Diffstat (limited to 'src/declarative/items')
-rw-r--r--src/declarative/items/qquickshadereffect.cpp177
1 files changed, 149 insertions, 28 deletions
diff --git a/src/declarative/items/qquickshadereffect.cpp b/src/declarative/items/qquickshadereffect.cpp
index 03247f9956..ea7350df97 100644
--- a/src/declarative/items/qquickshadereffect.cpp
+++ b/src/declarative/items/qquickshadereffect.cpp
@@ -474,15 +474,25 @@ void QQuickShaderEffect::reset()
void QQuickShaderEffect::updateProperties()
{
- QByteArray vertexCode = m_source.vertexCode;
- QByteArray fragmentCode = m_source.fragmentCode;
- if (vertexCode.isEmpty())
- vertexCode = qt_default_vertex_code;
- if (fragmentCode.isEmpty())
- fragmentCode = qt_default_fragment_code;
-
- lookThroughShaderCode(vertexCode);
- lookThroughShaderCode(fragmentCode);
+ if (m_source.vertexCode.isEmpty()) {
+ m_source.attributeNames.append(QByteArray(qt_position_attribute_name));
+ m_source.attributeNames.append(QByteArray(qt_texcoord_attribute_name));
+ m_source.respectsMatrix = true;
+ } else {
+ lookThroughShaderCode(m_source.vertexCode);
+ }
+ if (m_source.fragmentCode.isEmpty()) {
+ m_source.respectsOpacity = true;
+ QByteArray name("source");
+ m_source.uniformNames.insert(name);
+ SourceData d;
+ d.mapper = new QSignalMapper;
+ d.name = name;
+ d.sourceObject = 0;
+ m_sources.append(d);
+ } else {
+ lookThroughShaderCode(m_source.fragmentCode);
+ }
if (!m_mesh && !m_source.attributeNames.contains(qt_position_attribute_name))
qWarning("QQuickShaderEffect: Missing reference to \'%s\'.", qt_position_attribute_name);
@@ -501,38 +511,149 @@ void QQuickShaderEffect::updateProperties()
connectPropertySignals();
}
-void QQuickShaderEffect::lookThroughShaderCode(const QByteArray &code)
-{
- // Regexp for matching attributes and uniforms.
- // In human readable form: attribute|uniform [lowp|mediump|highp] <type> <name>
- static QRegExp re(QLatin1String("\\b(attribute|uniform)\\b\\s*\\b(?:lowp|mediump|highp)?\\b\\s*\\b(\\w+)\\b\\s*\\b(\\w+)"));
- Q_ASSERT(re.isValid());
+namespace {
+
+ enum VariableQualifier {
+ AttributeQualifier,
+ UniformQualifier
+ };
- int pos = -1;
+ inline bool qt_isalpha(char c)
+ {
+ char ch = c | 0x20;
+ return (ch >= 'a' && ch <= 'z') || c == '_';
+ }
- QString wideCode = QString::fromLatin1(code.constData(), code.size());
+ inline bool qt_isalnum(char c)
+ {
+ return qt_isalpha(c) || (c >= '0' && c <= '9');
+ }
- while ((pos = re.indexIn(wideCode, pos + 1)) != -1) {
- QByteArray decl = re.cap(1).toLatin1(); // uniform or attribute
- QByteArray type = re.cap(2).toLatin1(); // type
- QByteArray name = re.cap(3).toLatin1(); // variable name
+ inline bool qt_isspace(char c)
+ {
+ return c == ' ' || (c >= 0x09 && c <= 0x0d);
+ }
- if (decl == "attribute") {
- m_source.attributeNames.append(name);
+ // Returns -1 if not found, returns index to first character after the name if found.
+ int qt_search_for_variable(const char *s, int length, int index, VariableQualifier &decl,
+ int &typeIndex, int &typeLength,
+ int &nameIndex, int &nameLength)
+ {
+ enum Identifier {
+ QualifierIdentifier, // Base state
+ PrecisionIdentifier,
+ TypeIdentifier,
+ NameIdentifier
+ };
+ Identifier expected = QualifierIdentifier;
+ bool compilerDirectiveExpected = index == 0;
+
+ while (index < length) {
+ // Skip whitespace.
+ while (qt_isspace(s[index])) {
+ compilerDirectiveExpected |= s[index] == '\n';
+ ++index;
+ }
+
+ if (qt_isalpha(s[index])) {
+ // Read identifier.
+ int identifierIndex = index;
+ ++index;
+ while (qt_isalnum(s[index]))
+ ++index;
+ int identifierLength = index - identifierIndex;
+
+ switch (expected) {
+ case QualifierIdentifier:
+ if (qstrncmp("attribute", s + identifierIndex, identifierLength) == 0) {
+ decl = AttributeQualifier;
+ expected = PrecisionIdentifier;
+ } else if (qstrncmp("uniform", s + identifierIndex, identifierLength) == 0) {
+ decl = UniformQualifier;
+ expected = PrecisionIdentifier;
+ }
+ break;
+ case PrecisionIdentifier:
+ if (qstrncmp("lowp", s + identifierIndex, identifierLength) == 0
+ || qstrncmp("mediump", s + identifierIndex, identifierLength) == 0
+ || qstrncmp("highp", s + identifierIndex, identifierLength) == 0)
+ {
+ expected = TypeIdentifier;
+ break;
+ }
+ // Fall through.
+ case TypeIdentifier:
+ typeIndex = identifierIndex;
+ typeLength = identifierLength;
+ expected = NameIdentifier;
+ break;
+ case NameIdentifier:
+ nameIndex = identifierIndex;
+ nameLength = identifierLength;
+ return index; // Attribute or uniform declaration found. Return result.
+ default:
+ break;
+ }
+ } else if (s[index] == '#' && compilerDirectiveExpected) {
+ // Skip compiler directives.
+ ++index;
+ while (index < length && (s[index] != '\n' || s[index - 1] == '\\'))
+ ++index;
+ } else if (s[index] == '/' && s[index + 1] == '/') {
+ // Skip comments.
+ index += 2;
+ while (index < length && s[index] != '\n')
+ ++index;
+ } else if (s[index] == '/' && s[index + 1] == '*') {
+ // Skip comments.
+ index += 2;
+ while (index < length && (s[index] != '*' || s[index + 1] != '/'))
+ ++index;
+ if (index < length)
+ index += 2; // Skip star-slash.
+ } else {
+ expected = QualifierIdentifier;
+ ++index;
+ }
+ compilerDirectiveExpected = false;
+ }
+ return -1;
+ }
+}
+
+void QQuickShaderEffect::lookThroughShaderCode(const QByteArray &code)
+{
+ int index = 0;
+ int typeIndex, typeLength, nameIndex, nameLength;
+ const char *s = code.constData();
+ VariableQualifier decl;
+ while ((index = qt_search_for_variable(s, code.size(), index, decl, typeIndex, typeLength,
+ nameIndex, nameLength)) != -1)
+ {
+ if (decl == AttributeQualifier) {
+ m_source.attributeNames.append(QByteArray(s + nameIndex, nameLength));
} else {
- Q_ASSERT(decl == "uniform");
+ Q_ASSERT(decl == UniformQualifier);
+
+ const int matLen = sizeof("qt_Matrix") - 1;
+ const int opLen = sizeof("qt_Opacity") - 1;
+ const int mvpMatLen = sizeof("qt_ModelViewProjectionMatrix") - 1;
+ const int sampLen = sizeof("sampler2D") - 1;
- if (name == "qt_Matrix") {
+ if (nameLength == matLen && qstrncmp("qt_Matrix", s + nameIndex, matLen) == 0) {
m_source.respectsMatrix = true;
- } else if (name == "qt_ModelViewProjectionMatrix") {
+ } else if (nameLength == mvpMatLen && qstrncmp("qt_ModelViewProjectionMatrix",
+ s + nameIndex, mvpMatLen) == 0)
+ {
// TODO: Remove after grace period.
qWarning("ShaderEffect: qt_ModelViewProjectionMatrix is deprecated. Use qt_Matrix instead.");
m_source.respectsMatrix = true;
- } else if (name == "qt_Opacity") {
+ } else if (nameLength == opLen && qstrncmp("qt_Opacity", s + nameIndex, opLen) == 0) {
m_source.respectsOpacity = true;
} else {
+ QByteArray name(s + nameIndex, nameLength);
m_source.uniformNames.insert(name);
- if (type == "sampler2D") {
+ if (typeLength == sampLen && qstrncmp("sampler2D", s + typeIndex, sampLen) == 0) {
SourceData d;
d.mapper = new QSignalMapper;
d.name = name;