1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#ifndef QSSG_RENDER_SHADER_KEY_H
6#define QSSG_RENDER_SHADER_KEY_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtQuick3DUtils/private/qssgdataref_p.h>
20#include <QtQuick3DUtils/private/qssgrenderbasetypes_p.h>
21#include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterial_p.h>
22#include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h>
23
24QT_BEGIN_NAMESPACE
25// We have an ever expanding set of properties we like to hash into one or more 32 bit
26// quantities.
27// Furthermore we would like this set of properties to be convertable to string
28// So the shader cache file itself is somewhat human readable/diagnosable.
29// To do this we create a set of objects that act as properties to the master shader key.
30// These objects are tallied in order to figure out their actual offset into the shader key's
31// data store. They are also run through in order to create the string shader cache key.
32
33struct QSSGShaderKeyPropertyBase
34{
35 QByteArrayView name;
36 quint32 offset;
37 explicit constexpr QSSGShaderKeyPropertyBase(const char *inName = "") : name(inName), offset(0) {}
38 quint32 getOffset() const { return offset; }
39 void setOffset(quint32 of) { offset = of; }
40
41 template<quint32 TBitWidth>
42 quint32 getMaskTemplate() const
43 {
44 quint32 bit = offset % 32;
45 quint32 startValue = (1 << TBitWidth) - 1;
46 quint32 mask = startValue << bit;
47 return mask;
48 }
49
50 quint32 getIdx() const { return offset / 32; }
51
52protected:
53 void internalToString(QByteArray &ioStr, const QByteArrayView &inBuffer) const
54 {
55 ioStr.append(a: name);
56 ioStr.append(c: '=');
57 ioStr.append(a: inBuffer);
58 }
59
60 static void internalToString(QByteArray &ioStr, const QByteArrayView &name, bool inValue)
61 {
62 if (inValue) {
63 ioStr.append(a: name);
64 ioStr.append(c: '=');
65 ioStr.append(a: inValue ? QByteArrayView("true") : QByteArrayView("false"));
66 }
67 }
68 static bool getBoolValue(const QByteArray& str, const QByteArrayView &name)
69 {
70 const int index = str.indexOf(bv: name);
71 if (index < 0)
72 return false;
73 const qsizetype nameLen = name.size();
74 if (str[index + nameLen] != '=')
75 return false;
76 if (str.mid(index: index + nameLen + 1, len: 4) == QByteArrayView("true"))
77 return true;
78 return false;
79 }
80};
81
82struct QSSGShaderKeyBoolean : public QSSGShaderKeyPropertyBase
83{
84 enum {
85 BitWidth = 1,
86 };
87
88 explicit constexpr QSSGShaderKeyBoolean(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {}
89
90 quint32 getMask() const { return getMaskTemplate<BitWidth>(); }
91 void setValue(QSSGDataRef<quint32> inDataStore, bool inValue) const
92 {
93 const qint32 idx = qint32(getIdx());
94 Q_ASSERT(idx >= 0 && idx <= INT32_MAX);
95 Q_ASSERT(inDataStore.size() > idx);
96 quint32 mask = getMask();
97 quint32 &target = inDataStore[idx];
98 if (inValue) {
99 target = target | mask;
100 } else {
101 mask = ~mask;
102 target = target & mask;
103 }
104 }
105
106 bool getValue(QSSGDataView<quint32> inDataStore) const
107 {
108 quint32 idx = getIdx();
109 quint32 mask = getMask();
110 const quint32 &target = inDataStore[idx];
111 return (target & mask) ? true : false;
112 }
113
114 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
115 {
116 bool isHigh = getValue(inDataStore: inKeySet);
117 internalToString(ioStr, name, inValue: isHigh);
118 }
119 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
120 {
121 setValue(inDataStore: inKeySet, inValue: getBoolValue(str: ioStr, name));
122 }
123};
124
125template<quint32 TBitWidth>
126struct QSSGShaderKeyUnsigned : public QSSGShaderKeyPropertyBase
127{
128 enum {
129 BitWidth = TBitWidth,
130 };
131 explicit constexpr QSSGShaderKeyUnsigned(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {}
132 quint32 getMask() const { return getMaskTemplate<BitWidth>(); }
133 void setValue(QSSGDataRef<quint32> inDataStore, quint32 inValue) const
134 {
135 quint32 startValue = (1 << TBitWidth) - 1;
136 // Ensure inValue is within range of bit width.
137 inValue = inValue & startValue;
138 quint32 bit = offset % 32;
139 quint32 mask = getMask();
140 quint32 idx = getIdx();
141 inValue = inValue << bit;
142 quint32 &target = inDataStore[idx];
143 // Get rid of existing value
144 quint32 inverseMask = ~mask;
145 target = target & inverseMask;
146 target = target | inValue;
147 }
148
149 quint32 getValue(QSSGDataView<quint32> inDataStore) const
150 {
151 quint32 idx = getIdx();
152 quint32 bit = offset % 32;
153 quint32 mask = getMask();
154 const quint32 &target = inDataStore[idx];
155
156 quint32 retval = target & mask;
157 retval = retval >> bit;
158 return retval;
159 }
160
161 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
162 {
163 quint32 value = getValue(inDataStore: inKeySet);
164 char buf[64];
165 memset(s: buf, c: 0, n: sizeof (buf));
166 toStr(item: value, buffer: toDataRef(type: buf, count: 64));
167 internalToString(ioStr, buf);
168 }
169
170 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
171 {
172 const qsizetype nameLen = name.size();
173 const qsizetype strOffset = ioStr.indexOf(name);
174 if (strOffset >= 0) {
175 /* The key is stored as name=val */
176 if (ioStr[strOffset + nameLen] != '=')
177 return;
178 const QByteArray s = ioStr.right(n: ioStr.size() - strOffset - nameLen - 1);
179 int i = 0;
180 while (QChar(QLatin1Char(s[i])).isDigit())
181 i++;
182 const quint32 value = s.left(n: i).toInt();
183 setValue(inDataStore: inKeySet, inValue: value);
184 }
185 }
186
187private:
188 static quint32 toStr(quint32 item, QSSGDataRef<char> buffer)
189 {
190 // hope the buffer is big enough...
191 return static_cast<quint32>(::snprintf(s: buffer.begin(), maxlen: buffer.size(), format: "%u", item));
192 }
193};
194
195struct QSSGShaderKeyTextureChannel : public QSSGShaderKeyUnsigned<2>
196{
197 enum TexturChannelBits {
198 R = 0,
199 G = 1,
200 B = 2,
201 A = 3,
202 };
203 explicit QSSGShaderKeyTextureChannel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
204
205 TexturChannelBits getTextureChannel(QSSGDataView<quint32> inKeySet) const
206 {
207 return TexturChannelBits(getValue(inDataStore: inKeySet));
208 }
209
210 void setTextureChannel(TexturChannelBits channel, QSSGDataRef<quint32> inKeySet)
211 {
212 setValue(inDataStore: inKeySet, inValue: quint32(channel));
213 }
214 static constexpr char textureChannelToChar[4] = {
215 'R',
216 'G',
217 'B',
218 'A'
219 };
220 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
221 {
222 ioStr.append(a: name);
223 ioStr.append(c: '=');
224 ioStr.append(c: textureChannelToChar[getTextureChannel(inKeySet)]);
225 }
226 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
227 {
228 const qsizetype nameLen = name.size();
229 const qsizetype strOffset = ioStr.indexOf(bv: name);
230 if (strOffset >= 0) {
231 /* The key is stored as name=ch */
232 if (ioStr[strOffset + nameLen] != '=')
233 return;
234 const char ch = ioStr[strOffset + nameLen + 1];
235 if (ch == 'R')
236 setValue(inDataStore: inKeySet, inValue: TexturChannelBits::R);
237 else if (ch == 'G')
238 setValue(inDataStore: inKeySet, inValue: TexturChannelBits::G);
239 else if (ch == 'B')
240 setValue(inDataStore: inKeySet, inValue: TexturChannelBits::B);
241 else if (ch == 'A')
242 setValue(inDataStore: inKeySet, inValue: TexturChannelBits::A);
243 }
244 }
245};
246
247struct QSSGShaderKeyImageMap : public QSSGShaderKeyUnsigned<6>
248{
249 enum ImageMapBits {
250 Enabled = 1 << 0,
251 EnvMap = 1 << 1,
252 LightProbe = 1 << 2,
253 Identity = 1 << 3,
254 UsesUV1 = 1 << 4,
255 Linear = 1 << 5
256 };
257
258 explicit QSSGShaderKeyImageMap(const char *inName = "") : QSSGShaderKeyUnsigned<6>(inName) {}
259
260 bool getBitValue(ImageMapBits imageBit, QSSGDataView<quint32> inKeySet) const
261 {
262 return (getValue(inDataStore: inKeySet) & imageBit) ? true : false;
263 }
264
265 void setBitValue(ImageMapBits imageBit, bool inValue, QSSGDataRef<quint32> inKeySet)
266 {
267 quint32 theValue = getValue(inDataStore: inKeySet);
268 quint32 mask = imageBit;
269 if (inValue) {
270 theValue = theValue | mask;
271 } else {
272 mask = ~mask;
273 theValue = theValue & mask;
274 }
275 setValue(inDataStore: inKeySet, inValue: theValue);
276 }
277
278 bool isEnabled(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: Enabled, inKeySet); }
279 void setEnabled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: Enabled, inValue: val, inKeySet); }
280
281 bool isEnvMap(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: EnvMap, inKeySet); }
282 void setEnvMap(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: EnvMap, inValue: val, inKeySet); }
283
284 bool isLightProbe(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: LightProbe, inKeySet); }
285 void setLightProbe(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: LightProbe, inValue: val, inKeySet); }
286
287 bool isIdentityTransform(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: Identity, inKeySet); }
288 void setIdentityTransform(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: Identity, inValue: val, inKeySet); }
289
290 bool isUsingUV1(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: UsesUV1, inKeySet); }
291 void setUsesUV1(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: UsesUV1, inValue: val, inKeySet); }
292
293 bool isLinear(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: Linear, inKeySet); }
294 void setLinear(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: Linear, inValue: val, inKeySet); }
295
296 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
297 {
298 ioStr.append(a: name);
299 ioStr.append(a: QByteArrayView("={"));
300 internalToString(ioStr, name: QByteArrayView("enabled"), inValue: isEnabled(inKeySet));
301 ioStr.append(c: ';');
302 internalToString(ioStr, name: QByteArrayView("envMap"), inValue: isEnvMap(inKeySet));
303 ioStr.append(c: ';');
304 internalToString(ioStr, name: QByteArrayView("lightProbe"), inValue: isLightProbe(inKeySet));
305 ioStr.append(c: ';');
306 internalToString(ioStr, name: QByteArrayView("identity"), inValue: isIdentityTransform(inKeySet));
307 ioStr.append(c: ';');
308 internalToString(ioStr, name: QByteArrayView("usesUV1"), inValue: isUsingUV1(inKeySet));
309 ioStr.append(c: ';');
310 internalToString(ioStr, name: QByteArrayView("linear"), inValue: isLinear(inKeySet));
311 ioStr.append(c: '}');
312 }
313};
314
315struct QSSGShaderKeySpecularModel : QSSGShaderKeyUnsigned<2>
316{
317 explicit QSSGShaderKeySpecularModel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
318
319 void setSpecularModel(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialSpecularModel inModel)
320 {
321 setValue(inDataStore: inKeySet, inValue: quint32(inModel));
322 }
323
324 QSSGRenderDefaultMaterial::MaterialSpecularModel getSpecularModel(QSSGDataView<quint32> inKeySet) const
325 {
326 return static_cast<QSSGRenderDefaultMaterial::MaterialSpecularModel>(getValue(inDataStore: inKeySet));
327 }
328
329 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
330 {
331 ioStr.append(a: name);
332 ioStr.append(c: '=');
333 switch (getSpecularModel(inKeySet)) {
334 case QSSGRenderDefaultMaterial::MaterialSpecularModel::KGGX:
335 ioStr.append(a: QByteArrayView("KGGX"));
336 break;
337 case QSSGRenderDefaultMaterial::MaterialSpecularModel::Default:
338 ioStr.append(a: QByteArrayView("Default"));
339 break;
340 }
341 ioStr.append(c: ';');
342 }
343 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
344 {
345 const qsizetype nameLen = name.size();
346 const int strOffset = ioStr.indexOf(bv: name);
347 if (strOffset >= 0) {
348 /* The key is stored as name=specularMode; */
349 if (ioStr[strOffset + nameLen] != '=')
350 return;
351 const int codeOffsetBegin = strOffset + nameLen + 1;
352 int codeOffset = 0;
353 while (ioStr[codeOffsetBegin + codeOffset] != ';')
354 codeOffset++;
355 const QByteArray val = ioStr.mid(index: codeOffsetBegin, len: codeOffset);
356 if (val == QByteArrayView("KGGX"))
357 setSpecularModel(inKeySet, inModel: QSSGRenderDefaultMaterial::MaterialSpecularModel::KGGX);
358 if (val == QByteArrayView("Default"))
359 setSpecularModel(inKeySet, inModel: QSSGRenderDefaultMaterial::MaterialSpecularModel::Default);
360 }
361 }
362};
363
364struct QSSGShaderKeyAlphaMode : QSSGShaderKeyUnsigned<2>
365{
366 explicit QSSGShaderKeyAlphaMode(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
367
368 void setAlphaMode(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode inMode)
369 {
370 setValue(inDataStore: inKeySet, inValue: quint32(inMode));
371 }
372
373 QSSGRenderDefaultMaterial::MaterialAlphaMode getAlphaMode(QSSGDataView<quint32> inKeySet) const
374 {
375 return static_cast<QSSGRenderDefaultMaterial::MaterialAlphaMode>(getValue(inDataStore: inKeySet));
376 }
377
378 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
379 {
380 ioStr.append(a: name);
381 ioStr.append(c: '=');
382 switch (getAlphaMode(inKeySet)) {
383 case QSSGRenderDefaultMaterial::MaterialAlphaMode::Default:
384 ioStr.append(a: QByteArrayView("Default"));
385 break;
386 case QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask:
387 ioStr.append(a: QByteArrayView("Mask"));
388 break;
389 case QSSGRenderDefaultMaterial::MaterialAlphaMode::Blend:
390 ioStr.append(a: QByteArrayView("Blend"));
391 break;
392 case QSSGRenderDefaultMaterial::MaterialAlphaMode::Opaque:
393 ioStr.append(a: QByteArrayView("Opaque"));
394 break;
395 }
396 ioStr.append(c: ';');
397 }
398 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
399 {
400 const qsizetype nameLen = name.size();
401 const qsizetype strOffset = ioStr.indexOf(bv: name);
402 if (strOffset >= 0) {
403 /* The key is stored as name=alphaMode; */
404 if (ioStr[strOffset + nameLen] != '=')
405 return;
406 const int codeOffsetBegin = strOffset + nameLen + 1;
407 int codeOffset = 0;
408 while (ioStr[codeOffsetBegin + codeOffset] != ';')
409 codeOffset++;
410 const QByteArray val = ioStr.mid(index: codeOffsetBegin, len: codeOffset);
411 if (val == QByteArrayView("Default"))
412 setAlphaMode(inKeySet, inMode: QSSGRenderDefaultMaterial::MaterialAlphaMode::Default);
413 if (val == QByteArrayView("Mask"))
414 setAlphaMode(inKeySet, inMode: QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask);
415 if (val == QByteArrayView("Blend"))
416 setAlphaMode(inKeySet, inMode: QSSGRenderDefaultMaterial::MaterialAlphaMode::Blend);
417 if (val == QByteArrayView("Opaque"))
418 setAlphaMode(inKeySet, inMode: QSSGRenderDefaultMaterial::MaterialAlphaMode::Opaque);
419 }
420 }
421};
422
423struct QSSGShaderKeyVertexAttribute : public QSSGShaderKeyUnsigned<9>
424{
425 enum VertexAttributeBits {
426 Position = 1 << 0,
427 Normal = 1 << 1,
428 TexCoord0 = 1 << 2,
429 TexCoord1 = 1 << 3,
430 Tangent = 1 << 4,
431 Binormal = 1 << 5,
432 Color = 1 << 6,
433 JointAndWeight = 1 << 7,
434 TexCoordLightmap = 1 << 8
435 };
436
437 explicit QSSGShaderKeyVertexAttribute(const char *inName = "") : QSSGShaderKeyUnsigned<9>(inName) {}
438
439 bool getBitValue(VertexAttributeBits bit, QSSGDataView<quint32> inKeySet) const
440 {
441 return (getValue(inDataStore: inKeySet) & bit) ? true : false;
442 }
443 void setBitValue(VertexAttributeBits bit, QSSGDataRef<quint32> inKeySet, bool value) const
444 {
445 quint32 v = getValue(inDataStore: inKeySet);
446 v = value ? (v | bit) : (v & ~bit);
447 setValue(inDataStore: inKeySet, inValue: v);
448 }
449
450 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
451 {
452 ioStr.append(a: name);
453 ioStr.append(a: QByteArrayView("={"));
454 internalToString(ioStr, name: QByteArrayView("position"), inValue: getBitValue(bit: Position, inKeySet));
455 ioStr.append(c: ';');
456 internalToString(ioStr, name: QByteArrayView("normal"), inValue: getBitValue(bit: Normal, inKeySet));
457 ioStr.append(c: ';');
458 internalToString(ioStr, name: QByteArrayView("texcoord0"), inValue: getBitValue(bit: TexCoord0, inKeySet));
459 ioStr.append(c: ';');
460 internalToString(ioStr, name: QByteArrayView("texcoord1"), inValue: getBitValue(bit: TexCoord1, inKeySet));
461 ioStr.append(c: ';');
462 internalToString(ioStr, name: QByteArrayView("tangent"), inValue: getBitValue(bit: Tangent, inKeySet));
463 ioStr.append(c: ';');
464 internalToString(ioStr, name: QByteArrayView("binormal"), inValue: getBitValue(bit: Binormal, inKeySet));
465 ioStr.append(c: ';');
466 internalToString(ioStr, name: QByteArrayView("color"), inValue: getBitValue(bit: Color, inKeySet));
467 ioStr.append(c: ';');
468 internalToString(ioStr, name: QByteArrayView("texcoordlightmap"), inValue: getBitValue(bit: TexCoordLightmap, inKeySet));
469 ioStr.append(c: '}');
470 internalToString(ioStr, name: QByteArrayView("joint&weight"), inValue: getBitValue(bit: JointAndWeight, inKeySet));
471 ioStr.append(c: '}');
472 }
473 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
474 {
475 const qsizetype nameLen = name.size();
476 const qsizetype strOffset = ioStr.indexOf(bv: name);
477 if (strOffset >= 0) {
478 /* The key is stored as name={;;;;;;} */
479 if (ioStr[strOffset + nameLen] != '=')
480 return;
481 if (ioStr[strOffset + nameLen + 1] != '{')
482 return;
483 const int codeOffsetBegin = strOffset + nameLen + 2;
484 int codeOffset = 0;
485 while (ioStr[codeOffsetBegin + codeOffset] != '}')
486 codeOffset++;
487 const QByteArray val = ioStr.mid(index: codeOffsetBegin, len: codeOffset);
488 const QVector<QByteArray> list = val.split(sep: ';');
489 if (list.size() != 8)
490 return;
491 setBitValue(bit: Position, inKeySet, value: getBoolValue(str: list[0], name: QByteArrayView("position")));
492 setBitValue(bit: Normal, inKeySet, value: getBoolValue(str: list[1], name: QByteArrayView("normal")));
493 setBitValue(bit: TexCoord0, inKeySet, value: getBoolValue(str: list[2], name: QByteArrayView("texcoord0")));
494 setBitValue(bit: TexCoord1, inKeySet, value: getBoolValue(str: list[3], name: QByteArrayView("texcoord1")));
495 setBitValue(bit: Tangent, inKeySet, value: getBoolValue(str: list[4], name: QByteArrayView("tangent")));
496 setBitValue(bit: Binormal, inKeySet, value: getBoolValue(str: list[5], name: QByteArrayView("binormal")));
497 setBitValue(bit: Color, inKeySet, value: getBoolValue(str: list[6], name: QByteArrayView("color")));
498 setBitValue(bit: TexCoordLightmap, inKeySet, value: getBoolValue(str: list[7], name: QByteArrayView("texcoordlightmap")));
499 }
500 }
501};
502
503struct QSSGShaderDefaultMaterialKeyProperties
504{
505 enum {
506 LightCount = QSSG_MAX_NUM_LIGHTS,
507 };
508 enum {
509 SingleChannelImageCount = 13,
510 };
511 enum ImageMapNames {
512 DiffuseMap = 0,
513 BumpMap,
514 SpecularMap,
515 NormalMap,
516 ClearcoatNormalMap,
517 // single channel images
518 OpacityMap,
519 RoughnessMap,
520 MetalnessMap,
521 OcclusionMap,
522 TranslucencyMap,
523 HeightMap,
524 ClearcoatMap,
525 ClearcoatRoughnessMap,
526 TransmissionMap,
527 ThicknessMap,
528 BaseColorMap,
529 SpecularAmountMap,
530 EmissiveMap,
531
532 ImageMapCount,
533 SingleChannelImagesFirst = OpacityMap
534 };
535 enum ImageChannelNames {
536 OpacityChannel = 0,
537 RoughnessChannel,
538 MetalnessChannel,
539 OcclusionChannel,
540 TranslucencyChannel,
541 HeightChannel,
542 ClearcoatChannel,
543 ClearcoatRoughnessChannel,
544 TransmissionChannel,
545 ThicknessChannel,
546 BaseColorChannel,
547 SpecularAmountChannel,
548 EmissiveChannel,
549 };
550
551 QSSGShaderKeyBoolean m_hasLighting;
552 QSSGShaderKeyBoolean m_hasIbl;
553 QSSGShaderKeyUnsigned<4> m_lightCount;
554 QSSGShaderKeyBoolean m_lightFlags[LightCount];
555 QSSGShaderKeyBoolean m_lightSpotFlags[LightCount];
556 QSSGShaderKeyBoolean m_lightAreaFlags[LightCount];
557 QSSGShaderKeyBoolean m_lightShadowFlags[LightCount];
558 QSSGShaderKeyUnsigned<16> m_lightShadowMapSize[LightCount];
559 QSSGShaderKeyUnsigned<4> m_lightSoftShadowQuality[LightCount];
560 QSSGShaderKeyBoolean m_specularEnabled;
561 QSSGShaderKeyBoolean m_fresnelScaleBiasEnabled;
562 QSSGShaderKeyBoolean m_clearcoatFresnelScaleBiasEnabled;
563 QSSGShaderKeyBoolean m_fresnelEnabled;
564 QSSGShaderKeyBoolean m_baseColorSingleChannelEnabled;
565 QSSGShaderKeyBoolean m_specularSingleChannelEnabled;
566 QSSGShaderKeyBoolean m_emissiveSingleChannelEnabled;
567 QSSGShaderKeyBoolean m_invertOpacityMapValue;
568 QSSGShaderKeyBoolean m_vertexColorsEnabled;
569 QSSGShaderKeyBoolean m_vertexColorsMaskEnabled;
570 QSSGShaderKeyUnsigned<16> m_vertexColorRedMask;
571 QSSGShaderKeyUnsigned<16> m_vertexColorGreenMask;
572 QSSGShaderKeyUnsigned<16> m_vertexColorBlueMask;
573 QSSGShaderKeyUnsigned<16> m_vertexColorAlphaMask;
574 QSSGShaderKeySpecularModel m_specularModel;
575 QSSGShaderKeyImageMap m_imageMaps[ImageMapCount];
576 QSSGShaderKeyTextureChannel m_textureChannels[SingleChannelImageCount];
577 QSSGShaderKeyUnsigned<16> m_boneCount;
578 QSSGShaderKeyBoolean m_isDoubleSided;
579 QSSGShaderKeyBoolean m_overridesPosition;
580 QSSGShaderKeyBoolean m_usesProjectionMatrix;
581 QSSGShaderKeyBoolean m_usesInverseProjectionMatrix;
582 QSSGShaderKeyBoolean m_usesPointsTopology;
583 QSSGShaderKeyBoolean m_usesVarColor;
584 QSSGShaderKeyAlphaMode m_alphaMode;
585 QSSGShaderKeyVertexAttribute m_vertexAttributes;
586 QSSGShaderKeyBoolean m_usesFloatJointIndices;
587 qsizetype m_stringBufferSizeHint = 0;
588 QSSGShaderKeyBoolean m_usesInstancing;
589 QSSGShaderKeyUnsigned<8> m_targetCount;
590 QSSGShaderKeyUnsigned<8> m_targetPositionOffset;
591 QSSGShaderKeyUnsigned<8> m_targetNormalOffset;
592 QSSGShaderKeyUnsigned<8> m_targetTangentOffset;
593 QSSGShaderKeyUnsigned<8> m_targetBinormalOffset;
594 QSSGShaderKeyUnsigned<8> m_targetTexCoord0Offset;
595 QSSGShaderKeyUnsigned<8> m_targetTexCoord1Offset;
596 QSSGShaderKeyUnsigned<8> m_targetColorOffset;
597 QSSGShaderKeyBoolean m_blendParticles;
598 QSSGShaderKeyBoolean m_clearcoatEnabled;
599 QSSGShaderKeyBoolean m_transmissionEnabled;
600 QSSGShaderKeyBoolean m_specularAAEnabled;
601 QSSGShaderKeyBoolean m_lightmapEnabled;
602 QSSGShaderKeyBoolean m_specularGlossyEnabled;
603 QSSGShaderKeyUnsigned<4> m_debugMode;
604 QSSGShaderKeyBoolean m_fogEnabled;
605 QSSGShaderKeyUnsigned<3> m_viewCount;
606 QSSGShaderKeyBoolean m_usesViewIndex;
607
608 QSSGShaderDefaultMaterialKeyProperties()
609 : m_hasLighting("hasLighting")
610 , m_hasIbl("hasIbl")
611 , m_lightCount("lightCount")
612 , m_specularEnabled("specularEnabled")
613 , m_fresnelEnabled("fresnelEnabled")
614 , m_baseColorSingleChannelEnabled("baseColorSingleChannelEnabled")
615 , m_specularSingleChannelEnabled("specularSingleChannelEnabled")
616 , m_emissiveSingleChannelEnabled("emissiveSingleChannelEnabled")
617 , m_invertOpacityMapValue("invertOpacityMapValue")
618 , m_vertexColorsEnabled("vertexColorsEnabled")
619 , m_vertexColorsMaskEnabled("vertexColorsMaskEnabled")
620 , m_vertexColorRedMask("vertexColorRedMask")
621 , m_vertexColorGreenMask("vertexColorGreenMask")
622 , m_vertexColorBlueMask("vertexColorBlueMask")
623 , m_vertexColorAlphaMask("vertexColorAlphaMask")
624 , m_specularModel("specularModel")
625 , m_boneCount("boneCount")
626 , m_isDoubleSided("isDoubleSided")
627 , m_overridesPosition("overridesPosition")
628 , m_usesProjectionMatrix("usesProjectionMatrix")
629 , m_usesInverseProjectionMatrix("usesInverseProjectionMatrix")
630 , m_usesPointsTopology("usesPointsTopology")
631 , m_usesVarColor("usesVarColor")
632 , m_alphaMode("alphaMode")
633 , m_vertexAttributes("vertexAttributes")
634 , m_usesFloatJointIndices("usesFloatJointIndices")
635 , m_usesInstancing("usesInstancing")
636 , m_targetCount("targetCount")
637 , m_targetPositionOffset("targetPositionOffset")
638 , m_targetNormalOffset("targetNormalOffset")
639 , m_targetTangentOffset("targetTangentOffset")
640 , m_targetBinormalOffset("targetBinormalOffset")
641 , m_targetTexCoord0Offset("targetTexCoord0Offset")
642 , m_targetTexCoord1Offset("targetTexCoord1Offset")
643 , m_targetColorOffset("targetColorOffset")
644 , m_blendParticles("blendParticles")
645 , m_clearcoatEnabled("clearcoatEnabled")
646 , m_transmissionEnabled("transmissionEnabled")
647 , m_specularAAEnabled("specularAAEnabled")
648 , m_lightmapEnabled("lightmapEnabled")
649 , m_specularGlossyEnabled("specularGlossyEnabled")
650 , m_debugMode("debugMode")
651 , m_fogEnabled("fogEnabled")
652 , m_viewCount("viewCount")
653 , m_usesViewIndex("usesViewIndex")
654 {
655 m_lightFlags[0].name = "light0HasPosition";
656 m_lightFlags[1].name = "light1HasPosition";
657 m_lightFlags[2].name = "light2HasPosition";
658 m_lightFlags[3].name = "light3HasPosition";
659 m_lightFlags[4].name = "light4HasPosition";
660 m_lightFlags[5].name = "light5HasPosition";
661 m_lightFlags[6].name = "light6HasPosition";
662 m_lightFlags[7].name = "light7HasPosition";
663 m_lightFlags[8].name = "light8HasPosition";
664 m_lightFlags[9].name = "light9HasPosition";
665 m_lightFlags[10].name = "light10HasPosition";
666 m_lightFlags[11].name = "light11HasPosition";
667 m_lightFlags[12].name = "light12HasPosition";
668 m_lightFlags[13].name = "light13HasPosition";
669 m_lightFlags[14].name = "light14HasPosition";
670
671 m_lightSpotFlags[0].name = "light0HasSpot";
672 m_lightSpotFlags[1].name = "light1HasSpot";
673 m_lightSpotFlags[2].name = "light2HasSpot";
674 m_lightSpotFlags[3].name = "light3HasSpot";
675 m_lightSpotFlags[4].name = "light4HasSpot";
676 m_lightSpotFlags[5].name = "light5HasSpot";
677 m_lightSpotFlags[6].name = "light6HasSpot";
678 m_lightSpotFlags[7].name = "light7HasSpot";
679 m_lightSpotFlags[8].name = "light8HasSpot";
680 m_lightSpotFlags[9].name = "light9HasSpot";
681 m_lightSpotFlags[10].name = "light10HasSpot";
682 m_lightSpotFlags[11].name = "light11HasSpot";
683 m_lightSpotFlags[12].name = "light12HasSpot";
684 m_lightSpotFlags[13].name = "light13HasSpot";
685 m_lightSpotFlags[14].name = "light14HasSpot";
686
687 m_lightAreaFlags[0].name = "light0HasArea";
688 m_lightAreaFlags[1].name = "light1HasArea";
689 m_lightAreaFlags[2].name = "light2HasArea";
690 m_lightAreaFlags[3].name = "light3HasArea";
691 m_lightAreaFlags[4].name = "light4HasArea";
692 m_lightAreaFlags[5].name = "light5HasArea";
693 m_lightAreaFlags[6].name = "light6HasArea";
694 m_lightAreaFlags[7].name = "light7HasArea";
695 m_lightAreaFlags[8].name = "light8HasArea";
696 m_lightAreaFlags[9].name = "light9HasArea";
697 m_lightAreaFlags[10].name = "light10HasArea";
698 m_lightAreaFlags[11].name = "light11HasArea";
699 m_lightAreaFlags[12].name = "light12HasArea";
700 m_lightAreaFlags[13].name = "light13HasArea";
701 m_lightAreaFlags[14].name = "light14HasArea";
702
703 m_lightShadowFlags[0].name = "light0HasShadow";
704 m_lightShadowFlags[1].name = "light1HasShadow";
705 m_lightShadowFlags[2].name = "light2HasShadow";
706 m_lightShadowFlags[3].name = "light3HasShadow";
707 m_lightShadowFlags[4].name = "light4HasShadow";
708 m_lightShadowFlags[5].name = "light5HasShadow";
709 m_lightShadowFlags[6].name = "light6HasShadow";
710 m_lightShadowFlags[7].name = "light7HasShadow";
711 m_lightShadowFlags[8].name = "light8HasShadow";
712 m_lightShadowFlags[9].name = "light9HasShadow";
713 m_lightShadowFlags[10].name = "light10HasShadow";
714 m_lightShadowFlags[11].name = "light11HasShadow";
715 m_lightShadowFlags[12].name = "light12HasShadow";
716 m_lightShadowFlags[13].name = "light13HasShadow";
717 m_lightShadowFlags[14].name = "light14HasShadow";
718
719 m_lightShadowMapSize[0].name = "light0ShadowMapSize";
720 m_lightShadowMapSize[1].name = "light1ShadowMapSize";
721 m_lightShadowMapSize[2].name = "light2ShadowMapSize";
722 m_lightShadowMapSize[3].name = "light3ShadowMapSize";
723 m_lightShadowMapSize[4].name = "light4ShadowMapSize";
724 m_lightShadowMapSize[5].name = "light5ShadowMapSize";
725 m_lightShadowMapSize[6].name = "light6ShadowMapSize";
726 m_lightShadowMapSize[7].name = "light7ShadowMapSize";
727 m_lightShadowMapSize[8].name = "light8ShadowMapSize";
728 m_lightShadowMapSize[9].name = "light9ShadowMapSize";
729 m_lightShadowMapSize[10].name = "light10ShadowMapSize";
730 m_lightShadowMapSize[11].name = "light11ShadowMapSize";
731 m_lightShadowMapSize[12].name = "light12ShadowMapSize";
732 m_lightShadowMapSize[13].name = "light13ShadowMapSize";
733 m_lightShadowMapSize[14].name = "light14ShadowMapSize";
734
735 m_lightSoftShadowQuality[0].name = "light0SoftShadowQuality";
736 m_lightSoftShadowQuality[1].name = "light1SoftShadowQuality";
737 m_lightSoftShadowQuality[2].name = "light2SoftShadowQuality";
738 m_lightSoftShadowQuality[3].name = "light3SoftShadowQuality";
739 m_lightSoftShadowQuality[4].name = "light4SoftShadowQuality";
740 m_lightSoftShadowQuality[5].name = "light5SoftShadowQuality";
741 m_lightSoftShadowQuality[6].name = "light6SoftShadowQuality";
742 m_lightSoftShadowQuality[7].name = "light7SoftShadowQuality";
743 m_lightSoftShadowQuality[8].name = "light8SoftShadowQuality";
744 m_lightSoftShadowQuality[9].name = "light9SoftShadowQuality";
745 m_lightSoftShadowQuality[10].name = "light10SoftShadowQuality";
746 m_lightSoftShadowQuality[11].name = "light11SoftShadowQuality";
747 m_lightSoftShadowQuality[12].name = "light12SoftShadowQuality";
748 m_lightSoftShadowQuality[13].name = "light13SoftShadowQuality";
749 m_lightSoftShadowQuality[14].name = "light14SoftShadowQuality";
750
751 m_imageMaps[0].name = "diffuseMap";
752 m_imageMaps[1].name = "emissiveMap";
753 m_imageMaps[2].name = "specularMap";
754 m_imageMaps[3].name = "baseColorMap";
755 m_imageMaps[4].name = "bumpMap";
756 m_imageMaps[5].name = "specularAmountMap";
757 m_imageMaps[6].name = "normalMap";
758 m_imageMaps[7].name = "clearcoatNormalMap";
759 m_imageMaps[8].name = "opacityMap";
760 m_imageMaps[9].name = "roughnessMap";
761 m_imageMaps[10].name = "metalnessMap";
762 m_imageMaps[11].name = "occlusionMap";
763 m_imageMaps[12].name = "translucencyMap";
764 m_imageMaps[13].name = "heightMap";
765 m_imageMaps[14].name = "clearcoatMap";
766 m_imageMaps[15].name = "clearcoatRoughnessMap";
767 m_imageMaps[16].name = "transmissionMap";
768 m_imageMaps[17].name = "thicknessMap";
769
770 m_textureChannels[0].name = "opacityMap_channel";
771 m_textureChannels[1].name = "roughnessMap_channel";
772 m_textureChannels[2].name = "metalnessMap_channel";
773 m_textureChannels[3].name = "occlusionMap_channel";
774 m_textureChannels[4].name = "translucencyMap_channel";
775 m_textureChannels[5].name = "heightMap_channel";
776 m_textureChannels[6].name = "clearcoatMap_channel";
777 m_textureChannels[7].name = "clearcoatRoughnessMap_channel";
778 m_textureChannels[8].name = "transmissionMap_channel";
779 m_textureChannels[9].name = "thicknessMap_channel";
780 m_textureChannels[10].name = "baseColorMap_channel";
781 m_textureChannels[11].name = "specularAmountMap_channel";
782
783 init();
784 }
785
786 template<typename TVisitor>
787 void visitProperties(TVisitor &inVisitor)
788 {
789 inVisitor.visit(m_hasLighting);
790 inVisitor.visit(m_hasIbl);
791 inVisitor.visit(m_lightCount);
792
793 for (auto &lightFlag : m_lightFlags)
794 inVisitor.visit(lightFlag);
795
796 for (auto &lightSpotFlag : m_lightSpotFlags)
797 inVisitor.visit(lightSpotFlag);
798
799 for (auto &lightAreaFlag : m_lightAreaFlags)
800 inVisitor.visit(lightAreaFlag);
801
802 for (auto &lightShadowFlag : m_lightShadowFlags)
803 inVisitor.visit(lightShadowFlag);
804
805 for (auto &lightShadowMapSize : m_lightShadowMapSize)
806 inVisitor.visit(lightShadowMapSize);
807
808 for (auto &softShadowQuality : m_lightSoftShadowQuality)
809 inVisitor.visit(softShadowQuality);
810
811 inVisitor.visit(m_specularEnabled);
812 inVisitor.visit(m_fresnelEnabled);
813 inVisitor.visit(m_fresnelScaleBiasEnabled);
814 inVisitor.visit(m_clearcoatFresnelScaleBiasEnabled);
815 inVisitor.visit(m_baseColorSingleChannelEnabled);
816 inVisitor.visit(m_specularSingleChannelEnabled);
817 inVisitor.visit(m_emissiveSingleChannelEnabled);
818 inVisitor.visit(m_invertOpacityMapValue);
819 inVisitor.visit(m_vertexColorsEnabled);
820 inVisitor.visit(m_vertexColorsMaskEnabled);
821 inVisitor.visit(m_vertexColorRedMask);
822 inVisitor.visit(m_vertexColorGreenMask);
823 inVisitor.visit(m_vertexColorBlueMask);
824 inVisitor.visit(m_vertexColorAlphaMask);
825 inVisitor.visit(m_specularModel);
826
827 for (quint32 idx = 0, end = ImageMapCount; idx < end; ++idx)
828 inVisitor.visit(m_imageMaps[idx]);
829
830 for (auto &textureChannel : m_textureChannels)
831 inVisitor.visit(textureChannel);
832
833 inVisitor.visit(m_boneCount);
834 inVisitor.visit(m_isDoubleSided);
835 inVisitor.visit(m_overridesPosition);
836 inVisitor.visit(m_usesProjectionMatrix);
837 inVisitor.visit(m_usesInverseProjectionMatrix);
838 inVisitor.visit(m_usesPointsTopology);
839 inVisitor.visit(m_usesVarColor);
840 inVisitor.visit(m_alphaMode);
841 inVisitor.visit(m_vertexAttributes);
842 inVisitor.visit(m_usesFloatJointIndices);
843 inVisitor.visit(m_usesInstancing);
844 inVisitor.visit(m_targetCount);
845 inVisitor.visit(m_targetPositionOffset);
846 inVisitor.visit(m_targetNormalOffset);
847 inVisitor.visit(m_targetTangentOffset);
848 inVisitor.visit(m_targetBinormalOffset);
849 inVisitor.visit(m_targetTexCoord0Offset);
850 inVisitor.visit(m_targetTexCoord1Offset);
851 inVisitor.visit(m_targetColorOffset);
852 inVisitor.visit(m_blendParticles);
853 inVisitor.visit(m_clearcoatEnabled);
854 inVisitor.visit(m_transmissionEnabled);
855 inVisitor.visit(m_specularAAEnabled);
856 inVisitor.visit(m_lightmapEnabled);
857 inVisitor.visit(m_specularGlossyEnabled);
858 inVisitor.visit(m_debugMode);
859 inVisitor.visit(m_fogEnabled);
860 inVisitor.visit(m_viewCount);
861 inVisitor.visit(m_usesViewIndex);
862 }
863
864 struct OffsetVisitor
865 {
866 quint32 m_offset;
867 OffsetVisitor() : m_offset(0) {}
868 template<typename TPropType>
869 void visit(TPropType &inProp)
870 {
871 // if we cross the 32 bit border we just move
872 // to the next dword.
873 // This cost a few extra bits but prevents tedious errors like
874 // loosing shader key bits because they got moved beyond the 32 border
875 quint32 bit = m_offset % 32;
876 if (bit + TPropType::BitWidth > 32) {
877 m_offset += 32 - bit;
878 }
879
880 inProp.setOffset(m_offset);
881 m_offset += TPropType::BitWidth;
882 }
883 };
884
885 struct StringSizeVisitor
886 {
887 qsizetype size = 0;
888 template<typename P>
889 constexpr void visit(const P &prop)
890 {
891 size += prop.name.size();
892 }
893 };
894
895 struct InitVisitor
896 {
897 OffsetVisitor offsetVisitor;
898 StringSizeVisitor stringSizeVisitor;
899
900 template<typename P>
901 void visit(P &prop)
902 {
903 offsetVisitor.visit(prop);
904 stringSizeVisitor.visit(prop);
905 }
906 };
907
908 void init()
909 {
910 InitVisitor visitor;
911 visitProperties(inVisitor&: visitor);
912
913 // If this assert fires, then the default material key needs more bits.
914 Q_ASSERT(visitor.offsetVisitor.m_offset < 736);
915 // This is so we can do some guestimate of how big the string buffer needs
916 // to be to avoid doing a lot of allocations when concatenating the strings.
917 m_stringBufferSizeHint = visitor.stringSizeVisitor.size;
918 }
919};
920
921struct QSSGShaderDefaultMaterialKey
922{
923 enum {
924 DataBufferSize = 23,
925 };
926 quint32 m_dataBuffer[DataBufferSize]; // 23 * 4 * 8 = 736 bits
927 size_t m_featureSetHash;
928
929 explicit QSSGShaderDefaultMaterialKey(size_t inFeatureSetHash) : m_featureSetHash(inFeatureSetHash)
930 {
931 for (size_t idx = 0; idx < DataBufferSize; ++idx)
932 m_dataBuffer[idx] = 0;
933 }
934
935 QSSGShaderDefaultMaterialKey() : m_featureSetHash(0)
936 {
937 for (size_t idx = 0; idx < DataBufferSize; ++idx)
938 m_dataBuffer[idx] = 0;
939 }
940
941 size_t hash() const
942 {
943 size_t retval = 0;
944 for (size_t idx = 0; idx < DataBufferSize; ++idx)
945 retval = retval ^ qHash(key: m_dataBuffer[idx]);
946 return retval ^ m_featureSetHash;
947 }
948
949 bool operator==(const QSSGShaderDefaultMaterialKey &other) const
950 {
951 bool retval = true;
952 for (size_t idx = 0; idx < DataBufferSize && retval; ++idx)
953 retval = m_dataBuffer[idx] == other.m_dataBuffer[idx];
954 return retval && m_featureSetHash == other.m_featureSetHash;
955 }
956
957 // Cast operators to make getting properties easier.
958 operator QSSGDataRef<quint32>() { return toDataRef(type: m_dataBuffer, count: DataBufferSize); }
959 operator QSSGDataView<quint32>() const { return toDataView(type: m_dataBuffer, count: DataBufferSize); }
960
961 struct StringVisitor
962 {
963 QByteArray &m_str;
964 QSSGDataView<quint32> m_keyStore;
965 StringVisitor(QByteArray &s, QSSGDataView<quint32> ks) : m_str(s), m_keyStore(ks) {}
966 template<typename TPropType>
967 void visit(const TPropType &prop)
968 {
969 const qsizetype originalSize = m_str.size();
970 if (m_str.size())
971 m_str.append(c: ';');
972 prop.toString(m_str, m_keyStore);
973 // if the only thing we added was the semicolon
974 // then nuke the semicolon
975 if (originalSize && m_str.size() == (originalSize + 1))
976 m_str.resize(size: originalSize);
977 }
978 };
979
980 struct StringInVisitor
981 {
982 const QByteArray &m_str;
983 QSSGDataRef<quint32> m_keyStore;
984 StringInVisitor(const QByteArray &s, QSSGDataRef<quint32> ks) : m_str(s), m_keyStore(ks) {}
985
986 template<typename TPropType>
987 void visit(TPropType &prop)
988 {
989 prop.fromString(m_str, m_keyStore);
990 }
991 };
992
993 void toString(QByteArray &ioString, const QSSGShaderDefaultMaterialKeyProperties &inProperties) const
994 {
995 ioString.reserve(asize: inProperties.m_stringBufferSizeHint);
996 StringVisitor theVisitor(ioString, *this);
997 const_cast<QSSGShaderDefaultMaterialKeyProperties &>(inProperties).visitProperties(inVisitor&: theVisitor);
998 }
999 void fromString(QByteArray &ioString, QSSGShaderDefaultMaterialKeyProperties &inProperties)
1000 {
1001 StringInVisitor theVisitor(ioString, *this);
1002 inProperties.visitProperties(inVisitor&: theVisitor);
1003 }
1004 QByteArray toByteArray() const
1005 {
1006 QByteArray ret;
1007 ret.resize(size: sizeof(m_dataBuffer));
1008 memcpy(dest: ret.data(), src: m_dataBuffer, n: sizeof(m_dataBuffer));
1009 return ret;
1010 }
1011 bool fromByteArray(const QByteArray &data) const
1012 {
1013 if (data.size() != sizeof(m_dataBuffer))
1014 return false;
1015 memcpy(dest: (void *)m_dataBuffer, src: data.data(), n: sizeof(m_dataBuffer));
1016 return true;
1017 }
1018};
1019
1020Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGShaderDefaultMaterialKey>::value);
1021
1022
1023inline size_t qHash(const QSSGShaderDefaultMaterialKey &key)
1024{
1025 return key.hash();
1026}
1027
1028QT_END_NAMESPACE
1029
1030#endif
1031

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtquick3d/src/runtimerender/qssgrendershaderkeys_p.h