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 ¶mName, 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