| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 |  | 
| 30 | #include <QtTest/QtTest> | 
| 31 |  | 
| 32 | #include <QtCore/qmetaobject.h> | 
| 33 | #include <Qt3DRender/private/qshadergenerator_p.h> | 
| 34 | #include <Qt3DRender/private/qshaderlanguage_p.h> | 
| 35 |  | 
| 36 | using namespace Qt3DRender; | 
| 37 | namespace | 
| 38 | { | 
| 39 |     QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion, | 
| 40 |                                QShaderFormat::ShaderType shaderType= QShaderFormat::Fragment) | 
| 41 |     { | 
| 42 |         auto format = QShaderFormat(); | 
| 43 |         format.setApi(api); | 
| 44 |         format.setVersion(QVersionNumber(majorVersion, minorVersion)); | 
| 45 |         format.setShaderType(shaderType); | 
| 46 |         return format; | 
| 47 |     } | 
| 48 |  | 
| 49 |     QShaderNodePort createPort(QShaderNodePort::Direction portDirection, const QString &portName) | 
| 50 |     { | 
| 51 |         auto port = QShaderNodePort(); | 
| 52 |         port.direction = portDirection; | 
| 53 |         port.name = portName; | 
| 54 |         return port; | 
| 55 |     } | 
| 56 |  | 
| 57 |     QShaderNode createNode(const QVector<QShaderNodePort> &ports, const QStringList &layers = QStringList()) | 
| 58 |     { | 
| 59 |         auto node = QShaderNode(); | 
| 60 |         node.setUuid(QUuid::createUuid()); | 
| 61 |         node.setLayers(layers); | 
| 62 |         for (const auto &port : ports) | 
| 63 |             node.addPort(port); | 
| 64 |         return node; | 
| 65 |     } | 
| 66 |  | 
| 67 |     QShaderGraph::Edge createEdge(const QUuid &sourceUuid, const QString &sourceName, | 
| 68 |                                   const QUuid &targetUuid, const QString &targetName, | 
| 69 |                                   const QStringList &layers = QStringList()) | 
| 70 |     { | 
| 71 |         auto edge = QShaderGraph::Edge(); | 
| 72 |         edge.sourceNodeUuid = sourceUuid; | 
| 73 |         edge.sourcePortName = sourceName; | 
| 74 |         edge.targetNodeUuid = targetUuid; | 
| 75 |         edge.targetPortName = targetName; | 
| 76 |         edge.layers = layers; | 
| 77 |         return edge; | 
| 78 |     } | 
| 79 |  | 
| 80 |     QShaderGraph createFragmentShaderGraph() | 
| 81 |     { | 
| 82 |         const auto openGLES2 = createFormat(api: QShaderFormat::OpenGLES, majorVersion: 2, minorVersion: 0); | 
| 83 |         const auto openGL3 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 3, minorVersion: 0); | 
| 84 |  | 
| 85 |         auto graph = QShaderGraph(); | 
| 86 |  | 
| 87 |         auto worldPosition = createNode(ports: { | 
| 88 |             createPort(portDirection: QShaderNodePort::Output, portName: "value" ) | 
| 89 |         }); | 
| 90 |         worldPosition.setParameter(name: "name" , value: "worldPosition" ); | 
| 91 |         worldPosition.addRule(format: openGLES2, rule: QShaderNode::Rule("highp vec3 $value = $name;" , | 
| 92 |                                                            QByteArrayList() << "varying highp vec3 $name;" )); | 
| 93 |         worldPosition.addRule(format: openGL3, rule: QShaderNode::Rule("vec3 $value = $name;" , | 
| 94 |                                                          QByteArrayList() << "in vec3 $name;" )); | 
| 95 |  | 
| 96 |         auto texture = createNode(ports: { | 
| 97 |             createPort(portDirection: QShaderNodePort::Output, portName: "texture" ) | 
| 98 |         }); | 
| 99 |         texture.addRule(format: openGLES2, rule: QShaderNode::Rule("sampler2D $texture = texture;" , | 
| 100 |                                                      QByteArrayList() << "uniform sampler2D texture;" )); | 
| 101 |         texture.addRule(format: openGL3, rule: QShaderNode::Rule("sampler2D $texture = texture;" , | 
| 102 |                                                    QByteArrayList() << "uniform sampler2D texture;" )); | 
| 103 |  | 
| 104 |         auto texCoord = createNode(ports: { | 
| 105 |             createPort(portDirection: QShaderNodePort::Output, portName: "texCoord" ) | 
| 106 |         }); | 
| 107 |         texCoord.addRule(format: openGLES2, rule: QShaderNode::Rule("highp vec2 $texCoord = texCoord;" , | 
| 108 |                                                       QByteArrayList() << "varying highp vec2 texCoord;" )); | 
| 109 |         texCoord.addRule(format: openGL3, rule: QShaderNode::Rule("vec2 $texCoord = texCoord;" , | 
| 110 |                                                     QByteArrayList() << "in vec2 texCoord;" )); | 
| 111 |  | 
| 112 |         auto lightIntensity = createNode(ports: { | 
| 113 |             createPort(portDirection: QShaderNodePort::Output, portName: "lightIntensity" ) | 
| 114 |         }); | 
| 115 |         lightIntensity.addRule(format: openGLES2, rule: QShaderNode::Rule("highp float $lightIntensity = lightIntensity;" , | 
| 116 |                                                             QByteArrayList() << "uniform highp float lightIntensity;" )); | 
| 117 |         lightIntensity.addRule(format: openGL3, rule: QShaderNode::Rule("float $lightIntensity = lightIntensity;" , | 
| 118 |                                                           QByteArrayList() << "uniform float lightIntensity;" )); | 
| 119 |  | 
| 120 |         auto exposure = createNode(ports: { | 
| 121 |             createPort(portDirection: QShaderNodePort::Output, portName: "exposure" ) | 
| 122 |         }); | 
| 123 |         exposure.addRule(format: openGLES2, rule: QShaderNode::Rule("highp float $exposure = exposure;" , | 
| 124 |                                                       QByteArrayList() << "uniform highp float exposure;" )); | 
| 125 |         exposure.addRule(format: openGL3, rule: QShaderNode::Rule("float $exposure = exposure;" , | 
| 126 |                                                     QByteArrayList() << "uniform float exposure;" )); | 
| 127 |  | 
| 128 |         auto fragColor = createNode(ports: { | 
| 129 |             createPort(portDirection: QShaderNodePort::Input, portName: "fragColor" ) | 
| 130 |         }); | 
| 131 |         fragColor.addRule(format: openGLES2, rule: QShaderNode::Rule("gl_fragColor = $fragColor;" )); | 
| 132 |         fragColor.addRule(format: openGL3, rule: QShaderNode::Rule("fragColor = $fragColor;" , | 
| 133 |                                                      QByteArrayList() << "out vec4 fragColor;" )); | 
| 134 |  | 
| 135 |         auto sampleTexture = createNode(ports: { | 
| 136 |             createPort(portDirection: QShaderNodePort::Input, portName: "sampler" ), | 
| 137 |             createPort(portDirection: QShaderNodePort::Input, portName: "coord" ), | 
| 138 |             createPort(portDirection: QShaderNodePort::Output, portName: "color" ) | 
| 139 |         }); | 
| 140 |         sampleTexture.addRule(format: openGLES2, rule: QShaderNode::Rule("highp vec4 $color = texture2D($sampler, $coord);" )); | 
| 141 |         sampleTexture.addRule(format: openGL3, rule: QShaderNode::Rule("vec4 $color = texture($sampler, $coord);" )); | 
| 142 |  | 
| 143 |         auto lightFunction = createNode(ports: { | 
| 144 |             createPort(portDirection: QShaderNodePort::Input, portName: "baseColor" ), | 
| 145 |             createPort(portDirection: QShaderNodePort::Input, portName: "position" ), | 
| 146 |             createPort(portDirection: QShaderNodePort::Input, portName: "lightIntensity" ), | 
| 147 |             createPort(portDirection: QShaderNodePort::Output, portName: "outputColor" ) | 
| 148 |         }); | 
| 149 |         lightFunction.addRule(format: openGLES2, rule: QShaderNode::Rule("highp vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);" , | 
| 150 |                                                            QByteArrayList() << "#pragma include es2/lightmodel.frag.inc" )); | 
| 151 |         lightFunction.addRule(format: openGL3, rule: QShaderNode::Rule("vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);" , | 
| 152 |                                                          QByteArrayList() << "#pragma include gl3/lightmodel.frag.inc" )); | 
| 153 |  | 
| 154 |         auto exposureFunction = createNode(ports: { | 
| 155 |             createPort(portDirection: QShaderNodePort::Input, portName: "inputColor" ), | 
| 156 |             createPort(portDirection: QShaderNodePort::Input, portName: "exposure" ), | 
| 157 |             createPort(portDirection: QShaderNodePort::Output, portName: "outputColor" ) | 
| 158 |         }); | 
| 159 |         exposureFunction.addRule(format: openGLES2, rule: QShaderNode::Rule("highp vec4 $outputColor = $inputColor * pow(2.0, $exposure);" )); | 
| 160 |         exposureFunction.addRule(format: openGL3, rule: QShaderNode::Rule("vec4 $outputColor = $inputColor * pow(2.0, $exposure);" )); | 
| 161 |  | 
| 162 |         graph.addNode(node: worldPosition); | 
| 163 |         graph.addNode(node: texture); | 
| 164 |         graph.addNode(node: texCoord); | 
| 165 |         graph.addNode(node: lightIntensity); | 
| 166 |         graph.addNode(node: exposure); | 
| 167 |         graph.addNode(node: fragColor); | 
| 168 |         graph.addNode(node: sampleTexture); | 
| 169 |         graph.addNode(node: lightFunction); | 
| 170 |         graph.addNode(node: exposureFunction); | 
| 171 |  | 
| 172 |         graph.addEdge(edge: createEdge(sourceUuid: texture.uuid(), sourceName: "texture" , targetUuid: sampleTexture.uuid(), targetName: "sampler" )); | 
| 173 |         graph.addEdge(edge: createEdge(sourceUuid: texCoord.uuid(), sourceName: "texCoord" , targetUuid: sampleTexture.uuid(), targetName: "coord" )); | 
| 174 |  | 
| 175 |         graph.addEdge(edge: createEdge(sourceUuid: worldPosition.uuid(), sourceName: "value" , targetUuid: lightFunction.uuid(), targetName: "position" )); | 
| 176 |         graph.addEdge(edge: createEdge(sourceUuid: sampleTexture.uuid(), sourceName: "color" , targetUuid: lightFunction.uuid(), targetName: "baseColor" )); | 
| 177 |         graph.addEdge(edge: createEdge(sourceUuid: lightIntensity.uuid(), sourceName: "lightIntensity" , targetUuid: lightFunction.uuid(), targetName: "lightIntensity" )); | 
| 178 |  | 
| 179 |         graph.addEdge(edge: createEdge(sourceUuid: lightFunction.uuid(), sourceName: "outputColor" , targetUuid: exposureFunction.uuid(), targetName: "inputColor" )); | 
| 180 |         graph.addEdge(edge: createEdge(sourceUuid: exposure.uuid(), sourceName: "exposure" , targetUuid: exposureFunction.uuid(), targetName: "exposure" )); | 
| 181 |  | 
| 182 |         graph.addEdge(edge: createEdge(sourceUuid: exposureFunction.uuid(), sourceName: "outputColor" , targetUuid: fragColor.uuid(), targetName: "fragColor" )); | 
| 183 |  | 
| 184 |         return graph; | 
| 185 |     } | 
| 186 | } | 
| 187 |  | 
| 188 | class tst_QShaderGenerator : public QObject | 
| 189 | { | 
| 190 |     Q_OBJECT | 
| 191 | private slots: | 
| 192 |     void shouldHaveDefaultState(); | 
| 193 |     void shouldGenerateShaderCode_data(); | 
| 194 |     void shouldGenerateShaderCode(); | 
| 195 |     void shouldGenerateVersionCommands_data(); | 
| 196 |     void shouldGenerateVersionCommands(); | 
| 197 |     void shouldProcessLanguageQualifierAndTypeEnums_data(); | 
| 198 |     void shouldProcessLanguageQualifierAndTypeEnums(); | 
| 199 |     void shouldGenerateDifferentCodeDependingOnActiveLayers(); | 
| 200 |     void shouldUseGlobalVariableRatherThanTemporaries(); | 
| 201 |     void shouldGenerateTemporariesWisely(); | 
| 202 |     void shouldHandlePortNamesPrefixingOneAnother(); | 
| 203 |     void shouldHandleNodesWithMultipleOutputPorts(); | 
| 204 |     void shouldHandleExpressionsInInputNodes(); | 
| 205 |     void shouldGenerateLayerDefines(); | 
| 206 | }; | 
| 207 |  | 
| 208 | void tst_QShaderGenerator::shouldHaveDefaultState() | 
| 209 | { | 
| 210 |     // GIVEN | 
| 211 |     auto generator = QShaderGenerator(); | 
| 212 |  | 
| 213 |     // THEN | 
| 214 |     QVERIFY(generator.graph.nodes().isEmpty()); | 
| 215 |     QVERIFY(generator.graph.edges().isEmpty()); | 
| 216 |     QVERIFY(!generator.format.isValid()); | 
| 217 | } | 
| 218 |  | 
| 219 | void tst_QShaderGenerator::shouldGenerateShaderCode_data() | 
| 220 | { | 
| 221 |     QTest::addColumn<QShaderGraph>(name: "graph" ); | 
| 222 |     QTest::addColumn<QShaderFormat>(name: "format" ); | 
| 223 |     QTest::addColumn<QByteArray>(name: "expectedCode" ); | 
| 224 |  | 
| 225 |     const auto graph = createFragmentShaderGraph(); | 
| 226 |  | 
| 227 |     const auto openGLES2 = createFormat(api: QShaderFormat::OpenGLES, majorVersion: 2, minorVersion: 0); | 
| 228 |     const auto openGL3 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 3, minorVersion: 0); | 
| 229 |     const auto openGL32 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 3, minorVersion: 2); | 
| 230 |     const auto openGL4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0); | 
| 231 |  | 
| 232 |     const auto versionGLES2 = QByteArrayList() << "#version 100"  << "" ; | 
| 233 |     const auto versionGL3 = QByteArrayList() << "#version 130"  << "" ; | 
| 234 |     const auto versionGL32 = QByteArrayList() << "#version 150 core"  << "" ; | 
| 235 |     const auto versionGL4 = QByteArrayList() << "#version 400 core"  << "" ; | 
| 236 |  | 
| 237 |     const auto es2Code = QByteArrayList() | 
| 238 |             << "varying highp vec2 texCoord;"  | 
| 239 |             << "uniform sampler2D texture;"  | 
| 240 |             << "uniform highp float lightIntensity;"  | 
| 241 |             << "varying highp vec3 worldPosition;"  | 
| 242 |             << "uniform highp float exposure;"  | 
| 243 |             << "#pragma include es2/lightmodel.frag.inc"  | 
| 244 |             << ""  | 
| 245 |             << "void main()"  | 
| 246 |             << "{"  | 
| 247 |             << "    gl_fragColor = (((((lightModel(((texture2D(texture, texCoord))), "  | 
| 248 |                "worldPosition, lightIntensity)))) * pow(2.0, exposure)));"  | 
| 249 |             << "}"  | 
| 250 |             << "" ; | 
| 251 |  | 
| 252 |     const auto gl3Code = QByteArrayList() | 
| 253 |             << "in vec2 texCoord;"  | 
| 254 |             << "uniform sampler2D texture;"  | 
| 255 |             << "uniform float lightIntensity;"  | 
| 256 |             << "in vec3 worldPosition;"  | 
| 257 |             << "uniform float exposure;"  | 
| 258 |             << "#pragma include gl3/lightmodel.frag.inc"  | 
| 259 |             << "out vec4 fragColor;"  | 
| 260 |             << ""  | 
| 261 |             << "void main()"  | 
| 262 |             << "{"  | 
| 263 |             << "    fragColor = (((((lightModel(((texture(texture, texCoord))), worldPosition, "  | 
| 264 |                "lightIntensity)))) * pow(2.0, exposure)));"  | 
| 265 |             << "}"  | 
| 266 |             << "" ; | 
| 267 |  | 
| 268 |     QTest::newRow(dataTag: "EmptyGraphAndFormat" ) << QShaderGraph() << QShaderFormat() << QByteArrayLiteral("\n\n\nvoid main()\n{\n}\n" ); | 
| 269 |     QTest::newRow(dataTag: "LightExposureGraphAndES2" ) << graph << openGLES2 << (versionGLES2 + es2Code).join(sep: '\n'); | 
| 270 |     QTest::newRow(dataTag: "LightExposureGraphAndGL3" ) << graph << openGL3 << (versionGL3 + gl3Code).join(sep: '\n'); | 
| 271 |     QTest::newRow(dataTag: "LightExposureGraphAndGL32" ) << graph << openGL32 << (versionGL32 + gl3Code).join(sep: '\n'); | 
| 272 |     QTest::newRow(dataTag: "LightExposureGraphAndGL4" ) << graph << openGL4 << (versionGL4 + gl3Code).join(sep: '\n'); | 
| 273 | } | 
| 274 |  | 
| 275 | void tst_QShaderGenerator::shouldGenerateShaderCode() | 
| 276 | { | 
| 277 |     // GIVEN | 
| 278 |     QFETCH(QShaderGraph, graph); | 
| 279 |     QFETCH(QShaderFormat, format); | 
| 280 |  | 
| 281 |     auto generator = QShaderGenerator(); | 
| 282 |     generator.graph = graph; | 
| 283 |     generator.format = format; | 
| 284 |  | 
| 285 |     // WHEN | 
| 286 |     const auto code = generator.createShaderCode(); | 
| 287 |  | 
| 288 |     // THEN | 
| 289 |     QFETCH(QByteArray, expectedCode); | 
| 290 |     QCOMPARE(code, expectedCode); | 
| 291 | } | 
| 292 |  | 
| 293 | void tst_QShaderGenerator::shouldGenerateVersionCommands_data() | 
| 294 | { | 
| 295 |     QTest::addColumn<QShaderFormat>(name: "format" ); | 
| 296 |     QTest::addColumn<QByteArray>(name: "version" ); | 
| 297 |  | 
| 298 |     QTest::newRow(dataTag: "GLES2" ) << createFormat(api: QShaderFormat::OpenGLES, majorVersion: 2, minorVersion: 0) << QByteArrayLiteral("#version 100" ); | 
| 299 |     QTest::newRow(dataTag: "GLES3" ) << createFormat(api: QShaderFormat::OpenGLES, majorVersion: 3, minorVersion: 0) << QByteArrayLiteral("#version 300 es" ); | 
| 300 |  | 
| 301 |     QTest::newRow(dataTag: "GL20" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 2, minorVersion: 0) << QByteArrayLiteral("#version 110" ); | 
| 302 |     QTest::newRow(dataTag: "GL21" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 2, minorVersion: 1) << QByteArrayLiteral("#version 120" ); | 
| 303 |     QTest::newRow(dataTag: "GL30" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 3, minorVersion: 0) << QByteArrayLiteral("#version 130" ); | 
| 304 |     QTest::newRow(dataTag: "GL31" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 3, minorVersion: 1) << QByteArrayLiteral("#version 140" ); | 
| 305 |     QTest::newRow(dataTag: "GL32" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 3, minorVersion: 2) << QByteArrayLiteral("#version 150" ); | 
| 306 |     QTest::newRow(dataTag: "GL33" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 3, minorVersion: 3) << QByteArrayLiteral("#version 330" ); | 
| 307 |     QTest::newRow(dataTag: "GL40" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 4, minorVersion: 0) << QByteArrayLiteral("#version 400" ); | 
| 308 |     QTest::newRow(dataTag: "GL41" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 4, minorVersion: 1) << QByteArrayLiteral("#version 410" ); | 
| 309 |     QTest::newRow(dataTag: "GL42" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 4, minorVersion: 2) << QByteArrayLiteral("#version 420" ); | 
| 310 |     QTest::newRow(dataTag: "GL43" ) << createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 4, minorVersion: 3) << QByteArrayLiteral("#version 430" ); | 
| 311 |  | 
| 312 |     QTest::newRow(dataTag: "GL20core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 2, minorVersion: 0) << QByteArrayLiteral("#version 110" ); | 
| 313 |     QTest::newRow(dataTag: "GL21core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 2, minorVersion: 1) << QByteArrayLiteral("#version 120" ); | 
| 314 |     QTest::newRow(dataTag: "GL30core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 3, minorVersion: 0) << QByteArrayLiteral("#version 130" ); | 
| 315 |     QTest::newRow(dataTag: "GL31core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 3, minorVersion: 1) << QByteArrayLiteral("#version 140" ); | 
| 316 |     QTest::newRow(dataTag: "GL32core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 3, minorVersion: 2) << QByteArrayLiteral("#version 150 core" ); | 
| 317 |     QTest::newRow(dataTag: "GL33core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 3, minorVersion: 3) << QByteArrayLiteral("#version 330 core" ); | 
| 318 |     QTest::newRow(dataTag: "GL40core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0) << QByteArrayLiteral("#version 400 core" ); | 
| 319 |     QTest::newRow(dataTag: "GL41core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 1) << QByteArrayLiteral("#version 410 core" ); | 
| 320 |     QTest::newRow(dataTag: "GL42core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 2) << QByteArrayLiteral("#version 420 core" ); | 
| 321 |     QTest::newRow(dataTag: "GL43core" ) << createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 3) << QByteArrayLiteral("#version 430 core" ); | 
| 322 |  | 
| 323 |     QTest::newRow(dataTag: "GL20compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 2, minorVersion: 0) << QByteArrayLiteral("#version 110" ); | 
| 324 |     QTest::newRow(dataTag: "GL21compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 2, minorVersion: 1) << QByteArrayLiteral("#version 120" ); | 
| 325 |     QTest::newRow(dataTag: "GL30compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 3, minorVersion: 0) << QByteArrayLiteral("#version 130" ); | 
| 326 |     QTest::newRow(dataTag: "GL31compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 3, minorVersion: 1) << QByteArrayLiteral("#version 140" ); | 
| 327 |     QTest::newRow(dataTag: "GL32compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 3, minorVersion: 2) << QByteArrayLiteral("#version 150 compatibility" ); | 
| 328 |     QTest::newRow(dataTag: "GL33compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 3, minorVersion: 3) << QByteArrayLiteral("#version 330 compatibility" ); | 
| 329 |     QTest::newRow(dataTag: "GL40compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 4, minorVersion: 0) << QByteArrayLiteral("#version 400 compatibility" ); | 
| 330 |     QTest::newRow(dataTag: "GL41compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 4, minorVersion: 1) << QByteArrayLiteral("#version 410 compatibility" ); | 
| 331 |     QTest::newRow(dataTag: "GL42compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 4, minorVersion: 2) << QByteArrayLiteral("#version 420 compatibility" ); | 
| 332 |     QTest::newRow(dataTag: "GL43compatibility" ) << createFormat(api: QShaderFormat::OpenGLCompatibilityProfile, majorVersion: 4, minorVersion: 3) << QByteArrayLiteral("#version 430 compatibility" ); | 
| 333 | } | 
| 334 |  | 
| 335 | void tst_QShaderGenerator::shouldGenerateVersionCommands() | 
| 336 | { | 
| 337 |     // GIVEN | 
| 338 |     QFETCH(QShaderFormat, format); | 
| 339 |  | 
| 340 |     auto generator = QShaderGenerator(); | 
| 341 |     generator.format = format; | 
| 342 |  | 
| 343 |     // WHEN | 
| 344 |     const auto code = generator.createShaderCode(); | 
| 345 |  | 
| 346 |     // THEN | 
| 347 |     QFETCH(QByteArray, version); | 
| 348 |     const auto expectedCode = (QByteArrayList() << version | 
| 349 |                                                 << ""  | 
| 350 |                                                 << ""  | 
| 351 |                                                 << "void main()"  | 
| 352 |                                                 << "{"  | 
| 353 |                                                 << "}"  | 
| 354 |                                                 << "" ).join(sep: '\n'); | 
| 355 |     QCOMPARE(code, expectedCode); | 
| 356 | } | 
| 357 |  | 
| 358 |  | 
| 359 | namespace { | 
| 360 |     QString toGlsl(QShaderLanguage::StorageQualifier qualifier, const QShaderFormat &format) | 
| 361 |     { | 
| 362 |         if (format.version().majorVersion() <= 2) { | 
| 363 |             // Note we're assuming fragment shader only here, it'd be different | 
| 364 |             // values for vertex shader, will need to be fixed properly at some | 
| 365 |             // point but isn't necessary yet (this problem already exists in past | 
| 366 |             // commits anyway) | 
| 367 |             switch (qualifier) { | 
| 368 |             case QShaderLanguage::Const: | 
| 369 |                 return "const" ; | 
| 370 |             case QShaderLanguage::Input: | 
| 371 |                 return "varying" ; | 
| 372 |             case QShaderLanguage::BuiltIn: | 
| 373 |                 return "//" ; | 
| 374 |             case QShaderLanguage::Output: | 
| 375 |                 return "" ; // Although fragment shaders for <=2 only have fixed outputs | 
| 376 |             case QShaderLanguage::Uniform: | 
| 377 |                 return "uniform" ; | 
| 378 |             } | 
| 379 |         } else { | 
| 380 |             switch (qualifier) { | 
| 381 |             case QShaderLanguage::Const: | 
| 382 |                 return "const" ; | 
| 383 |             case QShaderLanguage::Input: | 
| 384 |                 return "in" ; | 
| 385 |             case QShaderLanguage::BuiltIn: | 
| 386 |                 return "//" ; | 
| 387 |             case QShaderLanguage::Output: | 
| 388 |                 return "out" ; | 
| 389 |             case QShaderLanguage::Uniform: | 
| 390 |                 return "uniform" ; | 
| 391 |             } | 
| 392 |         } | 
| 393 |  | 
| 394 |         Q_UNREACHABLE(); | 
| 395 |     } | 
| 396 |  | 
| 397 |     QString toGlsl(QShaderLanguage::VariableType type) | 
| 398 |     { | 
| 399 |         switch (type) { | 
| 400 |         case QShaderLanguage::Bool: | 
| 401 |             return "bool" ; | 
| 402 |         case QShaderLanguage::Int: | 
| 403 |             return "int" ; | 
| 404 |         case QShaderLanguage::Uint: | 
| 405 |             return "uint" ; | 
| 406 |         case QShaderLanguage::Float: | 
| 407 |             return "float" ; | 
| 408 |         case QShaderLanguage::Double: | 
| 409 |             return "double" ; | 
| 410 |         case QShaderLanguage::Vec2: | 
| 411 |             return "vec2" ; | 
| 412 |         case QShaderLanguage::Vec3: | 
| 413 |             return "vec3" ; | 
| 414 |         case QShaderLanguage::Vec4: | 
| 415 |             return "vec4" ; | 
| 416 |         case QShaderLanguage::DVec2: | 
| 417 |             return "dvec2" ; | 
| 418 |         case QShaderLanguage::DVec3: | 
| 419 |             return "dvec3" ; | 
| 420 |         case QShaderLanguage::DVec4: | 
| 421 |             return "dvec4" ; | 
| 422 |         case QShaderLanguage::BVec2: | 
| 423 |             return "bvec2" ; | 
| 424 |         case QShaderLanguage::BVec3: | 
| 425 |             return "bvec3" ; | 
| 426 |         case QShaderLanguage::BVec4: | 
| 427 |             return "bvec4" ; | 
| 428 |         case QShaderLanguage::IVec2: | 
| 429 |             return "ivec2" ; | 
| 430 |         case QShaderLanguage::IVec3: | 
| 431 |             return "ivec3" ; | 
| 432 |         case QShaderLanguage::IVec4: | 
| 433 |             return "ivec4" ; | 
| 434 |         case QShaderLanguage::UVec2: | 
| 435 |             return "uvec2" ; | 
| 436 |         case QShaderLanguage::UVec3: | 
| 437 |             return "uvec3" ; | 
| 438 |         case QShaderLanguage::UVec4: | 
| 439 |             return "uvec4" ; | 
| 440 |         case QShaderLanguage::Mat2: | 
| 441 |             return "mat2" ; | 
| 442 |         case QShaderLanguage::Mat3: | 
| 443 |             return "mat3" ; | 
| 444 |         case QShaderLanguage::Mat4: | 
| 445 |             return "mat4" ; | 
| 446 |         case QShaderLanguage::Mat2x2: | 
| 447 |             return "mat2x2" ; | 
| 448 |         case QShaderLanguage::Mat2x3: | 
| 449 |             return "mat2x3" ; | 
| 450 |         case QShaderLanguage::Mat2x4: | 
| 451 |             return "mat2x4" ; | 
| 452 |         case QShaderLanguage::Mat3x2: | 
| 453 |             return "mat3x2" ; | 
| 454 |         case QShaderLanguage::Mat3x3: | 
| 455 |             return "mat3x3" ; | 
| 456 |         case QShaderLanguage::Mat3x4: | 
| 457 |             return "mat3x4" ; | 
| 458 |         case QShaderLanguage::Mat4x2: | 
| 459 |             return "mat4x2" ; | 
| 460 |         case QShaderLanguage::Mat4x3: | 
| 461 |             return "mat4x3" ; | 
| 462 |         case QShaderLanguage::Mat4x4: | 
| 463 |             return "mat4x4" ; | 
| 464 |         case QShaderLanguage::DMat2: | 
| 465 |             return "dmat2" ; | 
| 466 |         case QShaderLanguage::DMat3: | 
| 467 |             return "dmat3" ; | 
| 468 |         case QShaderLanguage::DMat4: | 
| 469 |             return "dmat4" ; | 
| 470 |         case QShaderLanguage::DMat2x2: | 
| 471 |             return "dmat2x2" ; | 
| 472 |         case QShaderLanguage::DMat2x3: | 
| 473 |             return "dmat2x3" ; | 
| 474 |         case QShaderLanguage::DMat2x4: | 
| 475 |             return "dmat2x4" ; | 
| 476 |         case QShaderLanguage::DMat3x2: | 
| 477 |             return "dmat3x2" ; | 
| 478 |         case QShaderLanguage::DMat3x3: | 
| 479 |             return "dmat3x3" ; | 
| 480 |         case QShaderLanguage::DMat3x4: | 
| 481 |             return "dmat3x4" ; | 
| 482 |         case QShaderLanguage::DMat4x2: | 
| 483 |             return "dmat4x2" ; | 
| 484 |         case QShaderLanguage::DMat4x3: | 
| 485 |             return "dmat4x3" ; | 
| 486 |         case QShaderLanguage::DMat4x4: | 
| 487 |             return "dmat4x4" ; | 
| 488 |         case QShaderLanguage::Sampler1D: | 
| 489 |             return "sampler1D" ; | 
| 490 |         case QShaderLanguage::Sampler2D: | 
| 491 |             return "sampler2D" ; | 
| 492 |         case QShaderLanguage::Sampler3D: | 
| 493 |             return "sampler3D" ; | 
| 494 |         case QShaderLanguage::SamplerCube: | 
| 495 |             return "samplerCube" ; | 
| 496 |         case QShaderLanguage::Sampler2DRect: | 
| 497 |             return "sampler2DRect" ; | 
| 498 |         case QShaderLanguage::Sampler2DMs: | 
| 499 |             return "sampler2DMS" ; | 
| 500 |         case QShaderLanguage::SamplerBuffer: | 
| 501 |             return "samplerBuffer" ; | 
| 502 |         case QShaderLanguage::Sampler1DArray: | 
| 503 |             return "sampler1DArray" ; | 
| 504 |         case QShaderLanguage::Sampler2DArray: | 
| 505 |             return "sampler2DArray" ; | 
| 506 |         case QShaderLanguage::Sampler2DMsArray: | 
| 507 |             return "sampler2DMSArray" ; | 
| 508 |         case QShaderLanguage::SamplerCubeArray: | 
| 509 |             return "samplerCubeArray" ; | 
| 510 |         case QShaderLanguage::Sampler1DShadow: | 
| 511 |             return "sampler1DShadow" ; | 
| 512 |         case QShaderLanguage::Sampler2DShadow: | 
| 513 |             return "sampler2DShadow" ; | 
| 514 |         case QShaderLanguage::Sampler2DRectShadow: | 
| 515 |             return "sampler2DRectShadow" ; | 
| 516 |         case QShaderLanguage::Sampler1DArrayShadow: | 
| 517 |             return "sampler1DArrayShadow" ; | 
| 518 |         case QShaderLanguage::Sampler2DArrayShadow: | 
| 519 |             return "sampler2DArrayShadow" ; | 
| 520 |         case QShaderLanguage::SamplerCubeShadow: | 
| 521 |             return "samplerCubeShadow" ; | 
| 522 |         case QShaderLanguage::SamplerCubeArrayShadow: | 
| 523 |             return "samplerCubeArrayShadow" ; | 
| 524 |         case QShaderLanguage::ISampler1D: | 
| 525 |             return "isampler1D" ; | 
| 526 |         case QShaderLanguage::ISampler2D: | 
| 527 |             return "isampler2D" ; | 
| 528 |         case QShaderLanguage::ISampler3D: | 
| 529 |             return "isampler3D" ; | 
| 530 |         case QShaderLanguage::ISamplerCube: | 
| 531 |             return "isamplerCube" ; | 
| 532 |         case QShaderLanguage::ISampler2DRect: | 
| 533 |             return "isampler2DRect" ; | 
| 534 |         case QShaderLanguage::ISampler2DMs: | 
| 535 |             return "isampler2DMS" ; | 
| 536 |         case QShaderLanguage::ISamplerBuffer: | 
| 537 |             return "isamplerBuffer" ; | 
| 538 |         case QShaderLanguage::ISampler1DArray: | 
| 539 |             return "isampler1DArray" ; | 
| 540 |         case QShaderLanguage::ISampler2DArray: | 
| 541 |             return "isampler2DArray" ; | 
| 542 |         case QShaderLanguage::ISampler2DMsArray: | 
| 543 |             return "isampler2DMSArray" ; | 
| 544 |         case QShaderLanguage::ISamplerCubeArray: | 
| 545 |             return "isamplerCubeArray" ; | 
| 546 |         case QShaderLanguage::USampler1D: | 
| 547 |             return "usampler1D" ; | 
| 548 |         case QShaderLanguage::USampler2D: | 
| 549 |             return "usampler2D" ; | 
| 550 |         case QShaderLanguage::USampler3D: | 
| 551 |             return "usampler3D" ; | 
| 552 |         case QShaderLanguage::USamplerCube: | 
| 553 |             return "usamplerCube" ; | 
| 554 |         case QShaderLanguage::USampler2DRect: | 
| 555 |             return "usampler2DRect" ; | 
| 556 |         case QShaderLanguage::USampler2DMs: | 
| 557 |             return "usampler2DMS" ; | 
| 558 |         case QShaderLanguage::USamplerBuffer: | 
| 559 |             return "usamplerBuffer" ; | 
| 560 |         case QShaderLanguage::USampler1DArray: | 
| 561 |             return "usampler1DArray" ; | 
| 562 |         case QShaderLanguage::USampler2DArray: | 
| 563 |             return "usampler2DArray" ; | 
| 564 |         case QShaderLanguage::USampler2DMsArray: | 
| 565 |             return "usampler2DMSArray" ; | 
| 566 |         case QShaderLanguage::USamplerCubeArray: | 
| 567 |             return "usamplerCubeArray" ; | 
| 568 |         } | 
| 569 |  | 
| 570 |         Q_UNREACHABLE(); | 
| 571 |     } | 
| 572 | } | 
| 573 |  | 
| 574 | void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data() | 
| 575 | { | 
| 576 |     QTest::addColumn<QShaderGraph>(name: "graph" ); | 
| 577 |     QTest::addColumn<QShaderFormat>(name: "format" ); | 
| 578 |     QTest::addColumn<QByteArray>(name: "expectedCode" ); | 
| 579 |  | 
| 580 |     { | 
| 581 |         const auto es2 = createFormat(api: QShaderFormat::OpenGLES, majorVersion: 2, minorVersion: 0); | 
| 582 |         const auto es3 = createFormat(api: QShaderFormat::OpenGLES, majorVersion: 3, minorVersion: 0); | 
| 583 |         const auto gl2 = createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 2, minorVersion: 0); | 
| 584 |         const auto gl3 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 3, minorVersion: 0); | 
| 585 |         const auto gl4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0); | 
| 586 |  | 
| 587 |         const auto qualifierEnum = QMetaEnum::fromType<QShaderLanguage::StorageQualifier>(); | 
| 588 |         const auto typeEnum = QMetaEnum::fromType<QShaderLanguage::VariableType>(); | 
| 589 |  | 
| 590 |         for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) { | 
| 591 |             const auto qualifierName = qualifierEnum.key(index: qualifierIndex); | 
| 592 |             const auto qualifierValue = static_cast<QShaderLanguage::StorageQualifier>(qualifierEnum.value(index: qualifierIndex)); | 
| 593 |  | 
| 594 |             for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) { | 
| 595 |                 const auto typeName = typeEnum.key(index: typeIndex); | 
| 596 |                 const auto typeValue = static_cast<QShaderLanguage::VariableType>(typeEnum.value(index: typeIndex)); | 
| 597 |  | 
| 598 |                 auto graph = QShaderGraph(); | 
| 599 |  | 
| 600 |                 auto worldPosition = createNode(ports: { | 
| 601 |                     createPort(portDirection: QShaderNodePort::Output, portName: "value" ) | 
| 602 |                 }); | 
| 603 |                 worldPosition.setParameter(name: "name" , value: "worldPosition" ); | 
| 604 |                 worldPosition.setParameter(name: "qualifier" , value: QVariant::fromValue<QShaderLanguage::StorageQualifier>(value: qualifierValue)); | 
| 605 |                 worldPosition.setParameter(name: "type" , value: QVariant::fromValue<QShaderLanguage::VariableType>(value: typeValue)); | 
| 606 |                 worldPosition.addRule(format: es2, rule: QShaderNode::Rule("highp $type $value = $name;" , | 
| 607 |                                                              QByteArrayList() << "$qualifier highp $type $name;" )); | 
| 608 |                 worldPosition.addRule(format: gl2, rule: QShaderNode::Rule("$type $value = $name;" , | 
| 609 |                                                              QByteArrayList() << "$qualifier $type $name;" )); | 
| 610 |                 worldPosition.addRule(format: gl3, rule: QShaderNode::Rule("$type $value = $name;" , | 
| 611 |                                                              QByteArrayList() << "$qualifier $type $name;" )); | 
| 612 |  | 
| 613 |                 auto fragColor = createNode(ports: { | 
| 614 |                     createPort(portDirection: QShaderNodePort::Input, portName: "fragColor" ) | 
| 615 |                 }); | 
| 616 |                 fragColor.addRule(format: es2, rule: QShaderNode::Rule("gl_fragColor = $fragColor;" )); | 
| 617 |                 fragColor.addRule(format: gl2, rule: QShaderNode::Rule("gl_fragColor = $fragColor;" )); | 
| 618 |                 fragColor.addRule(format: gl3, rule: QShaderNode::Rule("fragColor = $fragColor;" , | 
| 619 |                                                          QByteArrayList() << "out vec4 fragColor;" )); | 
| 620 |  | 
| 621 |                 graph.addNode(node: worldPosition); | 
| 622 |                 graph.addNode(node: fragColor); | 
| 623 |  | 
| 624 |                 graph.addEdge(edge: createEdge(sourceUuid: worldPosition.uuid(), sourceName: "value" , targetUuid: fragColor.uuid(), targetName: "fragColor" )); | 
| 625 |  | 
| 626 |                 const auto gl2Code = (QByteArrayList() << "#version 110"  | 
| 627 |                                                        << ""  | 
| 628 |                                                        << QStringLiteral("%1 %2 worldPosition;" ).arg(a: toGlsl(qualifier: qualifierValue, format: gl2)) | 
| 629 |                                                                                                 .arg(a: toGlsl(type: typeValue)) | 
| 630 |                                                                                                 .toUtf8() | 
| 631 |                                                        << ""  | 
| 632 |                                                        << "void main()"  | 
| 633 |                                                        << "{"  | 
| 634 |                                                        << "    gl_fragColor = worldPosition;"  | 
| 635 |                                                        << "}"  | 
| 636 |                                                        << "" ).join(sep: "\n" ); | 
| 637 |                 const auto gl3Code = (QByteArrayList() << "#version 130"  | 
| 638 |                                                        << ""  | 
| 639 |                                                        << QStringLiteral("%1 %2 worldPosition;" ).arg(a: toGlsl(qualifier: qualifierValue, format: gl3)) | 
| 640 |                                                                                                 .arg(a: toGlsl(type: typeValue)) | 
| 641 |                                                                                                 .toUtf8() | 
| 642 |                                                        << "out vec4 fragColor;"  | 
| 643 |                                                        << ""  | 
| 644 |                                                        << "void main()"  | 
| 645 |                                                        << "{"  | 
| 646 |                                                        << "    fragColor = worldPosition;"  | 
| 647 |                                                        << "}"  | 
| 648 |                                                        << "" ).join(sep: "\n" ); | 
| 649 |                 const auto gl4Code = (QByteArrayList() << "#version 400 core"  | 
| 650 |                                                        << ""  | 
| 651 |                                                        << QStringLiteral("%1 %2 worldPosition;" ).arg(a: toGlsl(qualifier: qualifierValue, format: gl4)) | 
| 652 |                                                                                                 .arg(a: toGlsl(type: typeValue)) | 
| 653 |                                                                                                 .toUtf8() | 
| 654 |                                                        << "out vec4 fragColor;"  | 
| 655 |                                                        << ""  | 
| 656 |                                                        << "void main()"  | 
| 657 |                                                        << "{"  | 
| 658 |                                                        << "    fragColor = worldPosition;"  | 
| 659 |                                                        << "}"  | 
| 660 |                                                        << "" ).join(sep: "\n" ); | 
| 661 |                 const auto es2Code = (QByteArrayList() << "#version 100"  | 
| 662 |                                                        << ""  | 
| 663 |                                                        << QStringLiteral("%1 highp %2 worldPosition;" ).arg(a: toGlsl(qualifier: qualifierValue, format: es2)) | 
| 664 |                                                                                                       .arg(a: toGlsl(type: typeValue)) | 
| 665 |                                                                                                       .toUtf8() | 
| 666 |                                                        << ""  | 
| 667 |                                                        << "void main()"  | 
| 668 |                                                        << "{"  | 
| 669 |                                                        << "    gl_fragColor = worldPosition;"  | 
| 670 |                                                        << "}"  | 
| 671 |                                                        << "" ).join(sep: "\n" ); | 
| 672 |                 const auto es3Code = (QByteArrayList() << "#version 300 es"  | 
| 673 |                                                        << ""  | 
| 674 |                                                        << QStringLiteral("%1 highp %2 worldPosition;" ).arg(a: toGlsl(qualifier: qualifierValue, format: es3)) | 
| 675 |                                                                                                       .arg(a: toGlsl(type: typeValue)) | 
| 676 |                                                                                                       .toUtf8() | 
| 677 |                                                        << ""  | 
| 678 |                                                        << "void main()"  | 
| 679 |                                                        << "{"  | 
| 680 |                                                        << "    gl_fragColor = worldPosition;"  | 
| 681 |                                                        << "}"  | 
| 682 |                                                        << "" ).join(sep: "\n" ); | 
| 683 |  | 
| 684 |                 QTest::addRow(format: "%s %s ES2" , qualifierName, typeName) << graph << es2 << es2Code; | 
| 685 |                 QTest::addRow(format: "%s %s ES3" , qualifierName, typeName) << graph << es3 << es3Code; | 
| 686 |                 QTest::addRow(format: "%s %s GL2" , qualifierName, typeName) << graph << gl2 << gl2Code; | 
| 687 |                 QTest::addRow(format: "%s %s GL3" , qualifierName, typeName) << graph << gl3 << gl3Code; | 
| 688 |                 QTest::addRow(format: "%s %s GL4" , qualifierName, typeName) << graph << gl4 << gl4Code; | 
| 689 |             } | 
| 690 |         } | 
| 691 |     } | 
| 692 |  | 
| 693 |     { | 
| 694 |             const auto es2 = createFormat(api: QShaderFormat::OpenGLES, majorVersion: 2, minorVersion: 0, shaderType: QShaderFormat::Vertex); | 
| 695 |             const auto es3 = createFormat(api: QShaderFormat::OpenGLES, majorVersion: 3, minorVersion: 0, shaderType: QShaderFormat::Vertex); | 
| 696 |             const auto gl2 = createFormat(api: QShaderFormat::OpenGLNoProfile, majorVersion: 2, minorVersion: 0, shaderType: QShaderFormat::Vertex); | 
| 697 |             const auto gl3 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 3, minorVersion: 0, shaderType: QShaderFormat::Vertex); | 
| 698 |             const auto gl4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0, shaderType: QShaderFormat::Vertex); | 
| 699 |  | 
| 700 |             auto graph = QShaderGraph(); | 
| 701 |  | 
| 702 |             auto vertexPosition = createNode(ports: { | 
| 703 |                 createPort(portDirection: QShaderNodePort::Output, portName: "value" ) | 
| 704 |             }); | 
| 705 |             vertexPosition.setParameter(name: "name" , value: "vertexPosition" ); | 
| 706 |             vertexPosition.setParameter(name: "qualifier" , value: QVariant::fromValue<QShaderLanguage::StorageQualifier>(value: QShaderLanguage::Input)); | 
| 707 |             vertexPosition.setParameter(name: "type" , value: QVariant::fromValue<QShaderLanguage::VariableType>(value: QShaderLanguage::Vec4)); | 
| 708 |  | 
| 709 |             vertexPosition.addRule(format: es2, rule: QShaderNode::Rule("" , | 
| 710 |                                                          QByteArrayList() << "$qualifier highp $type $name;" )); | 
| 711 |             vertexPosition.addRule(format: gl2, rule: QShaderNode::Rule("" , | 
| 712 |                                                          QByteArrayList() << "$qualifier $type $name;" )); | 
| 713 |             vertexPosition.addRule(format: gl3, rule: QShaderNode::Rule("" , | 
| 714 |                                                          QByteArrayList() << "$qualifier $type $name;" )); | 
| 715 |  | 
| 716 |             graph.addNode(node: vertexPosition); | 
| 717 |  | 
| 718 |             const auto gl2Code = (QByteArrayList() << "#version 110"  | 
| 719 |                                                    << ""  | 
| 720 |                                                    << ""  | 
| 721 |                                                    << "void main()"  | 
| 722 |                                                    << "{"  | 
| 723 |                                                    << "}"  | 
| 724 |                                                    << "" ).join(sep: "\n" ); | 
| 725 |             const auto gl3Code = (QByteArrayList() << "#version 130"  | 
| 726 |                                                    << ""  | 
| 727 |                                                    << ""  | 
| 728 |                                                    << "void main()"  | 
| 729 |                                                    << "{"  | 
| 730 |                                                    << "}"  | 
| 731 |                                                    << "" ).join(sep: "\n" ); | 
| 732 |             const auto gl4Code = (QByteArrayList() << "#version 400 core"  | 
| 733 |                                                    << ""  | 
| 734 |                                                    << ""  | 
| 735 |                                                    << "void main()"  | 
| 736 |                                                    << "{"  | 
| 737 |                                                    << "}"  | 
| 738 |                                                    << "" ).join(sep: "\n" ); | 
| 739 |             const auto es2Code = (QByteArrayList() << "#version 100"  | 
| 740 |                                                    << ""  | 
| 741 |                                                    << ""  | 
| 742 |                                                    << "void main()"  | 
| 743 |                                                    << "{"  | 
| 744 |                                                    << "}"  | 
| 745 |                                                    << "" ).join(sep: "\n" ); | 
| 746 |             const auto es3Code = (QByteArrayList() << "#version 300 es"  | 
| 747 |                                                    << ""  | 
| 748 |                                                    << ""  | 
| 749 |                                                    << "void main()"  | 
| 750 |                                                    << "{"  | 
| 751 |                                                    << "}"  | 
| 752 |                                                    << "" ).join(sep: "\n" ); | 
| 753 |  | 
| 754 |             QTest::addRow(format: "Attribute header substitution ES2" ) << graph << es2 << es2Code; | 
| 755 |             QTest::addRow(format: "Attribute header substitution ES3" ) << graph << es3 << es3Code; | 
| 756 |             QTest::addRow(format: "Attribute header substitution GL2" ) << graph << gl2 << gl2Code; | 
| 757 |             QTest::addRow(format: "Attribute header substitution GL3" ) << graph << gl3 << gl3Code; | 
| 758 |             QTest::addRow(format: "Attribute header substitution GL4" ) << graph << gl4 << gl4Code; | 
| 759 |     } | 
| 760 | } | 
| 761 |  | 
| 762 | void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums() | 
| 763 | { | 
| 764 |     // GIVEN | 
| 765 |     QFETCH(QShaderGraph, graph); | 
| 766 |     QFETCH(QShaderFormat, format); | 
| 767 |  | 
| 768 |     auto generator = QShaderGenerator(); | 
| 769 |     generator.graph = graph; | 
| 770 |     generator.format = format; | 
| 771 |  | 
| 772 |     // WHEN | 
| 773 |     const auto code = generator.createShaderCode(); | 
| 774 |  | 
| 775 |     // THEN | 
| 776 |     QFETCH(QByteArray, expectedCode); | 
| 777 |     QCOMPARE(code, expectedCode); | 
| 778 | } | 
| 779 |  | 
| 780 | void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() | 
| 781 | { | 
| 782 |     // GIVEN | 
| 783 |     const auto gl4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0); | 
| 784 |  | 
| 785 |     auto texCoord = createNode(ports: { | 
| 786 |         createPort(portDirection: QShaderNodePort::Output, portName: "texCoord" ) | 
| 787 |     }, layers: { | 
| 788 |         "diffuseTexture" , | 
| 789 |         "normalTexture"  | 
| 790 |     }); | 
| 791 |     texCoord.addRule(format: gl4, rule: QShaderNode::Rule("vec2 $texCoord = texCoord;" , | 
| 792 |                                             QByteArrayList() << "in vec2 texCoord;" )); | 
| 793 |     auto diffuseUniform = createNode(ports: { | 
| 794 |         createPort(portDirection: QShaderNodePort::Output, portName: "color" ) | 
| 795 |     }, layers: {"diffuseUniform" }); | 
| 796 |     diffuseUniform.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $color = diffuseUniform;" , | 
| 797 |                                                   QByteArrayList() << "uniform vec4 diffuseUniform;" )); | 
| 798 |     auto diffuseTexture = createNode(ports: { | 
| 799 |         createPort(portDirection: QShaderNodePort::Input, portName: "coord" ), | 
| 800 |         createPort(portDirection: QShaderNodePort::Output, portName: "color" ) | 
| 801 |     }, layers: {"diffuseTexture" }); | 
| 802 |     diffuseTexture.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $color = texture2D(diffuseTexture, $coord);" , | 
| 803 |                                                  QByteArrayList() << "uniform sampler2D diffuseTexture;" )); | 
| 804 |     auto normalUniform = createNode(ports: { | 
| 805 |         createPort(portDirection: QShaderNodePort::Output, portName: "normal" ) | 
| 806 |     }, layers: {"normalUniform" }); | 
| 807 |     normalUniform.addRule(format: gl4, rule: QShaderNode::Rule("vec3 $normal = normalUniform;" , | 
| 808 |                                                  QByteArrayList() << "uniform vec3 normalUniform;" )); | 
| 809 |     auto normalTexture = createNode(ports: { | 
| 810 |         createPort(portDirection: QShaderNodePort::Input, portName: "coord" ), | 
| 811 |         createPort(portDirection: QShaderNodePort::Output, portName: "normal" ) | 
| 812 |     }, layers: {"normalTexture" }); | 
| 813 |     normalTexture.addRule(format: gl4, rule: QShaderNode::Rule("vec3 $normal = texture2D(normalTexture, $coord).rgb;" , | 
| 814 |                                                  QByteArrayList() << "uniform sampler2D normalTexture;" )); | 
| 815 |     auto lightFunction = createNode(ports: { | 
| 816 |         createPort(portDirection: QShaderNodePort::Input, portName: "color" ), | 
| 817 |         createPort(portDirection: QShaderNodePort::Input, portName: "normal" ), | 
| 818 |         createPort(portDirection: QShaderNodePort::Output, portName: "output" ) | 
| 819 |     }); | 
| 820 |     lightFunction.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $output = lightModel($color, $normal);" , | 
| 821 |                                                  QByteArrayList() << "#pragma include gl4/lightmodel.frag.inc" )); | 
| 822 |     auto fragColor = createNode(ports: { | 
| 823 |         createPort(portDirection: QShaderNodePort::Input, portName: "fragColor" ) | 
| 824 |     }); | 
| 825 |     fragColor.addRule(format: gl4, rule: QShaderNode::Rule("fragColor = $fragColor;" , | 
| 826 |                                              QByteArrayList() << "out vec4 fragColor;" )); | 
| 827 |  | 
| 828 |     const auto graph = [=] { | 
| 829 |         auto res = QShaderGraph(); | 
| 830 |  | 
| 831 |         res.addNode(node: texCoord); | 
| 832 |         res.addNode(node: diffuseUniform); | 
| 833 |         res.addNode(node: diffuseTexture); | 
| 834 |         res.addNode(node: normalUniform); | 
| 835 |         res.addNode(node: normalTexture); | 
| 836 |         res.addNode(node: lightFunction); | 
| 837 |         res.addNode(node: fragColor); | 
| 838 |  | 
| 839 |         res.addEdge(edge: createEdge(sourceUuid: diffuseUniform.uuid(), sourceName: "color" , targetUuid: lightFunction.uuid(), targetName: "color" , layers: {"diffuseUniform" })); | 
| 840 |         res.addEdge(edge: createEdge(sourceUuid: texCoord.uuid(), sourceName: "texCoord" , targetUuid: diffuseTexture.uuid(), targetName: "coord" , layers: {"diffuseTexture" })); | 
| 841 |         res.addEdge(edge: createEdge(sourceUuid: diffuseTexture.uuid(), sourceName: "color" , targetUuid: lightFunction.uuid(), targetName: "color" , layers: {"diffuseTexture" })); | 
| 842 |  | 
| 843 |         res.addEdge(edge: createEdge(sourceUuid: normalUniform.uuid(), sourceName: "normal" , targetUuid: lightFunction.uuid(), targetName: "normal" , layers: {"normalUniform" })); | 
| 844 |         res.addEdge(edge: createEdge(sourceUuid: texCoord.uuid(), sourceName: "texCoord" , targetUuid: normalTexture.uuid(), targetName: "coord" , layers: {"normalTexture" })); | 
| 845 |         res.addEdge(edge: createEdge(sourceUuid: normalTexture.uuid(), sourceName: "normal" , targetUuid: lightFunction.uuid(), targetName: "normal" , layers: {"normalTexture" })); | 
| 846 |  | 
| 847 |         res.addEdge(edge: createEdge(sourceUuid: lightFunction.uuid(), sourceName: "output" , targetUuid: fragColor.uuid(), targetName: "fragColor" )); | 
| 848 |  | 
| 849 |         return res; | 
| 850 |     }(); | 
| 851 |  | 
| 852 |     auto generator = QShaderGenerator(); | 
| 853 |     generator.graph = graph; | 
| 854 |     generator.format = gl4; | 
| 855 |  | 
| 856 |     { | 
| 857 |         // WHEN | 
| 858 |         const auto code = generator.createShaderCode(enabledLayers: {"diffuseUniform" , "normalUniform" }); | 
| 859 |  | 
| 860 |         // THEN | 
| 861 |         const auto expected = QByteArrayList() | 
| 862 |                 << "#version 400 core"  | 
| 863 |                 << ""  | 
| 864 |                 << "#define LAYER_diffuseUniform"  | 
| 865 |                 << "#define LAYER_normalUniform"  | 
| 866 |                 << "uniform vec3 normalUniform;"  | 
| 867 |                 << "uniform vec4 diffuseUniform;"  | 
| 868 |                 << "#pragma include gl4/lightmodel.frag.inc"  | 
| 869 |                 << "out vec4 fragColor;"  | 
| 870 |                 << ""  | 
| 871 |                 << "void main()"  | 
| 872 |                 << "{"  | 
| 873 |                 << "    fragColor = ((lightModel(diffuseUniform, normalUniform)));"  | 
| 874 |                 << "}"  | 
| 875 |                 << "" ; | 
| 876 |         QCOMPARE(code, expected.join("\n" )); | 
| 877 |     } | 
| 878 |  | 
| 879 |     { | 
| 880 |         // WHEN | 
| 881 |         const auto code = generator.createShaderCode(enabledLayers: {"diffuseUniform" , "normalTexture" }); | 
| 882 |  | 
| 883 |         // THEN | 
| 884 |         const auto expected = QByteArrayList() << "#version 400 core"  | 
| 885 |                                                << ""  | 
| 886 |                                                << "#define LAYER_diffuseUniform"  | 
| 887 |                                                << "#define LAYER_normalTexture"  | 
| 888 |                                                << "in vec2 texCoord;"  | 
| 889 |                                                << "uniform sampler2D normalTexture;"  | 
| 890 |                                                << "uniform vec4 diffuseUniform;"  | 
| 891 |                                                << "#pragma include gl4/lightmodel.frag.inc"  | 
| 892 |                                                << "out vec4 fragColor;"  | 
| 893 |                                                << ""  | 
| 894 |                                                << "void main()"  | 
| 895 |                                                << "{"  | 
| 896 |                                                << "    fragColor = ((lightModel(diffuseUniform, "  | 
| 897 |                                                   "texture2D(normalTexture, texCoord).rgb)));"  | 
| 898 |                                                << "}"  | 
| 899 |                                                << "" ; | 
| 900 |         QCOMPARE(code, expected.join("\n" )); | 
| 901 |     } | 
| 902 |  | 
| 903 |     { | 
| 904 |         // WHEN | 
| 905 |         const auto code = generator.createShaderCode(enabledLayers: {"diffuseTexture" , "normalUniform" }); | 
| 906 |  | 
| 907 |         // THEN | 
| 908 |         const auto expected = QByteArrayList() | 
| 909 |                 << "#version 400 core"  | 
| 910 |                 << ""  | 
| 911 |                 << "#define LAYER_diffuseTexture"  | 
| 912 |                 << "#define LAYER_normalUniform"  | 
| 913 |                 << "in vec2 texCoord;"  | 
| 914 |                 << "uniform vec3 normalUniform;"  | 
| 915 |                 << "uniform sampler2D diffuseTexture;"  | 
| 916 |                 << "#pragma include gl4/lightmodel.frag.inc"  | 
| 917 |                 << "out vec4 fragColor;"  | 
| 918 |                 << ""  | 
| 919 |                 << "void main()"  | 
| 920 |                 << "{"  | 
| 921 |                 << "    fragColor = ((lightModel(texture2D(diffuseTexture, texCoord), "  | 
| 922 |                    "normalUniform)));"  | 
| 923 |                 << "}"  | 
| 924 |                 << "" ; | 
| 925 |         QCOMPARE(code, expected.join("\n" )); | 
| 926 |     } | 
| 927 |  | 
| 928 |     { | 
| 929 |         // WHEN | 
| 930 |         const auto code = generator.createShaderCode(enabledLayers: {"diffuseTexture" , "normalTexture" }); | 
| 931 |  | 
| 932 |         // THEN | 
| 933 |         const auto expected = QByteArrayList() | 
| 934 |                 << "#version 400 core"  | 
| 935 |                 << ""  | 
| 936 |                 << "#define LAYER_diffuseTexture"  | 
| 937 |                 << "#define LAYER_normalTexture"  | 
| 938 |                 << "in vec2 texCoord;"  | 
| 939 |                 << "uniform sampler2D normalTexture;"  | 
| 940 |                 << "uniform sampler2D diffuseTexture;"  | 
| 941 |                 << "#pragma include gl4/lightmodel.frag.inc"  | 
| 942 |                 << "out vec4 fragColor;"  | 
| 943 |                 << ""  | 
| 944 |                 << "void main()"  | 
| 945 |                 << "{"  | 
| 946 |                 << "    fragColor = ((lightModel(texture2D(diffuseTexture, texCoord), "  | 
| 947 |                    "texture2D(normalTexture, texCoord).rgb)));"  | 
| 948 |                 << "}"  | 
| 949 |                 << "" ; | 
| 950 |         QCOMPARE(code, expected.join("\n" )); | 
| 951 |     } | 
| 952 | } | 
| 953 |  | 
| 954 | void tst_QShaderGenerator::shouldUseGlobalVariableRatherThanTemporaries() | 
| 955 | { | 
| 956 |     // GIVEN | 
| 957 |     const auto gl4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0); | 
| 958 |  | 
| 959 |     { | 
| 960 |         // WHEN | 
| 961 |         auto vertexPosition = createNode(ports: { | 
| 962 |                                              createPort(portDirection: QShaderNodePort::Output, portName: "vertexPosition" ) | 
| 963 |                                          }); | 
| 964 |         vertexPosition.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $vertexPosition = vertexPosition;" , | 
| 965 |                                                       QByteArrayList() << "in vec4 vertexPosition;" )); | 
| 966 |  | 
| 967 |         auto fakeMultiPlyNoSpace = createNode(ports: { | 
| 968 |                                                   createPort(portDirection: QShaderNodePort::Input, portName: "varName" ), | 
| 969 |                                                   createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 970 |                                               }); | 
| 971 |         fakeMultiPlyNoSpace.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = $varName*speed;" )); | 
| 972 |  | 
| 973 |         auto fakeMultiPlySpace = createNode(ports: { | 
| 974 |                                                   createPort(portDirection: QShaderNodePort::Input, portName: "varName" ), | 
| 975 |                                                   createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 976 |                                               }); | 
| 977 |         fakeMultiPlySpace.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = $varName * speed;" )); | 
| 978 |  | 
| 979 |         auto fakeJoinNoSpace = createNode(ports: { | 
| 980 |                                                   createPort(portDirection: QShaderNodePort::Input, portName: "varName" ), | 
| 981 |                                                   createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 982 |                                           }); | 
| 983 |         fakeJoinNoSpace.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = vec4($varName.xyz,$varName.w);" )); | 
| 984 |  | 
| 985 |         auto fakeJoinSpace = createNode(ports: { | 
| 986 |                                               createPort(portDirection: QShaderNodePort::Input, portName: "varName" ), | 
| 987 |                                               createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 988 |                                           }); | 
| 989 |         fakeJoinSpace.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = vec4($varName.xyz, $varName.w);" )); | 
| 990 |  | 
| 991 |         auto fakeAdd = createNode(ports: { | 
| 992 |                                             createPort(portDirection: QShaderNodePort::Input, portName: "varName" ), | 
| 993 |                                             createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 994 |                                         }); | 
| 995 |         fakeAdd.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = $varName.xyzw + $varName;" )); | 
| 996 |  | 
| 997 |         auto fakeSub = createNode(ports: { | 
| 998 |                                             createPort(portDirection: QShaderNodePort::Input, portName: "varName" ), | 
| 999 |                                             createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 1000 |                                         }); | 
| 1001 |         fakeSub.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = $varName.xyzw - $varName;" )); | 
| 1002 |  | 
| 1003 |         auto fakeDiv = createNode(ports: { | 
| 1004 |                                             createPort(portDirection: QShaderNodePort::Input, portName: "varName" ), | 
| 1005 |                                             createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 1006 |                                         }); | 
| 1007 |         fakeDiv.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = $varName / v0;" )); | 
| 1008 |  | 
| 1009 |         auto fragColor = createNode(ports: { | 
| 1010 |             createPort(portDirection: QShaderNodePort::Input, portName: "input1" ), | 
| 1011 |             createPort(portDirection: QShaderNodePort::Input, portName: "input2" ), | 
| 1012 |             createPort(portDirection: QShaderNodePort::Input, portName: "input3" ), | 
| 1013 |             createPort(portDirection: QShaderNodePort::Input, portName: "input4" ), | 
| 1014 |             createPort(portDirection: QShaderNodePort::Input, portName: "input5" ), | 
| 1015 |             createPort(portDirection: QShaderNodePort::Input, portName: "input6" ), | 
| 1016 |             createPort(portDirection: QShaderNodePort::Input, portName: "input7" ) | 
| 1017 |         }); | 
| 1018 |         fragColor.addRule(format: gl4, rule: QShaderNode::Rule("fragColor = $input1 + $input2 + $input3 + $input4 + $input5 + $input6 + $input7;" , | 
| 1019 |                                                  QByteArrayList() << "out vec4 fragColor;" )); | 
| 1020 |  | 
| 1021 |         const auto graph = [=] { | 
| 1022 |             auto res = QShaderGraph(); | 
| 1023 |  | 
| 1024 |             res.addNode(node: vertexPosition); | 
| 1025 |             res.addNode(node: fakeMultiPlyNoSpace); | 
| 1026 |             res.addNode(node: fakeMultiPlySpace); | 
| 1027 |             res.addNode(node: fakeJoinNoSpace); | 
| 1028 |             res.addNode(node: fakeJoinSpace); | 
| 1029 |             res.addNode(node: fakeAdd); | 
| 1030 |             res.addNode(node: fakeSub); | 
| 1031 |             res.addNode(node: fakeDiv); | 
| 1032 |             res.addNode(node: fragColor); | 
| 1033 |  | 
| 1034 |             res.addEdge(edge: createEdge(sourceUuid: vertexPosition.uuid(), sourceName: "vertexPosition" , targetUuid: fakeMultiPlyNoSpace.uuid(), targetName: "varName" )); | 
| 1035 |             res.addEdge(edge: createEdge(sourceUuid: vertexPosition.uuid(), sourceName: "vertexPosition" , targetUuid: fakeMultiPlySpace.uuid(), targetName: "varName" )); | 
| 1036 |             res.addEdge(edge: createEdge(sourceUuid: vertexPosition.uuid(), sourceName: "vertexPosition" , targetUuid: fakeJoinNoSpace.uuid(), targetName: "varName" )); | 
| 1037 |             res.addEdge(edge: createEdge(sourceUuid: vertexPosition.uuid(), sourceName: "vertexPosition" , targetUuid: fakeJoinSpace.uuid(), targetName: "varName" )); | 
| 1038 |             res.addEdge(edge: createEdge(sourceUuid: vertexPosition.uuid(), sourceName: "vertexPosition" , targetUuid: fakeAdd.uuid(), targetName: "varName" )); | 
| 1039 |             res.addEdge(edge: createEdge(sourceUuid: vertexPosition.uuid(), sourceName: "vertexPosition" , targetUuid: fakeSub.uuid(), targetName: "varName" )); | 
| 1040 |             res.addEdge(edge: createEdge(sourceUuid: vertexPosition.uuid(), sourceName: "vertexPosition" , targetUuid: fakeDiv.uuid(), targetName: "varName" )); | 
| 1041 |             res.addEdge(edge: createEdge(sourceUuid: fakeMultiPlyNoSpace.uuid(), sourceName: "out" , targetUuid: fragColor.uuid(), targetName: "input1" )); | 
| 1042 |             res.addEdge(edge: createEdge(sourceUuid: fakeMultiPlySpace.uuid(), sourceName: "out" , targetUuid: fragColor.uuid(), targetName: "input2" )); | 
| 1043 |             res.addEdge(edge: createEdge(sourceUuid: fakeJoinNoSpace.uuid(), sourceName: "out" , targetUuid: fragColor.uuid(), targetName: "input3" )); | 
| 1044 |             res.addEdge(edge: createEdge(sourceUuid: fakeJoinSpace.uuid(), sourceName: "out" , targetUuid: fragColor.uuid(), targetName: "input4" )); | 
| 1045 |             res.addEdge(edge: createEdge(sourceUuid: fakeAdd.uuid(), sourceName: "out" , targetUuid: fragColor.uuid(), targetName: "input5" )); | 
| 1046 |             res.addEdge(edge: createEdge(sourceUuid: fakeSub.uuid(), sourceName: "out" , targetUuid: fragColor.uuid(), targetName: "input6" )); | 
| 1047 |             res.addEdge(edge: createEdge(sourceUuid: fakeDiv.uuid(), sourceName: "out" , targetUuid: fragColor.uuid(), targetName: "input7" )); | 
| 1048 |  | 
| 1049 |             return res; | 
| 1050 |         }(); | 
| 1051 |  | 
| 1052 |         auto generator = QShaderGenerator(); | 
| 1053 |         generator.graph = graph; | 
| 1054 |         generator.format = gl4; | 
| 1055 |  | 
| 1056 |         const auto code = generator.createShaderCode(enabledLayers: {"diffuseUniform" , "normalUniform" }); | 
| 1057 |  | 
| 1058 |         // THEN | 
| 1059 |         const auto expected = QByteArrayList() | 
| 1060 |                 << "#version 400 core"  | 
| 1061 |                 << ""  | 
| 1062 |                 << "#define LAYER_diffuseUniform"  | 
| 1063 |                 << "#define LAYER_normalUniform"  | 
| 1064 |                 << "in vec4 vertexPosition;"  | 
| 1065 |                 << "out vec4 fragColor;"  | 
| 1066 |                 << ""  | 
| 1067 |                 << "void main()"  | 
| 1068 |                 << "{"  | 
| 1069 |                 << "    fragColor = (((((((vertexPosition*speed + vertexPosition * speed + ((vec4(vertexPosition.xyz,vertexPosition.w))) + ((vec4(vertexPosition.xyz, vertexPosition.w))) + ((vertexPosition.xyzw + vertexPosition)) + ((vertexPosition.xyzw - vertexPosition)) + ((vertexPosition / vertexPosition)))))))));"  | 
| 1070 |                 << "}"  | 
| 1071 |                 << "" ; | 
| 1072 |         QCOMPARE(code, expected.join("\n" )); | 
| 1073 |     } | 
| 1074 | } | 
| 1075 |  | 
| 1076 | void tst_QShaderGenerator::shouldGenerateTemporariesWisely() | 
| 1077 | { | 
| 1078 |     // GIVEN | 
| 1079 |     const auto gl4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0); | 
| 1080 |  | 
| 1081 |     { | 
| 1082 |         auto attribute = createNode(ports: { | 
| 1083 |                                         createPort(portDirection: QShaderNodePort::Output, portName: "vertexPosition" ) | 
| 1084 |                                     }); | 
| 1085 |         attribute.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $vertexPosition = vertexPosition;" , | 
| 1086 |                                                  QByteArrayList() << "in vec4 vertexPosition;" )); | 
| 1087 |  | 
| 1088 |         auto complexFunction = createNode(ports: { | 
| 1089 |                                               createPort(portDirection: QShaderNodePort::Input, portName: "inputVarName" ), | 
| 1090 |                                               createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 1091 |                                           }); | 
| 1092 |         complexFunction.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = $inputVarName * 2.0;" )); | 
| 1093 |  | 
| 1094 |         auto complexFunction2 = createNode(ports: { | 
| 1095 |                                               createPort(portDirection: QShaderNodePort::Input, portName: "inputVarName" ), | 
| 1096 |                                               createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 1097 |                                           }); | 
| 1098 |         complexFunction2.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = $inputVarName * 4.0;" )); | 
| 1099 |  | 
| 1100 |         auto complexFunction3 = createNode(ports: { | 
| 1101 |                                                createPort(portDirection: QShaderNodePort::Input, portName: "a" ), | 
| 1102 |                                                createPort(portDirection: QShaderNodePort::Input, portName: "b" ), | 
| 1103 |                                                createPort(portDirection: QShaderNodePort::Output, portName: "out" ) | 
| 1104 |                                            }); | 
| 1105 |         complexFunction3.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $out = $a + $b;" )); | 
| 1106 |  | 
| 1107 |         auto shaderOutput1 = createNode(ports: { | 
| 1108 |                                             createPort(portDirection: QShaderNodePort::Input, portName: "input" ) | 
| 1109 |                                         }); | 
| 1110 |  | 
| 1111 |         shaderOutput1.addRule(format: gl4, rule: QShaderNode::Rule("shaderOutput1 = $input;" , | 
| 1112 |                                                      QByteArrayList() << "out vec4 shaderOutput1;" )); | 
| 1113 |  | 
| 1114 |         auto shaderOutput2 = createNode(ports: { | 
| 1115 |                                             createPort(portDirection: QShaderNodePort::Input, portName: "input" ) | 
| 1116 |                                         }); | 
| 1117 |  | 
| 1118 |         shaderOutput2.addRule(format: gl4, rule: QShaderNode::Rule("shaderOutput2 = $input;" , | 
| 1119 |                                                      QByteArrayList() << "out vec4 shaderOutput2;" )); | 
| 1120 |  | 
| 1121 |         { | 
| 1122 |             // WHEN | 
| 1123 |             const auto graph = [=] { | 
| 1124 |                 auto res = QShaderGraph(); | 
| 1125 |  | 
| 1126 |                 res.addNode(node: attribute); | 
| 1127 |                 res.addNode(node: complexFunction); | 
| 1128 |                 res.addNode(node: shaderOutput1); | 
| 1129 |  | 
| 1130 |                 res.addEdge(edge: createEdge(sourceUuid: attribute.uuid(), sourceName: "vertexPosition" , targetUuid: complexFunction.uuid(), targetName: "inputVarName" )); | 
| 1131 |                 res.addEdge(edge: createEdge(sourceUuid: complexFunction.uuid(), sourceName: "out" , targetUuid: shaderOutput1.uuid(), targetName: "input" )); | 
| 1132 |  | 
| 1133 |                 return res; | 
| 1134 |             }(); | 
| 1135 |  | 
| 1136 |             auto generator = QShaderGenerator(); | 
| 1137 |             generator.graph = graph; | 
| 1138 |             generator.format = gl4; | 
| 1139 |  | 
| 1140 |             const auto code = generator.createShaderCode(); | 
| 1141 |  | 
| 1142 |             // THEN | 
| 1143 |             const auto expected = QByteArrayList() | 
| 1144 |                     << "#version 400 core"  | 
| 1145 |                     << ""  | 
| 1146 |                     << "in vec4 vertexPosition;"  | 
| 1147 |                     << "out vec4 shaderOutput1;"  | 
| 1148 |                     << ""  | 
| 1149 |                     << "void main()"  | 
| 1150 |                     << "{"  | 
| 1151 |                     << "    shaderOutput1 = vertexPosition * 2.0;"  | 
| 1152 |                     << "}"  | 
| 1153 |                     << "" ; | 
| 1154 |             QCOMPARE(code, expected.join("\n" )); | 
| 1155 |         } | 
| 1156 |  | 
| 1157 |         { | 
| 1158 |             // WHEN | 
| 1159 |             const auto graph = [=] { | 
| 1160 |                 auto res = QShaderGraph(); | 
| 1161 |  | 
| 1162 |                 res.addNode(node: attribute); | 
| 1163 |                 res.addNode(node: complexFunction); | 
| 1164 |                 res.addNode(node: shaderOutput1); | 
| 1165 |                 res.addNode(node: shaderOutput2); | 
| 1166 |  | 
| 1167 |                 res.addEdge(edge: createEdge(sourceUuid: attribute.uuid(), sourceName: "vertexPosition" , targetUuid: complexFunction.uuid(), targetName: "inputVarName" )); | 
| 1168 |                 res.addEdge(edge: createEdge(sourceUuid: complexFunction.uuid(), sourceName: "out" , targetUuid: shaderOutput1.uuid(), targetName: "input" )); | 
| 1169 |                 res.addEdge(edge: createEdge(sourceUuid: complexFunction.uuid(), sourceName: "out" , targetUuid: shaderOutput2.uuid(), targetName: "input" )); | 
| 1170 |  | 
| 1171 |                 return res; | 
| 1172 |             }(); | 
| 1173 |  | 
| 1174 |             auto generator = QShaderGenerator(); | 
| 1175 |             generator.graph = graph; | 
| 1176 |             generator.format = gl4; | 
| 1177 |  | 
| 1178 |             const auto code = generator.createShaderCode(); | 
| 1179 |  | 
| 1180 |             // THEN | 
| 1181 |             const auto expected = QByteArrayList() << "#version 400 core"  | 
| 1182 |                                                    << ""  | 
| 1183 |                                                    << "in vec4 vertexPosition;"  | 
| 1184 |                                                    << "out vec4 shaderOutput2;"  | 
| 1185 |                                                    << "out vec4 shaderOutput1;"  | 
| 1186 |                                                    << ""  | 
| 1187 |                                                    << "void main()"  | 
| 1188 |                                                    << "{"  | 
| 1189 |                                                    << "    vec4 v1 = vertexPosition * 2.0;"  | 
| 1190 |                                                    << "    shaderOutput2 = v1;"  | 
| 1191 |                                                    << "    shaderOutput1 = v1;"  | 
| 1192 |                                                    << "}"  | 
| 1193 |                                                    << "" ; | 
| 1194 |             QCOMPARE(code, expected.join("\n" )); | 
| 1195 |         } | 
| 1196 |  | 
| 1197 |         { | 
| 1198 |             // WHEN | 
| 1199 |             const auto graph = [=] { | 
| 1200 |                 auto res = QShaderGraph(); | 
| 1201 |  | 
| 1202 |                 res.addNode(node: attribute); | 
| 1203 |                 res.addNode(node: complexFunction); | 
| 1204 |                 res.addNode(node: complexFunction2); | 
| 1205 |                 res.addNode(node: complexFunction3); | 
| 1206 |                 res.addNode(node: shaderOutput1); | 
| 1207 |                 res.addNode(node: shaderOutput2); | 
| 1208 |  | 
| 1209 |                 res.addEdge(edge: createEdge(sourceUuid: attribute.uuid(), sourceName: "vertexPosition" , targetUuid: complexFunction.uuid(), targetName: "inputVarName" )); | 
| 1210 |                 res.addEdge(edge: createEdge(sourceUuid: attribute.uuid(), sourceName: "vertexPosition" , targetUuid: complexFunction2.uuid(), targetName: "inputVarName" )); | 
| 1211 |  | 
| 1212 |                 res.addEdge(edge: createEdge(sourceUuid: complexFunction.uuid(), sourceName: "out" , targetUuid: complexFunction3.uuid(), targetName: "a" )); | 
| 1213 |                 res.addEdge(edge: createEdge(sourceUuid: complexFunction2.uuid(), sourceName: "out" , targetUuid: complexFunction3.uuid(), targetName: "b" )); | 
| 1214 |  | 
| 1215 |                 res.addEdge(edge: createEdge(sourceUuid: complexFunction3.uuid(), sourceName: "out" , targetUuid: shaderOutput1.uuid(), targetName: "input" )); | 
| 1216 |                 res.addEdge(edge: createEdge(sourceUuid: complexFunction2.uuid(), sourceName: "out" , targetUuid: shaderOutput2.uuid(), targetName: "input" )); | 
| 1217 |  | 
| 1218 |                 return res; | 
| 1219 |             }(); | 
| 1220 |  | 
| 1221 |             auto generator = QShaderGenerator(); | 
| 1222 |             generator.graph = graph; | 
| 1223 |             generator.format = gl4; | 
| 1224 |  | 
| 1225 |             const auto code = generator.createShaderCode(); | 
| 1226 |  | 
| 1227 |             // THEN | 
| 1228 |             const auto expected = QByteArrayList() | 
| 1229 |                     << "#version 400 core"  | 
| 1230 |                     << ""  | 
| 1231 |                     << "in vec4 vertexPosition;"  | 
| 1232 |                     << "out vec4 shaderOutput2;"  | 
| 1233 |                     << "out vec4 shaderOutput1;"  | 
| 1234 |                     << ""  | 
| 1235 |                     << "void main()"  | 
| 1236 |                     << "{"  | 
| 1237 |                     << "    vec4 v2 = vertexPosition * 4.0;"  | 
| 1238 |                     << "    shaderOutput2 = v2;"  | 
| 1239 |                     << "    shaderOutput1 = (vertexPosition * 2.0 + v2);"  | 
| 1240 |                     << "}"  | 
| 1241 |                     << "" ; | 
| 1242 |             QCOMPARE(code, expected.join("\n" )); | 
| 1243 |         } | 
| 1244 |     } | 
| 1245 | } | 
| 1246 |  | 
| 1247 | void tst_QShaderGenerator::shouldHandlePortNamesPrefixingOneAnother() | 
| 1248 | { | 
| 1249 |     // GIVEN | 
| 1250 |     const auto gl4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0); | 
| 1251 |  | 
| 1252 |     auto color1 = createNode(ports: { | 
| 1253 |                                  createPort(portDirection: QShaderNodePort::Output, portName: "output" ) | 
| 1254 |                              }); | 
| 1255 |     color1.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $output = color1;" , | 
| 1256 |                                           QByteArrayList() << "in vec4 color1;" )); | 
| 1257 |  | 
| 1258 |     auto color2 = createNode(ports: { | 
| 1259 |                                  createPort(portDirection: QShaderNodePort::Output, portName: "output" ) | 
| 1260 |                              }); | 
| 1261 |     color2.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $output = color2;" , | 
| 1262 |                                           QByteArrayList() << "in vec4 color2;" )); | 
| 1263 |  | 
| 1264 |     auto addColor = createNode(ports: { | 
| 1265 |                                    createPort(portDirection: QShaderNodePort::Output, portName: "color" ), | 
| 1266 |                                    createPort(portDirection: QShaderNodePort::Input, portName: "color1" ), | 
| 1267 |                                    createPort(portDirection: QShaderNodePort::Input, portName: "color2" ), | 
| 1268 |                                }); | 
| 1269 |     addColor.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $color = $color1 + $color2;" )); | 
| 1270 |  | 
| 1271 |     auto shaderOutput = createNode(ports: { | 
| 1272 |                                        createPort(portDirection: QShaderNodePort::Input, portName: "input" ) | 
| 1273 |                                    }); | 
| 1274 |  | 
| 1275 |     shaderOutput.addRule(format: gl4, rule: QShaderNode::Rule("shaderOutput = $input;" , | 
| 1276 |                                                 QByteArrayList() << "out vec4 shaderOutput;" )); | 
| 1277 |  | 
| 1278 |     // WHEN | 
| 1279 |     const auto graph = [=] { | 
| 1280 |         auto res = QShaderGraph(); | 
| 1281 |  | 
| 1282 |         res.addNode(node: color1); | 
| 1283 |         res.addNode(node: color2); | 
| 1284 |         res.addNode(node: addColor); | 
| 1285 |         res.addNode(node: shaderOutput); | 
| 1286 |  | 
| 1287 |         res.addEdge(edge: createEdge(sourceUuid: color1.uuid(), sourceName: "output" , targetUuid: addColor.uuid(), targetName: "color1" )); | 
| 1288 |         res.addEdge(edge: createEdge(sourceUuid: color2.uuid(), sourceName: "output" , targetUuid: addColor.uuid(), targetName: "color2" )); | 
| 1289 |         res.addEdge(edge: createEdge(sourceUuid: addColor.uuid(), sourceName: "color" , targetUuid: shaderOutput.uuid(), targetName: "input" )); | 
| 1290 |  | 
| 1291 |         return res; | 
| 1292 |     }(); | 
| 1293 |  | 
| 1294 |     auto generator = QShaderGenerator(); | 
| 1295 |     generator.graph = graph; | 
| 1296 |     generator.format = gl4; | 
| 1297 |  | 
| 1298 |     const auto code = generator.createShaderCode(); | 
| 1299 |  | 
| 1300 |     // THEN | 
| 1301 |     const auto expected = QByteArrayList() << "#version 400 core"  | 
| 1302 |                                            << ""  | 
| 1303 |                                            << "in vec4 color2;"  | 
| 1304 |                                            << "in vec4 color1;"  | 
| 1305 |                                            << "out vec4 shaderOutput;"  | 
| 1306 |                                            << ""  | 
| 1307 |                                            << "void main()"  | 
| 1308 |                                            << "{"  | 
| 1309 |                                            << "    shaderOutput = ((color1 + color2));"  | 
| 1310 |                                            << "}"  | 
| 1311 |                                            << "" ; | 
| 1312 |     QCOMPARE(code, expected.join("\n" )); | 
| 1313 | } | 
| 1314 |  | 
| 1315 | void tst_QShaderGenerator::shouldHandleNodesWithMultipleOutputPorts() | 
| 1316 | { | 
| 1317 |     // GIVEN | 
| 1318 |     const auto gl4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0); | 
| 1319 |  | 
| 1320 |     auto input = createNode(ports: { | 
| 1321 |                                 createPort(portDirection: QShaderNodePort::Output, portName: "output0" ), | 
| 1322 |                                 createPort(portDirection: QShaderNodePort::Output, portName: "output1" ) | 
| 1323 |                             }); | 
| 1324 |     input.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $output0 = globalIn0;"  | 
| 1325 |                                          "float $output1 = globalIn1;" , | 
| 1326 |                                          QByteArrayList() << "in vec4 globalIn0;"  << "in float globalIn1;" )); | 
| 1327 |  | 
| 1328 |     auto function = createNode(ports: { | 
| 1329 |                                    createPort(portDirection: QShaderNodePort::Input, portName: "input0" ), | 
| 1330 |                                    createPort(portDirection: QShaderNodePort::Input, portName: "input1" ), | 
| 1331 |                                    createPort(portDirection: QShaderNodePort::Output, portName: "output0" ), | 
| 1332 |                                    createPort(portDirection: QShaderNodePort::Output, portName: "output1" ) | 
| 1333 |                                }); | 
| 1334 |     function.addRule(format: gl4, rule: QShaderNode::Rule("vec4 $output0 = $input0;"  | 
| 1335 |                                             "float $output1 = $input1;" )); | 
| 1336 |  | 
| 1337 |     auto output = createNode(ports: { | 
| 1338 |                                  createPort(portDirection: QShaderNodePort::Input, portName: "input0" ), | 
| 1339 |                                  createPort(portDirection: QShaderNodePort::Input, portName: "input1" ) | 
| 1340 |                              }); | 
| 1341 |  | 
| 1342 |     output.addRule(format: gl4, rule: QShaderNode::Rule("globalOut0 = $input0;"  | 
| 1343 |                                           "globalOut1 = $input1;" , | 
| 1344 |                                           QByteArrayList() << "out vec4 globalOut0;"  << "out float globalOut1;" )); | 
| 1345 |  | 
| 1346 |     // WHEN | 
| 1347 |     const auto graph = [=] { | 
| 1348 |         auto res = QShaderGraph(); | 
| 1349 |  | 
| 1350 |         res.addNode(node: input); | 
| 1351 |         res.addNode(node: function); | 
| 1352 |         res.addNode(node: output); | 
| 1353 |  | 
| 1354 |         res.addEdge(edge: createEdge(sourceUuid: input.uuid(), sourceName: "output0" , targetUuid: function.uuid(), targetName: "input0" )); | 
| 1355 |         res.addEdge(edge: createEdge(sourceUuid: input.uuid(), sourceName: "output1" , targetUuid: function.uuid(), targetName: "input1" )); | 
| 1356 |  | 
| 1357 |         res.addEdge(edge: createEdge(sourceUuid: function.uuid(), sourceName: "output0" , targetUuid: output.uuid(), targetName: "input0" )); | 
| 1358 |         res.addEdge(edge: createEdge(sourceUuid: function.uuid(), sourceName: "output1" , targetUuid: output.uuid(), targetName: "input1" )); | 
| 1359 |  | 
| 1360 |         return res; | 
| 1361 |     }(); | 
| 1362 |  | 
| 1363 |     auto generator = QShaderGenerator(); | 
| 1364 |     generator.graph = graph; | 
| 1365 |     generator.format = gl4; | 
| 1366 |  | 
| 1367 |     const auto code = generator.createShaderCode(); | 
| 1368 |  | 
| 1369 |     // THEN | 
| 1370 |     const auto expected = QByteArrayList() | 
| 1371 |             << "#version 400 core"  | 
| 1372 |             << ""  | 
| 1373 |             << "in vec4 globalIn0;"  | 
| 1374 |             << "in float globalIn1;"  | 
| 1375 |             << "out vec4 globalOut0;"  | 
| 1376 |             << "out float globalOut1;"  | 
| 1377 |             << ""  | 
| 1378 |             << "void main()"  | 
| 1379 |             << "{"  | 
| 1380 |             << "    globalOut0 = globalIn0;"  | 
| 1381 |             << "    globalOut1 = globalIn1;"  | 
| 1382 |             << "}"  | 
| 1383 |             << "" ; | 
| 1384 |     QCOMPARE(code, expected.join("\n" )); | 
| 1385 | } | 
| 1386 |  | 
| 1387 | void tst_QShaderGenerator::shouldHandleExpressionsInInputNodes() | 
| 1388 | { | 
| 1389 |     // GIVEN | 
| 1390 |     const auto gl4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0); | 
| 1391 |  | 
| 1392 |     auto input = createNode(ports: { | 
| 1393 |                                 createPort(portDirection: QShaderNodePort::Output, portName: "output" ) | 
| 1394 |                             }); | 
| 1395 |     input.addRule(format: gl4, rule: QShaderNode::Rule("float $output = 3 + 4;" )); | 
| 1396 |  | 
| 1397 |     auto output = createNode(ports: { | 
| 1398 |                                  createPort(portDirection: QShaderNodePort::Input, portName: "input" ) | 
| 1399 |                              }); | 
| 1400 |  | 
| 1401 |     output.addRule(format: gl4, rule: QShaderNode::Rule("globalOut = $input;" , | 
| 1402 |                                           QByteArrayList() << "out float globalOut;" )); | 
| 1403 |  | 
| 1404 |     // WHEN | 
| 1405 |     const auto graph = [=] { | 
| 1406 |         auto res = QShaderGraph(); | 
| 1407 |  | 
| 1408 |         res.addNode(node: input); | 
| 1409 |         res.addNode(node: output); | 
| 1410 |  | 
| 1411 |         res.addEdge(edge: createEdge(sourceUuid: input.uuid(), sourceName: "output" , targetUuid: output.uuid(), targetName: "input" )); | 
| 1412 |  | 
| 1413 |         return res; | 
| 1414 |     }(); | 
| 1415 |  | 
| 1416 |     auto generator = QShaderGenerator(); | 
| 1417 |     generator.graph = graph; | 
| 1418 |     generator.format = gl4; | 
| 1419 |  | 
| 1420 |     const auto code = generator.createShaderCode(); | 
| 1421 |  | 
| 1422 |     // THEN | 
| 1423 |     const auto expected = QByteArrayList() | 
| 1424 |             << "#version 400 core"  | 
| 1425 |             << ""  | 
| 1426 |             << "out float globalOut;"  | 
| 1427 |             << ""  | 
| 1428 |             << "void main()"  | 
| 1429 |             << "{"  | 
| 1430 |             << "    globalOut = 3 + 4;"  | 
| 1431 |             << "}"  | 
| 1432 |             << "" ; | 
| 1433 |     QCOMPARE(code, expected.join("\n" )); | 
| 1434 | } | 
| 1435 |  | 
| 1436 | void tst_QShaderGenerator::shouldGenerateLayerDefines() | 
| 1437 | { | 
| 1438 |     // GIVEN | 
| 1439 |     const auto gl4 = createFormat(api: QShaderFormat::OpenGLCoreProfile, majorVersion: 4, minorVersion: 0); | 
| 1440 |  | 
| 1441 |     auto generator = QShaderGenerator(); | 
| 1442 |     generator.format = gl4; | 
| 1443 |  | 
| 1444 |     // WHEN | 
| 1445 |     const auto code = generator.createShaderCode(enabledLayers: {"layer1" , "layer2" }); | 
| 1446 |  | 
| 1447 |     // THEN | 
| 1448 |     const auto expected = QByteArrayList() | 
| 1449 |             << "#version 400 core"  | 
| 1450 |             << ""  | 
| 1451 |             << "#define LAYER_layer1"  | 
| 1452 |             << "#define LAYER_layer2"  | 
| 1453 |             << ""  | 
| 1454 |             << "void main()"  | 
| 1455 |             << "{"  | 
| 1456 |             << "}"  | 
| 1457 |             << "" ; | 
| 1458 |     QCOMPARE(code, expected.join("\n" )); | 
| 1459 | } | 
| 1460 |  | 
| 1461 | QTEST_MAIN(tst_QShaderGenerator) | 
| 1462 |  | 
| 1463 | #include "tst_qshadergenerator.moc" | 
| 1464 |  |