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
47QT_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 */
289QShaderDescription::QShaderDescription()
290 : d(new QShaderDescriptionPrivate)
291{
292}
293
294/*!
295 \internal
296 */
297void QShaderDescription::detach()
298{
299 qAtomicDetach(d);
300}
301
302/*!
303 \internal
304 */
305QShaderDescription::QShaderDescription(const QShaderDescription &other)
306 : d(other.d)
307{
308 d->ref.ref();
309}
310
311/*!
312 \internal
313 */
314QShaderDescription &QShaderDescription::operator=(const QShaderDescription &other)
315{
316 qAtomicAssign(d, x: other.d);
317 return *this;
318}
319
320/*!
321 Destructor.
322 */
323QShaderDescription::~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 */
333bool 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 */
346QByteArray QShaderDescription::toCbor() const
347{
348 return QCborValue::fromJsonValue(v: 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 */
358QByteArray QShaderDescription::toJson() const
359{
360 return d->makeDoc().toJson();
361}
362
363void 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 */
377QShaderDescription QShaderDescription::fromBinaryJson(const QByteArray &data)
378{
379 QShaderDescription desc;
380QT_WARNING_PUSH
381QT_WARNING_DISABLE_DEPRECATED
382 QShaderDescriptionPrivate::get(desc: &desc)->loadDoc(doc: QJsonDocument::fromBinaryData(data));
383QT_WARNING_POP
384 return desc;
385}
386#endif
387
388/*!
389 Deserializes the given CBOR \a data and returns a new QShaderDescription.
390 */
391QShaderDescription QShaderDescription::fromCbor(const QByteArray &data)
392{
393 QShaderDescription desc;
394 const QCborValue cbor = QCborValue::fromCbor(ba: data);
395 if (cbor.isMap()) {
396 const QJsonDocument doc(cbor.toMap().toJsonObject());
397 QShaderDescriptionPrivate::get(desc: &desc)->loadDoc(doc);
398 }
399 if (cbor.isArray()) {
400 const QJsonDocument doc(cbor.toArray().toJsonArray());
401 QShaderDescriptionPrivate::get(desc: &desc)->loadDoc(doc);
402 }
403 return desc;
404}
405
406QShaderDescription QShaderDescription::deserialize(QDataStream *stream, int version)
407{
408 QShaderDescription desc;
409 QShaderDescriptionPrivate::get(desc: &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 */
418QVector<QShaderDescription::InOutVariable> QShaderDescription::inputVariables() const
419{
420 return d->inVars;
421}
422
423/*!
424 \return the list of output variables.
425 */
426QVector<QShaderDescription::InOutVariable> QShaderDescription::outputVariables() const
427{
428 return d->outVars;
429}
430
431/*!
432 \return the list of uniform blocks.
433 */
434QVector<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 */
446QVector<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 */
517QVector<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 */
544QVector<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 */
571QVector<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 */
586std::array<uint, 3> QShaderDescription::computeShaderLocalSize() const
587{
588 return d->localSize;
589}
590
591static struct TypeTab {
592 QString k;
593 QShaderDescription::VariableType v;
594} typeTab[] = {
595 { .k: QLatin1String("float"), .v: QShaderDescription::Float },
596 { .k: QLatin1String("vec2"), .v: QShaderDescription::Vec2 },
597 { .k: QLatin1String("vec3"), .v: QShaderDescription::Vec3 },
598 { .k: QLatin1String("vec4"), .v: QShaderDescription::Vec4 },
599 { .k: QLatin1String("mat2"), .v: QShaderDescription::Mat2 },
600 { .k: QLatin1String("mat3"), .v: QShaderDescription::Mat3 },
601 { .k: QLatin1String("mat4"), .v: QShaderDescription::Mat4 },
602
603 { .k: QLatin1String("struct"), .v: QShaderDescription::Struct },
604
605 { .k: QLatin1String("sampler1D"), .v: QShaderDescription::Sampler1D },
606 { .k: QLatin1String("sampler2D"), .v: QShaderDescription::Sampler2D },
607 { .k: QLatin1String("sampler2DMS"), .v: QShaderDescription::Sampler2DMS },
608 { .k: QLatin1String("sampler3D"), .v: QShaderDescription::Sampler3D },
609 { .k: QLatin1String("samplerCube"), .v: QShaderDescription::SamplerCube },
610 { .k: QLatin1String("sampler1DArray"), .v: QShaderDescription::Sampler1DArray },
611 { .k: QLatin1String("sampler2DArray"), .v: QShaderDescription::Sampler2DArray },
612 { .k: QLatin1String("sampler2DMSArray"), .v: QShaderDescription::Sampler2DMSArray },
613 { .k: QLatin1String("sampler3DArray"), .v: QShaderDescription::Sampler3DArray },
614 { .k: QLatin1String("samplerCubeArray"), .v: QShaderDescription::SamplerCubeArray },
615 { .k: QLatin1String("samplerRect"), .v: QShaderDescription::SamplerRect },
616 { .k: QLatin1String("samplerBuffer"), .v: QShaderDescription::SamplerBuffer },
617
618 { .k: QLatin1String("mat2x3"), .v: QShaderDescription::Mat2x3 },
619 { .k: QLatin1String("mat2x4"), .v: QShaderDescription::Mat2x4 },
620 { .k: QLatin1String("mat3x2"), .v: QShaderDescription::Mat3x2 },
621 { .k: QLatin1String("mat3x4"), .v: QShaderDescription::Mat3x4 },
622 { .k: QLatin1String("mat4x2"), .v: QShaderDescription::Mat4x2 },
623 { .k: QLatin1String("mat4x3"), .v: QShaderDescription::Mat4x3 },
624
625 { .k: QLatin1String("int"), .v: QShaderDescription::Int },
626 { .k: QLatin1String("ivec2"), .v: QShaderDescription::Int2 },
627 { .k: QLatin1String("ivec3"), .v: QShaderDescription::Int3 },
628 { .k: QLatin1String("ivec4"), .v: QShaderDescription::Int4 },
629
630 { .k: QLatin1String("uint"), .v: QShaderDescription::Uint },
631 { .k: QLatin1String("uvec2"), .v: QShaderDescription::Uint2 },
632 { .k: QLatin1String("uvec3"), .v: QShaderDescription::Uint3 },
633 { .k: QLatin1String("uvec4"), .v: QShaderDescription::Uint4 },
634
635 { .k: QLatin1String("bool"), .v: QShaderDescription::Bool },
636 { .k: QLatin1String("bvec2"), .v: QShaderDescription::Bool2 },
637 { .k: QLatin1String("bvec3"), .v: QShaderDescription::Bool3 },
638 { .k: QLatin1String("bvec4"), .v: QShaderDescription::Bool4 },
639
640 { .k: QLatin1String("double"), .v: QShaderDescription::Double },
641 { .k: QLatin1String("dvec2"), .v: QShaderDescription::Double2 },
642 { .k: QLatin1String("dvec3"), .v: QShaderDescription::Double3 },
643 { .k: QLatin1String("dvec4"), .v: QShaderDescription::Double4 },
644 { .k: QLatin1String("dmat2"), .v: QShaderDescription::DMat2 },
645 { .k: QLatin1String("dmat3"), .v: QShaderDescription::DMat3 },
646 { .k: QLatin1String("dmat4"), .v: QShaderDescription::DMat4 },
647 { .k: QLatin1String("dmat2x3"), .v: QShaderDescription::DMat2x3 },
648 { .k: QLatin1String("dmat2x4"), .v: QShaderDescription::DMat2x4 },
649 { .k: QLatin1String("dmat3x2"), .v: QShaderDescription::DMat3x2 },
650 { .k: QLatin1String("dmat3x4"), .v: QShaderDescription::DMat3x4 },
651 { .k: QLatin1String("dmat4x2"), .v: QShaderDescription::DMat4x2 },
652 { .k: QLatin1String("dmat4x3"), .v: QShaderDescription::DMat4x3 },
653
654 { .k: QLatin1String("image1D"), .v: QShaderDescription::Image1D },
655 { .k: QLatin1String("image2D"), .v: QShaderDescription::Image2D },
656 { .k: QLatin1String("image2DMS"), .v: QShaderDescription::Image2DMS },
657 { .k: QLatin1String("image3D"), .v: QShaderDescription::Image3D },
658 { .k: QLatin1String("imageCube"), .v: QShaderDescription::ImageCube },
659 { .k: QLatin1String("image1DArray"), .v: QShaderDescription::Image1DArray },
660 { .k: QLatin1String("image2DArray"), .v: QShaderDescription::Image2DArray },
661 { .k: QLatin1String("image2DMSArray"), .v: QShaderDescription::Image2DMSArray },
662 { .k: QLatin1String("image3DArray"), .v: QShaderDescription::Image3DArray },
663 { .k: QLatin1String("imageCubeArray"), .v: QShaderDescription::ImageCubeArray },
664 { .k: QLatin1String("imageRect"), .v: QShaderDescription::ImageRect },
665 { .k: QLatin1String("imageBuffer"), .v: QShaderDescription::ImageBuffer }
666};
667
668static 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
677static 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
686static struct ImageFormatTab {
687 QString k;
688 QShaderDescription::ImageFormat v;
689} imageFormatTab[] {
690 { .k: QLatin1String("unknown"), .v: QShaderDescription::ImageFormatUnknown },
691 { .k: QLatin1String("rgba32f"), .v: QShaderDescription::ImageFormatRgba32f },
692 { .k: QLatin1String("rgba16"), .v: QShaderDescription::ImageFormatRgba16f },
693 { .k: QLatin1String("r32f"), .v: QShaderDescription::ImageFormatR32f },
694 { .k: QLatin1String("rgba8"), .v: QShaderDescription::ImageFormatRgba8 },
695 { .k: QLatin1String("rgba8_snorm"), .v: QShaderDescription::ImageFormatRgba8Snorm },
696 { .k: QLatin1String("rg32f"), .v: QShaderDescription::ImageFormatRg32f },
697 { .k: QLatin1String("rg16f"), .v: QShaderDescription::ImageFormatRg16f },
698 { .k: QLatin1String("r11f_g11f_b10f"), .v: QShaderDescription::ImageFormatR11fG11fB10f },
699 { .k: QLatin1String("r16f"), .v: QShaderDescription::ImageFormatR16f },
700 { .k: QLatin1String("rgba16"), .v: QShaderDescription::ImageFormatRgba16 },
701 { .k: QLatin1String("rgb10_a2"), .v: QShaderDescription::ImageFormatRgb10A2 },
702 { .k: QLatin1String("rg16"), .v: QShaderDescription::ImageFormatRg16 },
703 { .k: QLatin1String("rg8"), .v: QShaderDescription::ImageFormatRg8 },
704 { .k: QLatin1String("r16"), .v: QShaderDescription::ImageFormatR16 },
705 { .k: QLatin1String("r8"), .v: QShaderDescription::ImageFormatR8 },
706 { .k: QLatin1String("rgba16_snorm"), .v: QShaderDescription::ImageFormatRgba16Snorm },
707 { .k: QLatin1String("rg16_snorm"), .v: QShaderDescription::ImageFormatRg16Snorm },
708 { .k: QLatin1String("rg8_snorm"), .v: QShaderDescription::ImageFormatRg8Snorm },
709 { .k: QLatin1String("r16_snorm"), .v: QShaderDescription::ImageFormatR16Snorm },
710 { .k: QLatin1String("r8_snorm"), .v: QShaderDescription::ImageFormatR8Snorm },
711 { .k: QLatin1String("rgba32i"), .v: QShaderDescription::ImageFormatRgba32i },
712 { .k: QLatin1String("rgba16i"), .v: QShaderDescription::ImageFormatRgba16i },
713 { .k: QLatin1String("rgba8i"), .v: QShaderDescription::ImageFormatRgba8i },
714 { .k: QLatin1String("r32i"), .v: QShaderDescription::ImageFormatR32i },
715 { .k: QLatin1String("rg32i"), .v: QShaderDescription::ImageFormatRg32i },
716 { .k: QLatin1String("rg16i"), .v: QShaderDescription::ImageFormatRg16i },
717 { .k: QLatin1String("rg8i"), .v: QShaderDescription::ImageFormatRg8i },
718 { .k: QLatin1String("r16i"), .v: QShaderDescription::ImageFormatR16i },
719 { .k: QLatin1String("r8i"), .v: QShaderDescription::ImageFormatR8i },
720 { .k: QLatin1String("rgba32ui"), .v: QShaderDescription::ImageFormatRgba32ui },
721 { .k: QLatin1String("rgba16ui"), .v: QShaderDescription::ImageFormatRgba16ui },
722 { .k: QLatin1String("rgba8ui"), .v: QShaderDescription::ImageFormatRgba8ui },
723 { .k: QLatin1String("r32ui"), .v: QShaderDescription::ImageFormatR32ui },
724 { .k: QLatin1String("rgb10_a2ui"), .v: QShaderDescription::ImageFormatRgb10a2ui },
725 { .k: QLatin1String("rg32ui"), .v: QShaderDescription::ImageFormatRg32ui },
726 { .k: QLatin1String("rg16ui"), .v: QShaderDescription::ImageFormatRg16ui },
727 { .k: QLatin1String("rg8ui"), .v: QShaderDescription::ImageFormatRg8ui },
728 { .k: QLatin1String("r16ui"), .v: QShaderDescription::ImageFormatR16ui },
729 { .k: QLatin1String("r8ui"), .v: QShaderDescription::ImageFormatR8ui }
730};
731
732static 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
741static 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
751QDebug 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
773QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var)
774{
775 QDebugStateSaver saver(dbg);
776 dbg.nospace() << "InOutVariable(" << typeStr(t: 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(f: 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
793QDebug operator<<(QDebug dbg, const QShaderDescription::BlockVariable &var)
794{
795 QDebugStateSaver saver(dbg);
796 dbg.nospace() << "BlockVariable(" << typeStr(t: 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
812QDebug 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
824QDebug 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
831QDebug 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
844static const QString nameKey = QLatin1String("name");
845static const QString typeKey = QLatin1String("type");
846static const QString locationKey = QLatin1String("location");
847static const QString bindingKey = QLatin1String("binding");
848static const QString setKey = QLatin1String("set");
849static const QString imageFormatKey = QLatin1String("imageFormat");
850static const QString imageFlagsKey = QLatin1String("imageFlags");
851static const QString offsetKey = QLatin1String("offset");
852static const QString arrayDimsKey = QLatin1String("arrayDims");
853static const QString arrayStrideKey = QLatin1String("arrayStride");
854static const QString matrixStrideKey = QLatin1String("matrixStride");
855static const QString matrixRowMajorKey = QLatin1String("matrixRowMajor");
856static const QString structMembersKey = QLatin1String("structMembers");
857static const QString membersKey = QLatin1String("members");
858static const QString inputsKey = QLatin1String("inputs");
859static const QString outputsKey = QLatin1String("outputs");
860static const QString uniformBlocksKey = QLatin1String("uniformBlocks");
861static const QString blockNameKey = QLatin1String("blockName");
862static const QString structNameKey = QLatin1String("structName");
863static const QString instanceNameKey = QLatin1String("instanceName");
864static const QString sizeKey = QLatin1String("size");
865static const QString knownSizeKey = QLatin1String("knownSize");
866static const QString pushConstantBlocksKey = QLatin1String("pushConstantBlocks");
867static const QString storageBlocksKey = QLatin1String("storageBlocks");
868static const QString combinedImageSamplersKey = QLatin1String("combinedImageSamplers");
869static const QString storageImagesKey = QLatin1String("storageImages");
870static const QString localSizeKey = QLatin1String("localSize");
871
872static 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(f: 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(value: dim);
888 (*obj)[arrayDimsKey] = dimArr;
889 }
890}
891
892static 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
904static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
905{
906 QJsonObject obj;
907 obj[nameKey] = v.name;
908 obj[typeKey] = typeStr(t: v.type);
909 addDeco(obj: &obj, v);
910 return obj;
911}
912
913static void serializeInOutVar(QDataStream *stream, const QShaderDescription::InOutVariable &v)
914{
915 (*stream) << v.name;
916 (*stream) << int(v.type);
917 serializeDecorations(stream, v);
918}
919
920static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v)
921{
922 QJsonObject obj;
923 obj[nameKey] = v.name;
924 obj[typeKey] = typeStr(t: 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(value: 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(value: blockMemberObject(v: sv));
943 obj[structMembersKey] = arr;
944 }
945 return obj;
946}
947
948static 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, v: sv);
963}
964
965QJsonDocument QShaderDescriptionPrivate::makeDoc()
966{
967 QJsonObject root;
968
969 QJsonArray jinputs;
970 for (const QShaderDescription::InOutVariable &v : qAsConst(t&: inVars))
971 jinputs.append(value: inOutObject(v));
972 if (!jinputs.isEmpty())
973 root[inputsKey] = jinputs;
974
975 QJsonArray joutputs;
976 for (const QShaderDescription::InOutVariable &v : qAsConst(t&: outVars))
977 joutputs.append(value: 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(value: blockMemberObject(v));
994 juniformBlock[membersKey] = members;
995 juniformBlocks.append(value: 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(value: blockMemberObject(v));
1008 jpushConstantBlock[membersKey] = members;
1009 jpushConstantBlocks.append(value: 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(value: blockMemberObject(v));
1027 jstorageBlock[membersKey] = members;
1028 jstorageBlocks.append(value: jstorageBlock);
1029 }
1030 if (!jstorageBlocks.isEmpty())
1031 root[storageBlocksKey] = jstorageBlocks;
1032
1033 QJsonArray jcombinedSamplers;
1034 for (const QShaderDescription::InOutVariable &v : qAsConst(t&: combinedImageSamplers)) {
1035 QJsonObject sampler;
1036 sampler[nameKey] = v.name;
1037 sampler[typeKey] = typeStr(t: v.type);
1038 addDeco(obj: &sampler, v);
1039 jcombinedSamplers.append(value: sampler);
1040 }
1041 if (!jcombinedSamplers.isEmpty())
1042 root[combinedImageSamplersKey] = jcombinedSamplers;
1043
1044 QJsonArray jstorageImages;
1045 for (const QShaderDescription::InOutVariable &v : qAsConst(t&: storageImages)) {
1046 QJsonObject image;
1047 image[nameKey] = v.name;
1048 image[typeKey] = typeStr(t: v.type);
1049 addDeco(obj: &image, v);
1050 jstorageImages.append(value: 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(value: QJsonValue(int(localSize[i])));
1058 root[localSizeKey] = jlocalSize;
1059
1060 return QJsonDocument(root);
1061}
1062
1063void QShaderDescriptionPrivate::writeToStream(QDataStream *stream)
1064{
1065 (*stream) << inVars.count();
1066 for (const QShaderDescription::InOutVariable &v : qAsConst(t&: inVars))
1067 serializeInOutVar(stream, v);
1068
1069 (*stream) << outVars.count();
1070 for (const QShaderDescription::InOutVariable &v : qAsConst(t&: 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(t&: 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(t&: 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
1124static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj)
1125{
1126 QShaderDescription::InOutVariable var;
1127 var.name = obj[nameKey].toString();
1128 var.type = mapType(t: obj[typeKey].toString());
1129 if (obj.contains(key: locationKey))
1130 var.location = obj[locationKey].toInt();
1131 if (obj.contains(key: bindingKey))
1132 var.binding = obj[bindingKey].toInt();
1133 if (obj.contains(key: setKey))
1134 var.descriptorSet = obj[setKey].toInt();
1135 if (obj.contains(key: imageFormatKey))
1136 var.imageFormat = mapImageFormat(f: obj[imageFormatKey].toString());
1137 if (obj.contains(key: imageFlagsKey))
1138 var.imageFlags = QShaderDescription::ImageFlags(obj[imageFlagsKey].toInt());
1139 if (obj.contains(key: arrayDimsKey)) {
1140 QJsonArray dimArr = obj[arrayDimsKey].toArray();
1141 for (int i = 0; i < dimArr.count(); ++i)
1142 var.arrayDims.append(t: dimArr.at(i).toInt());
1143 }
1144 return var;
1145}
1146
1147static 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(asize: f);
1161 for (int i = 0; i < f; ++i)
1162 (*stream) >> v->arrayDims[i];
1163 }
1164}
1165
1166static 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, v: &var);
1174 return var;
1175}
1176
1177static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj)
1178{
1179 QShaderDescription::BlockVariable var;
1180 var.name = obj[nameKey].toString();
1181 var.type = mapType(t: obj[typeKey].toString());
1182 var.offset = obj[offsetKey].toInt();
1183 var.size = obj[sizeKey].toInt();
1184 if (obj.contains(key: arrayDimsKey)) {
1185 QJsonArray dimArr = obj[arrayDimsKey].toArray();
1186 for (int i = 0; i < dimArr.count(); ++i)
1187 var.arrayDims.append(t: dimArr.at(i).toInt());
1188 }
1189 if (obj.contains(key: arrayStrideKey))
1190 var.arrayStride = obj[arrayStrideKey].toInt();
1191 if (obj.contains(key: matrixStrideKey))
1192 var.matrixStride = obj[matrixStrideKey].toInt();
1193 if (obj.contains(key: matrixRowMajorKey))
1194 var.matrixIsRowMajor = obj[matrixRowMajorKey].toBool();
1195 if (obj.contains(key: structMembersKey)) {
1196 QJsonArray arr = obj[structMembersKey].toArray();
1197 for (int i = 0; i < arr.count(); ++i)
1198 var.structMembers.append(t: blockVar(obj: arr.at(i).toObject()));
1199 }
1200 return var;
1201}
1202
1203static 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(asize: 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(asize: count);
1222 for (int i = 0; i < count; ++i)
1223 var.structMembers[i] = deserializeBlockMemberVar(stream, version);
1224 return var;
1225}
1226
1227void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
1228{
1229 if (doc.isNull()) {
1230 qWarning(msg: "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(key: inputsKey)) {
1247 QJsonArray inputs = root[inputsKey].toArray();
1248 for (int i = 0; i < inputs.count(); ++i)
1249 inVars.append(t: inOutVar(obj: inputs[i].toObject()));
1250 }
1251
1252 if (root.contains(key: outputsKey)) {
1253 QJsonArray outputs = root[outputsKey].toArray();
1254 for (int i = 0; i < outputs.count(); ++i)
1255 outVars.append(t: inOutVar(obj: outputs[i].toObject()));
1256 }
1257
1258 if (root.contains(key: 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(key: bindingKey))
1267 ub.binding = ubObj[bindingKey].toInt();
1268 if (ubObj.contains(key: setKey))
1269 ub.descriptorSet = ubObj[setKey].toInt();
1270 QJsonArray members = ubObj[membersKey].toArray();
1271 for (const QJsonValue &member : members)
1272 ub.members.append(t: blockVar(obj: member.toObject()));
1273 uniformBlocks.append(t: ub);
1274 }
1275 }
1276
1277 if (root.contains(key: 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(t: blockVar(obj: member.toObject()));
1287 pushConstantBlocks.append(t: pc);
1288 }
1289 }
1290
1291 if (root.contains(key: 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(key: bindingKey))
1300 sb.binding = sbObj[bindingKey].toInt();
1301 if (sbObj.contains(key: setKey))
1302 sb.descriptorSet = sbObj[setKey].toInt();
1303 QJsonArray members = sbObj[membersKey].toArray();
1304 for (const QJsonValue &member : members)
1305 sb.members.append(t: blockVar(obj: member.toObject()));
1306 storageBlocks.append(t: sb);
1307 }
1308 }
1309
1310 if (root.contains(key: combinedImageSamplersKey)) {
1311 QJsonArray samplers = root[combinedImageSamplersKey].toArray();
1312 for (int i = 0; i < samplers.count(); ++i)
1313 combinedImageSamplers.append(t: inOutVar(obj: samplers[i].toObject()));
1314 }
1315
1316 if (root.contains(key: storageImagesKey)) {
1317 QJsonArray images = root[storageImagesKey].toArray();
1318 for (int i = 0; i < images.count(); ++i)
1319 storageImages.append(t: inOutVar(obj: images[i].toObject()));
1320 }
1321
1322 if (root.contains(key: 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
1331void 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(asize: count);
1338 for (int i = 0; i < count; ++i)
1339 inVars[i] = deserializeInOutVar(stream, version);
1340
1341 (*stream) >> count;
1342 outVars.resize(asize: count);
1343 for (int i = 0; i < count; ++i)
1344 outVars[i] = deserializeInOutVar(stream, version);
1345
1346 (*stream) >> count;
1347 uniformBlocks.resize(asize: 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(asize: 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(asize: 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(asize: 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(asize: 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(asize: 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(asize: 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, v: &combinedImageSamplers[i]);
1396 }
1397
1398 (*stream) >> count;
1399 storageImages.resize(asize: 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, v: &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 */
1418bool 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 */
1439bool 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 */
1457bool 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 */
1476bool 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 */
1492bool 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 */
1505bool 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
1515QT_END_NAMESPACE
1516

source code of qtbase/src/gui/rhi/qshaderdescription.cpp