1 /****************************************************************************
2 **
3 ** Copyright (C) 2008-2012 NVIDIA Corporation.
4 ** Copyright (C) 2019 The Qt Company Ltd.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of Qt Quick 3D.
8 **
9 ** $QT_BEGIN_LICENSE:GPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU
20 ** General Public License version 3 or (at your option) any later version
21 ** approved by the KDE Free Qt Foundation. The licenses are as published by
22 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
23 ** included in the packaging of this file. Please review the following
24 ** information to ensure the GNU General Public License requirements will
25 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
26 **
27 ** $QT_END_LICENSE$
28 **
29 ****************************************************************************/
30 
31 #include "qssgrendershadercodegenerator_p.h"
32 
33 QT_BEGIN_NAMESPACE
34 
QSSGShaderCodeGeneratorBase(const QSSGRenderContextType & ctxType)35 QSSGShaderCodeGeneratorBase::QSSGShaderCodeGeneratorBase(const QSSGRenderContextType &ctxType)
36     : m_renderContextType(ctxType)
37 {
38 }
39 
40 QSSGShaderCodeGeneratorBase::~QSSGShaderCodeGeneratorBase() = default;
begin()41 void QSSGShaderCodeGeneratorBase::begin()
42 {
43     m_uniforms.clear();
44     getVaryings().clear();
45     m_attributes.clear();
46     m_includes.clear();
47     m_codes.clear();
48     m_finalShaderBuilder.clear();
49     m_codeBuilder.clear();
50     m_constantBuffers.clear();
51     m_constantBufferParams.clear();
52 }
append(const QByteArray & data)53 void QSSGShaderCodeGeneratorBase::append(const QByteArray &data)
54 {
55     m_codeBuilder.append(data);
56     m_codeBuilder.append("\n");
57 }
58 
addUniform(const QByteArray & name,const QByteArray & type)59 void QSSGShaderCodeGeneratorBase::addUniform(const QByteArray &name, const QByteArray &type)
60 {
61     m_uniforms.insert(name, type);
62 }
addConstantBuffer(const QByteArray & name,const QByteArray & layout)63 void QSSGShaderCodeGeneratorBase::addConstantBuffer(const QByteArray &name, const QByteArray &layout)
64 {
65     m_constantBuffers.insert(name, layout);
66 }
addConstantBufferParam(const QByteArray & cbName,const QByteArray & paramName,const QByteArray & type)67 void QSSGShaderCodeGeneratorBase::addConstantBufferParam(const QByteArray &cbName, const QByteArray &paramName, const QByteArray &type)
68 {
69     TParamPair theParamPair(paramName, type);
70     TConstantBufferParamPair theBufferParamPair(cbName, theParamPair);
71     m_constantBufferParams.push_back(theBufferParamPair);
72 }
73 
addAttribute(const QByteArray & name,const QByteArray & type)74 void QSSGShaderCodeGeneratorBase::addAttribute(const QByteArray &name, const QByteArray &type)
75 {
76     m_attributes.insert(name, type);
77 }
78 
addVarying(const QByteArray & name,const QByteArray & type)79 void QSSGShaderCodeGeneratorBase::addVarying(const QByteArray &name, const QByteArray &type)
80 {
81     getVaryings().insert(name, type);
82 }
83 
addLocalVariable(const QByteArray & name,const QByteArray & type,int tabCount)84 void QSSGShaderCodeGeneratorBase::addLocalVariable(const QByteArray &name, const QByteArray &type, int tabCount)
85 {
86     for (; tabCount >= 0; --tabCount)
87         m_codeBuilder.append("    ");
88     m_codeBuilder.append(type);
89     m_codeBuilder.append(" ");
90     m_codeBuilder.append(name);
91     m_codeBuilder.append(";\n");
92 }
93 
addInclude(const QByteArray & name)94 void QSSGShaderCodeGeneratorBase::addInclude(const QByteArray &name)
95 {
96     m_includes.insert(name);
97 }
98 
hasCode(Enum value)99 bool QSSGShaderCodeGeneratorBase::hasCode(Enum value)
100 {
101     return m_codes.contains(value);
102 }
setCode(Enum value)103 void QSSGShaderCodeGeneratorBase::setCode(Enum value)
104 {
105     m_codes.insert(quint32(value));
106 }
107 
setupWorldPosition()108 void QSSGShaderCodeGeneratorBase::setupWorldPosition()
109 {
110     if (!hasCode(WorldPosition)) {
111         setCode(WorldPosition);
112         addUniform("modelMatrix", "mat4");
113         append("    vec3 varWorldPos = (modelMatrix * vec4(attr_pos, 1.0)).xyz;");
114     }
115 }
116 
generateViewVector()117 void QSSGShaderCodeGeneratorBase::generateViewVector()
118 {
119     if (!hasCode(ViewVector)) {
120         setCode(ViewVector);
121         setupWorldPosition();
122         addInclude("viewProperties.glsllib");
123         append("    vec3 view_vector = normalize(cameraPosition - varWorldPos);");
124     }
125 }
126 
generateWorldNormal()127 void QSSGShaderCodeGeneratorBase::generateWorldNormal()
128 {
129     if (!hasCode(WorldNormal)) {
130         setCode(WorldNormal);
131         addAttribute("attr_norm", "vec3");
132         addUniform("normalMatrix", "mat3");
133         append("    vec3 world_normal = normalize(normalMatrix * objectNormal).xyz;");
134     }
135 }
136 
generateEnvMapReflection(QSSGShaderCodeGeneratorBase & inFragmentShader)137 void QSSGShaderCodeGeneratorBase::generateEnvMapReflection(QSSGShaderCodeGeneratorBase &inFragmentShader)
138 {
139     if (!hasCode(EnvMapReflection)) {
140         setCode(EnvMapReflection);
141         setupWorldPosition();
142         generateWorldNormal();
143         addInclude("viewProperties.glsllib");
144         addVarying("var_object_to_camera", "vec3");
145         append("    var_object_to_camera = normalize( varWorldPos - cameraPosition );");
146         // World normal cannot be relied upon in the vertex shader because of bump maps.
147         inFragmentShader.append("    vec3 environment_map_reflection = reflect("
148                                     "vec3(var_object_to_camera.x, var_object_to_camera.y, "
149                                     "var_object_to_camera.z), world_normal.xyz );\n"
150                                 "    environment_map_reflection *= vec3( 0.5, 0.5, 0 );\n"
151                                 "    environment_map_reflection += vec3( 0.5, 0.5, 1.0 );");
152     }
153 }
154 
generateUVCoords()155 void QSSGShaderCodeGeneratorBase::generateUVCoords()
156 {
157     if (!hasCode(UVCoords)) {
158         setCode(UVCoords);
159         addAttribute("attr_uv0", "vec2");
160         append("    vec2 uv_coords = attr_uv0;");
161     }
162 }
163 
generateTextureSwizzle(QSSGRenderTextureSwizzleMode swizzleMode,QByteArray & texSwizzle,QByteArray & lookupSwizzle)164 void QSSGShaderCodeGeneratorBase::generateTextureSwizzle(QSSGRenderTextureSwizzleMode swizzleMode,
165                                                            QByteArray &texSwizzle,
166                                                            QByteArray &lookupSwizzle)
167 {
168     QSSGRenderContextTypes deprecatedContextFlags(QSSGRenderContextType::GL2 | QSSGRenderContextType::GLES2);
169 
170     if (!(deprecatedContextFlags & m_renderContextType)) {
171         switch (swizzleMode) {
172         case QSSGRenderTextureSwizzleMode::L8toR8:
173         case QSSGRenderTextureSwizzleMode::L16toR16:
174             texSwizzle.append(".rgb");
175             lookupSwizzle.append(".rrr");
176             break;
177         case QSSGRenderTextureSwizzleMode::L8A8toRG8:
178             texSwizzle.append(".rgba");
179             lookupSwizzle.append(".rrrg");
180             break;
181         case QSSGRenderTextureSwizzleMode::A8toR8:
182             texSwizzle.append(".a");
183             lookupSwizzle.append(".r");
184             break;
185         default:
186             break;
187         }
188     }
189 }
190 
generateShadedWireframeBase()191 void QSSGShaderCodeGeneratorBase::generateShadedWireframeBase()
192 {
193     // how this all work see
194     // http://developer.download.nvidia.com/SDK/10.5/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf
195     append("// project points to screen space\n"
196            "    vec3 p0 = vec3(viewportMatrix * (gl_in[0].gl_Position / gl_in[0].gl_Position.w));\n"
197            "    vec3 p1 = vec3(viewportMatrix * (gl_in[1].gl_Position / gl_in[1].gl_Position.w));\n"
198            "    vec3 p2 = vec3(viewportMatrix * (gl_in[2].gl_Position / gl_in[2].gl_Position.w));\n"
199            "// compute triangle heights\n"
200            "    float e1 = length(p1 - p2);\n"
201            "    float e2 = length(p2 - p0);\n"
202            "    float e3 = length(p1 - p0);\n"
203            "    float alpha = acos( (e2*e2 + e3*e3 - e1*e1) / (2.0*e2*e3) );\n"
204            "    float beta = acos( (e1*e1 + e3*e3 - e2*e2) / (2.0*e1*e3) );\n"
205            "    float ha = abs( e3 * sin( beta ) );\n"
206            "    float hb = abs( e3 * sin( alpha ) );\n"
207            "    float hc = abs( e2 * sin( alpha ) );\n");
208 }
209 
addShaderItemMap(const QByteArray & itemType,const TStrTableStrMap & itemMap)210 void QSSGShaderCodeGeneratorBase::addShaderItemMap(const QByteArray &itemType, const TStrTableStrMap &itemMap)
211 {
212     m_finalShaderBuilder.append("\n");
213 
214     for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
215         m_finalShaderBuilder.append(itemType);
216         m_finalShaderBuilder.append(" ");
217         m_finalShaderBuilder.append(iter.value());
218         m_finalShaderBuilder.append(" ");
219         m_finalShaderBuilder.append(iter.key());
220         m_finalShaderBuilder.append(";\n");
221     }
222 }
223 
addShaderConstantBufferItemMap(const QByteArray & itemType,const TStrTableStrMap & cbMap,TConstantBufferParamArray cbParamsArray)224 void QSSGShaderCodeGeneratorBase::addShaderConstantBufferItemMap(const QByteArray &itemType,
225                                                                    const TStrTableStrMap &cbMap,
226                                                                    TConstantBufferParamArray cbParamsArray)
227 {
228     m_finalShaderBuilder.append("\n");
229 
230     // iterate over all constant buffers
231     for (TStrTableStrMap::const_iterator iter = cbMap.begin(), end = cbMap.end(); iter != end; ++iter) {
232         m_finalShaderBuilder.append(iter.value());
233         m_finalShaderBuilder.append(" ");
234         m_finalShaderBuilder.append(itemType);
235         m_finalShaderBuilder.append(" ");
236         m_finalShaderBuilder.append(iter.key());
237         m_finalShaderBuilder.append(" {\n");
238         // iterate over all param entries and add match
239         for (TConstantBufferParamArray::const_iterator iter1 = cbParamsArray.begin(), end = cbParamsArray.end(); iter1 != end; ++iter1) {
240             if (iter1->first == iter.key()) {
241                 m_finalShaderBuilder.append(iter1->second.second);
242                 m_finalShaderBuilder.append(" ");
243                 m_finalShaderBuilder.append(iter1->second.first);
244                 m_finalShaderBuilder.append(";\n");
245             }
246         }
247 
248         m_finalShaderBuilder.append("};\n");
249     }
250 }
251 
buildShaderSource()252 QByteArray QSSGShaderCodeGeneratorBase::buildShaderSource()
253 {
254     for (auto iter = m_includes.constBegin(), end = m_includes.constEnd(); iter != end; ++iter) {
255         m_finalShaderBuilder.append("#include \"");
256         m_finalShaderBuilder.append(*iter);
257         m_finalShaderBuilder.append("\"\n");
258     }
259     addShaderItemMap("attribute", m_attributes);
260     addShaderItemMap("uniform", m_uniforms);
261     addShaderConstantBufferItemMap("uniform", m_constantBuffers, m_constantBufferParams);
262     addShaderItemMap("varying", getVaryings());
263     m_finalShaderBuilder.append("\n");
264     m_finalShaderBuilder.append(m_codeBuilder);
265     return m_finalShaderBuilder;
266 }
267 
operator <<(const QByteArray & data)268 QSSGShaderCodeGeneratorBase &QSSGShaderCodeGeneratorBase::operator<<(const QByteArray &data)
269 {
270     m_codeBuilder.append(data);
271     return *this;
272 }
273 
QSSGShaderVertexCodeGenerator(const QSSGRenderContextType & ctxType)274 QSSGShaderVertexCodeGenerator::QSSGShaderVertexCodeGenerator(const QSSGRenderContextType &ctxType)
275     : QSSGShaderCodeGeneratorBase(ctxType)
276 {
277 }
getVaryings()278 TStrTableStrMap &QSSGShaderVertexCodeGenerator::getVaryings()
279 {
280     return m_varyings;
281 }
282 
QSSGShaderTessControlCodeGenerator(QSSGShaderVertexCodeGenerator & vert,const QSSGRenderContextType & ctxType)283 QSSGShaderTessControlCodeGenerator::QSSGShaderTessControlCodeGenerator(QSSGShaderVertexCodeGenerator &vert,
284                                                                            const QSSGRenderContextType &ctxType)
285     : QSSGShaderCodeGeneratorBase(ctxType), m_vertGenerator(vert)
286 {
287 }
288 
289 // overwritten from base
addShaderItemMap(const QByteArray & itemType,const TStrTableStrMap & itemMap)290 void QSSGShaderTessControlCodeGenerator::addShaderItemMap(const QByteArray &itemType, const TStrTableStrMap &itemMap)
291 {
292     QByteArray extVtx("");
293     QByteArray extTC("");
294     QByteArray type(itemType);
295     if (type != QByteArrayLiteral("varying")) {
296         extVtx = "[]";
297         extTC = "TC[]";
298         type = "attribute";
299     }
300 
301     m_finalShaderBuilder.append("\n");
302 
303     for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
304         m_finalShaderBuilder.append(type);
305         m_finalShaderBuilder.append(" ");
306         m_finalShaderBuilder.append(iter.value());
307         m_finalShaderBuilder.append(" ");
308         m_finalShaderBuilder.append(iter.key());
309         m_finalShaderBuilder.append(extVtx);
310         m_finalShaderBuilder.append(";\n");
311     }
312 
313     // if this is varyings write output of tess control shader
314     if (!extVtx.isEmpty()) {
315         m_finalShaderBuilder.append("\n");
316         type = "varying";
317 
318         for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
319             m_finalShaderBuilder.append(type);
320             m_finalShaderBuilder.append(" ");
321             m_finalShaderBuilder.append(iter.value());
322             m_finalShaderBuilder.append(" ");
323             m_finalShaderBuilder.append(iter.key());
324             m_finalShaderBuilder.append(extTC);
325             m_finalShaderBuilder.append(";\n");
326         }
327     }
328 }
getVaryings()329 TStrTableStrMap &QSSGShaderTessControlCodeGenerator::getVaryings()
330 {
331     return m_vertGenerator.m_varyings;
332 }
333 
QSSGShaderTessEvalCodeGenerator(QSSGShaderTessControlCodeGenerator & tc,const QSSGRenderContextType & ctxType)334 QSSGShaderTessEvalCodeGenerator::QSSGShaderTessEvalCodeGenerator(QSSGShaderTessControlCodeGenerator &tc,
335                                                                      const QSSGRenderContextType &ctxType)
336     : QSSGShaderCodeGeneratorBase(ctxType), m_tessControlGenerator(tc), m_hasGeometryStage(false)
337 {
338 }
339 // overwritten from base
addShaderItemMap(const QByteArray & itemType,const TStrTableStrMap & itemMap)340 void QSSGShaderTessEvalCodeGenerator::addShaderItemMap(const QByteArray &itemType, const TStrTableStrMap &itemMap)
341 {
342     QByteArray extTC("");
343     QByteArray extTE("");
344     QByteArray type(itemType);
345     if (type != QByteArrayLiteral("varying")) {
346         extTC = "TC[]";
347         type = "attribute";
348     }
349     if (m_hasGeometryStage) {
350         extTE = "TE";
351     }
352 
353     m_finalShaderBuilder.append("\n");
354 
355     for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
356         m_finalShaderBuilder.append(type);
357         m_finalShaderBuilder.append(" ");
358         m_finalShaderBuilder.append(iter.value());
359         m_finalShaderBuilder.append(" ");
360         m_finalShaderBuilder.append(iter.key());
361         m_finalShaderBuilder.append(extTC);
362         m_finalShaderBuilder.append(";\n");
363     }
364 
365     // if this are varyings write output of tess eval shader
366     if (!extTC.isEmpty()) {
367         m_finalShaderBuilder.append("\n");
368         type = "varying";
369 
370         for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
371             m_finalShaderBuilder.append(type);
372             m_finalShaderBuilder.append(" ");
373             m_finalShaderBuilder.append(iter.value());
374             m_finalShaderBuilder.append(" ");
375             m_finalShaderBuilder.append(iter.key());
376             m_finalShaderBuilder.append(extTE);
377             m_finalShaderBuilder.append(";\n");
378         }
379     }
380 }
getVaryings()381 TStrTableStrMap &QSSGShaderTessEvalCodeGenerator::getVaryings()
382 {
383     return m_tessControlGenerator.m_vertGenerator.getVaryings();
384 }
setGeometryStage(bool hasGeometryStage)385 void QSSGShaderTessEvalCodeGenerator::setGeometryStage(bool hasGeometryStage)
386 {
387     m_hasGeometryStage = hasGeometryStage;
388 }
389 
QSSGShaderGeometryCodeGenerator(QSSGShaderVertexCodeGenerator & vert,const QSSGRenderContextType & ctxType)390 QSSGShaderGeometryCodeGenerator::QSSGShaderGeometryCodeGenerator(QSSGShaderVertexCodeGenerator &vert,
391                                                                      const QSSGRenderContextType &ctxType)
392     : QSSGShaderCodeGeneratorBase(ctxType), m_vertGenerator(vert)
393 {
394 }
395 
396 // overwritten from base
addShaderItemMap(const QByteArray & itemType,const TStrTableStrMap & itemMap)397 void QSSGShaderGeometryCodeGenerator::addShaderItemMap(const QByteArray &itemType, const TStrTableStrMap &itemMap)
398 {
399     QByteArray inExt("");
400     QByteArray type(itemType);
401     if (type != QByteArrayLiteral("varying")) {
402         type = "attribute";
403         if (m_hasTessellationStage)
404             inExt = "TE[]";
405         else
406             inExt = "[]";
407     }
408 
409     m_finalShaderBuilder.append("\n");
410 
411     for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
412         m_finalShaderBuilder.append(type);
413         m_finalShaderBuilder.append(" ");
414         m_finalShaderBuilder.append(iter.value());
415         m_finalShaderBuilder.append(" ");
416         m_finalShaderBuilder.append(iter.key());
417         m_finalShaderBuilder.append(inExt);
418         m_finalShaderBuilder.append(";\n");
419     }
420 
421     // if this are varyings write output of geometry shader
422     if (itemType != QByteArrayLiteral("varying")) {
423         m_finalShaderBuilder.append("\n");
424         type = "varying";
425 
426         for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
427             m_finalShaderBuilder.append(type);
428             m_finalShaderBuilder.append(" ");
429             m_finalShaderBuilder.append(iter.value());
430             m_finalShaderBuilder.append(" ");
431             m_finalShaderBuilder.append(iter.key());
432             m_finalShaderBuilder.append(";\n");
433         }
434     }
435 }
getVaryings()436 TStrTableStrMap &QSSGShaderGeometryCodeGenerator::getVaryings()
437 {
438     return m_vertGenerator.m_varyings;
439 }
setTessellationStage(bool hasTessellationStage)440 void QSSGShaderGeometryCodeGenerator::setTessellationStage(bool hasTessellationStage)
441 {
442     m_hasTessellationStage = hasTessellationStage;
443 }
444 
QSSGShaderFragmentCodeGenerator(QSSGShaderVertexCodeGenerator & vert,const QSSGRenderContextType & ctxType)445 QSSGShaderFragmentCodeGenerator::QSSGShaderFragmentCodeGenerator(QSSGShaderVertexCodeGenerator &vert,
446                                                                      const QSSGRenderContextType &ctxType)
447     : QSSGShaderCodeGeneratorBase(ctxType), m_vertGenerator(vert)
448 {
449 }
getVaryings()450 TStrTableStrMap &QSSGShaderFragmentCodeGenerator::getVaryings()
451 {
452     return m_vertGenerator.m_varyings;
453 }
454 
455 QT_END_NAMESPACE
456