1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Gui module
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36 
37 #include "qshaderdescription_p_p.h"
38 #include "qshader_p_p.h"
39 #include <QDebug>
40 #include <QDataStream>
41 #include <QJsonObject>
42 #include <QJsonArray>
43 #include <QCborValue>
44 #include <QCborMap>
45 #include <QCborArray>
46 
47 QT_BEGIN_NAMESPACE
48 
49 /*!
50     \class QShaderDescription
51     \internal
52     \inmodule QtGui
53 
54     \brief Describes the interface of a shader.
55 
56     A shader typically has a set of inputs and outputs. A vertex shader for
57     example has a number of input variables and may use one or more uniform
58     buffers to access data (e.g. a modelview matrix) provided by the
59     application. The shader for the fragment stage receives data from the
60     vertex stage (in a simple setup) and may also rely on data from uniform
61     buffers, images, and samplers.
62 
63     When it comes to vertex inputs and the layout of the uniform buffers (what
64     are the names of the members? what is there size, offset, and so on),
65     applications and frameworks may need to discover this dynamically at run
66     time. This is typical when the shader is not built-in but provided by an
67     external entity, like the user.
68 
69     Modern and lean graphics APIs may no longer provide a way to query shader
70     reflection information at run time. Therefore, such data is now
71     automatically generated by QShaderBaker and is provided as a
72     QShaderDescription object for each and every QShader.
73 
74     \section2 Example
75 
76     Take the following vertex shader:
77 
78     \badcode
79         #version 440
80 
81         layout(location = 0) in vec4 position;
82         layout(location = 1) in vec3 color;
83         layout(location = 0) out vec3 v_color;
84 
85         layout(std140, binding = 0) uniform buf {
86             mat4 mvp;
87             float opacity;
88         } ubuf;
89 
90         out gl_PerVertex { vec4 gl_Position; };
91 
92         void main()
93         {
94             v_color = color;
95             gl_Position = ubuf.mvp * position;
96         }
97     \endcode
98 
99     This shader has two inputs: \c position at location 0 with a type of \c
100     vec4, and \c color at location 1 with a type of \c vec3. It has one output:
101     \c v_color, although this is typically not interesting for applications.
102     What is more important, there is a uniform block at binding 0 with a size
103     of 68 bytes and two members, a 4x4 matrix named \c mvp at offset 0, and a
104     float \c opacity at offset 64.
105 
106     All this is described by a QShaderDescription object. QShaderDescription
107     can also be serialized to JSON and CBOR, and can be deserialized
108     from CBOR. In practice this is rarely needed since QShader
109     takes care of the associated QShaderDescription automatically, but if the
110     QShaderDescription of the above shader would be written out as JSON, it
111     would look like the following:
112 
113     \badcode
114         {
115             "inputs": [
116                 {
117                     "location": 1,
118                     "name": "color",
119                     "type": "vec3"
120                 },
121                 {
122                     "location": 0,
123                     "name": "position",
124                     "type": "vec4"
125                 }
126             ],
127             "outputs": [
128                 {
129                     "location": 0,
130                     "name": "v_color",
131                     "type": "vec3"
132                 }
133             ],
134             "uniformBlocks": [
135                 {
136                     "binding": 0,
137                     "blockName": "buf",
138                     "members": [
139                         {
140                             "matrixStride": 16,
141                             "name": "mvp",
142                             "offset": 0,
143                             "size": 64,
144                             "type": "mat4"
145                         },
146                         {
147                             "name": "opacity",
148                             "offset": 64,
149                             "size": 4,
150                             "type": "float"
151                         }
152                     ],
153                     "set": 0,
154                     "size": 68,
155                     "structName": "ubuf"
156                 }
157             ]
158         }
159     \endcode
160 
161     The C++ API allows accessing a data structure like the above. For
162     simplicity the inner structs only contain public data members, also
163     considering that their layout is unlikely to change in the future.
164 
165     \sa QShaderBaker, QShader
166  */
167 
168 /*!
169     \enum QShaderDescription::VariableType
170     Represents the type of a variable or block member.
171 
172     \value Unknown
173     \value Float
174     \value Vec2
175     \value Vec3
176     \value Vec4
177     \value Mat2
178     \value Mat2x3
179     \value Mat2x4
180     \value Mat3
181     \value Mat3x2
182     \value Mat3x4
183     \value Mat4
184     \value Mat4x2
185     \value Mat4x3
186     \value Int
187     \value Int2
188     \value Int3
189     \value Int4
190     \value Uint
191     \value Uint2
192     \value Uint3
193     \value Uint4
194     \value Bool
195     \value Bool2
196     \value Bool3
197     \value Bool4
198     \value Double
199     \value Double2
200     \value Double3
201     \value Double4
202     \value DMat2
203     \value DMat2x3
204     \value DMat2x4
205     \value DMat3
206     \value DMat3x2
207     \value DMat3x4
208     \value DMat4
209     \value DMat4x2
210     \value DMat4x3
211     \value Sampler1D
212     \value Sampler2D
213     \value Sampler2DMS
214     \value Sampler3D
215     \value SamplerCube
216     \value Sampler1DArray
217     \value Sampler2DArray
218     \value Sampler2DMSArray
219     \value Sampler3DArray
220     \value SamplerCubeArray
221     \value SamplerRect
222     \value SamplerBuffer
223     \value Image1D
224     \value Image2D
225     \value Image2DMS
226     \value Image3D
227     \value ImageCube
228     \value Image1DArray
229     \value Image2DArray
230     \value Image2DMSArray
231     \value Image3DArray
232     \value ImageCubeArray
233     \value ImageRect
234     \value ImageBuffer
235     \value Struct
236  */
237 
238 /*!
239     \class QShaderDescription::InOutVariable
240     \internal
241     \inmodule QtGui
242 
243     \brief Describes an input or output variable in the shader.
244  */
245 
246 /*!
247     \class QShaderDescription::BlockVariable
248     \internal
249     \inmodule QtGui
250 
251     \brief Describes a member of a uniform or push constant block.
252  */
253 
254 /*!
255     \class QShaderDescription::UniformBlock
256     \internal
257     \inmodule QtGui
258 
259     \brief Describes a uniform block.
260 
261     \note When translating to shading languages without uniform block support
262     (like GLSL 120 or GLSL/ES 100), uniform blocks are replaced with ordinary
263     uniforms in a struct. The name of the struct, and so the prefix for the
264     uniforms generated from the block members, is given by structName.
265  */
266 
267 /*!
268     \class QShaderDescription::PushConstantBlock
269     \internal
270     \inmodule QtGui
271 
272     \brief Describes a push constant block.
273  */
274 
275 /*!
276     \class QShaderDescription::StorageBlock
277     \internal
278     \inmodule QtGui
279 
280     \brief Describes a shader storage block.
281  */
282 
283 /*!
284     Constructs a new, empty QShaderDescription.
285 
286     \note Being empty implies that isValid() returns \c false for the
287     newly constructed instance.
288  */
QShaderDescription()289 QShaderDescription::QShaderDescription()
290     : d(new QShaderDescriptionPrivate)
291 {
292 }
293 
294 /*!
295     \internal
296  */
detach()297 void QShaderDescription::detach()
298 {
299     qAtomicDetach(d);
300 }
301 
302 /*!
303     \internal
304  */
QShaderDescription(const QShaderDescription & other)305 QShaderDescription::QShaderDescription(const QShaderDescription &other)
306     : d(other.d)
307 {
308     d->ref.ref();
309 }
310 
311 /*!
312     \internal
313  */
operator =(const QShaderDescription & other)314 QShaderDescription &QShaderDescription::operator=(const QShaderDescription &other)
315 {
316     qAtomicAssign(d, other.d);
317     return *this;
318 }
319 
320 /*!
321     Destructor.
322  */
~QShaderDescription()323 QShaderDescription::~QShaderDescription()
324 {
325     if (!d->ref.deref())
326         delete d;
327 }
328 
329 /*!
330    \return true if the QShaderDescription contains at least one entry in one of
331    the variable and block lists.
332  */
isValid() const333 bool QShaderDescription::isValid() const
334 {
335     return !d->inVars.isEmpty() || !d->outVars.isEmpty()
336         || !d->uniformBlocks.isEmpty() || !d->pushConstantBlocks.isEmpty() || !d->storageBlocks.isEmpty()
337         || !d->combinedImageSamplers.isEmpty() || !d->storageImages.isEmpty();
338 }
339 
340 /*!
341    \return a serialized binary version of the data in CBOR (Concise Binary
342    Object Representation) format.
343 
344    \sa QCborValue, toJson()
345  */
toCbor() const346 QByteArray QShaderDescription::toCbor() const
347 {
348     return QCborValue::fromJsonValue(d->makeDoc().object()).toCbor();
349 }
350 
351 /*!
352     \return a serialized JSON text version of the data.
353 
354     \note There is no deserialization method provided for JSON text.
355 
356     \sa toCbor()
357  */
toJson() const358 QByteArray QShaderDescription::toJson() const
359 {
360     return d->makeDoc().toJson();
361 }
362 
serialize(QDataStream * stream) const363 void QShaderDescription::serialize(QDataStream *stream) const
364 {
365     d->writeToStream(stream);
366 }
367 
368 #if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
369 /*!
370     \deprecated
371 
372     Deserializes the given binary JSON \a data and returns a new
373     QShaderDescription.
374 
375     \sa fromCbor()
376  */
fromBinaryJson(const QByteArray & data)377 QShaderDescription QShaderDescription::fromBinaryJson(const QByteArray &data)
378 {
379     QShaderDescription desc;
380 QT_WARNING_PUSH
381 QT_WARNING_DISABLE_DEPRECATED
382     QShaderDescriptionPrivate::get(&desc)->loadDoc(QJsonDocument::fromBinaryData(data));
383 QT_WARNING_POP
384     return desc;
385 }
386 #endif
387 
388 /*!
389     Deserializes the given CBOR \a data and returns a new QShaderDescription.
390  */
fromCbor(const QByteArray & data)391 QShaderDescription QShaderDescription::fromCbor(const QByteArray &data)
392 {
393     QShaderDescription desc;
394     const QCborValue cbor = QCborValue::fromCbor(data);
395     if (cbor.isMap()) {
396         const QJsonDocument doc(cbor.toMap().toJsonObject());
397         QShaderDescriptionPrivate::get(&desc)->loadDoc(doc);
398     }
399     if (cbor.isArray()) {
400         const QJsonDocument doc(cbor.toArray().toJsonArray());
401         QShaderDescriptionPrivate::get(&desc)->loadDoc(doc);
402     }
403     return desc;
404 }
405 
deserialize(QDataStream * stream,int version)406 QShaderDescription QShaderDescription::deserialize(QDataStream *stream, int version)
407 {
408     QShaderDescription desc;
409     QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream, version);
410     return desc;
411 }
412 
413 /*!
414     \return the list of input variables. This includes vertex inputs (sometimes
415     called attributes) for the vertex stage, and inputs for other stages
416     (sometimes called varyings).
417  */
inputVariables() const418 QVector<QShaderDescription::InOutVariable> QShaderDescription::inputVariables() const
419 {
420     return d->inVars;
421 }
422 
423 /*!
424     \return the list of output variables.
425  */
outputVariables() const426 QVector<QShaderDescription::InOutVariable> QShaderDescription::outputVariables() const
427 {
428     return d->outVars;
429 }
430 
431 /*!
432     \return the list of uniform blocks.
433  */
uniformBlocks() const434 QVector<QShaderDescription::UniformBlock> QShaderDescription::uniformBlocks() const
435 {
436     return d->uniformBlocks;
437 }
438 
439 /*!
440     \return the list of push constant blocks.
441 
442     \note Avoid relying on push constant blocks for shaders that are to be used
443     in combination with the Qt Rendering Hardware Interface since that
444     currently has no support for them.
445  */
pushConstantBlocks() const446 QVector<QShaderDescription::PushConstantBlock> QShaderDescription::pushConstantBlocks() const
447 {
448     return d->pushConstantBlocks;
449 }
450 
451 /*!
452     \return the list of shader storage blocks.
453 
454     For example, with GLSL/Vulkan shaders as source, the declaration
455 
456     \badcode
457         struct Stuff {
458             vec2 a;
459             vec2 b;
460         };
461         layout(std140, binding = 0) buffer StuffSsbo {
462             vec4 whatever;
463             Stuff stuff[];
464         } buf;
465     \endcode
466 
467     generates the following: (shown as textual JSON here)
468 
469     \badcode
470         "storageBlocks": [ {
471             "binding": 0,
472             "blockName": "StuffSsbo",
473             "instanceName": "buf",
474             "knownSize": 16,
475             "members": [
476                 {
477                     "name": "whatever",
478                     "offset": 0,
479                     "size": 16,
480                     "type": "vec4"
481                 },
482                 {
483                     "arrayDims": [
484                         0
485                     ],
486                     "name": "stuff",
487                     "offset": 16,
488                     "size": 0,
489                     "structMembers": [
490                         {
491                             "name": "a",
492                             "offset": 0,
493                             "size": 8,
494                             "type": "vec2"
495                         },
496                         {
497                             "name": "b",
498                             "offset": 8,
499                             "size": 8,
500                             "type": "vec2"
501                         }
502                     ],
503                     "type": "struct"
504                 }
505             ],
506             "set": 0
507         } ]
508     \endcode
509 
510     \note The size of the last member in the storage block is undefined. This shows
511     up as \c size 0 and an array dimension of \c{[0]}. The storage block's \c knownSize
512     excludes the size of the last member since that will only be known at run time.
513 
514     \note SSBOs are not available with some graphics APIs, such as, OpenGL 2.x or
515     OpenGL ES older than 3.1.
516  */
storageBlocks() const517 QVector<QShaderDescription::StorageBlock> QShaderDescription::storageBlocks() const
518 {
519     return d->storageBlocks;
520 }
521 
522 /*!
523     \return the list of combined image samplers
524 
525     With GLSL/Vulkan shaders as source a \c{layout(binding = 1) uniform sampler2D tex;}
526     uniform generates the following: (shown as textual JSON here)
527 
528     \badcode
529        "combinedImageSamplers": [
530             {
531                 "binding": 1,
532                 "name": "tex",
533                 "set": 0,
534                 "type": "sampler2D"
535             }
536         ]
537     \endcode
538 
539     This does not mean that other language versions of the shader must also use
540     a combined image sampler, especially considering that the concept may not
541     exist everywhere. For instance, a HLSL version will likely just use a
542     Texture2D and SamplerState object with registers t1 and s1, respectively.
543   */
combinedImageSamplers() const544 QVector<QShaderDescription::InOutVariable> QShaderDescription::combinedImageSamplers() const
545 {
546     return d->combinedImageSamplers;
547 }
548 
549 /*!
550     \return the list of image variables.
551 
552     These will likely occur in compute shaders. For example,
553     \c{layout (binding = 0, rgba8) uniform readonly image2D inputImage;}
554     generates the following: (shown as textual JSON here)
555 
556     \badcode
557        "storageImages": [
558             {
559                 "binding": 0,
560                 "imageFormat": "rgba8",
561                 "name": "inputImage",
562                 "set": 0,
563                 "type": "image2D"
564             }
565         ]
566     \endcode
567 
568     \note Separate image objects are not compatible with some graphics APIs,
569     such as, OpenGL 2.x or OpenGL ES older than 3.1.
570   */
storageImages() const571 QVector<QShaderDescription::InOutVariable> QShaderDescription::storageImages() const
572 {
573     return d->storageImages;
574 }
575 
576 /*!
577     Returns the local size of a compute shader.
578 
579     For example, for a compute shader with the following declaration the
580     function returns { 256, 16, 1}.
581 
582     \badcode
583         layout(local_size_x = 256, local_size_y = 16, local_size_z = 1) in;
584     \endcode
585  */
computeShaderLocalSize() const586 std::array<uint, 3> QShaderDescription::computeShaderLocalSize() const
587 {
588     return d->localSize;
589 }
590 
591 static struct TypeTab {
592     QString k;
593     QShaderDescription::VariableType v;
594 } typeTab[] = {
595     { QLatin1String("float"), QShaderDescription::Float },
596     { QLatin1String("vec2"), QShaderDescription::Vec2 },
597     { QLatin1String("vec3"), QShaderDescription::Vec3 },
598     { QLatin1String("vec4"), QShaderDescription::Vec4 },
599     { QLatin1String("mat2"), QShaderDescription::Mat2 },
600     { QLatin1String("mat3"), QShaderDescription::Mat3 },
601     { QLatin1String("mat4"), QShaderDescription::Mat4 },
602 
603     { QLatin1String("struct"), QShaderDescription::Struct },
604 
605     { QLatin1String("sampler1D"), QShaderDescription::Sampler1D },
606     { QLatin1String("sampler2D"), QShaderDescription::Sampler2D },
607     { QLatin1String("sampler2DMS"), QShaderDescription::Sampler2DMS },
608     { QLatin1String("sampler3D"), QShaderDescription::Sampler3D },
609     { QLatin1String("samplerCube"), QShaderDescription::SamplerCube },
610     { QLatin1String("sampler1DArray"), QShaderDescription::Sampler1DArray },
611     { QLatin1String("sampler2DArray"), QShaderDescription::Sampler2DArray },
612     { QLatin1String("sampler2DMSArray"), QShaderDescription::Sampler2DMSArray },
613     { QLatin1String("sampler3DArray"), QShaderDescription::Sampler3DArray },
614     { QLatin1String("samplerCubeArray"), QShaderDescription::SamplerCubeArray },
615     { QLatin1String("samplerRect"), QShaderDescription::SamplerRect },
616     { QLatin1String("samplerBuffer"), QShaderDescription::SamplerBuffer },
617 
618     { QLatin1String("mat2x3"), QShaderDescription::Mat2x3 },
619     { QLatin1String("mat2x4"), QShaderDescription::Mat2x4 },
620     { QLatin1String("mat3x2"), QShaderDescription::Mat3x2 },
621     { QLatin1String("mat3x4"), QShaderDescription::Mat3x4 },
622     { QLatin1String("mat4x2"), QShaderDescription::Mat4x2 },
623     { QLatin1String("mat4x3"), QShaderDescription::Mat4x3 },
624 
625     { QLatin1String("int"), QShaderDescription::Int },
626     { QLatin1String("ivec2"), QShaderDescription::Int2 },
627     { QLatin1String("ivec3"), QShaderDescription::Int3 },
628     { QLatin1String("ivec4"), QShaderDescription::Int4 },
629 
630     { QLatin1String("uint"), QShaderDescription::Uint },
631     { QLatin1String("uvec2"), QShaderDescription::Uint2 },
632     { QLatin1String("uvec3"), QShaderDescription::Uint3 },
633     { QLatin1String("uvec4"), QShaderDescription::Uint4 },
634 
635     { QLatin1String("bool"), QShaderDescription::Bool },
636     { QLatin1String("bvec2"), QShaderDescription::Bool2 },
637     { QLatin1String("bvec3"), QShaderDescription::Bool3 },
638     { QLatin1String("bvec4"), QShaderDescription::Bool4 },
639 
640     { QLatin1String("double"), QShaderDescription::Double },
641     { QLatin1String("dvec2"), QShaderDescription::Double2 },
642     { QLatin1String("dvec3"), QShaderDescription::Double3 },
643     { QLatin1String("dvec4"), QShaderDescription::Double4 },
644     { QLatin1String("dmat2"), QShaderDescription::DMat2 },
645     { QLatin1String("dmat3"), QShaderDescription::DMat3 },
646     { QLatin1String("dmat4"), QShaderDescription::DMat4 },
647     { QLatin1String("dmat2x3"), QShaderDescription::DMat2x3 },
648     { QLatin1String("dmat2x4"), QShaderDescription::DMat2x4 },
649     { QLatin1String("dmat3x2"), QShaderDescription::DMat3x2 },
650     { QLatin1String("dmat3x4"), QShaderDescription::DMat3x4 },
651     { QLatin1String("dmat4x2"), QShaderDescription::DMat4x2 },
652     { QLatin1String("dmat4x3"), QShaderDescription::DMat4x3 },
653 
654     { QLatin1String("image1D"), QShaderDescription::Image1D },
655     { QLatin1String("image2D"), QShaderDescription::Image2D },
656     { QLatin1String("image2DMS"), QShaderDescription::Image2DMS },
657     { QLatin1String("image3D"), QShaderDescription::Image3D },
658     { QLatin1String("imageCube"), QShaderDescription::ImageCube },
659     { QLatin1String("image1DArray"), QShaderDescription::Image1DArray },
660     { QLatin1String("image2DArray"), QShaderDescription::Image2DArray },
661     { QLatin1String("image2DMSArray"), QShaderDescription::Image2DMSArray },
662     { QLatin1String("image3DArray"), QShaderDescription::Image3DArray },
663     { QLatin1String("imageCubeArray"), QShaderDescription::ImageCubeArray },
664     { QLatin1String("imageRect"), QShaderDescription::ImageRect },
665     { QLatin1String("imageBuffer"), QShaderDescription::ImageBuffer }
666 };
667 
typeStr(const QShaderDescription::VariableType & t)668 static QString typeStr(const QShaderDescription::VariableType &t)
669 {
670     for (size_t i = 0; i < sizeof(typeTab) / sizeof(TypeTab); ++i) {
671         if (typeTab[i].v == t)
672             return typeTab[i].k;
673     }
674     return QString();
675 }
676 
mapType(const QString & t)677 static QShaderDescription::VariableType mapType(const QString &t)
678 {
679     for (size_t i = 0; i < sizeof(typeTab) / sizeof(TypeTab); ++i) {
680         if (typeTab[i].k == t)
681             return typeTab[i].v;
682     }
683     return QShaderDescription::Unknown;
684 }
685 
686 static struct ImageFormatTab {
687     QString k;
688     QShaderDescription::ImageFormat v;
689 } imageFormatTab[] {
690     { QLatin1String("unknown"), QShaderDescription::ImageFormatUnknown },
691     { QLatin1String("rgba32f"), QShaderDescription::ImageFormatRgba32f },
692     { QLatin1String("rgba16"), QShaderDescription::ImageFormatRgba16f },
693     { QLatin1String("r32f"), QShaderDescription::ImageFormatR32f },
694     { QLatin1String("rgba8"), QShaderDescription::ImageFormatRgba8 },
695     { QLatin1String("rgba8_snorm"), QShaderDescription::ImageFormatRgba8Snorm },
696     { QLatin1String("rg32f"), QShaderDescription::ImageFormatRg32f },
697     { QLatin1String("rg16f"), QShaderDescription::ImageFormatRg16f },
698     { QLatin1String("r11f_g11f_b10f"), QShaderDescription::ImageFormatR11fG11fB10f },
699     { QLatin1String("r16f"), QShaderDescription::ImageFormatR16f },
700     { QLatin1String("rgba16"), QShaderDescription::ImageFormatRgba16 },
701     { QLatin1String("rgb10_a2"), QShaderDescription::ImageFormatRgb10A2 },
702     { QLatin1String("rg16"), QShaderDescription::ImageFormatRg16 },
703     { QLatin1String("rg8"), QShaderDescription::ImageFormatRg8 },
704     { QLatin1String("r16"), QShaderDescription::ImageFormatR16 },
705     { QLatin1String("r8"), QShaderDescription::ImageFormatR8 },
706     { QLatin1String("rgba16_snorm"), QShaderDescription::ImageFormatRgba16Snorm },
707     { QLatin1String("rg16_snorm"), QShaderDescription::ImageFormatRg16Snorm },
708     { QLatin1String("rg8_snorm"), QShaderDescription::ImageFormatRg8Snorm },
709     { QLatin1String("r16_snorm"), QShaderDescription::ImageFormatR16Snorm },
710     { QLatin1String("r8_snorm"), QShaderDescription::ImageFormatR8Snorm },
711     { QLatin1String("rgba32i"), QShaderDescription::ImageFormatRgba32i },
712     { QLatin1String("rgba16i"), QShaderDescription::ImageFormatRgba16i },
713     { QLatin1String("rgba8i"), QShaderDescription::ImageFormatRgba8i },
714     { QLatin1String("r32i"), QShaderDescription::ImageFormatR32i },
715     { QLatin1String("rg32i"), QShaderDescription::ImageFormatRg32i },
716     { QLatin1String("rg16i"), QShaderDescription::ImageFormatRg16i },
717     { QLatin1String("rg8i"), QShaderDescription::ImageFormatRg8i },
718     { QLatin1String("r16i"), QShaderDescription::ImageFormatR16i },
719     { QLatin1String("r8i"), QShaderDescription::ImageFormatR8i },
720     { QLatin1String("rgba32ui"), QShaderDescription::ImageFormatRgba32ui },
721     { QLatin1String("rgba16ui"), QShaderDescription::ImageFormatRgba16ui },
722     { QLatin1String("rgba8ui"), QShaderDescription::ImageFormatRgba8ui },
723     { QLatin1String("r32ui"), QShaderDescription::ImageFormatR32ui },
724     { QLatin1String("rgb10_a2ui"), QShaderDescription::ImageFormatRgb10a2ui },
725     { QLatin1String("rg32ui"), QShaderDescription::ImageFormatRg32ui },
726     { QLatin1String("rg16ui"), QShaderDescription::ImageFormatRg16ui },
727     { QLatin1String("rg8ui"), QShaderDescription::ImageFormatRg8ui },
728     { QLatin1String("r16ui"), QShaderDescription::ImageFormatR16ui },
729     { QLatin1String("r8ui"), QShaderDescription::ImageFormatR8ui }
730 };
731 
imageFormatStr(const QShaderDescription::ImageFormat & f)732 static QString imageFormatStr(const QShaderDescription::ImageFormat &f)
733 {
734     for (size_t i = 0; i < sizeof(imageFormatTab) / sizeof(ImageFormatTab); ++i) {
735         if (imageFormatTab[i].v == f)
736             return imageFormatTab[i].k;
737     }
738     return QString();
739 }
740 
mapImageFormat(const QString & f)741 static QShaderDescription::ImageFormat mapImageFormat(const QString &f)
742 {
743     for (size_t i = 0; i < sizeof(imageFormatTab) / sizeof(ImageFormatTab); ++i) {
744         if (imageFormatTab[i].k == f)
745             return imageFormatTab[i].v;
746     }
747     return QShaderDescription::ImageFormatUnknown;
748 }
749 
750 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug dbg,const QShaderDescription & sd)751 QDebug operator<<(QDebug dbg, const QShaderDescription &sd)
752 {
753     const QShaderDescriptionPrivate *d = sd.d;
754     QDebugStateSaver saver(dbg);
755 
756     if (sd.isValid()) {
757         dbg.nospace() << "QShaderDescription("
758                       << "inVars " << d->inVars
759                       << " outVars " << d->outVars
760                       << " uniformBlocks " << d->uniformBlocks
761                       << " pcBlocks " << d->pushConstantBlocks
762                       << " storageBlocks " << d->storageBlocks
763                       << " combinedSamplers " << d->combinedImageSamplers
764                       << " images " << d->storageImages
765                       << ')';
766     } else {
767         dbg.nospace() << "QShaderDescription(null)";
768     }
769 
770     return dbg;
771 }
772 
operator <<(QDebug dbg,const QShaderDescription::InOutVariable & var)773 QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var)
774 {
775     QDebugStateSaver saver(dbg);
776     dbg.nospace() << "InOutVariable(" << typeStr(var.type) << ' ' << var.name;
777     if (var.location >= 0)
778         dbg.nospace() << " location=" << var.location;
779     if (var.binding >= 0)
780         dbg.nospace() << " binding=" << var.binding;
781     if (var.descriptorSet >= 0)
782         dbg.nospace() << " set=" << var.descriptorSet;
783     if (var.imageFormat != QShaderDescription::ImageFormatUnknown)
784         dbg.nospace() << " imageFormat=" << imageFormatStr(var.imageFormat);
785     if (var.imageFlags)
786         dbg.nospace() << " imageFlags=" << var.imageFlags;
787     if (!var.arrayDims.isEmpty())
788         dbg.nospace() << " array=" << var.arrayDims;
789     dbg.nospace() << ')';
790     return dbg;
791 }
792 
operator <<(QDebug dbg,const QShaderDescription::BlockVariable & var)793 QDebug operator<<(QDebug dbg, const QShaderDescription::BlockVariable &var)
794 {
795     QDebugStateSaver saver(dbg);
796     dbg.nospace() << "BlockVariable(" << typeStr(var.type) << ' ' << var.name
797                   << " offset=" << var.offset << " size=" << var.size;
798     if (!var.arrayDims.isEmpty())
799         dbg.nospace() << " array=" << var.arrayDims;
800     if (var.arrayStride)
801         dbg.nospace() << " arrayStride=" << var.arrayStride;
802     if (var.matrixStride)
803         dbg.nospace() << " matrixStride=" << var.matrixStride;
804     if (var.matrixIsRowMajor)
805         dbg.nospace() << " [rowmaj]";
806     if (!var.structMembers.isEmpty())
807         dbg.nospace() << " structMembers=" << var.structMembers;
808     dbg.nospace() << ')';
809     return dbg;
810 }
811 
operator <<(QDebug dbg,const QShaderDescription::UniformBlock & blk)812 QDebug operator<<(QDebug dbg, const QShaderDescription::UniformBlock &blk)
813 {
814     QDebugStateSaver saver(dbg);
815     dbg.nospace() << "UniformBlock(" << blk.blockName << ' ' << blk.structName << " size=" << blk.size;
816     if (blk.binding >= 0)
817         dbg.nospace() << " binding=" << blk.binding;
818     if (blk.descriptorSet >= 0)
819         dbg.nospace() << " set=" << blk.descriptorSet;
820     dbg.nospace() << ' ' << blk.members << ')';
821     return dbg;
822 }
823 
operator <<(QDebug dbg,const QShaderDescription::PushConstantBlock & blk)824 QDebug operator<<(QDebug dbg, const QShaderDescription::PushConstantBlock &blk)
825 {
826     QDebugStateSaver saver(dbg);
827     dbg.nospace() << "PushConstantBlock(" << blk.name << " size=" << blk.size << ' ' << blk.members << ')';
828     return dbg;
829 }
830 
operator <<(QDebug dbg,const QShaderDescription::StorageBlock & blk)831 QDebug operator<<(QDebug dbg, const QShaderDescription::StorageBlock &blk)
832 {
833     QDebugStateSaver saver(dbg);
834     dbg.nospace() << "StorageBlock(" << blk.blockName << ' ' << blk.instanceName << " knownSize=" << blk.knownSize;
835     if (blk.binding >= 0)
836         dbg.nospace() << " binding=" << blk.binding;
837     if (blk.descriptorSet >= 0)
838         dbg.nospace() << " set=" << blk.descriptorSet;
839     dbg.nospace() << ' ' << blk.members << ')';
840     return dbg;
841 }
842 #endif
843 
844 static const QString nameKey = QLatin1String("name");
845 static const QString typeKey = QLatin1String("type");
846 static const QString locationKey = QLatin1String("location");
847 static const QString bindingKey = QLatin1String("binding");
848 static const QString setKey = QLatin1String("set");
849 static const QString imageFormatKey = QLatin1String("imageFormat");
850 static const QString imageFlagsKey = QLatin1String("imageFlags");
851 static const QString offsetKey = QLatin1String("offset");
852 static const QString arrayDimsKey = QLatin1String("arrayDims");
853 static const QString arrayStrideKey = QLatin1String("arrayStride");
854 static const QString matrixStrideKey = QLatin1String("matrixStride");
855 static const QString matrixRowMajorKey = QLatin1String("matrixRowMajor");
856 static const QString structMembersKey = QLatin1String("structMembers");
857 static const QString membersKey = QLatin1String("members");
858 static const QString inputsKey = QLatin1String("inputs");
859 static const QString outputsKey = QLatin1String("outputs");
860 static const QString uniformBlocksKey = QLatin1String("uniformBlocks");
861 static const QString blockNameKey = QLatin1String("blockName");
862 static const QString structNameKey = QLatin1String("structName");
863 static const QString instanceNameKey = QLatin1String("instanceName");
864 static const QString sizeKey = QLatin1String("size");
865 static const QString knownSizeKey = QLatin1String("knownSize");
866 static const QString pushConstantBlocksKey = QLatin1String("pushConstantBlocks");
867 static const QString storageBlocksKey = QLatin1String("storageBlocks");
868 static const QString combinedImageSamplersKey = QLatin1String("combinedImageSamplers");
869 static const QString storageImagesKey = QLatin1String("storageImages");
870 static const QString localSizeKey = QLatin1String("localSize");
871 
addDeco(QJsonObject * obj,const QShaderDescription::InOutVariable & v)872 static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v)
873 {
874     if (v.location >= 0)
875         (*obj)[locationKey] = v.location;
876     if (v.binding >= 0)
877         (*obj)[bindingKey] = v.binding;
878     if (v.descriptorSet >= 0)
879         (*obj)[setKey] = v.descriptorSet;
880     if (v.imageFormat != QShaderDescription::ImageFormatUnknown)
881         (*obj)[imageFormatKey] = imageFormatStr(v.imageFormat);
882     if (v.imageFlags)
883         (*obj)[imageFlagsKey] = int(v.imageFlags);
884     if (!v.arrayDims.isEmpty()) {
885         QJsonArray dimArr;
886         for (int dim : v.arrayDims)
887             dimArr.append(dim);
888         (*obj)[arrayDimsKey] = dimArr;
889     }
890 }
891 
serializeDecorations(QDataStream * stream,const QShaderDescription::InOutVariable & v)892 static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v)
893 {
894     (*stream) << v.location;
895     (*stream) << v.binding;
896     (*stream) << v.descriptorSet;
897     (*stream) << int(v.imageFormat);
898     (*stream) << int(v.imageFlags);
899     (*stream) << v.arrayDims.count();
900     for (int dim : v.arrayDims)
901         (*stream) << dim;
902 }
903 
inOutObject(const QShaderDescription::InOutVariable & v)904 static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
905 {
906     QJsonObject obj;
907     obj[nameKey] = v.name;
908     obj[typeKey] = typeStr(v.type);
909     addDeco(&obj, v);
910     return obj;
911 }
912 
serializeInOutVar(QDataStream * stream,const QShaderDescription::InOutVariable & v)913 static void serializeInOutVar(QDataStream *stream, const QShaderDescription::InOutVariable &v)
914 {
915     (*stream) << v.name;
916     (*stream) << int(v.type);
917     serializeDecorations(stream, v);
918 }
919 
blockMemberObject(const QShaderDescription::BlockVariable & v)920 static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v)
921 {
922     QJsonObject obj;
923     obj[nameKey] = v.name;
924     obj[typeKey] = typeStr(v.type);
925     obj[offsetKey] = v.offset;
926     obj[sizeKey] = v.size;
927     if (!v.arrayDims.isEmpty()) {
928         QJsonArray dimArr;
929         for (int dim : v.arrayDims)
930             dimArr.append(dim);
931         obj[arrayDimsKey] = dimArr;
932     }
933     if (v.arrayStride)
934         obj[arrayStrideKey] = v.arrayStride;
935     if (v.matrixStride)
936         obj[matrixStrideKey] = v.matrixStride;
937     if (v.matrixIsRowMajor)
938         obj[matrixRowMajorKey] = true;
939     if (!v.structMembers.isEmpty()) {
940         QJsonArray arr;
941         for (const QShaderDescription::BlockVariable &sv : v.structMembers)
942             arr.append(blockMemberObject(sv));
943         obj[structMembersKey] = arr;
944     }
945     return obj;
946 }
947 
serializeBlockMemberVar(QDataStream * stream,const QShaderDescription::BlockVariable & v)948 static void serializeBlockMemberVar(QDataStream *stream, const QShaderDescription::BlockVariable &v)
949 {
950     (*stream) << v.name;
951     (*stream) << int(v.type);
952     (*stream) << v.offset;
953     (*stream) << v.size;
954     (*stream) << v.arrayDims.count();
955     for (int dim : v.arrayDims)
956         (*stream) << dim;
957     (*stream) << v.arrayStride;
958     (*stream) << v.matrixStride;
959     (*stream) << v.matrixIsRowMajor;
960     (*stream) << v.structMembers.count();
961     for (const QShaderDescription::BlockVariable &sv : v.structMembers)
962         serializeBlockMemberVar(stream, sv);
963 }
964 
makeDoc()965 QJsonDocument QShaderDescriptionPrivate::makeDoc()
966 {
967     QJsonObject root;
968 
969     QJsonArray jinputs;
970     for (const QShaderDescription::InOutVariable &v : qAsConst(inVars))
971         jinputs.append(inOutObject(v));
972     if (!jinputs.isEmpty())
973         root[inputsKey] = jinputs;
974 
975     QJsonArray joutputs;
976     for (const QShaderDescription::InOutVariable &v : qAsConst(outVars))
977         joutputs.append(inOutObject(v));
978     if (!joutputs.isEmpty())
979         root[outputsKey] = joutputs;
980 
981     QJsonArray juniformBlocks;
982     for (const QShaderDescription::UniformBlock &b : uniformBlocks) {
983         QJsonObject juniformBlock;
984         juniformBlock[blockNameKey] = b.blockName;
985         juniformBlock[structNameKey] = b.structName;
986         juniformBlock[sizeKey] = b.size;
987         if (b.binding >= 0)
988             juniformBlock[bindingKey] = b.binding;
989         if (b.descriptorSet >= 0)
990             juniformBlock[setKey] = b.descriptorSet;
991         QJsonArray members;
992         for (const QShaderDescription::BlockVariable &v : b.members)
993             members.append(blockMemberObject(v));
994         juniformBlock[membersKey] = members;
995         juniformBlocks.append(juniformBlock);
996     }
997     if (!juniformBlocks.isEmpty())
998         root[uniformBlocksKey] = juniformBlocks;
999 
1000     QJsonArray jpushConstantBlocks;
1001     for (const QShaderDescription::PushConstantBlock &b : pushConstantBlocks) {
1002         QJsonObject jpushConstantBlock;
1003         jpushConstantBlock[nameKey] = b.name;
1004         jpushConstantBlock[sizeKey] = b.size;
1005         QJsonArray members;
1006         for (const QShaderDescription::BlockVariable &v : b.members)
1007             members.append(blockMemberObject(v));
1008         jpushConstantBlock[membersKey] = members;
1009         jpushConstantBlocks.append(jpushConstantBlock);
1010     }
1011     if (!jpushConstantBlocks.isEmpty())
1012         root[pushConstantBlocksKey] = jpushConstantBlocks;
1013 
1014     QJsonArray jstorageBlocks;
1015     for (const QShaderDescription::StorageBlock &b : storageBlocks) {
1016         QJsonObject jstorageBlock;
1017         jstorageBlock[blockNameKey] = b.blockName;
1018         jstorageBlock[instanceNameKey] = b.instanceName;
1019         jstorageBlock[knownSizeKey] = b.knownSize;
1020         if (b.binding >= 0)
1021             jstorageBlock[bindingKey] = b.binding;
1022         if (b.descriptorSet >= 0)
1023             jstorageBlock[setKey] = b.descriptorSet;
1024         QJsonArray members;
1025         for (const QShaderDescription::BlockVariable &v : b.members)
1026             members.append(blockMemberObject(v));
1027         jstorageBlock[membersKey] = members;
1028         jstorageBlocks.append(jstorageBlock);
1029     }
1030     if (!jstorageBlocks.isEmpty())
1031         root[storageBlocksKey] = jstorageBlocks;
1032 
1033     QJsonArray jcombinedSamplers;
1034     for (const QShaderDescription::InOutVariable &v : qAsConst(combinedImageSamplers)) {
1035         QJsonObject sampler;
1036         sampler[nameKey] = v.name;
1037         sampler[typeKey] = typeStr(v.type);
1038         addDeco(&sampler, v);
1039         jcombinedSamplers.append(sampler);
1040     }
1041     if (!jcombinedSamplers.isEmpty())
1042         root[combinedImageSamplersKey] = jcombinedSamplers;
1043 
1044     QJsonArray jstorageImages;
1045     for (const QShaderDescription::InOutVariable &v : qAsConst(storageImages)) {
1046         QJsonObject image;
1047         image[nameKey] = v.name;
1048         image[typeKey] = typeStr(v.type);
1049         addDeco(&image, v);
1050         jstorageImages.append(image);
1051     }
1052     if (!jstorageImages.isEmpty())
1053         root[storageImagesKey] = jstorageImages;
1054 
1055     QJsonArray jlocalSize;
1056     for (int i = 0; i < 3; ++i)
1057         jlocalSize.append(QJsonValue(int(localSize[i])));
1058     root[localSizeKey] = jlocalSize;
1059 
1060     return QJsonDocument(root);
1061 }
1062 
writeToStream(QDataStream * stream)1063 void QShaderDescriptionPrivate::writeToStream(QDataStream *stream)
1064 {
1065     (*stream) << inVars.count();
1066     for (const QShaderDescription::InOutVariable &v : qAsConst(inVars))
1067         serializeInOutVar(stream, v);
1068 
1069     (*stream) << outVars.count();
1070     for (const QShaderDescription::InOutVariable &v : qAsConst(outVars))
1071         serializeInOutVar(stream, v);
1072 
1073     (*stream) << uniformBlocks.count();
1074     for (const QShaderDescription::UniformBlock &b : uniformBlocks) {
1075         (*stream) << b.blockName;
1076         (*stream) << b.structName;
1077         (*stream) << b.size;
1078         (*stream) << b.binding;
1079         (*stream) << b.descriptorSet;
1080         (*stream) << b.members.count();
1081         for (const QShaderDescription::BlockVariable &v : b.members)
1082             serializeBlockMemberVar(stream, v);
1083     }
1084 
1085     (*stream) << pushConstantBlocks.count();
1086     for (const QShaderDescription::PushConstantBlock &b : pushConstantBlocks) {
1087         (*stream) << b.name;
1088         (*stream) << b.size;
1089         (*stream) << b.members.count();
1090         for (const QShaderDescription::BlockVariable &v : b.members)
1091             serializeBlockMemberVar(stream, v);
1092     }
1093 
1094     (*stream) << storageBlocks.count();
1095     for (const QShaderDescription::StorageBlock &b : storageBlocks) {
1096         (*stream) << b.blockName;
1097         (*stream) << b.instanceName;
1098         (*stream) << b.knownSize;
1099         (*stream) << b.binding;
1100         (*stream) << b.descriptorSet;
1101         (*stream) << b.members.count();
1102         for (const QShaderDescription::BlockVariable &v : b.members)
1103             serializeBlockMemberVar(stream, v);
1104     }
1105 
1106     (*stream) << combinedImageSamplers.count();
1107     for (const QShaderDescription::InOutVariable &v : qAsConst(combinedImageSamplers)) {
1108         (*stream) << v.name;
1109         (*stream) << int(v.type);
1110         serializeDecorations(stream, v);
1111     }
1112 
1113     (*stream) << storageImages.count();
1114     for (const QShaderDescription::InOutVariable &v : qAsConst(storageImages)) {
1115         (*stream) << v.name;
1116         (*stream) << int(v.type);
1117         serializeDecorations(stream, v);
1118     }
1119 
1120     for (size_t i = 0; i < 3; ++i)
1121         (*stream) << localSize[i];
1122 }
1123 
inOutVar(const QJsonObject & obj)1124 static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj)
1125 {
1126     QShaderDescription::InOutVariable var;
1127     var.name = obj[nameKey].toString();
1128     var.type = mapType(obj[typeKey].toString());
1129     if (obj.contains(locationKey))
1130         var.location = obj[locationKey].toInt();
1131     if (obj.contains(bindingKey))
1132         var.binding = obj[bindingKey].toInt();
1133     if (obj.contains(setKey))
1134         var.descriptorSet = obj[setKey].toInt();
1135     if (obj.contains(imageFormatKey))
1136         var.imageFormat = mapImageFormat(obj[imageFormatKey].toString());
1137     if (obj.contains(imageFlagsKey))
1138         var.imageFlags = QShaderDescription::ImageFlags(obj[imageFlagsKey].toInt());
1139     if (obj.contains(arrayDimsKey)) {
1140         QJsonArray dimArr = obj[arrayDimsKey].toArray();
1141         for (int i = 0; i < dimArr.count(); ++i)
1142             var.arrayDims.append(dimArr.at(i).toInt());
1143     }
1144     return var;
1145 }
1146 
deserializeDecorations(QDataStream * stream,int version,QShaderDescription::InOutVariable * v)1147 static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v)
1148 {
1149     (*stream) >> v->location;
1150     (*stream) >> v->binding;
1151     (*stream) >> v->descriptorSet;
1152     int f;
1153     (*stream) >> f;
1154     v->imageFormat = QShaderDescription::ImageFormat(f);
1155     (*stream) >> f;
1156     v->imageFlags = QShaderDescription::ImageFlags(f);
1157 
1158     if (version > QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS) {
1159         (*stream) >> f;
1160         v->arrayDims.resize(f);
1161         for (int i = 0; i < f; ++i)
1162             (*stream) >> v->arrayDims[i];
1163     }
1164 }
1165 
deserializeInOutVar(QDataStream * stream,int version)1166 static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream, int version)
1167 {
1168     QShaderDescription::InOutVariable var;
1169     (*stream) >> var.name;
1170     int t;
1171     (*stream) >> t;
1172     var.type = QShaderDescription::VariableType(t);
1173     deserializeDecorations(stream, version, &var);
1174     return var;
1175 }
1176 
blockVar(const QJsonObject & obj)1177 static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj)
1178 {
1179     QShaderDescription::BlockVariable var;
1180     var.name = obj[nameKey].toString();
1181     var.type = mapType(obj[typeKey].toString());
1182     var.offset = obj[offsetKey].toInt();
1183     var.size = obj[sizeKey].toInt();
1184     if (obj.contains(arrayDimsKey)) {
1185         QJsonArray dimArr = obj[arrayDimsKey].toArray();
1186         for (int i = 0; i < dimArr.count(); ++i)
1187             var.arrayDims.append(dimArr.at(i).toInt());
1188     }
1189     if (obj.contains(arrayStrideKey))
1190         var.arrayStride = obj[arrayStrideKey].toInt();
1191     if (obj.contains(matrixStrideKey))
1192         var.matrixStride = obj[matrixStrideKey].toInt();
1193     if (obj.contains(matrixRowMajorKey))
1194         var.matrixIsRowMajor = obj[matrixRowMajorKey].toBool();
1195     if (obj.contains(structMembersKey)) {
1196         QJsonArray arr = obj[structMembersKey].toArray();
1197         for (int i = 0; i < arr.count(); ++i)
1198             var.structMembers.append(blockVar(arr.at(i).toObject()));
1199     }
1200     return var;
1201 }
1202 
deserializeBlockMemberVar(QDataStream * stream,int version)1203 static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream, int version)
1204 {
1205     QShaderDescription::BlockVariable var;
1206     (*stream) >> var.name;
1207     int t;
1208     (*stream) >> t;
1209     var.type = QShaderDescription::VariableType(t);
1210     (*stream) >> var.offset;
1211     (*stream) >> var.size;
1212     int count;
1213     (*stream) >> count;
1214     var.arrayDims.resize(count);
1215     for (int i = 0; i < count; ++i)
1216         (*stream) >> var.arrayDims[i];
1217     (*stream) >> var.arrayStride;
1218     (*stream) >> var.matrixStride;
1219     (*stream) >> var.matrixIsRowMajor;
1220     (*stream) >> count;
1221     var.structMembers.resize(count);
1222     for (int i = 0; i < count; ++i)
1223         var.structMembers[i] = deserializeBlockMemberVar(stream, version);
1224     return var;
1225 }
1226 
loadDoc(const QJsonDocument & doc)1227 void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
1228 {
1229     if (doc.isNull()) {
1230         qWarning("QShaderDescription: JSON document is empty");
1231         return;
1232     }
1233 
1234     Q_ASSERT(ref.loadRelaxed() == 1); // must be detached
1235 
1236     inVars.clear();
1237     outVars.clear();
1238     uniformBlocks.clear();
1239     pushConstantBlocks.clear();
1240     storageBlocks.clear();
1241     combinedImageSamplers.clear();
1242     storageImages.clear();
1243 
1244     QJsonObject root = doc.object();
1245 
1246     if (root.contains(inputsKey)) {
1247         QJsonArray inputs = root[inputsKey].toArray();
1248         for (int i = 0; i < inputs.count(); ++i)
1249             inVars.append(inOutVar(inputs[i].toObject()));
1250     }
1251 
1252     if (root.contains(outputsKey)) {
1253         QJsonArray outputs = root[outputsKey].toArray();
1254         for (int i = 0; i < outputs.count(); ++i)
1255             outVars.append(inOutVar(outputs[i].toObject()));
1256     }
1257 
1258     if (root.contains(uniformBlocksKey)) {
1259         QJsonArray ubs = root[uniformBlocksKey].toArray();
1260         for (int i = 0; i < ubs.count(); ++i) {
1261             QJsonObject ubObj = ubs[i].toObject();
1262             QShaderDescription::UniformBlock ub;
1263             ub.blockName = ubObj[blockNameKey].toString();
1264             ub.structName = ubObj[structNameKey].toString();
1265             ub.size = ubObj[sizeKey].toInt();
1266             if (ubObj.contains(bindingKey))
1267                 ub.binding = ubObj[bindingKey].toInt();
1268             if (ubObj.contains(setKey))
1269                 ub.descriptorSet = ubObj[setKey].toInt();
1270             QJsonArray members = ubObj[membersKey].toArray();
1271             for (const QJsonValue &member : members)
1272                 ub.members.append(blockVar(member.toObject()));
1273             uniformBlocks.append(ub);
1274         }
1275     }
1276 
1277     if (root.contains(pushConstantBlocksKey)) {
1278         QJsonArray pcs = root[pushConstantBlocksKey].toArray();
1279         for (int i = 0; i < pcs.count(); ++i) {
1280             QJsonObject pcObj = pcs[i].toObject();
1281             QShaderDescription::PushConstantBlock pc;
1282             pc.name = pcObj[nameKey].toString();
1283             pc.size = pcObj[sizeKey].toInt();
1284             QJsonArray members = pcObj[membersKey].toArray();
1285             for (const QJsonValue &member : members)
1286                 pc.members.append(blockVar(member.toObject()));
1287             pushConstantBlocks.append(pc);
1288         }
1289     }
1290 
1291     if (root.contains(storageBlocksKey)) {
1292         QJsonArray ubs = root[storageBlocksKey].toArray();
1293         for (int i = 0; i < ubs.count(); ++i) {
1294             QJsonObject sbObj = ubs[i].toObject();
1295             QShaderDescription::StorageBlock sb;
1296             sb.blockName = sbObj[blockNameKey].toString();
1297             sb.instanceName = sbObj[instanceNameKey].toString();
1298             sb.knownSize = sbObj[knownSizeKey].toInt();
1299             if (sbObj.contains(bindingKey))
1300                 sb.binding = sbObj[bindingKey].toInt();
1301             if (sbObj.contains(setKey))
1302                 sb.descriptorSet = sbObj[setKey].toInt();
1303             QJsonArray members = sbObj[membersKey].toArray();
1304             for (const QJsonValue &member : members)
1305                 sb.members.append(blockVar(member.toObject()));
1306             storageBlocks.append(sb);
1307         }
1308     }
1309 
1310     if (root.contains(combinedImageSamplersKey)) {
1311         QJsonArray samplers = root[combinedImageSamplersKey].toArray();
1312         for (int i = 0; i < samplers.count(); ++i)
1313             combinedImageSamplers.append(inOutVar(samplers[i].toObject()));
1314     }
1315 
1316     if (root.contains(storageImagesKey)) {
1317         QJsonArray images = root[storageImagesKey].toArray();
1318         for (int i = 0; i < images.count(); ++i)
1319             storageImages.append(inOutVar(images[i].toObject()));
1320     }
1321 
1322     if (root.contains(localSizeKey)) {
1323         QJsonArray localSizeArr = root[localSizeKey].toArray();
1324         if (localSizeArr.count() == 3) {
1325             for (int i = 0; i < 3; ++i)
1326                 localSize[i] = localSizeArr[i].toInt();
1327         }
1328     }
1329 }
1330 
loadFromStream(QDataStream * stream,int version)1331 void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version)
1332 {
1333     Q_ASSERT(ref.loadRelaxed() == 1); // must be detached
1334 
1335     int count;
1336     (*stream) >> count;
1337     inVars.resize(count);
1338     for (int i = 0; i < count; ++i)
1339         inVars[i] = deserializeInOutVar(stream, version);
1340 
1341     (*stream) >> count;
1342     outVars.resize(count);
1343     for (int i = 0; i < count; ++i)
1344         outVars[i] = deserializeInOutVar(stream, version);
1345 
1346     (*stream) >> count;
1347     uniformBlocks.resize(count);
1348     for (int i = 0; i < count; ++i) {
1349         (*stream) >> uniformBlocks[i].blockName;
1350         (*stream) >> uniformBlocks[i].structName;
1351         (*stream) >> uniformBlocks[i].size;
1352         (*stream) >> uniformBlocks[i].binding;
1353         (*stream) >> uniformBlocks[i].descriptorSet;
1354         int memberCount;
1355         (*stream) >> memberCount;
1356         uniformBlocks[i].members.resize(memberCount);
1357         for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1358             uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
1359     }
1360 
1361     (*stream) >> count;
1362     pushConstantBlocks.resize(count);
1363     for (int i = 0; i < count; ++i) {
1364         (*stream) >> pushConstantBlocks[i].name;
1365         (*stream) >> pushConstantBlocks[i].size;
1366         int memberCount;
1367         (*stream) >> memberCount;
1368         pushConstantBlocks[i].members.resize(memberCount);
1369         for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1370             pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
1371     }
1372 
1373     (*stream) >> count;
1374     storageBlocks.resize(count);
1375     for (int i = 0; i < count; ++i) {
1376         (*stream) >> storageBlocks[i].blockName;
1377         (*stream) >> storageBlocks[i].instanceName;
1378         (*stream) >> storageBlocks[i].knownSize;
1379         (*stream) >> storageBlocks[i].binding;
1380         (*stream) >> storageBlocks[i].descriptorSet;
1381         int memberCount;
1382         (*stream) >> memberCount;
1383         storageBlocks[i].members.resize(memberCount);
1384         for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1385             storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
1386     }
1387 
1388     (*stream) >> count;
1389     combinedImageSamplers.resize(count);
1390     for (int i = 0; i < count; ++i) {
1391         (*stream) >> combinedImageSamplers[i].name;
1392         int t;
1393         (*stream) >> t;
1394         combinedImageSamplers[i].type = QShaderDescription::VariableType(t);
1395         deserializeDecorations(stream, version, &combinedImageSamplers[i]);
1396     }
1397 
1398     (*stream) >> count;
1399     storageImages.resize(count);
1400     for (int i = 0; i < count; ++i) {
1401         (*stream) >> storageImages[i].name;
1402         int t;
1403         (*stream) >> t;
1404         storageImages[i].type = QShaderDescription::VariableType(t);
1405         deserializeDecorations(stream, version, &storageImages[i]);
1406     }
1407 
1408     for (size_t i = 0; i < 3; ++i)
1409         (*stream) >> localSize[i];
1410 }
1411 
1412 /*!
1413     Returns \c true if the two QShaderDescription objects \a lhs and \a rhs are
1414     equal.
1415 
1416     \relates QShaderDescription
1417  */
operator ==(const QShaderDescription & lhs,const QShaderDescription & rhs)1418 bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW
1419 {
1420     if (lhs.d == rhs.d)
1421         return true;
1422 
1423     return lhs.d->inVars == rhs.d->inVars
1424             && lhs.d->outVars == rhs.d->outVars
1425             && lhs.d->uniformBlocks == rhs.d->uniformBlocks
1426             && lhs.d->pushConstantBlocks == rhs.d->pushConstantBlocks
1427             && lhs.d->storageBlocks == rhs.d->storageBlocks
1428             && lhs.d->combinedImageSamplers == rhs.d->combinedImageSamplers
1429             && lhs.d->storageImages == rhs.d->storageImages
1430             && lhs.d->localSize == rhs.d->localSize;
1431 }
1432 
1433 /*!
1434     Returns \c true if the two InOutVariable objects \a lhs and \a rhs are
1435     equal.
1436 
1437     \relates QShaderDescription::InOutVariable
1438  */
operator ==(const QShaderDescription::InOutVariable & lhs,const QShaderDescription::InOutVariable & rhs)1439 bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW
1440 {
1441     return lhs.name == rhs.name
1442             && lhs.type == rhs.type
1443             && lhs.location == rhs.location
1444             && lhs.binding == rhs.binding
1445             && lhs.descriptorSet == rhs.descriptorSet
1446             && lhs.imageFormat == rhs.imageFormat
1447             && lhs.imageFlags == rhs.imageFlags
1448             && lhs.arrayDims == rhs.arrayDims;
1449 }
1450 
1451 /*!
1452     Returns \c true if the two BlockVariable objects \a lhs and \a rhs are
1453     equal.
1454 
1455     \relates QShaderDescription::BlockVariable
1456  */
operator ==(const QShaderDescription::BlockVariable & lhs,const QShaderDescription::BlockVariable & rhs)1457 bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW
1458 {
1459     return lhs.name == rhs.name
1460             && lhs.type == rhs.type
1461             && lhs.offset == rhs.offset
1462             && lhs.size == rhs.size
1463             && lhs.arrayDims == rhs.arrayDims
1464             && lhs.arrayStride == rhs.arrayStride
1465             && lhs.matrixStride == rhs.matrixStride
1466             && lhs.matrixIsRowMajor == rhs.matrixIsRowMajor
1467             && lhs.structMembers == rhs.structMembers;
1468 }
1469 
1470 /*!
1471     Returns \c true if the two UniformBlock objects \a lhs and \a rhs are
1472     equal.
1473 
1474     \relates QShaderDescription::UniformBlock
1475  */
operator ==(const QShaderDescription::UniformBlock & lhs,const QShaderDescription::UniformBlock & rhs)1476 bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW
1477 {
1478     return lhs.blockName == rhs.blockName
1479             && lhs.structName == rhs.structName
1480             && lhs.size == rhs.size
1481             && lhs.binding == rhs.binding
1482             && lhs.descriptorSet == rhs.descriptorSet
1483             && lhs.members == rhs.members;
1484 }
1485 
1486 /*!
1487     Returns \c true if the two PushConstantBlock objects \a lhs and \a rhs are
1488     equal.
1489 
1490     \relates QShaderDescription::PushConstantBlock
1491  */
operator ==(const QShaderDescription::PushConstantBlock & lhs,const QShaderDescription::PushConstantBlock & rhs)1492 bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW
1493 {
1494     return lhs.name == rhs.name
1495             && lhs.size == rhs.size
1496             && lhs.members == rhs.members;
1497 }
1498 
1499 /*!
1500     Returns \c true if the two StorageBlock objects \a lhs and \a rhs are
1501     equal.
1502 
1503     \relates QShaderDescription::StorageBlock
1504  */
operator ==(const QShaderDescription::StorageBlock & lhs,const QShaderDescription::StorageBlock & rhs)1505 bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW
1506 {
1507     return lhs.blockName == rhs.blockName
1508             && lhs.instanceName == rhs.instanceName
1509             && lhs.knownSize == rhs.knownSize
1510             && lhs.binding == rhs.binding
1511             && lhs.descriptorSet == rhs.descriptorSet
1512             && lhs.members == rhs.members;
1513 }
1514 
1515 QT_END_NAMESPACE
1516