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 #ifndef QSSG_RENDER_SHADER_KEY_H
32 #define QSSG_RENDER_SHADER_KEY_H
33 
34 //
35 //  W A R N I N G
36 //  -------------
37 //
38 // This file is not part of the Qt API.  It exists purely as an
39 // implementation detail.  This header file may change from version to
40 // version without notice, or even be removed.
41 //
42 // We mean it.
43 //
44 
45 #include <QtQuick3DUtils/private/qssgdataref_p.h>
46 
47 #include <QtQuick3DRender/private/qssgrenderbasetypes_p.h>
48 
49 #include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterial_p.h>
50 #include <QtQuick3DRuntimeRender/private/qssgrendertessmodevalues_p.h>
51 
52 QT_BEGIN_NAMESPACE
53 // We have an ever expanding set of properties we like to hash into one or more 32 bit
54 // quantities.
55 // Furthermore we would like this set of properties to be convertable to string
56 // So the shader cache file itself is somewhat human readable/diagnosable.
57 // To do this we create a set of objects that act as properties to the master shader key.
58 // These objects are tallied in order to figure out their actual offset into the shader key's
59 // data store.  They are also run through in order to create the string shader cache key.
60 
61 struct QSSGShaderKeyPropertyBase
62 {
63     const char *name;
64     quint32 offset;
nameQSSGShaderKeyPropertyBase65     QSSGShaderKeyPropertyBase(const char *inName = "") : name(inName), offset(0) {}
getOffsetQSSGShaderKeyPropertyBase66     quint32 getOffset() const { return offset; }
setOffsetQSSGShaderKeyPropertyBase67     void setOffset(quint32 of) { offset = of; }
68 
69     template<quint32 TBitWidth>
getMaskTemplateQSSGShaderKeyPropertyBase70     quint32 getMaskTemplate() const
71     {
72         quint32 bit = offset % 32;
73         quint32 startValue = (1 << TBitWidth) - 1;
74         quint32 mask = startValue << bit;
75         return mask;
76     }
77 
getIdxQSSGShaderKeyPropertyBase78     quint32 getIdx() const { return offset / 32; }
79 
80 protected:
internalToStringQSSGShaderKeyPropertyBase81     void internalToString(QString &ioStr, const char *inBuffer) const
82     {
83         ioStr.append(QString::fromLocal8Bit(name));
84         ioStr.append(QStringLiteral("="));
85         ioStr.append(QString::fromLocal8Bit(inBuffer));
86     }
87 
internalToStringQSSGShaderKeyPropertyBase88     static void internalToString(QString &ioStr, const char *name, bool inValue)
89     {
90         if (inValue) {
91             ioStr.append(QString::fromLocal8Bit(name));
92             ioStr.append(QStringLiteral("="));
93             ioStr.append(inValue ? QStringLiteral("true") : QStringLiteral("false"));
94         }
95     }
96 };
97 
98 struct QSSGShaderKeyBoolean : public QSSGShaderKeyPropertyBase
99 {
100     enum {
101         BitWidth = 1,
102     };
103 
QSSGShaderKeyPropertyBaseQSSGShaderKeyBoolean104     QSSGShaderKeyBoolean(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {}
105 
getMaskQSSGShaderKeyBoolean106     quint32 getMask() const { return getMaskTemplate<BitWidth>(); }
setValueQSSGShaderKeyBoolean107     void setValue(QSSGDataRef<quint32> inDataStore, bool inValue) const
108     {
109         const qint32 idx = qint32(getIdx());
110         Q_ASSERT(idx >= 0 && idx <= INT32_MAX);
111         Q_ASSERT(inDataStore.size() > idx);
112         quint32 mask = getMask();
113         quint32 &target = inDataStore[idx];
114         if (inValue) {
115             target = target | mask;
116         } else {
117             mask = ~mask;
118             target = target & mask;
119         }
120     }
121 
getValueQSSGShaderKeyBoolean122     bool getValue(QSSGDataView<quint32> inDataStore) const
123     {
124         quint32 idx = getIdx();
125         quint32 mask = getMask();
126         const quint32 &target = inDataStore[idx];
127         return (target & mask) ? true : false;
128     }
129 
toStringQSSGShaderKeyBoolean130     void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const
131     {
132         bool isHigh = getValue(inKeySet);
133         internalToString(ioStr, name, isHigh);
134     }
135 };
136 
137 template<quint32 TBitWidth>
138 struct QSSGShaderKeyUnsigned : public QSSGShaderKeyPropertyBase
139 {
140     enum {
141         BitWidth = TBitWidth,
142     };
QSSGShaderKeyPropertyBaseQSSGShaderKeyUnsigned143     QSSGShaderKeyUnsigned(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {}
getMaskQSSGShaderKeyUnsigned144     quint32 getMask() const { return getMaskTemplate<BitWidth>(); }
setValueQSSGShaderKeyUnsigned145     void setValue(QSSGDataRef<quint32> inDataStore, quint32 inValue) const
146     {
147         quint32 startValue = (1 << TBitWidth) - 1;
148         // Ensure inValue is within range of bit width.
149         inValue = inValue & startValue;
150         quint32 bit = offset % 32;
151         quint32 mask = getMask();
152         quint32 idx = getIdx();
153         inValue = inValue << bit;
154         quint32 &target = inDataStore[idx];
155         // Get rid of existing value
156         quint32 inverseMask = ~mask;
157         target = target & inverseMask;
158         target = target | inValue;
159     }
160 
getValueQSSGShaderKeyUnsigned161     quint32 getValue(QSSGDataView<quint32> inDataStore) const
162     {
163         quint32 idx = getIdx();
164         quint32 bit = offset % 32;
165         quint32 mask = getMask();
166         const quint32 &target = inDataStore[idx];
167 
168         quint32 retval = target & mask;
169         retval = retval >> bit;
170         return retval;
171     }
172 
toStringQSSGShaderKeyUnsigned173     void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const
174     {
175         quint32 value = getValue(inKeySet);
176         char buf[64];
177         toStr(value, toDataRef(buf, 64));
178         internalToString(ioStr, buf);
179     }
180 
181 private:
toStrQSSGShaderKeyUnsigned182     static quint32 toStr(quint32 item, QSSGDataRef<char> buffer)
183     {
184         // hope the buffer is big enough...
185         return static_cast<quint32>(::snprintf(buffer.begin(), buffer.size(), "%u", item));
186     }
187 };
188 
189 struct QSSGShaderKeyTessellation : public QSSGShaderKeyUnsigned<4>
190 {
191     enum TessellationBits {
192         noTessellation = 1 << 0,
193         linearTessellation = 1 << 1,
194         phongTessellation = 1 << 2,
195         npatchTessellation = 1 << 3
196     };
197 
198     QSSGShaderKeyTessellation(const char *inName = "") : QSSGShaderKeyUnsigned<4>(inName) {}
199 
getBitValueQSSGShaderKeyTessellation200     bool getBitValue(TessellationBits swizzleBit, QSSGDataView<quint32> inKeySet) const
201     {
202         return (getValue(inKeySet) & swizzleBit) ? true : false;
203     }
204 
setBitValueQSSGShaderKeyTessellation205     void setBitValue(TessellationBits swizzleBit, bool inValue, QSSGDataRef<quint32> inKeySet)
206     {
207         quint32 theValue = getValue(inKeySet);
208         quint32 mask = swizzleBit;
209         if (inValue) {
210             theValue = theValue | mask;
211         } else {
212             mask = ~mask;
213             theValue = theValue & mask;
214         }
215         setValue(inKeySet, theValue);
216     }
217 
setTessellationModeQSSGShaderKeyTessellation218     void setTessellationMode(QSSGDataRef<quint32> inKeySet, TessellationModeValues tessellationMode, bool val)
219     {
220         switch (tessellationMode) {
221         case TessellationModeValues::NoTessellation:
222             setBitValue(noTessellation, val, inKeySet);
223             break;
224         case TessellationModeValues::Linear:
225             setBitValue(linearTessellation, val, inKeySet);
226             break;
227         case TessellationModeValues::NPatch:
228             setBitValue(npatchTessellation, val, inKeySet);
229             break;
230         case TessellationModeValues::Phong:
231             setBitValue(phongTessellation, val, inKeySet);
232             break;
233         }
234     }
235 
isNoTessellationQSSGShaderKeyTessellation236     bool isNoTessellation(QSSGDataView<quint32> inKeySet) const { return getBitValue(noTessellation, inKeySet); }
setNoTessellationQSSGShaderKeyTessellation237     void setNoTessellation(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(noTessellation, val, inKeySet); }
238 
isLinearTessellationQSSGShaderKeyTessellation239     bool isLinearTessellation(QSSGDataView<quint32> inKeySet) const
240     {
241         return getBitValue(linearTessellation, inKeySet);
242     }
setLinearTessellationQSSGShaderKeyTessellation243     void setLinearTessellation(QSSGDataRef<quint32> inKeySet, bool val)
244     {
245         setBitValue(linearTessellation, val, inKeySet);
246     }
247 
isNPatchTessellationQSSGShaderKeyTessellation248     bool isNPatchTessellation(QSSGDataView<quint32> inKeySet) const
249     {
250         return getBitValue(npatchTessellation, inKeySet);
251     }
setNPatchTessellationQSSGShaderKeyTessellation252     void setNPatchTessellation(QSSGDataRef<quint32> inKeySet, bool val)
253     {
254         setBitValue(npatchTessellation, val, inKeySet);
255     }
256 
isPhongTessellationQSSGShaderKeyTessellation257     bool isPhongTessellation(QSSGDataView<quint32> inKeySet) const
258     {
259         return getBitValue(phongTessellation, inKeySet);
260     }
setPhongTessellationQSSGShaderKeyTessellation261     void setPhongTessellation(QSSGDataRef<quint32> inKeySet, bool val)
262     {
263         setBitValue(phongTessellation, val, inKeySet);
264     }
265 
toStringQSSGShaderKeyTessellation266     void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const
267     {
268         ioStr.append(QString::fromLocal8Bit(name));
269         ioStr.append(QStringLiteral("={"));
270         internalToString(ioStr, "noTessellation", isNoTessellation(inKeySet));
271         ioStr.append(QStringLiteral(";"));
272         internalToString(ioStr, "linearTessellation", isLinearTessellation(inKeySet));
273         ioStr.append(QStringLiteral(";"));
274         internalToString(ioStr, "npatchTessellation", isNPatchTessellation(inKeySet));
275         ioStr.append(QStringLiteral(";"));
276         internalToString(ioStr, "phongTessellation", isPhongTessellation(inKeySet));
277         ioStr.append(QStringLiteral("}"));
278     }
279 };
280 
281 struct QSSGShaderKeyTextureChannel : public QSSGShaderKeyUnsigned<2>
282 {
283     enum TexturChannelBits {
284         R = 0,
285         G = 1,
286         B = 2,
287         A = 3,
288     };
289     QSSGShaderKeyTextureChannel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
290 
getTextureChannelQSSGShaderKeyTextureChannel291     TexturChannelBits getTextureChannel(QSSGDataView<quint32> inKeySet) const
292     {
293         return TexturChannelBits(getValue(inKeySet));
294     }
295 
setTextureChannelQSSGShaderKeyTextureChannel296     void setTextureChannel(TexturChannelBits channel, QSSGDataRef<quint32> inKeySet)
297     {
298         setValue(inKeySet, quint32(channel));
299     }
300     const QString enumToStr[4] = {
301         QStringLiteral("R"),
302         QStringLiteral("G"),
303         QStringLiteral("B"),
304         QStringLiteral("A"),
305     };
toStringQSSGShaderKeyTextureChannel306     void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const
307     {
308         ioStr.append(QString::fromLocal8Bit(name));
309         ioStr.append(QStringLiteral("="));
310         ioStr.append(enumToStr[getTextureChannel(inKeySet)]);
311     }
312 };
313 
314 struct QSSGShaderKeyTextureSwizzle : public QSSGShaderKeyUnsigned<5>
315 {
316     enum TextureSwizzleBits {
317         noSwizzle = 1 << 0,
318         L8toR8 = 1 << 1,
319         A8toR8 = 1 << 2,
320         L8A8toRG8 = 1 << 3,
321         L16toR16 = 1 << 4
322     };
323 
324     QSSGShaderKeyTextureSwizzle(const char *inName = "") : QSSGShaderKeyUnsigned<5>(inName) {}
325 
getBitValueQSSGShaderKeyTextureSwizzle326     bool getBitValue(TextureSwizzleBits swizzleBit, QSSGDataView<quint32> inKeySet) const
327     {
328         return (getValue(inKeySet) & swizzleBit) ? true : false;
329     }
330 
setBitValueQSSGShaderKeyTextureSwizzle331     void setBitValue(TextureSwizzleBits swizzleBit, bool inValue, QSSGDataRef<quint32> inKeySet)
332     {
333         quint32 theValue = getValue(inKeySet);
334         quint32 mask = swizzleBit;
335         if (inValue) {
336             theValue = theValue | mask;
337         } else {
338             mask = ~mask;
339             theValue = theValue & mask;
340         }
341         setValue(inKeySet, theValue);
342     }
343 
setSwizzleModeQSSGShaderKeyTextureSwizzle344     void setSwizzleMode(QSSGDataRef<quint32> inKeySet, QSSGRenderTextureSwizzleMode swizzleMode, bool val)
345     {
346         switch (swizzleMode) {
347         case QSSGRenderTextureSwizzleMode::NoSwizzle:
348             setBitValue(noSwizzle, val, inKeySet);
349             break;
350         case QSSGRenderTextureSwizzleMode::L8toR8:
351             setBitValue(L8toR8, val, inKeySet);
352             break;
353         case QSSGRenderTextureSwizzleMode::A8toR8:
354             setBitValue(A8toR8, val, inKeySet);
355             break;
356         case QSSGRenderTextureSwizzleMode::L8A8toRG8:
357             setBitValue(L8A8toRG8, val, inKeySet);
358             break;
359         case QSSGRenderTextureSwizzleMode::L16toR16:
360             setBitValue(L16toR16, val, inKeySet);
361             break;
362         }
363     }
364 
isNoSwizzledQSSGShaderKeyTextureSwizzle365     bool isNoSwizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(noSwizzle, inKeySet); }
setNoSwizzledQSSGShaderKeyTextureSwizzle366     void setNoSwizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(noSwizzle, val, inKeySet); }
367 
isL8SwizzledQSSGShaderKeyTextureSwizzle368     bool isL8Swizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(L8toR8, inKeySet); }
setL8SwizzledQSSGShaderKeyTextureSwizzle369     void setL8Swizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(L8toR8, val, inKeySet); }
370 
isA8SwizzledQSSGShaderKeyTextureSwizzle371     bool isA8Swizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(A8toR8, inKeySet); }
setA8SwizzledQSSGShaderKeyTextureSwizzle372     void setA8Swizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(A8toR8, val, inKeySet); }
373 
isL8A8SwizzledQSSGShaderKeyTextureSwizzle374     bool isL8A8Swizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(L8A8toRG8, inKeySet); }
setL8A8SwizzledQSSGShaderKeyTextureSwizzle375     void setL8A8Swizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(L8A8toRG8, val, inKeySet); }
376 
isL16SwizzledQSSGShaderKeyTextureSwizzle377     bool isL16Swizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(L16toR16, inKeySet); }
setL16SwizzledQSSGShaderKeyTextureSwizzle378     void setL16Swizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(L16toR16, val, inKeySet); }
379 
toStringQSSGShaderKeyTextureSwizzle380     void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const
381     {
382         ioStr.append(QString::fromLocal8Bit(name));
383         ioStr.append(QStringLiteral("={"));
384         internalToString(ioStr, "noswizzle", isNoSwizzled(inKeySet));
385         ioStr.append(QStringLiteral(";"));
386         internalToString(ioStr, "l8swizzle", isL8Swizzled(inKeySet));
387         ioStr.append(QStringLiteral(";"));
388         internalToString(ioStr, "a8swizzle", isA8Swizzled(inKeySet));
389         ioStr.append(QStringLiteral(";"));
390         internalToString(ioStr, "l8a8swizzle", isL8A8Swizzled(inKeySet));
391         ioStr.append(QStringLiteral(";"));
392         internalToString(ioStr, "l16swizzle", isL16Swizzled(inKeySet));
393         ioStr.append(QStringLiteral("}"));
394     }
395 };
396 
397 struct QSSGShaderKeyImageMap : public QSSGShaderKeyUnsigned<6>
398 {
399     enum ImageMapBits {
400         Enabled = 1 << 0,
401         EnvMap = 1 << 1,
402         LightProbe = 1 << 2,
403         InvertUV = 1 << 3,
404         Premultiplied = 1 << 4,
405         Identity = 1 << 5
406     };
407 
408     QSSGShaderKeyImageMap(const char *inName = "") : QSSGShaderKeyUnsigned<6>(inName) {}
409 
getBitValueQSSGShaderKeyImageMap410     bool getBitValue(ImageMapBits imageBit, QSSGDataView<quint32> inKeySet) const
411     {
412         return (getValue(inKeySet) & imageBit) ? true : false;
413     }
414 
setBitValueQSSGShaderKeyImageMap415     void setBitValue(ImageMapBits imageBit, bool inValue, QSSGDataRef<quint32> inKeySet)
416     {
417         quint32 theValue = getValue(inKeySet);
418         quint32 mask = imageBit;
419         if (inValue) {
420             theValue = theValue | mask;
421         } else {
422             mask = ~mask;
423             theValue = theValue & mask;
424         }
425         setValue(inKeySet, theValue);
426     }
427 
isEnabledQSSGShaderKeyImageMap428     bool isEnabled(QSSGDataView<quint32> inKeySet) const { return getBitValue(Enabled, inKeySet); }
setEnabledQSSGShaderKeyImageMap429     void setEnabled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(Enabled, val, inKeySet); }
430 
isEnvMapQSSGShaderKeyImageMap431     bool isEnvMap(QSSGDataView<quint32> inKeySet) const { return getBitValue(EnvMap, inKeySet); }
setEnvMapQSSGShaderKeyImageMap432     void setEnvMap(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(EnvMap, val, inKeySet); }
433 
isLightProbeQSSGShaderKeyImageMap434     bool isLightProbe(QSSGDataView<quint32> inKeySet) const { return getBitValue(LightProbe, inKeySet); }
setLightProbeQSSGShaderKeyImageMap435     void setLightProbe(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(LightProbe, val, inKeySet); }
436 
isInvertUVMapQSSGShaderKeyImageMap437     bool isInvertUVMap(QSSGDataView<quint32> inKeySet) const { return getBitValue(InvertUV, inKeySet); }
setInvertUVMapQSSGShaderKeyImageMap438     void setInvertUVMap(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(InvertUV, val, inKeySet); }
439 
isPremultipliedQSSGShaderKeyImageMap440     bool isPremultiplied(QSSGDataView<quint32> inKeySet) const { return getBitValue(Premultiplied, inKeySet); }
setPremultipliedQSSGShaderKeyImageMap441     void setPremultiplied(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(Premultiplied, val, inKeySet); }
442 
isIdentityTransformQSSGShaderKeyImageMap443     bool isIdentityTransform(QSSGDataView<quint32> inKeySet) const { return getBitValue(Identity, inKeySet); }
setIdentityTransformQSSGShaderKeyImageMap444     void setIdentityTransform(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(Identity, val, inKeySet); }
445 
toStringQSSGShaderKeyImageMap446     void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const
447     {
448         ioStr.append(QString::fromLocal8Bit(name));
449         ioStr.append(QStringLiteral("={"));
450         internalToString(ioStr, "enabled", isEnabled(inKeySet));
451         ioStr.append(QStringLiteral(";"));
452         internalToString(ioStr, "envMap", isEnvMap(inKeySet));
453         ioStr.append(QStringLiteral(";"));
454         internalToString(ioStr, "lightProbe", isLightProbe(inKeySet));
455         ioStr.append(QStringLiteral(";"));
456         internalToString(ioStr, "invertUV", isInvertUVMap(inKeySet));
457         ioStr.append(QStringLiteral(";"));
458         internalToString(ioStr, "premultiplied", isPremultiplied(inKeySet));
459         ioStr.append(QStringLiteral(";"));
460         internalToString(ioStr, "identity", isIdentityTransform(inKeySet));
461         ioStr.append(QStringLiteral("}"));
462     }
463 };
464 
465 struct QSSGShaderKeySpecularModel : QSSGShaderKeyUnsigned<2>
466 {
467     QSSGShaderKeySpecularModel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
468 
setSpecularModelQSSGShaderKeySpecularModel469     void setSpecularModel(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialSpecularModel inModel)
470     {
471         setValue(inKeySet, quint32(inModel));
472     }
473 
getSpecularModelQSSGShaderKeySpecularModel474     QSSGRenderDefaultMaterial::MaterialSpecularModel getSpecularModel(QSSGDataView<quint32> inKeySet) const
475     {
476         return static_cast<QSSGRenderDefaultMaterial::MaterialSpecularModel>(getValue(inKeySet));
477     }
478 
toStringQSSGShaderKeySpecularModel479     void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const
480     {
481         ioStr.append(QString::fromLocal8Bit(name));
482         ioStr.append(QStringLiteral("="));
483         switch (getSpecularModel(inKeySet)) {
484         case QSSGRenderDefaultMaterial::MaterialSpecularModel::KGGX:
485             ioStr.append(QStringLiteral("KGGX"));
486             break;
487         case QSSGRenderDefaultMaterial::MaterialSpecularModel::KWard:
488             ioStr.append(QStringLiteral("KWard"));
489             break;
490         case QSSGRenderDefaultMaterial::MaterialSpecularModel::Default:
491             ioStr.append(QStringLiteral("Default"));
492             break;
493         }
494         ioStr.append(QStringLiteral(";"));
495     }
496 };
497 
498 struct QSSGShaderKeyAlphaMode : QSSGShaderKeyUnsigned<2>
499 {
500     QSSGShaderKeyAlphaMode(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {}
501 
setAlphaModeQSSGShaderKeyAlphaMode502     void setAlphaMode(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode inMode)
503     {
504         setValue(inKeySet, quint32(inMode));
505     }
506 
getAlphaModeQSSGShaderKeyAlphaMode507     QSSGRenderDefaultMaterial::MaterialAlphaMode getAlphaMode(QSSGDataView<quint32> inKeySet) const
508     {
509         return static_cast<QSSGRenderDefaultMaterial::MaterialAlphaMode>(getValue(inKeySet));
510     }
511 
toStringQSSGShaderKeyAlphaMode512     void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const
513     {
514         ioStr.append(QString::fromLocal8Bit(name));
515         ioStr.append(QStringLiteral("="));
516         switch (getAlphaMode(inKeySet)) {
517         case QSSGRenderDefaultMaterial::MaterialAlphaMode::Opaque:
518             ioStr.append(QStringLiteral("Opaque"));
519             break;
520         case QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask:
521             ioStr.append(QStringLiteral("Mask"));
522             break;
523         case QSSGRenderDefaultMaterial::MaterialAlphaMode::Blend:
524             ioStr.append(QStringLiteral("Blend"));
525             break;
526         case QSSGRenderDefaultMaterial::MaterialAlphaMode::Default:
527             ioStr.append(QStringLiteral("Default"));
528             break;
529         }
530         ioStr.append(QStringLiteral(";"));
531     }
532 };
533 
534 struct QSSGShaderKeyVertexAttribute : public QSSGShaderKeyUnsigned<7>
535 {
536     enum VertexAttributeBits {
537         Position = 1 << 0,
538         Normal = 1 << 1,
539         TexCoord0 = 1 << 2,
540         TexCoord1 = 1 << 3,
541         Tangent = 1 << 4,
542         Binormal = 1 << 5,
543         Color = 1 << 6
544     };
545 
546     QSSGShaderKeyVertexAttribute(const char *inName = "") : QSSGShaderKeyUnsigned<7>(inName) {}
547 
getBitValueQSSGShaderKeyVertexAttribute548     bool getBitValue(VertexAttributeBits bit, QSSGDataView<quint32> inKeySet) const
549     {
550         return (getValue(inKeySet) & bit) ? true : false;
551     }
552 
toStringQSSGShaderKeyVertexAttribute553     void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const
554     {
555         ioStr.append(QString::fromLocal8Bit(name));
556         ioStr.append(QStringLiteral("={"));
557         internalToString(ioStr, "position", getBitValue(Position, inKeySet));
558         ioStr.append(QStringLiteral(";"));
559         internalToString(ioStr, "normal", getBitValue(Normal, inKeySet));
560         ioStr.append(QStringLiteral(";"));
561         internalToString(ioStr, "texcoord0", getBitValue(TexCoord0, inKeySet));
562         ioStr.append(QStringLiteral(";"));
563         internalToString(ioStr, "texcoord1", getBitValue(TexCoord1, inKeySet));
564         ioStr.append(QStringLiteral(";"));
565         internalToString(ioStr, "tangent", getBitValue(Tangent, inKeySet));
566         ioStr.append(QStringLiteral(";"));
567         internalToString(ioStr, "binormal", getBitValue(Binormal, inKeySet));
568         ioStr.append(QStringLiteral(";"));
569         internalToString(ioStr, "color", getBitValue(Color, inKeySet));
570         ioStr.append(QStringLiteral("}"));
571     }
572 };
573 
574 struct QSSGShaderDefaultMaterialKeyProperties
575 {
576     enum {
577         LightCount = 7,
578     };
579     enum {
580         SingleChannelImageCount = 5,
581     };
582     enum ImageMapNames {
583         DiffuseMap = 0,
584         EmissiveMap,
585         SpecularMap,
586         BaseColorMap,
587         BumpMap,
588         SpecularAmountMap,
589         NormalMap,
590         DisplacementMap,
591         LightmapIndirect,
592         LightmapRadiosity,
593         LightmapShadow,
594         // single channel images
595         OpacityMap,
596         RoughnessMap,
597         MetalnessMap,
598         OcclusionMap,
599         TranslucencyMap,
600 
601         ImageMapCount,
602         SingleChannelImagesFirst = OpacityMap
603     };
604     enum ImageChannelNames {
605         OpacityChannel = 0,
606         RoughnessChannel,
607         MetalnessChannel,
608         OcclusionChannel,
609         TranslucencyChannel,
610     };
611 
612     QSSGShaderKeyBoolean m_hasLighting;
613     QSSGShaderKeyBoolean m_hasIbl;
614     QSSGShaderKeyUnsigned<3> m_lightCount;
615     QSSGShaderKeyBoolean m_lightFlags[LightCount];
616     QSSGShaderKeyBoolean m_lightSpotFlags[LightCount];
617     QSSGShaderKeyBoolean m_lightAreaFlags[LightCount];
618     QSSGShaderKeyBoolean m_lightShadowFlags[LightCount];
619     QSSGShaderKeyBoolean m_specularEnabled;
620     QSSGShaderKeyBoolean m_fresnelEnabled;
621     QSSGShaderKeyBoolean m_vertexColorsEnabled;
622     QSSGShaderKeySpecularModel m_specularModel;
623     QSSGShaderKeyImageMap m_imageMaps[ImageMapCount];
624     QSSGShaderKeyTextureSwizzle m_textureSwizzle[ImageMapCount];
625     QSSGShaderKeyTextureChannel m_textureChannels[SingleChannelImageCount];
626     QSSGShaderKeyTessellation m_tessellationMode;
627     QSSGShaderKeyBoolean m_hasSkinning;
628     QSSGShaderKeyBoolean m_wireframeMode;
629     QSSGShaderKeyBoolean m_isDoubleSided;
630     QSSGShaderKeyAlphaMode m_alphaMode;
631     QSSGShaderKeyVertexAttribute m_vertexAttributes;
632 
QSSGShaderDefaultMaterialKeyPropertiesQSSGShaderDefaultMaterialKeyProperties633     QSSGShaderDefaultMaterialKeyProperties()
634         : m_hasLighting("hasLighting")
635         , m_hasIbl("hasIbl")
636         , m_lightCount("lightCount")
637         , m_specularEnabled("specularEnabled")
638         , m_fresnelEnabled("fresnelEnabled")
639         , m_vertexColorsEnabled("vertexColorsEnabled")
640         , m_specularModel("specularModel")
641         , m_tessellationMode("tessellationMode")
642         , m_hasSkinning("hasSkinning")
643         , m_wireframeMode("wireframeMode")
644         , m_isDoubleSided("isDoubleSided")
645         , m_alphaMode("alphaMode")
646         , m_vertexAttributes("vertexAttributes")
647     {
648         m_lightFlags[0].name = "light0HasPosition";
649         m_lightFlags[1].name = "light1HasPosition";
650         m_lightFlags[2].name = "light2HasPosition";
651         m_lightFlags[3].name = "light3HasPosition";
652         m_lightFlags[4].name = "light4HasPosition";
653         m_lightFlags[5].name = "light5HasPosition";
654         m_lightFlags[6].name = "light6HasPosition";
655         m_lightSpotFlags[0].name = "light0HasSpot";
656         m_lightSpotFlags[1].name = "light1HasSpot";
657         m_lightSpotFlags[2].name = "light2HasSpot";
658         m_lightSpotFlags[3].name = "light3HasSpot";
659         m_lightSpotFlags[4].name = "light4HasSpot";
660         m_lightSpotFlags[5].name = "light5HasSpot";
661         m_lightSpotFlags[6].name = "light6HasSpot";
662         m_lightAreaFlags[0].name = "light0HasArea";
663         m_lightAreaFlags[1].name = "light1HasArea";
664         m_lightAreaFlags[2].name = "light2HasArea";
665         m_lightAreaFlags[3].name = "light3HasArea";
666         m_lightAreaFlags[4].name = "light4HasArea";
667         m_lightAreaFlags[5].name = "light5HasArea";
668         m_lightAreaFlags[6].name = "light6HasArea";
669         m_lightShadowFlags[0].name = "light0HasShadow";
670         m_lightShadowFlags[1].name = "light1HasShadow";
671         m_lightShadowFlags[2].name = "light2HasShadow";
672         m_lightShadowFlags[3].name = "light3HasShadow";
673         m_lightShadowFlags[4].name = "light4HasShadow";
674         m_lightShadowFlags[5].name = "light5HasShadow";
675         m_lightShadowFlags[6].name = "light6HasShadow";
676 
677         m_imageMaps[0].name = "diffuseMap";
678         m_imageMaps[1].name = "emissiveMap";
679         m_imageMaps[2].name = "specularMap";
680         m_imageMaps[3].name = "baseColorMap";
681         m_imageMaps[4].name = "bumpMap";
682         m_imageMaps[5].name = "specularAmountMap";
683         m_imageMaps[6].name = "normalMap";
684         m_imageMaps[7].name = "displacementMap";
685         m_imageMaps[8].name = "lightmapIndirect";
686         m_imageMaps[9].name = "lightmapRadiosity";
687         m_imageMaps[10].name = "lightmapShadow";
688         m_imageMaps[11].name = "opacityMap";
689         m_imageMaps[12].name = "roughnessMap";
690         m_imageMaps[13].name = "metalnessMap";
691         m_imageMaps[14].name = "occlusionMap";
692         m_imageMaps[15].name = "translucencyMap";
693 
694         m_textureSwizzle[0].name = "diffuseMap_swizzle";
695         m_textureSwizzle[1].name = "emissiveMap_swizzle";
696         m_textureSwizzle[2].name = "specularMap_swizzle";
697         m_textureSwizzle[3].name = "baseColorMap_swizzle";
698         m_textureSwizzle[4].name = "bumpMap_swizzle";
699         m_textureSwizzle[5].name = "specularAmountMap_swizzle";
700         m_textureSwizzle[6].name = "normalMap_swizzle";
701         m_textureSwizzle[7].name = "displacementMap_swizzle";
702         m_textureSwizzle[8].name = "lightmapIndirect_swizzle";
703         m_textureSwizzle[9].name = "lightmapRadiosity_swizzle";
704         m_textureSwizzle[10].name = "lightmapShadow_swizzle";
705         m_textureSwizzle[11].name = "opacityMap_swizzle";
706         m_textureSwizzle[12].name = "roughnessMap_swizzle";
707         m_textureSwizzle[13].name = "metalnessMap_swizzle";
708         m_textureSwizzle[14].name = "occlusionMap_swizzle";
709         m_textureSwizzle[15].name = "translucencyMap_swizzle";
710 
711         m_textureChannels[0].name = "opacityMap_channel";
712         m_textureChannels[1].name = "roughnessMap_channel";
713         m_textureChannels[2].name = "metalnessMap_channel";
714         m_textureChannels[3].name = "occlusionMap_channel";
715         m_textureChannels[4].name = "translucencyMap_channel";
716 
717         setPropertyOffsets();
718     }
719 
720     template<typename TVisitor>
visitPropertiesQSSGShaderDefaultMaterialKeyProperties721     void visitProperties(TVisitor &inVisitor)
722     {
723         inVisitor.visit(m_hasLighting);
724         inVisitor.visit(m_hasIbl);
725         inVisitor.visit(m_lightCount);
726 
727         for (quint32 idx = 0, end = LightCount; idx < end; ++idx) {
728             inVisitor.visit(m_lightFlags[idx]);
729         }
730 
731         for (quint32 idx = 0, end = LightCount; idx < end; ++idx) {
732             inVisitor.visit(m_lightSpotFlags[idx]);
733         }
734 
735         for (quint32 idx = 0, end = LightCount; idx < end; ++idx) {
736             inVisitor.visit(m_lightAreaFlags[idx]);
737         }
738 
739         for (quint32 idx = 0, end = LightCount; idx < end; ++idx) {
740             inVisitor.visit(m_lightShadowFlags[idx]);
741         }
742 
743         inVisitor.visit(m_specularEnabled);
744         inVisitor.visit(m_fresnelEnabled);
745         inVisitor.visit(m_vertexColorsEnabled);
746         inVisitor.visit(m_specularModel);
747 
748         for (quint32 idx = 0, end = ImageMapCount; idx < end; ++idx) {
749             inVisitor.visit(m_imageMaps[idx]);
750             inVisitor.visit(m_textureSwizzle[idx]);
751         }
752         for (quint32 idx = 0, end = SingleChannelImageCount; idx < end; ++idx)
753             inVisitor.visit(m_textureChannels[idx]);
754 
755         inVisitor.visit(m_tessellationMode);
756         inVisitor.visit(m_hasSkinning);
757         inVisitor.visit(m_wireframeMode);
758         inVisitor.visit(m_isDoubleSided);
759         inVisitor.visit(m_alphaMode);
760         inVisitor.visit(m_vertexAttributes);
761     }
762 
763     struct OffsetVisitor
764     {
765         quint32 m_offset;
OffsetVisitorQSSGShaderDefaultMaterialKeyProperties::OffsetVisitor766         OffsetVisitor() : m_offset(0) {}
767         template<typename TPropType>
visitQSSGShaderDefaultMaterialKeyProperties::OffsetVisitor768         void visit(TPropType &inProp)
769         {
770             // if we cross the 32 bit border we just move
771             // to the next dword.
772             // This cost a few extra bits but prevents tedious errors like
773             // loosing shader key bits because they got moved beyond the 32 border
774             quint32 bit = m_offset % 32;
775             if (bit + TPropType::BitWidth > 31) {
776                 m_offset += 32 - bit;
777             }
778 
779             inProp.setOffset(m_offset);
780             m_offset += TPropType::BitWidth;
781         }
782     };
783 
setPropertyOffsetsQSSGShaderDefaultMaterialKeyProperties784     void setPropertyOffsets()
785     {
786         OffsetVisitor visitor;
787         visitProperties(visitor);
788         // If this assert fires, then the default material key needs more bits.
789         Q_ASSERT(visitor.m_offset < 320);
790     }
791 };
792 
793 struct QSSGShaderDefaultMaterialKey
794 {
795     enum {
796         DataBufferSize = 10,
797     };
798     quint32 m_dataBuffer[DataBufferSize];
799     uint m_featureSetHash;
800 
QSSGShaderDefaultMaterialKeyQSSGShaderDefaultMaterialKey801     QSSGShaderDefaultMaterialKey(uint inFeatureSetHash) : m_featureSetHash(inFeatureSetHash)
802     {
803         for (size_t idx = 0; idx < DataBufferSize; ++idx)
804             m_dataBuffer[idx] = 0;
805     }
806 
QSSGShaderDefaultMaterialKeyQSSGShaderDefaultMaterialKey807     QSSGShaderDefaultMaterialKey() : m_featureSetHash(0)
808     {
809         for (size_t idx = 0; idx < DataBufferSize; ++idx)
810             m_dataBuffer[idx] = 0;
811     }
812 
hashQSSGShaderDefaultMaterialKey813     uint hash() const
814     {
815         uint retval = 0;
816         for (size_t idx = 0; idx < DataBufferSize; ++idx)
817             retval = retval ^ qHash(m_dataBuffer[idx]);
818         return retval ^ m_featureSetHash;
819     }
820 
821     bool operator==(const QSSGShaderDefaultMaterialKey &other) const
822     {
823         bool retval = true;
824         for (size_t idx = 0; idx < DataBufferSize && retval; ++idx)
825             retval = m_dataBuffer[idx] == other.m_dataBuffer[idx];
826         return retval && m_featureSetHash == other.m_featureSetHash;
827     }
828 
829     // Cast operators to make getting properties easier.
830     operator QSSGDataRef<quint32>() { return toDataRef(m_dataBuffer, DataBufferSize); }
831     operator QSSGDataView<quint32>() const { return toDataView(m_dataBuffer, DataBufferSize); }
832 
833     struct StringVisitor
834     {
835         QByteArray &m_str;
836         QSSGDataView<quint32> m_keyStore;
StringVisitorQSSGShaderDefaultMaterialKey::StringVisitor837         StringVisitor(QByteArray &s, QSSGDataView<quint32> ks) : m_str(s), m_keyStore(ks) {}
838         template<typename TPropType>
visitQSSGShaderDefaultMaterialKey::StringVisitor839         void visit(const TPropType &prop)
840         {
841             quint32 originalSize = m_str.size();
842             if (m_str.size())
843                 m_str.append(";");
844             QString str = QString::fromUtf8(m_str);
845             prop.toString(str, m_keyStore);
846             // if the only thing we added was the semicolon
847             // then nuke the semicolon
848             m_str = str.toLocal8Bit();
849             if (originalSize && m_str.size() == int(originalSize + 1))
850                 m_str.resize(int(originalSize));
851         }
852     };
853 
toStringQSSGShaderDefaultMaterialKey854     void toString(QByteArray &ioString, QSSGShaderDefaultMaterialKeyProperties &inProperties) const
855     {
856         StringVisitor theVisitor(ioString, *this);
857         inProperties.visitProperties(theVisitor);
858     }
859 };
860 
861 Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGShaderDefaultMaterialKey>::value);
862 
863 
qHash(const QSSGShaderDefaultMaterialKey & key)864 inline uint qHash(const QSSGShaderDefaultMaterialKey &key)
865 {
866     return key.hash();
867 }
868 
869 QT_END_NAMESPACE
870 
871 #endif
872