Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssgrendershaderkeys_p.h
Go to the documentation of this file.
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/qssgrenderlight_p.h>
23#include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h>
24
25QT_BEGIN_NAMESPACE
26// We have an ever expanding set of properties we like to hash into one or more 32 bit
27// quantities.
28// Furthermore we would like this set of properties to be convertable to string
29// So the shader cache file itself is somewhat human readable/diagnosable.
30// To do this we create a set of objects that act as properties to the master shader key.
31// These objects are tallied in order to figure out their actual offset into the shader key's
32// data store. They are also run through in order to create the string shader cache key.
33
34struct QSSGShaderKeyPropertyBase
35{
36 QByteArrayView name;
37 quint32 offset;
38 explicit constexpr QSSGShaderKeyPropertyBase(const char *inName = "") : name(inName), offset(0) {}
39 quint32 getOffset() const { return offset; }
40 void setOffset(quint32 of) { offset = of; }
41
42 template<quint32 TBitWidth>
43 quint32 getMaskTemplate() const
44 {
45 quint32 bit = offset % 32;
46 quint32 startValue = (1 << TBitWidth) - 1;
47 quint32 mask = startValue << bit;
48 return mask;
49 }
50
51 quint32 getIdx() const { return offset / 32; }
52
53protected:
54 void internalToString(QByteArray &ioStr, const QByteArrayView &inBuffer) const
55 {
56 ioStr.append(name);
57 ioStr.append('=');
58 ioStr.append(inBuffer);
59 }
60
61 static void internalToString(QByteArray &ioStr, const QByteArrayView &name, bool inValue)
62 {
63 if (inValue) {
64 ioStr.append(name);
65 ioStr.append('=');
66 ioStr.append(inValue ? QByteArrayView("true") : QByteArrayView("false"));
67 }
68 }
69 static bool getBoolValue(const QByteArray& str, const QByteArrayView &name)
70 {
71 const int index = str.indexOf(name);
72 if (index < 0)
73 return false;
74 const qsizetype nameLen = name.size();
75 if (str[index + nameLen] != '=')
76 return false;
77 if (str.mid(index + nameLen + 1, 4) == QByteArrayView("true"))
78 return true;
79 return false;
80 }
81};
82
83struct QSSGShaderKeyBoolean : public QSSGShaderKeyPropertyBase
84{
85 enum {
87 };
88
89 explicit constexpr QSSGShaderKeyBoolean(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {}
90
91 quint32 getMask() const { return getMaskTemplate<BitWidth>(); }
92 void setValue(QSSGDataRef<quint32> inDataStore, bool inValue) const
93 {
94 const qint32 idx = qint32(getIdx());
95 Q_ASSERT(idx >= 0 && idx <= INT32_MAX);
96 Q_ASSERT(inDataStore.size() > idx);
97 quint32 mask = getMask();
98 quint32 &target = inDataStore[idx];
99 if (inValue) {
100 target = target | mask;
101 } else {
102 mask = ~mask;
103 target = target & mask;
104 }
105 }
106
107 bool getValue(QSSGDataView<quint32> inDataStore) const
108 {
109 quint32 idx = getIdx();
110 quint32 mask = getMask();
111 const quint32 &target = inDataStore[idx];
112 return (target & mask) ? true : false;
113 }
114
115 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
116 {
117 bool isHigh = getValue(inKeySet);
118 internalToString(ioStr, name, isHigh);
119 }
120 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
121 {
122 setValue(inKeySet, getBoolValue(ioStr, name));
123 }
124};
125
126template<quint32 TBitWidth>
127struct QSSGShaderKeyUnsigned : public QSSGShaderKeyPropertyBase
128{
129 enum {
130 BitWidth = TBitWidth,
131 };
132 explicit constexpr QSSGShaderKeyUnsigned(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {}
133 quint32 getMask() const { return getMaskTemplate<BitWidth>(); }
134 void setValue(QSSGDataRef<quint32> inDataStore, quint32 inValue) const
135 {
136 quint32 startValue = (1 << TBitWidth) - 1;
137 // Ensure inValue is within range of bit width.
138 inValue = inValue & startValue;
139 quint32 bit = offset % 32;
140 quint32 mask = getMask();
141 quint32 idx = getIdx();
142 inValue = inValue << bit;
143 quint32 &target = inDataStore[idx];
144 // Get rid of existing value
145 quint32 inverseMask = ~mask;
146 target = target & inverseMask;
147 target = target | inValue;
148 }
149
150 quint32 getValue(QSSGDataView<quint32> inDataStore) const
151 {
152 quint32 idx = getIdx();
153 quint32 bit = offset % 32;
154 quint32 mask = getMask();
155 const quint32 &target = inDataStore[idx];
156
157 quint32 retval = target & mask;
158 retval = retval >> bit;
159 return retval;
160 }
161
162 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
163 {
164 quint32 value = getValue(inKeySet);
165 char buf[64];
166 memset(buf, 0, sizeof (buf));
167 toStr(value, toDataRef(buf, 64));
168 internalToString(ioStr, buf);
169 }
170
171 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
172 {
173 const qsizetype nameLen = name.size();
174 const qsizetype strOffset = ioStr.indexOf(name);
175 if (strOffset >= 0) {
176 /* The key is stored as name=val */
177 if (ioStr[strOffset + nameLen] != '=')
178 return;
179 const QByteArray s = ioStr.right(ioStr.size() - strOffset - nameLen - 1);
180 int i = 0;
181 while (QChar(QLatin1Char(s[i])).isDigit())
182 i++;
183 const quint32 value = s.left(i).toInt();
184 setValue(inKeySet, value);
185 }
186 }
187
188private:
189 static quint32 toStr(quint32 item, QSSGDataRef<char> buffer)
190 {
191 // hope the buffer is big enough...
192 return static_cast<quint32>(::snprintf(buffer.begin(), buffer.size(), "%u", item));
193 }
194};
195
197{
199 R = 0,
200 G = 1,
201 B = 2,
202 A = 3,
203 };
204 explicit QSSGShaderKeyTextureChannel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
205
206 TexturChannelBits getTextureChannel(QSSGDataView<quint32> inKeySet) const
207 {
208 return TexturChannelBits(getValue(inKeySet));
209 }
210
211 void setTextureChannel(TexturChannelBits channel, QSSGDataRef<quint32> inKeySet)
212 {
213 setValue(inKeySet, quint32(channel));
214 }
215 static constexpr char textureChannelToChar[4] = {
216 'R',
217 'G',
218 'B',
219 'A'
220 };
221 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
222 {
223 ioStr.append(name);
224 ioStr.append('=');
225 ioStr.append(textureChannelToChar[getTextureChannel(inKeySet)]);
226 }
227 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
228 {
229 const qsizetype nameLen = name.size();
230 const qsizetype strOffset = ioStr.indexOf(name);
231 if (strOffset >= 0) {
232 /* The key is stored as name=ch */
233 if (ioStr[strOffset + nameLen] != '=')
234 return;
235 const char ch = ioStr[strOffset + nameLen + 1];
236 if (ch == 'R')
237 setValue(inKeySet, TexturChannelBits::R);
238 else if (ch == 'G')
239 setValue(inKeySet, TexturChannelBits::G);
240 else if (ch == 'B')
241 setValue(inKeySet, TexturChannelBits::B);
242 else if (ch == 'A')
243 setValue(inKeySet, TexturChannelBits::A);
244 }
245 }
246};
247
249{
251 Enabled = 1 << 0,
252 EnvMap = 1 << 1,
253 LightProbe = 1 << 2,
254 Identity = 1 << 3,
255 UsesUV1 = 1 << 4,
256 Linear = 1 << 5
257 };
258
259 explicit QSSGShaderKeyImageMap(const char *inName = "") : QSSGShaderKeyUnsigned<6>(inName) {}
260
261 bool getBitValue(ImageMapBits imageBit, QSSGDataView<quint32> inKeySet) const
262 {
263 return (getValue(inKeySet) & imageBit) ? true : false;
264 }
265
266 void setBitValue(ImageMapBits imageBit, bool inValue, QSSGDataRef<quint32> inKeySet)
267 {
268 quint32 theValue = getValue(inKeySet);
269 quint32 mask = imageBit;
270 if (inValue) {
271 theValue = theValue | mask;
272 } else {
273 mask = ~mask;
274 theValue = theValue & mask;
275 }
276 setValue(inKeySet, theValue);
277 }
278
279 bool isEnabled(QSSGDataView<quint32> inKeySet) const { return getBitValue(Enabled, inKeySet); }
280 void setEnabled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(Enabled, val, inKeySet); }
281
282 bool isEnvMap(QSSGDataView<quint32> inKeySet) const { return getBitValue(EnvMap, inKeySet); }
283 void setEnvMap(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(EnvMap, val, inKeySet); }
284
285 bool isLightProbe(QSSGDataView<quint32> inKeySet) const { return getBitValue(LightProbe, inKeySet); }
286 void setLightProbe(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(LightProbe, val, inKeySet); }
287
288 bool isIdentityTransform(QSSGDataView<quint32> inKeySet) const { return getBitValue(Identity, inKeySet); }
289 void setIdentityTransform(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(Identity, val, inKeySet); }
290
291 bool isUsingUV1(QSSGDataView<quint32> inKeySet) const { return getBitValue(UsesUV1, inKeySet); }
292 void setUsesUV1(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(UsesUV1, val, inKeySet); }
293
294 bool isLinear(QSSGDataView<quint32> inKeySet) const { return getBitValue(Linear, inKeySet); }
295 void setLinear(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(Linear, val, inKeySet); }
296
297 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
298 {
299 ioStr.append(name);
300 ioStr.append(QByteArrayView("={"));
301 internalToString(ioStr, QByteArrayView("enabled"), isEnabled(inKeySet));
302 ioStr.append(';');
303 internalToString(ioStr, QByteArrayView("envMap"), isEnvMap(inKeySet));
304 ioStr.append(';');
305 internalToString(ioStr, QByteArrayView("lightProbe"), isLightProbe(inKeySet));
306 ioStr.append(';');
307 internalToString(ioStr, QByteArrayView("identity"), isIdentityTransform(inKeySet));
308 ioStr.append(';');
309 internalToString(ioStr, QByteArrayView("usesUV1"), isUsingUV1(inKeySet));
310 ioStr.append(';');
311 internalToString(ioStr, QByteArrayView("linear"), isLinear(inKeySet));
312 ioStr.append('}');
313 }
314};
315
317{
318 explicit QSSGShaderKeySpecularModel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
319
320 void setSpecularModel(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialSpecularModel inModel)
321 {
322 setValue(inKeySet, quint32(inModel));
323 }
324
326 {
327 return static_cast<QSSGRenderDefaultMaterial::MaterialSpecularModel>(getValue(inKeySet));
328 }
329
330 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
331 {
332 ioStr.append(name);
333 ioStr.append('=');
334 switch (getSpecularModel(inKeySet)) {
335 case QSSGRenderDefaultMaterial::MaterialSpecularModel::SchlickGGX:
336 ioStr.append(QByteArrayView("SchlickGGX"));
337 break;
338 case QSSGRenderDefaultMaterial::MaterialSpecularModel::BlinnPhong:
339 ioStr.append(QByteArrayView("BlinnPhong"));
340 break;
341 }
342 }
343 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
344 {
345 const qsizetype nameLen = name.size();
346 const int strOffset = ioStr.indexOf(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(codeOffsetBegin, codeOffset);
356 if (val == QByteArrayView("SchlickGGX"))
357 setSpecularModel(inKeySet, QSSGRenderDefaultMaterial::MaterialSpecularModel::SchlickGGX);
358 if (val == QByteArrayView("BlinnPhong"))
359 setSpecularModel(inKeySet, QSSGRenderDefaultMaterial::MaterialSpecularModel::BlinnPhong);
360 }
361 }
362};
363
365{
366 explicit QSSGShaderKeyDiffuseModel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
367
368 void setDiffuseModel(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialDiffuseModel inModel)
369 {
370 setValue(inKeySet, quint32(inModel));
371 }
372
374 {
375 return static_cast<QSSGRenderDefaultMaterial::MaterialDiffuseModel>(getValue(inKeySet));
376 }
377
378 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
379 {
380 ioStr.append(name);
381 ioStr.append('=');
382 switch (getDiffuseModel(inKeySet)) {
383 case QSSGRenderDefaultMaterial::MaterialDiffuseModel::Burley:
384 ioStr.append(QByteArrayView("Burley"));
385 break;
386 case QSSGRenderDefaultMaterial::MaterialDiffuseModel::Lambert:
387 ioStr.append(QByteArrayView("Lambert"));
388 break;
389 case QSSGRenderDefaultMaterial::MaterialDiffuseModel::LambertWrap:
390 ioStr.append(QByteArrayView("LambertWrap"));
391 break;
392 }
393 }
394 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
395 {
396 const qsizetype nameLen = name.size();
397 const int strOffset = ioStr.indexOf(name);
398 if (strOffset >= 0) {
399 /* The key is stored as name=specularMode; */
400 if (ioStr[strOffset + nameLen] != '=')
401 return;
402 const int codeOffsetBegin = strOffset + nameLen + 1;
403 int codeOffset = 0;
404 while (ioStr[codeOffsetBegin + codeOffset] != ';')
405 codeOffset++;
406 const QByteArray val = ioStr.mid(codeOffsetBegin, codeOffset);
407 if (val == QByteArrayView("Burley"))
408 setDiffuseModel(inKeySet, QSSGRenderDefaultMaterial::MaterialDiffuseModel::Burley);
409 if (val == QByteArrayView("Lambert"))
410 setDiffuseModel(inKeySet, QSSGRenderDefaultMaterial::MaterialDiffuseModel::Lambert);
411 if (val == QByteArrayView("LambertWrap"))
412 setDiffuseModel(inKeySet, QSSGRenderDefaultMaterial::MaterialDiffuseModel::LambertWrap);
413 }
414 }
415};
416
418{
419 // possible values:
420 // SoftShadowQuality::Hard : 00
421 // SoftShadowQuality::PCF4 : 01
422 // SoftShadowQuality::PCF8 : 10
423 // SoftShadowQuality::PCF16 : 11
424 // All others map to PCF16
425
426 explicit QSSGShaderKeyShadowSoftness(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
427
428 void setShadowSoftness(QSSGDataRef<quint32> inKeySet, QSSGRenderLight::SoftShadowQuality inQuality)
429 {
430 quint32 val = 0;
431 switch (inQuality) {
432 case QSSGRenderLight::SoftShadowQuality::Hard:
433 val = 0;
434 break;
435 case QSSGRenderLight::SoftShadowQuality::PCF4:
436 val = 1;
437 break;
438 case QSSGRenderLight::SoftShadowQuality::PCF8:
439 val = 2;
440 break;
441 case QSSGRenderLight::SoftShadowQuality::PCF16:
442 default:
443 val = 3;
444 break;
445 }
446 setValue(inKeySet, val);
447 }
448
449 QSSGRenderLight::SoftShadowQuality getShadowSoftness(QSSGDataView<quint32> inKeySet) const
450 {
451 quint32 val = getValue(inKeySet);
452 switch (val) {
453 case 0:
454 return QSSGRenderLight::SoftShadowQuality::Hard;
455 case 1:
456 return QSSGRenderLight::SoftShadowQuality::PCF4;
457 case 2:
458 return QSSGRenderLight::SoftShadowQuality::PCF8;
459 case 3:
460 default:
461 return QSSGRenderLight::SoftShadowQuality::PCF16;
462 }
463 }
464
465 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
466 {
467 ioStr.append(name);
468 ioStr.append('=');
469 switch (getShadowSoftness(inKeySet)) {
470 case QSSGRenderLight::SoftShadowQuality::Hard:
471 ioStr.append(QByteArrayView("Hard"));
472 break;
473 case QSSGRenderLight::SoftShadowQuality::PCF4:
474 ioStr.append(QByteArrayView("PCF4"));
475 break;
476 case QSSGRenderLight::SoftShadowQuality::PCF8:
477 ioStr.append(QByteArrayView("PCF8"));
478 break;
479 case QSSGRenderLight::SoftShadowQuality::PCF16:
480 case QSSGRenderLight::SoftShadowQuality::PCF32:
481 case QSSGRenderLight::SoftShadowQuality::PCF64:
482 ioStr.append(QByteArrayView("PCF16"));
483 break;
484 }
485 }
486
487 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
488 {
489 const qsizetype nameLen = name.size();
490 const int strOffset = ioStr.indexOf(name);
491 if (strOffset >= 0) {
492 /* The key is stored as name=shadowSoftness; */
493 if (ioStr[strOffset + nameLen] != '=')
494 return;
495 const int codeOffsetBegin = strOffset + nameLen + 1;
496 int codeOffset = 0;
497 while (ioStr[codeOffsetBegin + codeOffset] != ';')
498 codeOffset++;
499 const QByteArray val = ioStr.mid(codeOffsetBegin, codeOffset);
500 if (val == QByteArrayView("Hard"))
501 setShadowSoftness(inKeySet, QSSGRenderLight::SoftShadowQuality::Hard);
502 if (val == QByteArrayView("PCF4"))
503 setShadowSoftness(inKeySet, QSSGRenderLight::SoftShadowQuality::PCF4);
504 if (val == QByteArrayView("PCF8"))
505 setShadowSoftness(inKeySet, QSSGRenderLight::SoftShadowQuality::PCF8);
506 if (val == QByteArrayView("PCF16"))
507 setShadowSoftness(inKeySet, QSSGRenderLight::SoftShadowQuality::PCF16);
508 }
509 }
510
511};
512
514{
515 explicit QSSGShaderKeyAlphaMode(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
516
517 void setAlphaMode(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode inMode)
518 {
519 setValue(inKeySet, quint32(inMode));
520 }
521
522 QSSGRenderDefaultMaterial::MaterialAlphaMode getAlphaMode(QSSGDataView<quint32> inKeySet) const
523 {
524 return static_cast<QSSGRenderDefaultMaterial::MaterialAlphaMode>(getValue(inKeySet));
525 }
526
527 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
528 {
529 ioStr.append(name);
530 ioStr.append('=');
531 switch (getAlphaMode(inKeySet)) {
532 case QSSGRenderDefaultMaterial::MaterialAlphaMode::Default:
533 ioStr.append(QByteArrayView("Default"));
534 break;
535 case QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask:
536 ioStr.append(QByteArrayView("Mask"));
537 break;
538 case QSSGRenderDefaultMaterial::MaterialAlphaMode::Blend:
539 ioStr.append(QByteArrayView("Blend"));
540 break;
541 case QSSGRenderDefaultMaterial::MaterialAlphaMode::Opaque:
542 ioStr.append(QByteArrayView("Opaque"));
543 break;
544 }
545 }
546 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
547 {
548 const qsizetype nameLen = name.size();
549 const qsizetype strOffset = ioStr.indexOf(name);
550 if (strOffset >= 0) {
551 /* The key is stored as name=alphaMode; */
552 if (ioStr[strOffset + nameLen] != '=')
553 return;
554 const int codeOffsetBegin = strOffset + nameLen + 1;
555 int codeOffset = 0;
556 while (ioStr[codeOffsetBegin + codeOffset] != ';')
557 codeOffset++;
558 const QByteArray val = ioStr.mid(codeOffsetBegin, codeOffset);
559 if (val == QByteArrayView("Default"))
560 setAlphaMode(inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode::Default);
561 if (val == QByteArrayView("Mask"))
562 setAlphaMode(inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask);
563 if (val == QByteArrayView("Blend"))
564 setAlphaMode(inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode::Blend);
565 if (val == QByteArrayView("Opaque"))
566 setAlphaMode(inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode::Opaque);
567 }
568 }
569};
570
572{
574 Position = 1 << 0,
575 Normal = 1 << 1,
576 TexCoord0 = 1 << 2,
577 TexCoord1 = 1 << 3,
578 Tangent = 1 << 4,
579 Binormal = 1 << 5,
580 Color = 1 << 6,
583 };
584
585 explicit QSSGShaderKeyVertexAttribute(const char *inName = "") : QSSGShaderKeyUnsigned<9>(inName) {}
586
587 bool getBitValue(VertexAttributeBits bit, QSSGDataView<quint32> inKeySet) const
588 {
589 return (getValue(inKeySet) & bit) ? true : false;
590 }
591 void setBitValue(VertexAttributeBits bit, QSSGDataRef<quint32> inKeySet, bool value) const
592 {
593 quint32 v = getValue(inKeySet);
594 v = value ? (v | bit) : (v & ~bit);
595 setValue(inKeySet, v);
596 }
597
598 void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const
599 {
600 ioStr.append(name);
601 ioStr.append(QByteArrayView("={"));
602 internalToString(ioStr, QByteArrayView("position"), getBitValue(Position, inKeySet));
603 ioStr.append(';');
604 internalToString(ioStr, QByteArrayView("normal"), getBitValue(Normal, inKeySet));
605 ioStr.append(';');
606 internalToString(ioStr, QByteArrayView("texcoord0"), getBitValue(TexCoord0, inKeySet));
607 ioStr.append(';');
608 internalToString(ioStr, QByteArrayView("texcoord1"), getBitValue(TexCoord1, inKeySet));
609 ioStr.append(';');
610 internalToString(ioStr, QByteArrayView("tangent"), getBitValue(Tangent, inKeySet));
611 ioStr.append(';');
612 internalToString(ioStr, QByteArrayView("binormal"), getBitValue(Binormal, inKeySet));
613 ioStr.append(';');
614 internalToString(ioStr, QByteArrayView("color"), getBitValue(Color, inKeySet));
615 ioStr.append(';');
616 internalToString(ioStr, QByteArrayView("texcoordlightmap"), getBitValue(TexCoordLightmap, inKeySet));
617 ioStr.append(';');
618 internalToString(ioStr, QByteArrayView("joint&weight"), getBitValue(JointAndWeight, inKeySet));
619 ioStr.append('}');
620 }
621 void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet)
622 {
623 const qsizetype nameLen = name.size();
624 const qsizetype strOffset = ioStr.indexOf(name);
625 if (strOffset >= 0) {
626 /* The key is stored as name={;;;;;;} */
627 if (ioStr[strOffset + nameLen] != '=')
628 return;
629 if (ioStr[strOffset + nameLen + 1] != '{')
630 return;
631 const int codeOffsetBegin = strOffset + nameLen + 2;
632 int codeOffset = 0;
633 while (ioStr[codeOffsetBegin + codeOffset] != '}')
634 codeOffset++;
635 const QByteArray val = ioStr.mid(codeOffsetBegin, codeOffset);
636 const QVector<QByteArray> list = val.split(';');
637 if (list.size() != 8)
638 return;
639 setBitValue(Position, inKeySet, getBoolValue(list[0], QByteArrayView("position")));
640 setBitValue(Normal, inKeySet, getBoolValue(list[1], QByteArrayView("normal")));
641 setBitValue(TexCoord0, inKeySet, getBoolValue(list[2], QByteArrayView("texcoord0")));
642 setBitValue(TexCoord1, inKeySet, getBoolValue(list[3], QByteArrayView("texcoord1")));
643 setBitValue(Tangent, inKeySet, getBoolValue(list[4], QByteArrayView("tangent")));
644 setBitValue(Binormal, inKeySet, getBoolValue(list[5], QByteArrayView("binormal")));
645 setBitValue(Color, inKeySet, getBoolValue(list[6], QByteArrayView("color")));
646 setBitValue(TexCoordLightmap, inKeySet, getBoolValue(list[7], QByteArrayView("texcoordlightmap")));
647 }
648 }
649};
650
652{
653 enum {
655 };
695
751
753 : m_hasLighting("hasLighting")
754 , m_hasPunctualLights("hasPunctualLights")
755 , m_hasShadows("hasShadows")
756 , m_hasIbl("hasIbl")
757 , m_specularEnabled("specularEnabled")
758 , m_fresnelScaleBiasEnabled("fresnelScaleBiasEnabled")
759 , m_clearcoatFresnelScaleBiasEnabled("clearcoatFresnelScaleBiasEnabled")
760 , m_fresnelEnabled("fresnelEnabled")
761 , m_baseColorSingleChannelEnabled("baseColorSingleChannelEnabled")
762 , m_specularSingleChannelEnabled("specularSingleChannelEnabled")
763 , m_emissiveSingleChannelEnabled("emissiveSingleChannelEnabled")
764 , m_invertOpacityMapValue("invertOpacityMapValue")
765 , m_vertexColorsEnabled("vertexColorsEnabled")
766 , m_vertexColorsMaskEnabled("vertexColorsMaskEnabled")
767 , m_vertexColorRedMask("vertexColorRedMask")
768 , m_vertexColorGreenMask("vertexColorGreenMask")
769 , m_vertexColorBlueMask("vertexColorBlueMask")
770 , m_vertexColorAlphaMask("vertexColorAlphaMask")
771 , m_specularModel("specularModel")
772 , m_diffuseModel("diffuseModel")
773 , m_boneCount("boneCount")
774 , m_isDoubleSided("isDoubleSided")
775 , m_overridesPosition("overridesPosition")
776 , m_usesProjectionMatrix("usesProjectionMatrix")
777 , m_usesInverseProjectionMatrix("usesInverseProjectionMatrix")
778 , m_usesPointsTopology("usesPointsTopology")
779 , m_usesVarColor("usesVarColor")
780 , m_alphaMode("alphaMode")
781 , m_vertexAttributes("vertexAttributes")
782 , m_usesFloatJointIndices("usesFloatJointIndices")
783 , m_usesInstancing("usesInstancing")
784 , m_targetCount("targetCount")
785 , m_targetPositionOffset("targetPositionOffset")
786 , m_targetNormalOffset("targetNormalOffset")
787 , m_targetTangentOffset("targetTangentOffset")
788 , m_targetBinormalOffset("targetBinormalOffset")
789 , m_targetTexCoord0Offset("targetTexCoord0Offset")
790 , m_targetTexCoord1Offset("targetTexCoord1Offset")
791 , m_targetColorOffset("targetColorOffset")
792 , m_blendParticles("blendParticles")
793 , m_clearcoatEnabled("clearcoatEnabled")
794 , m_transmissionEnabled("transmissionEnabled")
795 , m_specularAAEnabled("specularAAEnabled")
796 , m_lightmapEnabled("lightmapEnabled")
797 , m_specularGlossyEnabled("specularGlossyEnabled")
798 , m_metallicRoughnessEnabled("metallicRoughnessEnabled")
799 , m_debugMode("debugMode")
800 , m_fogEnabled("fogEnabled")
801 , m_viewCount("viewCount")
802 , m_usesViewIndex("usesViewIndex")
803 , m_orderIndependentTransparency("orderIndependentTransparency")
804 , m_shadowSoftness("shadowSoftness")
805 {
806 m_imageMaps[0].name = "diffuseMap";
807 m_imageMaps[1].name = "emissiveMap";
808 m_imageMaps[2].name = "specularMap";
809 m_imageMaps[3].name = "baseColorMap";
810 m_imageMaps[4].name = "bumpMap";
811 m_imageMaps[5].name = "specularAmountMap";
812 m_imageMaps[6].name = "normalMap";
813 m_imageMaps[7].name = "clearcoatNormalMap";
814 m_imageMaps[8].name = "opacityMap";
815 m_imageMaps[9].name = "roughnessMap";
816 m_imageMaps[10].name = "metalnessMap";
817 m_imageMaps[11].name = "occlusionMap";
818 m_imageMaps[12].name = "translucencyMap";
819 m_imageMaps[13].name = "heightMap";
820 m_imageMaps[14].name = "clearcoatMap";
821 m_imageMaps[15].name = "clearcoatRoughnessMap";
822 m_imageMaps[16].name = "transmissionMap";
823 m_imageMaps[17].name = "thicknessMap";
824
825 m_textureChannels[0].name = "opacityMap_channel";
826 m_textureChannels[1].name = "roughnessMap_channel";
827 m_textureChannels[2].name = "metalnessMap_channel";
828 m_textureChannels[3].name = "occlusionMap_channel";
829 m_textureChannels[4].name = "translucencyMap_channel";
830 m_textureChannels[5].name = "heightMap_channel";
831 m_textureChannels[6].name = "clearcoatMap_channel";
832 m_textureChannels[7].name = "clearcoatRoughnessMap_channel";
833 m_textureChannels[8].name = "transmissionMap_channel";
834 m_textureChannels[9].name = "thicknessMap_channel";
835 m_textureChannels[10].name = "baseColorMap_channel";
836 m_textureChannels[11].name = "specularAmountMap_channel";
837 m_textureChannels[12].name = "emissiveMap_channel";
838
839 init();
840 }
841
842 template<typename TVisitor>
843 void visitProperties(TVisitor &inVisitor)
844 {
845 inVisitor.visit(m_hasLighting);
846 inVisitor.visit(m_hasPunctualLights);
847 inVisitor.visit(m_hasShadows);
848 inVisitor.visit(m_hasIbl);
849 inVisitor.visit(m_specularEnabled);
850 inVisitor.visit(m_fresnelEnabled);
851 inVisitor.visit(m_fresnelScaleBiasEnabled);
852 inVisitor.visit(m_clearcoatFresnelScaleBiasEnabled);
853 inVisitor.visit(m_baseColorSingleChannelEnabled);
854 inVisitor.visit(m_specularSingleChannelEnabled);
855 inVisitor.visit(m_emissiveSingleChannelEnabled);
856 inVisitor.visit(m_invertOpacityMapValue);
857 inVisitor.visit(m_vertexColorsEnabled);
858 inVisitor.visit(m_vertexColorsMaskEnabled);
859 inVisitor.visit(m_vertexColorRedMask);
860 inVisitor.visit(m_vertexColorGreenMask);
861 inVisitor.visit(m_vertexColorBlueMask);
862 inVisitor.visit(m_vertexColorAlphaMask);
863 inVisitor.visit(m_specularModel);
864 inVisitor.visit(m_diffuseModel);
865
866 for (quint32 idx = 0, end = ImageMapCount; idx < end; ++idx)
867 inVisitor.visit(m_imageMaps[idx]);
868
869 for (auto &textureChannel : m_textureChannels)
870 inVisitor.visit(textureChannel);
871
872 inVisitor.visit(m_boneCount);
873 inVisitor.visit(m_isDoubleSided);
874 inVisitor.visit(m_overridesPosition);
875 inVisitor.visit(m_usesProjectionMatrix);
876 inVisitor.visit(m_usesInverseProjectionMatrix);
877 inVisitor.visit(m_usesPointsTopology);
878 inVisitor.visit(m_usesVarColor);
879 inVisitor.visit(m_alphaMode);
880 inVisitor.visit(m_vertexAttributes);
881 inVisitor.visit(m_usesFloatJointIndices);
882 inVisitor.visit(m_usesInstancing);
883 inVisitor.visit(m_targetCount);
884 inVisitor.visit(m_targetPositionOffset);
885 inVisitor.visit(m_targetNormalOffset);
886 inVisitor.visit(m_targetTangentOffset);
887 inVisitor.visit(m_targetBinormalOffset);
888 inVisitor.visit(m_targetTexCoord0Offset);
889 inVisitor.visit(m_targetTexCoord1Offset);
890 inVisitor.visit(m_targetColorOffset);
891 inVisitor.visit(m_blendParticles);
892 inVisitor.visit(m_clearcoatEnabled);
893 inVisitor.visit(m_transmissionEnabled);
894 inVisitor.visit(m_specularAAEnabled);
895 inVisitor.visit(m_lightmapEnabled);
896 inVisitor.visit(m_specularGlossyEnabled);
897 inVisitor.visit(m_metallicRoughnessEnabled);
898 inVisitor.visit(m_debugMode);
899 inVisitor.visit(m_fogEnabled);
900 inVisitor.visit(m_viewCount);
901 inVisitor.visit(m_usesViewIndex);
902 inVisitor.visit(m_orderIndependentTransparency);
903 inVisitor.visit(m_shadowSoftness);
904 }
905
907 {
910 template<typename TPropType>
911 void visit(TPropType &inProp)
912 {
913 // if we cross the 32 bit border we just move
914 // to the next dword.
915 // This cost a few extra bits but prevents tedious errors like
916 // loosing shader key bits because they got moved beyond the 32 border
917 quint32 bit = m_offset % 32;
918 if (bit + TPropType::BitWidth > 32) {
919 m_offset += 32 - bit;
920 }
921
922 inProp.setOffset(m_offset);
923 m_offset += TPropType::BitWidth;
924 }
925 };
926
928 {
930 template<typename P>
931 constexpr void visit(const P &prop)
932 {
933 size += prop.name.size();
934 }
935 };
936
938 {
941
942 template<typename P>
943 void visit(P &prop)
944 {
945 offsetVisitor.visit(prop);
946 stringSizeVisitor.visit(prop);
947 }
948 };
949
950 void init()
951 {
952 InitVisitor visitor;
953 visitProperties(visitor);
954
955 // If this assert fires, then the default material key needs more bits.
956 Q_ASSERT(visitor.offsetVisitor.m_offset < 768);
957 // This is so we can do some guestimate of how big the string buffer needs
958 // to be to avoid doing a lot of allocations when concatenating the strings.
959 m_stringBufferSizeHint = visitor.stringSizeVisitor.size;
960 }
961};
962
964{
965 enum {
967 };
968 quint32 m_dataBuffer[DataBufferSize]; // 24 * 4 * 8 = 768 bits
970
972 {
973 for (size_t idx = 0; idx < DataBufferSize; ++idx)
974 m_dataBuffer[idx] = 0;
975 }
976
978 {
979 for (size_t idx = 0; idx < DataBufferSize; ++idx)
980 m_dataBuffer[idx] = 0;
981 }
982
983 size_t hash() const
984 {
985 size_t retval = 0;
986 for (size_t idx = 0; idx < DataBufferSize; ++idx)
987 retval = retval ^ qHash(m_dataBuffer[idx]);
988 return retval ^ m_featureSetHash;
989 }
990
991 bool operator==(const QSSGShaderDefaultMaterialKey &other) const
992 {
993 bool retval = true;
994 for (size_t idx = 0; idx < DataBufferSize && retval; ++idx)
995 retval = m_dataBuffer[idx] == other.m_dataBuffer[idx];
996 return retval && m_featureSetHash == other.m_featureSetHash;
997 }
998
999 // Cast operators to make getting properties easier.
1002
1004 {
1008 template<typename TPropType>
1009 void visit(const TPropType &prop)
1010 {
1011 const qsizetype originalSize = m_str.size();
1012 if (m_str.size())
1013 m_str.append(';');
1015 // if the only thing we added was the semicolon
1016 // then nuke the semicolon
1017 if (originalSize && m_str.size() == (originalSize + 1))
1019 }
1020 };
1021
1023 {
1026 StringInVisitor(const QByteArray &s, QSSGDataRef<quint32> ks) : m_str(s), m_keyStore(ks) {}
1027
1028 template<typename TPropType>
1029 void visit(TPropType &prop)
1030 {
1031 prop.fromString(m_str, m_keyStore);
1032 }
1033 };
1034
1035 void toString(QByteArray &ioString, const QSSGShaderDefaultMaterialKeyProperties &inProperties) const
1036 {
1037 ioString.reserve(inProperties.m_stringBufferSizeHint);
1038 StringVisitor theVisitor(ioString, *this);
1039 const_cast<QSSGShaderDefaultMaterialKeyProperties &>(inProperties).visitProperties(theVisitor);
1040 }
1041 void fromString(QByteArray &ioString, QSSGShaderDefaultMaterialKeyProperties &inProperties)
1042 {
1043 StringInVisitor theVisitor(ioString, *this);
1044 inProperties.visitProperties(theVisitor);
1045 }
1047 {
1048 QByteArray ret;
1049 ret.resize(sizeof(m_dataBuffer));
1050 memcpy(ret.data(), m_dataBuffer, sizeof(m_dataBuffer));
1051 return ret;
1052 }
1053 bool fromByteArray(const QByteArray &data) const
1054 {
1055 if (data.size() != sizeof(m_dataBuffer))
1056 return false;
1057 memcpy((void *)m_dataBuffer, data.data(), sizeof(m_dataBuffer));
1058 return true;
1059 }
1060};
1061
1062Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGShaderDefaultMaterialKey>::value);
1063
1064
1066{
1067 return key.hash();
1068}
1069
1070QT_END_NAMESPACE
1071
1072#endif
size_t qHash(const QSSGShaderDefaultMaterialKey &key)
QSSGShaderKeyUnsigned< 8 > m_targetTexCoord1Offset
QSSGShaderKeyTextureChannel m_textureChannels[SingleChannelImageCount]
QSSGShaderKeyUnsigned< 16 > m_vertexColorAlphaMask
QSSGShaderKeyImageMap m_imageMaps[ImageMapCount]
QSSGShaderKeyUnsigned< 8 > m_targetPositionOffset
QSSGShaderKeyUnsigned< 8 > m_targetTexCoord0Offset
QSSGShaderKeyUnsigned< 16 > m_vertexColorBlueMask
QSSGShaderKeyVertexAttribute m_vertexAttributes
QSSGShaderKeyUnsigned< 8 > m_targetBinormalOffset
QSSGShaderKeyUnsigned< 16 > m_vertexColorGreenMask
QSSGShaderKeyUnsigned< 3 > m_orderIndependentTransparency
QSSGShaderKeyUnsigned< 16 > m_vertexColorRedMask
StringInVisitor(const QByteArray &s, QSSGDataRef< quint32 > ks)
void toString(QByteArray &ioString, const QSSGShaderDefaultMaterialKeyProperties &inProperties) const
quint32 m_dataBuffer[DataBufferSize]
QSSGShaderDefaultMaterialKey(size_t inFeatureSetHash)
bool operator==(const QSSGShaderDefaultMaterialKey &other) const
void fromString(QByteArray &ioString, QSSGShaderDefaultMaterialKeyProperties &inProperties)
bool fromByteArray(const QByteArray &data) const
void toString(QByteArray &ioStr, QSSGDataView< quint32 > inKeySet) const
QSSGRenderDefaultMaterial::MaterialAlphaMode getAlphaMode(QSSGDataView< quint32 > inKeySet) const
QSSGShaderKeyAlphaMode(const char *inName="")
void setAlphaMode(QSSGDataRef< quint32 > inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode inMode)
void fromString(const QByteArray &ioStr, QSSGDataRef< quint32 > inKeySet)
void setValue(QSSGDataRef< quint32 > inDataStore, bool inValue) const
void toString(QByteArray &ioStr, QSSGDataView< quint32 > inKeySet) const
constexpr QSSGShaderKeyBoolean(const char *inName="")
bool getValue(QSSGDataView< quint32 > inDataStore) const
void fromString(const QByteArray &ioStr, QSSGDataRef< quint32 > inKeySet)
QSSGShaderKeyDiffuseModel(const char *inName="")
void setDiffuseModel(QSSGDataRef< quint32 > inKeySet, QSSGRenderDefaultMaterial::MaterialDiffuseModel inModel)
QSSGRenderDefaultMaterial::MaterialDiffuseModel getDiffuseModel(QSSGDataView< quint32 > inKeySet) const
void fromString(const QByteArray &ioStr, QSSGDataRef< quint32 > inKeySet)
void toString(QByteArray &ioStr, QSSGDataView< quint32 > inKeySet) const
void setIdentityTransform(QSSGDataRef< quint32 > inKeySet, bool val)
void setBitValue(ImageMapBits imageBit, bool inValue, QSSGDataRef< quint32 > inKeySet)
void setEnabled(QSSGDataRef< quint32 > inKeySet, bool val)
bool isUsingUV1(QSSGDataView< quint32 > inKeySet) const
QSSGShaderKeyImageMap(const char *inName="")
void toString(QByteArray &ioStr, QSSGDataView< quint32 > inKeySet) const
bool isIdentityTransform(QSSGDataView< quint32 > inKeySet) const
bool isEnabled(QSSGDataView< quint32 > inKeySet) const
bool isLightProbe(QSSGDataView< quint32 > inKeySet) const
void setLinear(QSSGDataRef< quint32 > inKeySet, bool val)
void setUsesUV1(QSSGDataRef< quint32 > inKeySet, bool val)
bool isEnvMap(QSSGDataView< quint32 > inKeySet) const
bool getBitValue(ImageMapBits imageBit, QSSGDataView< quint32 > inKeySet) const
void setLightProbe(QSSGDataRef< quint32 > inKeySet, bool val)
bool isLinear(QSSGDataView< quint32 > inKeySet) const
void setEnvMap(QSSGDataRef< quint32 > inKeySet, bool val)
QSSGShaderKeyShadowSoftness(const char *inName="")
void setShadowSoftness(QSSGDataRef< quint32 > inKeySet, QSSGRenderLight::SoftShadowQuality inQuality)
void toString(QByteArray &ioStr, QSSGDataView< quint32 > inKeySet) const
void fromString(const QByteArray &ioStr, QSSGDataRef< quint32 > inKeySet)
QSSGRenderLight::SoftShadowQuality getShadowSoftness(QSSGDataView< quint32 > inKeySet) const
QSSGRenderDefaultMaterial::MaterialSpecularModel getSpecularModel(QSSGDataView< quint32 > inKeySet) const
void setSpecularModel(QSSGDataRef< quint32 > inKeySet, QSSGRenderDefaultMaterial::MaterialSpecularModel inModel)
void fromString(const QByteArray &ioStr, QSSGDataRef< quint32 > inKeySet)
void toString(QByteArray &ioStr, QSSGDataView< quint32 > inKeySet) const
QSSGShaderKeySpecularModel(const char *inName="")
void fromString(const QByteArray &ioStr, QSSGDataRef< quint32 > inKeySet)
void setTextureChannel(TexturChannelBits channel, QSSGDataRef< quint32 > inKeySet)
static constexpr char textureChannelToChar[4]
TexturChannelBits getTextureChannel(QSSGDataView< quint32 > inKeySet) const
void toString(QByteArray &ioStr, QSSGDataView< quint32 > inKeySet) const
QSSGShaderKeyTextureChannel(const char *inName="")
void fromString(const QByteArray &ioStr, QSSGDataRef< quint32 > inKeySet)
constexpr QSSGShaderKeyUnsigned(const char *inName="")
void setValue(QSSGDataRef< quint32 > inDataStore, quint32 inValue) const
quint32 getValue(QSSGDataView< quint32 > inDataStore) const
void toString(QByteArray &ioStr, QSSGDataView< quint32 > inKeySet) const
void toString(QByteArray &ioStr, QSSGDataView< quint32 > inKeySet) const
bool getBitValue(VertexAttributeBits bit, QSSGDataView< quint32 > inKeySet) const
QSSGShaderKeyVertexAttribute(const char *inName="")
void fromString(const QByteArray &ioStr, QSSGDataRef< quint32 > inKeySet)
void setBitValue(VertexAttributeBits bit, QSSGDataRef< quint32 > inKeySet, bool value) const