aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@digia.com>2013-08-14 07:27:07 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-02 14:24:36 +0200
commitb480fa83a632b2ae5606e2870b47358328b479a2 (patch)
treebdd3e1b68a5a15a3950e13a50db911a93cdf279a /src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
parent9be35c270082d1614886874e17cc3f90a7a3f489 (diff)
New scenegraph renderer and atlas textures.
The renderer tries to batch primitives together where possible, isolate non-changing subparts of the scene from changing subparts and retain vertexdata on the GPU as much as possible. Atlas textures are crucial in enabling batching. The renderer and atlas texture are described in detail in the doc page "Qt Quick Scene Graph Renderer". Change-Id: Ia476c7f0f42e1fc57a2cef528e93ee88cf8f7055 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
Diffstat (limited to 'src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp')
-rw-r--r--src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp290
1 files changed, 290 insertions, 0 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
new file mode 100644
index 0000000000..830dbbbd7d
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+
+// Duct Tape tokenizer for the purpose of parsing and rewriting
+// shader source code
+
+QT_BEGIN_NAMESPACE
+
+namespace QSGShaderRewriter {
+
+struct Tokenizer {
+
+ enum Token {
+ Token_Invalid,
+ Token_Void,
+ Token_OpenBrace,
+ Token_CloseBrace,
+ Token_SemiColon,
+ Token_Identifier,
+ Token_Macro,
+ Token_Unspecified,
+
+ Token_EOF
+ };
+
+ static const char *NAMES[];
+
+ void initialize(const char *input);
+ Token next();
+
+ const char *stream;
+ const char *pos;
+ const char *identifier;
+};
+
+const char *Tokenizer::NAMES[] = {
+ "Invalid",
+ "Void",
+ "OpenBrace",
+ "CloseBrace",
+ "SemiColon",
+ "Identifier",
+ "Macro",
+ "Unspecified",
+ "EOF"
+};
+
+void Tokenizer::initialize(const char *input)
+{
+ stream = input;
+ pos = input;
+ identifier = input;
+}
+
+#define foo
+
+
+Tokenizer::Token Tokenizer::next()
+{
+ while (*pos != 0) {
+ char c = *pos++;
+ switch (c) {
+ case '/':
+
+ if (*pos == '/') {
+ // '//' comment
+ ++pos;
+ while (*pos != 0 && *pos != '\n') ++pos;
+ if (*pos != 0) ++pos; // skip the newline
+
+ } else if (*pos == '*') {
+ // /* */ comment
+ ++pos;
+ while (*pos != 0 && *pos != '*' && pos[1] != '/') ++pos;
+ if (*pos != 0) pos += 2;
+ }
+ break;
+
+ case '#': {
+ while (*pos != 0) {
+ if (*pos == '\n') {
+ ++pos;
+ break;
+ } else if (*pos == '\\') {
+ ++pos;
+ while (*pos != 0 && (*pos == ' ' || *pos == '\t'))
+ ++pos;
+ if (*pos != 0 && (*pos == '\n' || (*pos == '\r' && pos[1] == '\n')))
+ pos+=2;
+ } else {
+ ++pos;
+ }
+ }
+ break;
+ }
+
+ case 'v': {
+ if (*pos == 'o' && pos[1] == 'i' && pos[2] == 'd') {
+ pos += 3;
+ return Token_Void;
+ }
+ }
+
+ case ';': return Token_SemiColon;
+ case 0: return Token_EOF;
+ case '{': return Token_OpenBrace;
+ case '}': return Token_CloseBrace;
+
+ case ' ':
+ case '\n':
+ case '\r': break;
+ default:
+ // Identifier...
+ if ((c >= 'a' && c <= 'z' ) || (c >= 'A' && c <= 'Z' ) || c == '_') {
+ identifier = pos - 1;
+ while (*pos != 0 && ((*pos >= 'a' && *pos <= 'z')
+ || (*pos >= 'A' && *pos <= 'Z')
+ || *pos == '_'
+ || (*pos >= '0' && *pos <= '9'))) {
+ ++pos;
+ }
+ return Token_Identifier;
+ } else {
+ return Token_Unspecified;
+ }
+ }
+ }
+
+ return Token_Invalid;
+}
+
+}
+
+using namespace QSGShaderRewriter;
+
+QByteArray qsgShaderRewriter_insertZAttributes(const char *input)
+{
+ Tokenizer tok;
+ tok.initialize(input);
+
+ Tokenizer::Token lt = tok.next();
+ Tokenizer::Token t = tok.next();
+
+ // First find "void main() { ... "
+ while (t != Tokenizer::Token_EOF) {
+ if (lt == Tokenizer::Token_Void && t == Tokenizer::Token_Identifier) {
+ if (qstrncmp("main", tok.identifier, 4) == 0)
+ break;
+ }
+ lt = t;
+ t = tok.next();
+ }
+
+ // Find first brace '{'
+ while (t != Tokenizer::Token_EOF && t != Tokenizer::Token_OpenBrace) t = tok.next();
+ int braceDepth = 1;
+ t = tok.next();
+
+ // Find matching brace and insert our code there...
+ while (t != Tokenizer::Token_EOF) {
+ switch (t) {
+ case Tokenizer::Token_CloseBrace:
+ braceDepth--;
+ if (braceDepth == 0) {
+ QByteArray result;
+ result.reserve(1024);
+ result += "attribute highp float _qt_order;\n";
+ result += "uniform highp float _qt_zRange;\n";
+ result += QByteArray::fromRawData(input, tok.pos - 1 - input);
+ result += " gl_Position.z = gl_Position.z * _qt_zRange + _qt_order;\n";
+ result += QByteArray(tok.pos - 1);
+ return result;
+ }
+ break;
+ case Tokenizer::Token_OpenBrace:
+ ++braceDepth;
+ break;
+ default:
+ break;
+ }
+ t = tok.next();
+ }
+ return QByteArray();
+}
+
+#ifdef QSGSHADERREWRITER_STANDALONE
+
+const char *selftest =
+ "#define highp lowp stuff \n"
+ "#define multiline \\ \n"
+ " continue defining multiline \n"
+ " \n"
+ "attribute highp vec4 qt_Position; \n"
+ "attribute highp vec2 qt_TexCoord; \n"
+ " \n"
+ "uniform highp mat4 qt_Matrix; \n"
+ " \n"
+ "varying lowp vec2 vTexCoord; \n"
+ " \n"
+ "// commented out main(){} \n"
+ "/* commented out main() { } again */ \n"
+ "/* \n"
+ " multline comment with main() { } \n"
+ " */ \n"
+ " \n"
+ "void main() { \n"
+ " gl_Position = qt_Matrix * qt_Position; \n"
+ " vTexCoord = qt_TexCoord; \n"
+ " if (gl_Position < 0) { \n"
+ " vTexCoord.y = -vTexCoord.y; \n"
+ " } \n"
+ "} \n"
+ "";
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ QString fileName;
+ QStringList args = app.arguments();
+
+ QByteArray content;
+
+ for (int i=0; i<args.length(); ++i) {
+ const QString &a = args.at(i);
+ if (a == QStringLiteral("--file") && i < args.length() - 1) {
+ qDebug() << "Reading file: " << args.at(i);
+ QFile file(args.at(++i));
+ if (!file.open(QFile::ReadOnly)) {
+ qDebug() << "Error: failed to open file," << file.errorString();
+ return 1;
+ }
+ content = file.readAll();
+ } else if (a == QStringLiteral("--selftest")) {
+ qDebug() << "doing a selftest";
+ content = QByteArray(selftest);
+ } else if (a == QStringLiteral("--help") || a == QStringLiteral("-h")) {
+ qDebug() << "usage:" << endl
+ << " --file [name] A vertex shader file to rewrite" << endl;
+ }
+ }
+
+ QByteArray rewritten = qsgShaderRewriter_insertZAttributes(content);
+
+ qDebug() << "Rewritten to:";
+ qDebug() << rewritten.constData();
+}
+#endif
+
+QT_END_NAMESPACE