1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qshaderdescription_p.h"
5#include "qshader_p.h"
6#include <QDebug>
7#include <QDataStream>
8#include <QJsonObject>
9#include <QJsonArray>
10
11QT_BEGIN_NAMESPACE
12
13/*!
14 \class QShaderDescription
15 \ingroup painting-3D
16 \inmodule QtGui
17 \since 6.6
18
19 \brief Describes the interface of a shader.
20
21 \warning The QRhi family of classes in the Qt Gui module, including QShader
22 and QShaderDescription, offer limited compatibility guarantees. There are
23 no source or binary compatibility guarantees for these classes, meaning the
24 API is only guaranteed to work with the Qt version the application was
25 developed against. Source incompatible changes are however aimed to be kept
26 at a minimum and will only be made in minor releases (6.7, 6.8, and so on).
27 To use these classes in an application, link to
28 \c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c
29 rhi prefix, for example \c{#include <rhi/qshaderdescription.h>}.
30
31 A shader typically has a set of inputs and outputs. A vertex shader for
32 example has a number of input variables and may use one or more uniform
33 buffers to access data (e.g. a modelview matrix) provided by the
34 application. The shader for the fragment stage receives data from the
35 vertex stage (in a simple setup) and may also rely on data from uniform
36 buffers, images, and samplers.
37
38 When it comes to vertex inputs and the layout of the uniform buffers (what
39 are the names of the members? what is there size, offset, and so on),
40 applications and frameworks may need to discover this dynamically at run
41 time. This is typical when the shader is not built-in but provided by an
42 external entity, like the user.
43
44 Modern and lean graphics APIs may no longer provide a way to query shader
45 reflection information at run time. Therefore, such data is now
46 automatically generated by QShaderBaker and is provided as a
47 QShaderDescription object for each and every QShader.
48
49 \section2 Example
50
51 Take the following vertex shader:
52
53 \badcode
54 #version 440
55
56 layout(location = 0) in vec4 position;
57 layout(location = 1) in vec3 color;
58 layout(location = 0) out vec3 v_color;
59
60 layout(std140, binding = 0) uniform buf {
61 mat4 mvp;
62 float opacity;
63 } ubuf;
64
65 void main()
66 {
67 v_color = color;
68 gl_Position = ubuf.mvp * position;
69 }
70 \endcode
71
72 This shader has two inputs: \c position at location 0 with a type of \c
73 vec4, and \c color at location 1 with a type of \c vec3. It has one output:
74 \c v_color, although this is typically not interesting for applications.
75 What is more important, there is a uniform block at binding 0 with a size
76 of 68 bytes and two members, a 4x4 matrix named \c mvp at offset 0, and a
77 float \c opacity at offset 64.
78
79 All this is described by a QShaderDescription object. QShaderDescription can
80 be serialized to JSON and to a binary format via QDataStream, and can be
81 deserialized from this binary format. In practice this is rarely needed
82 since QShader takes care of the associated QShaderDescription automatically,
83 but if the QShaderDescription of the above shader would be written out as
84 JSON (like it is done by the \c qsb tool's \c{-d} option), it would look
85 like the following:
86
87 \badcode
88 {
89 "inputs": [
90 {
91 "location": 1,
92 "name": "color",
93 "type": "vec3"
94 },
95 {
96 "location": 0,
97 "name": "position",
98 "type": "vec4"
99 }
100 ],
101 "outputs": [
102 {
103 "location": 0,
104 "name": "v_color",
105 "type": "vec3"
106 }
107 ],
108 "uniformBlocks": [
109 {
110 "binding": 0,
111 "blockName": "buf",
112 "members": [
113 {
114 "matrixStride": 16,
115 "name": "mvp",
116 "offset": 0,
117 "size": 64,
118 "type": "mat4"
119 },
120 {
121 "name": "opacity",
122 "offset": 64,
123 "size": 4,
124 "type": "float"
125 }
126 ],
127 "set": 0,
128 "size": 68,
129 "structName": "ubuf"
130 }
131 ]
132 }
133 \endcode
134
135 The C++ API allows accessing a data structure like the above. For
136 simplicity the inner structs only contain public data members, also
137 considering that their layout is unlikely to change in the future.
138
139 \sa QShaderBaker, QShader
140 */
141
142/*!
143 \enum QShaderDescription::VariableType
144 Represents the type of a variable or block member.
145
146 \value Unknown
147 \value Float
148 \value Vec2
149 \value Vec3
150 \value Vec4
151 \value Mat2
152 \value Mat2x3
153 \value Mat2x4
154 \value Mat3
155 \value Mat3x2
156 \value Mat3x4
157 \value Mat4
158 \value Mat4x2
159 \value Mat4x3
160 \value Int
161 \value Int2
162 \value Int3
163 \value Int4
164 \value Uint
165 \value Uint2
166 \value Uint3
167 \value Uint4
168 \value Bool
169 \value Bool2
170 \value Bool3
171 \value Bool4
172 \value Double
173 \value Double2
174 \value Double3
175 \value Double4
176 \value DMat2
177 \value DMat2x3
178 \value DMat2x4
179 \value DMat3
180 \value DMat3x2
181 \value DMat3x4
182 \value DMat4
183 \value DMat4x2
184 \value DMat4x3
185 \value Sampler1D
186 \value Sampler2D
187 \value Sampler2DMS
188 \value Sampler3D
189 \value SamplerCube
190 \value Sampler1DArray
191 \value Sampler2DArray
192 \value Sampler2DMSArray
193 \value Sampler3DArray
194 \value SamplerCubeArray
195 \value SamplerRect
196 \value SamplerBuffer
197 \value SamplerExternalOES
198 \value Sampler For separate samplers.
199 \value Image1D
200 \value Image2D
201 \value Image2DMS
202 \value Image3D
203 \value ImageCube
204 \value Image1DArray
205 \value Image2DArray
206 \value Image2DMSArray
207 \value Image3DArray
208 \value ImageCubeArray
209 \value ImageRect
210 \value ImageBuffer
211 \value Struct
212 \value Half
213 \value Half2
214 \value Half3
215 \value Half4
216 */
217
218/*!
219 \enum QShaderDescription::ImageFormat
220 Image format.
221
222 \value ImageFormatUnknown
223 \value ImageFormatRgba32f
224 \value ImageFormatRgba16f
225 \value ImageFormatR32f
226 \value ImageFormatRgba8
227 \value ImageFormatRgba8Snorm
228 \value ImageFormatRg32f
229 \value ImageFormatRg16f
230 \value ImageFormatR11fG11fB10f
231 \value ImageFormatR16f
232 \value ImageFormatRgba16
233 \value ImageFormatRgb10A2
234 \value ImageFormatRg16
235 \value ImageFormatRg8
236 \value ImageFormatR16
237 \value ImageFormatR8
238 \value ImageFormatRgba16Snorm
239 \value ImageFormatRg16Snorm
240 \value ImageFormatRg8Snorm
241 \value ImageFormatR16Snorm
242 \value ImageFormatR8Snorm
243 \value ImageFormatRgba32i
244 \value ImageFormatRgba16i
245 \value ImageFormatRgba8i
246 \value ImageFormatR32i
247 \value ImageFormatRg32i
248 \value ImageFormatRg16i
249 \value ImageFormatRg8i
250 \value ImageFormatR16i
251 \value ImageFormatR8i
252 \value ImageFormatRgba32ui
253 \value ImageFormatRgba16ui
254 \value ImageFormatRgba8ui
255 \value ImageFormatR32ui
256 \value ImageFormatRgb10a2ui
257 \value ImageFormatRg32ui
258 \value ImageFormatRg16ui
259 \value ImageFormatRg8ui
260 \value ImageFormatR16ui
261 \value ImageFormatR8ui
262 */
263
264/*!
265 \enum QShaderDescription::ImageFlag
266 Image flags.
267
268 \value ReadOnlyImage
269 \value WriteOnlyImage
270 */
271
272/*!
273 \enum QShaderDescription::QualifierFlag
274 Qualifier flags.
275
276 \value QualifierReadOnly
277 \value QualifierWriteOnly
278 \value QualifierCoherent
279 \value QualifierVolatile
280 \value QualifierRestrict
281 */
282
283/*!
284 \struct QShaderDescription::InOutVariable
285 \inmodule QtGui
286 \since 6.6
287
288 \brief Describes an input or output variable in the shader.
289
290 \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
291 for details.
292 */
293
294/*!
295 \variable QShaderDescription::InOutVariable::name
296 */
297
298/*!
299 \variable QShaderDescription::InOutVariable::type
300 */
301
302/*!
303 \variable QShaderDescription::InOutVariable::location
304 */
305
306/*!
307 \variable QShaderDescription::InOutVariable::binding
308 */
309
310/*!
311 \variable QShaderDescription::InOutVariable::descriptorSet
312 */
313
314/*!
315 \variable QShaderDescription::InOutVariable::imageFormat
316 */
317
318/*!
319 \variable QShaderDescription::InOutVariable::imageFlags
320 */
321
322/*!
323 \variable QShaderDescription::InOutVariable::arrayDims
324 */
325
326/*!
327 \variable QShaderDescription::InOutVariable::perPatch
328 */
329
330/*!
331 \variable QShaderDescription::InOutVariable::structMembers
332 */
333
334/*!
335 \struct QShaderDescription::BlockVariable
336 \inmodule QtGui
337 \since 6.6
338
339 \brief Describes a member of a uniform or push constant block.
340
341 \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
342 for details.
343 */
344
345/*!
346 \variable QShaderDescription::BlockVariable::name
347 */
348
349/*!
350 \variable QShaderDescription::BlockVariable::type
351 */
352
353/*!
354 \variable QShaderDescription::BlockVariable::offset
355 */
356
357/*!
358 \variable QShaderDescription::BlockVariable::size
359 */
360
361/*!
362 \variable QShaderDescription::BlockVariable::arrayDims
363 */
364
365/*!
366 \variable QShaderDescription::BlockVariable::arrayStride
367 */
368
369/*!
370 \variable QShaderDescription::BlockVariable::matrixStride
371 */
372
373/*!
374 \variable QShaderDescription::BlockVariable::matrixIsRowMajor
375 */
376
377/*!
378 \variable QShaderDescription::BlockVariable::structMembers
379 */
380
381/*!
382 \struct QShaderDescription::UniformBlock
383 \inmodule QtGui
384 \since 6.6
385
386 \brief Describes a uniform block.
387
388 \note When translating to shading languages without uniform block support
389 (like GLSL 120 or GLSL/ES 100), uniform blocks are replaced with ordinary
390 uniforms in a struct. The name of the struct, and so the prefix for the
391 uniforms generated from the block members, is given by structName.
392
393 \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
394 for details.
395 */
396
397/*!
398 \variable QShaderDescription::UniformBlock::blockName
399 */
400
401/*!
402 \variable QShaderDescription::UniformBlock::structName
403 */
404
405/*!
406 \variable QShaderDescription::UniformBlock::size
407 */
408
409/*!
410 \variable QShaderDescription::UniformBlock::binding
411 */
412
413/*!
414 \variable QShaderDescription::UniformBlock::descriptorSet
415 */
416
417/*!
418 \variable QShaderDescription::UniformBlock::members
419 */
420
421/*!
422 \struct QShaderDescription::PushConstantBlock
423 \inmodule QtGui
424 \since 6.6
425
426 \brief Describes a push constant block.
427
428 \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
429 for details.
430 */
431
432/*!
433 \variable QShaderDescription::PushConstantBlock::name
434 */
435
436/*!
437 \variable QShaderDescription::PushConstantBlock::size
438 */
439
440/*!
441 \variable QShaderDescription::PushConstantBlock::members
442 */
443
444/*!
445 \struct QShaderDescription::StorageBlock
446 \inmodule QtGui
447 \since 6.6
448
449 \brief Describes a shader storage block.
450
451 \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
452 for details.
453 */
454
455/*!
456 \variable QShaderDescription::StorageBlock::blockName
457 */
458
459/*!
460 \variable QShaderDescription::StorageBlock::instanceName
461 */
462
463/*!
464 \variable QShaderDescription::StorageBlock::knownSize
465 */
466
467/*!
468 \variable QShaderDescription::StorageBlock::binding
469 */
470
471/*!
472 \variable QShaderDescription::StorageBlock::descriptorSet
473 */
474
475/*!
476 \variable QShaderDescription::StorageBlock::members
477 */
478
479/*!
480 \variable QShaderDescription::StorageBlock::runtimeArrayStride
481 */
482
483/*!
484 \variable QShaderDescription::StorageBlock::qualifierFlags
485 */
486
487/*!
488 \struct QShaderDescription::BuiltinVariable
489 \inmodule QtGui
490 \since 6.6
491
492 \brief Describes a built-in variable.
493
494 \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
495 for details.
496 */
497
498/*!
499 \variable QShaderDescription::BuiltinVariable::type
500 */
501
502/*!
503 \variable QShaderDescription::BuiltinVariable::varType
504 */
505
506/*!
507 \variable QShaderDescription::BuiltinVariable::arrayDims
508 */
509
510/*!
511 \enum QShaderDescription::BuiltinType
512 Built-in variable type.
513
514 \value PositionBuiltin
515 \value PointSizeBuiltin
516 \value ClipDistanceBuiltin
517 \value CullDistanceBuiltin
518 \value VertexIdBuiltin
519 \value InstanceIdBuiltin
520 \value PrimitiveIdBuiltin
521 \value InvocationIdBuiltin
522 \value LayerBuiltin
523 \value ViewportIndexBuiltin
524 \value TessLevelOuterBuiltin
525 \value TessLevelInnerBuiltin
526 \value TessCoordBuiltin
527 \value PatchVerticesBuiltin
528 \value FragCoordBuiltin
529 \value PointCoordBuiltin
530 \value FrontFacingBuiltin
531 \value SampleIdBuiltin
532 \value SamplePositionBuiltin
533 \value SampleMaskBuiltin
534 \value FragDepthBuiltin
535 \value NumWorkGroupsBuiltin
536 \value WorkgroupSizeBuiltin
537 \value WorkgroupIdBuiltin
538 \value LocalInvocationIdBuiltin
539 \value GlobalInvocationIdBuiltin
540 \value LocalInvocationIndexBuiltin
541 \value VertexIndexBuiltin
542 \value InstanceIndexBuiltin
543 */
544
545/*!
546 Constructs a new, empty QShaderDescription.
547
548 \note Being empty implies that isValid() returns \c false for the
549 newly constructed instance.
550 */
551QShaderDescription::QShaderDescription()
552 : d(new QShaderDescriptionPrivate)
553{
554}
555
556/*!
557 \internal
558 */
559void QShaderDescription::detach()
560{
561 qAtomicDetach(d);
562}
563
564/*!
565 Constructs a copy of \a other.
566 */
567QShaderDescription::QShaderDescription(const QShaderDescription &other)
568 : d(other.d)
569{
570 d->ref.ref();
571}
572
573/*!
574 Assigns \a other to this object.
575 */
576QShaderDescription &QShaderDescription::operator=(const QShaderDescription &other)
577{
578 qAtomicAssign(d, x: other.d);
579 return *this;
580}
581
582/*!
583 Destructor.
584 */
585QShaderDescription::~QShaderDescription()
586{
587 if (!d->ref.deref())
588 delete d;
589}
590
591/*!
592 \return true if the QShaderDescription contains at least one entry in one of
593 the variable and block lists.
594 */
595bool QShaderDescription::isValid() const
596{
597 return !d->inVars.isEmpty() || !d->outVars.isEmpty()
598 || !d->uniformBlocks.isEmpty() || !d->pushConstantBlocks.isEmpty() || !d->storageBlocks.isEmpty()
599 || !d->combinedImageSamplers.isEmpty() || !d->storageImages.isEmpty()
600 || !d->separateImages.isEmpty() || !d->separateSamplers.isEmpty()
601 || !d->inBuiltins.isEmpty() || !d->outBuiltins.isEmpty();
602}
603
604/*!
605 \return a serialized JSON text version of the data.
606
607 \note There is no deserialization method provided for JSON text.
608
609 \sa serialize()
610 */
611QByteArray QShaderDescription::toJson() const
612{
613 return d->makeDoc().toJson();
614}
615
616/*!
617 Serializes this QShaderDescription to \a stream. \a version specifies
618 the qsb version.
619
620 \sa deserialize(), toJson()
621 */
622void QShaderDescription::serialize(QDataStream *stream, int version) const
623{
624 d->writeToStream(stream, version);
625}
626
627/*!
628 \return a new QShaderDescription loaded from \a stream. \a version specifies
629 the qsb version.
630
631 \sa serialize()
632 */
633QShaderDescription QShaderDescription::deserialize(QDataStream *stream, int version)
634{
635 QShaderDescription desc;
636 QShaderDescriptionPrivate::get(desc: &desc)->loadFromStream(stream, version);
637 return desc;
638}
639
640/*!
641 \return the list of input variables. This includes vertex inputs (sometimes
642 called attributes) for the vertex stage, and inputs for other stages
643 (sometimes called varyings).
644 */
645QList<QShaderDescription::InOutVariable> QShaderDescription::inputVariables() const
646{
647 return d->inVars;
648}
649
650/*!
651 \return the list of output variables.
652 */
653QList<QShaderDescription::InOutVariable> QShaderDescription::outputVariables() const
654{
655 return d->outVars;
656}
657
658/*!
659 \return the list of uniform blocks.
660 */
661QList<QShaderDescription::UniformBlock> QShaderDescription::uniformBlocks() const
662{
663 return d->uniformBlocks;
664}
665
666/*!
667 \return the list of push constant blocks.
668
669 \note Avoid relying on push constant blocks for shaders that are to be used
670 in combination with the Qt Rendering Hardware Interface since that
671 currently has no support for them.
672 */
673QList<QShaderDescription::PushConstantBlock> QShaderDescription::pushConstantBlocks() const
674{
675 return d->pushConstantBlocks;
676}
677
678/*!
679 \return the list of shader storage blocks.
680
681 For example, with GLSL/Vulkan shaders as source, the declaration
682
683 \badcode
684 struct Stuff {
685 vec2 a;
686 vec2 b;
687 };
688 layout(std140, binding = 0) buffer StuffSsbo {
689 vec4 whatever;
690 Stuff stuff[];
691 } buf;
692 \endcode
693
694 generates the following: (shown as textual JSON here)
695
696 \badcode
697 "storageBlocks": [ {
698 "binding": 0,
699 "blockName": "StuffSsbo",
700 "instanceName": "buf",
701 "knownSize": 16,
702 "runtimeArrayStride": 16
703 "members": [
704 {
705 "name": "whatever",
706 "offset": 0,
707 "size": 16,
708 "type": "vec4"
709 },
710 {
711 "arrayDims": [
712 0
713 ],
714 "name": "stuff",
715 "offset": 16,
716 "size": 0,
717 "structMembers": [
718 {
719 "name": "a",
720 "offset": 0,
721 "size": 8,
722 "type": "vec2"
723 },
724 {
725 "name": "b",
726 "offset": 8,
727 "size": 8,
728 "type": "vec2"
729 }
730 ],
731 "type": "struct"
732 }
733 ],
734 "set": 0
735 } ]
736 \endcode
737
738 \note The size of the last member in the storage block is undefined. This shows
739 up as \c size 0 and an array dimension of \c{[0]}. The storage block's \c knownSize
740 excludes the size of the last member since that will only be known at run time. The
741 stride in bytes between array items for a last member with undefined array size is
742 \c runtimeArrayStride. This value is determined according to the specified buffer
743 memory layout standard (std140, std430) rules.
744
745 \note SSBOs are not available with some graphics APIs, such as, OpenGL 2.x or
746 OpenGL ES older than 3.1.
747 */
748QList<QShaderDescription::StorageBlock> QShaderDescription::storageBlocks() const
749{
750 return d->storageBlocks;
751}
752
753/*!
754 \return the list of combined image samplers
755
756 With GLSL/Vulkan shaders as source a \c{layout(binding = 1) uniform sampler2D tex;}
757 uniform generates the following: (shown as textual JSON here)
758
759 \badcode
760 "combinedImageSamplers": [
761 {
762 "binding": 1,
763 "name": "tex",
764 "set": 0,
765 "type": "sampler2D"
766 }
767 ]
768 \endcode
769
770 This does not mean that other language versions of the shader must also use
771 a combined image sampler, especially considering that the concept may not
772 exist everywhere. For instance, a HLSL version will likely just use a
773 Texture2D and SamplerState object with registers t1 and s1, respectively.
774 */
775QList<QShaderDescription::InOutVariable> QShaderDescription::combinedImageSamplers() const
776{
777 return d->combinedImageSamplers;
778}
779
780QList<QShaderDescription::InOutVariable> QShaderDescription::separateImages() const
781{
782 return d->separateImages;
783}
784
785QList<QShaderDescription::InOutVariable> QShaderDescription::separateSamplers() const
786{
787 return d->separateSamplers;
788}
789
790/*!
791 \return the list of image variables.
792
793 These will likely occur in compute shaders. For example,
794 \c{layout (binding = 0, rgba8) uniform readonly image2D inputImage;}
795 generates the following: (shown as textual JSON here)
796
797 \badcode
798 "storageImages": [
799 {
800 "binding": 0,
801 "imageFormat": "rgba8",
802 "name": "inputImage",
803 "set": 0,
804 "type": "image2D"
805 }
806 ]
807 \endcode
808
809 \note Separate image objects are not compatible with some graphics APIs,
810 such as, OpenGL 2.x or OpenGL ES older than 3.1.
811 */
812QList<QShaderDescription::InOutVariable> QShaderDescription::storageImages() const
813{
814 return d->storageImages;
815}
816
817/*!
818 \return the list of active builtins used as input. For example, a
819 tessellation evaluation shader reading the value of gl_TessCoord and
820 gl_Position will have TessCoordBuiltin and PositionBuiltin listed here.
821 */
822QVector<QShaderDescription::BuiltinVariable> QShaderDescription::inputBuiltinVariables() const
823{
824 return d->inBuiltins;
825}
826
827/*!
828 \return the list of active built-in variables used as input. For example, a
829 vertex shader will very often have PositionBuiltin as an output built-in.
830 */
831QVector<QShaderDescription::BuiltinVariable> QShaderDescription::outputBuiltinVariables() const
832{
833 return d->outBuiltins;
834}
835
836/*!
837 \return the local size of a compute shader.
838
839 For example, for a compute shader with the following declaration the
840 function returns { 256, 16, 1}.
841
842 \badcode
843 layout(local_size_x = 256, local_size_y = 16, local_size_z = 1) in;
844 \endcode
845 */
846std::array<uint, 3> QShaderDescription::computeShaderLocalSize() const
847{
848 return d->localSize;
849}
850
851/*!
852 \return the number of output vertices.
853
854 For example, for a tessellation control shader with the following
855 declaration the function returns 3.
856
857 \badcode
858 layout(vertices = 3) out;
859 \endcode
860 */
861uint QShaderDescription::tessellationOutputVertexCount() const
862{
863 return d->tessOutVertCount;
864}
865
866/*!
867 \enum QShaderDescription::TessellationMode
868
869 \value UnknownTessellationMode
870 \value TrianglesTessellationMode
871 \value QuadTessellationMode
872 \value IsolineTessellationMode
873 */
874
875/*!
876 \return the tessellation execution mode for a tessellation control or
877 evaluation shader.
878
879 When not set, the returned value is UnknownTessellationMode.
880
881 For example, for a tessellation evaluation shader with the following
882 declaration the function returns TrianglesTessellationMode.
883
884 \badcode
885 layout(triangles) in;
886 \endcode
887 */
888QShaderDescription::TessellationMode QShaderDescription::tessellationMode() const
889{
890 return d->tessMode;
891}
892
893/*!
894 \enum QShaderDescription::TessellationWindingOrder
895
896 \value UnknownTessellationWindingOrder
897 \value CwTessellationWindingOrder
898 \value CcwTessellationWindingOrder
899 */
900
901/*!
902 \return the tessellation winding order for a tessellation control or
903 evaluation shader.
904
905 When not set, the returned value is UnknownTessellationWindingOrder.
906
907 For example, for a tessellation evaluation shader with the following
908 declaration the function returns CcwTessellationWindingOrder.
909
910 \badcode
911 layout(triangles, fractional_odd_spacing, ccw) in;
912 \endcode
913 */
914QShaderDescription::TessellationWindingOrder QShaderDescription::tessellationWindingOrder() const
915{
916 return d->tessWind;
917}
918
919/*!
920 \enum QShaderDescription::TessellationPartitioning
921
922 \value UnknownTessellationPartitioning
923 \value EqualTessellationPartitioning
924 \value FractionalEvenTessellationPartitioning
925 \value FractionalOddTessellationPartitioning
926 */
927
928/*!
929 \return the tessellation partitioning mode for a tessellation control or
930 evaluation shader.
931
932 When not set, the returned value is UnknownTessellationPartitioning.
933
934 For example, for a tessellation evaluation shader with the following
935 declaration the function returns FractionalOddTessellationPartitioning.
936
937 \badcode
938 layout(triangles, fractional_odd_spacing, ccw) in;
939 \endcode
940 */
941QShaderDescription::TessellationPartitioning QShaderDescription::tessellationPartitioning() const
942{
943 return d->tessPart;
944}
945
946static const struct TypeTab {
947 const char k[20];
948 QShaderDescription::VariableType v;
949} typeTab[] = {
950 { .k: "float", .v: QShaderDescription::Float },
951 { .k: "vec2", .v: QShaderDescription::Vec2 },
952 { .k: "vec3", .v: QShaderDescription::Vec3 },
953 { .k: "vec4", .v: QShaderDescription::Vec4 },
954 { .k: "mat2", .v: QShaderDescription::Mat2 },
955 { .k: "mat3", .v: QShaderDescription::Mat3 },
956 { .k: "mat4", .v: QShaderDescription::Mat4 },
957
958 { .k: "struct", .v: QShaderDescription::Struct },
959
960 { .k: "sampler1D", .v: QShaderDescription::Sampler1D },
961 { .k: "sampler2D", .v: QShaderDescription::Sampler2D },
962 { .k: "sampler2DMS", .v: QShaderDescription::Sampler2DMS },
963 { .k: "sampler3D", .v: QShaderDescription::Sampler3D },
964 { .k: "samplerCube", .v: QShaderDescription::SamplerCube },
965 { .k: "sampler1DArray", .v: QShaderDescription::Sampler1DArray },
966 { .k: "sampler2DArray", .v: QShaderDescription::Sampler2DArray },
967 { .k: "sampler2DMSArray", .v: QShaderDescription::Sampler2DMSArray },
968 { .k: "sampler3DArray", .v: QShaderDescription::Sampler3DArray },
969 { .k: "samplerCubeArray", .v: QShaderDescription::SamplerCubeArray },
970 { .k: "samplerRect", .v: QShaderDescription::SamplerRect },
971 { .k: "samplerBuffer", .v: QShaderDescription::SamplerBuffer },
972 { .k: "samplerExternalOES", .v: QShaderDescription::SamplerExternalOES },
973 { .k: "sampler", .v: QShaderDescription::Sampler },
974
975 { .k: "mat2x3", .v: QShaderDescription::Mat2x3 },
976 { .k: "mat2x4", .v: QShaderDescription::Mat2x4 },
977 { .k: "mat3x2", .v: QShaderDescription::Mat3x2 },
978 { .k: "mat3x4", .v: QShaderDescription::Mat3x4 },
979 { .k: "mat4x2", .v: QShaderDescription::Mat4x2 },
980 { .k: "mat4x3", .v: QShaderDescription::Mat4x3 },
981
982 { .k: "int", .v: QShaderDescription::Int },
983 { .k: "ivec2", .v: QShaderDescription::Int2 },
984 { .k: "ivec3", .v: QShaderDescription::Int3 },
985 { .k: "ivec4", .v: QShaderDescription::Int4 },
986
987 { .k: "uint", .v: QShaderDescription::Uint },
988 { .k: "uvec2", .v: QShaderDescription::Uint2 },
989 { .k: "uvec3", .v: QShaderDescription::Uint3 },
990 { .k: "uvec4", .v: QShaderDescription::Uint4 },
991
992 { .k: "bool", .v: QShaderDescription::Bool },
993 { .k: "bvec2", .v: QShaderDescription::Bool2 },
994 { .k: "bvec3", .v: QShaderDescription::Bool3 },
995 { .k: "bvec4", .v: QShaderDescription::Bool4 },
996
997 { .k: "double", .v: QShaderDescription::Double },
998 { .k: "dvec2", .v: QShaderDescription::Double2 },
999 { .k: "dvec3", .v: QShaderDescription::Double3 },
1000 { .k: "dvec4", .v: QShaderDescription::Double4 },
1001 { .k: "dmat2", .v: QShaderDescription::DMat2 },
1002 { .k: "dmat3", .v: QShaderDescription::DMat3 },
1003 { .k: "dmat4", .v: QShaderDescription::DMat4 },
1004 { .k: "dmat2x3", .v: QShaderDescription::DMat2x3 },
1005 { .k: "dmat2x4", .v: QShaderDescription::DMat2x4 },
1006 { .k: "dmat3x2", .v: QShaderDescription::DMat3x2 },
1007 { .k: "dmat3x4", .v: QShaderDescription::DMat3x4 },
1008 { .k: "dmat4x2", .v: QShaderDescription::DMat4x2 },
1009 { .k: "dmat4x3", .v: QShaderDescription::DMat4x3 },
1010
1011 { .k: "image1D", .v: QShaderDescription::Image1D },
1012 { .k: "image2D", .v: QShaderDescription::Image2D },
1013 { .k: "image2DMS", .v: QShaderDescription::Image2DMS },
1014 { .k: "image3D", .v: QShaderDescription::Image3D },
1015 { .k: "imageCube", .v: QShaderDescription::ImageCube },
1016 { .k: "image1DArray", .v: QShaderDescription::Image1DArray },
1017 { .k: "image2DArray", .v: QShaderDescription::Image2DArray },
1018 { .k: "image2DMSArray", .v: QShaderDescription::Image2DMSArray },
1019 { .k: "image3DArray", .v: QShaderDescription::Image3DArray },
1020 { .k: "imageCubeArray", .v: QShaderDescription::ImageCubeArray },
1021 { .k: "imageRect", .v: QShaderDescription::ImageRect },
1022 { .k: "imageBuffer", .v: QShaderDescription::ImageBuffer },
1023
1024 { .k: "half", .v: QShaderDescription::Half },
1025 { .k: "half2", .v: QShaderDescription::Half2 },
1026 { .k: "half3", .v: QShaderDescription::Half3 },
1027 { .k: "half4", .v: QShaderDescription::Half4 } };
1028
1029static QLatin1StringView typeStr(QShaderDescription::VariableType t)
1030{
1031 for (size_t i = 0; i < sizeof(typeTab) / sizeof(TypeTab); ++i) {
1032 if (typeTab[i].v == t)
1033 return QLatin1StringView(typeTab[i].k);
1034 }
1035 return {};
1036}
1037
1038static const struct ImageFormatTab {
1039 const char k[15];
1040 QShaderDescription::ImageFormat v;
1041} imageFormatTab[] {
1042 { .k: "unknown", .v: QShaderDescription::ImageFormatUnknown },
1043 { .k: "rgba32f", .v: QShaderDescription::ImageFormatRgba32f },
1044 { .k: "rgba16", .v: QShaderDescription::ImageFormatRgba16f },
1045 { .k: "r32f", .v: QShaderDescription::ImageFormatR32f },
1046 { .k: "rgba8", .v: QShaderDescription::ImageFormatRgba8 },
1047 { .k: "rgba8_snorm", .v: QShaderDescription::ImageFormatRgba8Snorm },
1048 { .k: "rg32f", .v: QShaderDescription::ImageFormatRg32f },
1049 { .k: "rg16f", .v: QShaderDescription::ImageFormatRg16f },
1050 { .k: "r11f_g11f_b10f", .v: QShaderDescription::ImageFormatR11fG11fB10f },
1051 { .k: "r16f", .v: QShaderDescription::ImageFormatR16f },
1052 { .k: "rgba16", .v: QShaderDescription::ImageFormatRgba16 },
1053 { .k: "rgb10_a2", .v: QShaderDescription::ImageFormatRgb10A2 },
1054 { .k: "rg16", .v: QShaderDescription::ImageFormatRg16 },
1055 { .k: "rg8", .v: QShaderDescription::ImageFormatRg8 },
1056 { .k: "r16", .v: QShaderDescription::ImageFormatR16 },
1057 { .k: "r8", .v: QShaderDescription::ImageFormatR8 },
1058 { .k: "rgba16_snorm", .v: QShaderDescription::ImageFormatRgba16Snorm },
1059 { .k: "rg16_snorm", .v: QShaderDescription::ImageFormatRg16Snorm },
1060 { .k: "rg8_snorm", .v: QShaderDescription::ImageFormatRg8Snorm },
1061 { .k: "r16_snorm", .v: QShaderDescription::ImageFormatR16Snorm },
1062 { .k: "r8_snorm", .v: QShaderDescription::ImageFormatR8Snorm },
1063 { .k: "rgba32i", .v: QShaderDescription::ImageFormatRgba32i },
1064 { .k: "rgba16i", .v: QShaderDescription::ImageFormatRgba16i },
1065 { .k: "rgba8i", .v: QShaderDescription::ImageFormatRgba8i },
1066 { .k: "r32i", .v: QShaderDescription::ImageFormatR32i },
1067 { .k: "rg32i", .v: QShaderDescription::ImageFormatRg32i },
1068 { .k: "rg16i", .v: QShaderDescription::ImageFormatRg16i },
1069 { .k: "rg8i", .v: QShaderDescription::ImageFormatRg8i },
1070 { .k: "r16i", .v: QShaderDescription::ImageFormatR16i },
1071 { .k: "r8i", .v: QShaderDescription::ImageFormatR8i },
1072 { .k: "rgba32ui", .v: QShaderDescription::ImageFormatRgba32ui },
1073 { .k: "rgba16ui", .v: QShaderDescription::ImageFormatRgba16ui },
1074 { .k: "rgba8ui", .v: QShaderDescription::ImageFormatRgba8ui },
1075 { .k: "r32ui", .v: QShaderDescription::ImageFormatR32ui },
1076 { .k: "rgb10_a2ui", .v: QShaderDescription::ImageFormatRgb10a2ui },
1077 { .k: "rg32ui", .v: QShaderDescription::ImageFormatRg32ui },
1078 { .k: "rg16ui", .v: QShaderDescription::ImageFormatRg16ui },
1079 { .k: "rg8ui", .v: QShaderDescription::ImageFormatRg8ui },
1080 { .k: "r16ui", .v: QShaderDescription::ImageFormatR16ui },
1081 { .k: "r8ui", .v: QShaderDescription::ImageFormatR8ui }
1082};
1083
1084static QLatin1StringView imageFormatStr(QShaderDescription::ImageFormat f)
1085{
1086 for (size_t i = 0; i < sizeof(imageFormatTab) / sizeof(ImageFormatTab); ++i) {
1087 if (imageFormatTab[i].v == f)
1088 return QLatin1StringView(imageFormatTab[i].k);
1089 }
1090 return {};
1091}
1092
1093static const struct BuiltinTypeTab {
1094 const char k[21];
1095 QShaderDescription::BuiltinType v;
1096} builtinTypeTab[] = {
1097 { .k: "Position", .v: QShaderDescription::PositionBuiltin },
1098 { .k: "PointSize", .v: QShaderDescription::PointSizeBuiltin },
1099 { .k: "ClipDistance", .v: QShaderDescription::ClipDistanceBuiltin },
1100 { .k: "CullDistance", .v: QShaderDescription::CullDistanceBuiltin },
1101 { .k: "VertexId", .v: QShaderDescription::VertexIdBuiltin },
1102 { .k: "InstanceId", .v: QShaderDescription::InstanceIdBuiltin },
1103 { .k: "PrimitiveId", .v: QShaderDescription::PrimitiveIdBuiltin },
1104 { .k: "InvocationId", .v: QShaderDescription::InvocationIdBuiltin },
1105 { .k: "Layer", .v: QShaderDescription::LayerBuiltin },
1106 { .k: "ViewportIndex", .v: QShaderDescription::ViewportIndexBuiltin },
1107 { .k: "TessLevelOuter", .v: QShaderDescription::TessLevelOuterBuiltin },
1108 { .k: "TessLevelInner", .v: QShaderDescription::TessLevelInnerBuiltin },
1109 { .k: "TessCoord", .v: QShaderDescription::TessCoordBuiltin },
1110 { .k: "PatchVertices", .v: QShaderDescription::PatchVerticesBuiltin },
1111 { .k: "FragCoord", .v: QShaderDescription::FragCoordBuiltin },
1112 { .k: "PointCoord", .v: QShaderDescription::PointCoordBuiltin },
1113 { .k: "FrontFacing", .v: QShaderDescription::FrontFacingBuiltin },
1114 { .k: "SampleId", .v: QShaderDescription::SampleIdBuiltin },
1115 { .k: "SamplePosition", .v: QShaderDescription::SamplePositionBuiltin },
1116 { .k: "SampleMask", .v: QShaderDescription::SampleMaskBuiltin },
1117 { .k: "FragDepth", .v: QShaderDescription::FragDepthBuiltin },
1118 { .k: "NumWorkGroups", .v: QShaderDescription::NumWorkGroupsBuiltin },
1119 { .k: "WorkgroupSize", .v: QShaderDescription::WorkgroupSizeBuiltin },
1120 { .k: "WorkgroupId", .v: QShaderDescription::WorkgroupIdBuiltin },
1121 { .k: "LocalInvocationId", .v: QShaderDescription::LocalInvocationIdBuiltin },
1122 { .k: "GlobalInvocationId", .v: QShaderDescription::GlobalInvocationIdBuiltin },
1123 { .k: "LocalInvocationIndex", .v: QShaderDescription::LocalInvocationIndexBuiltin },
1124 { .k: "VertexIndex", .v: QShaderDescription::VertexIndexBuiltin },
1125 { .k: "InstanceIndex", .v: QShaderDescription::InstanceIndexBuiltin }
1126};
1127
1128static QLatin1StringView builtinTypeStr(QShaderDescription::BuiltinType t)
1129{
1130 for (size_t i = 0; i < sizeof(builtinTypeTab) / sizeof(BuiltinTypeTab); ++i) {
1131 if (builtinTypeTab[i].v == t)
1132 return QLatin1StringView(builtinTypeTab[i].k);
1133 }
1134 return {};
1135}
1136
1137static const struct TessellationModeTab {
1138 const char k[10];
1139 QShaderDescription::TessellationMode v;
1140} tessellationModeTab[] {
1141 { .k: "unknown", .v: QShaderDescription::UnknownTessellationMode },
1142 { .k: "triangles", .v: QShaderDescription::TrianglesTessellationMode },
1143 { .k: "quad", .v: QShaderDescription::QuadTessellationMode },
1144 { .k: "isoline", .v: QShaderDescription::IsolineTessellationMode }
1145};
1146
1147static QLatin1StringView tessModeStr(QShaderDescription::TessellationMode mode)
1148{
1149 for (size_t i = 0; i < sizeof(tessellationModeTab) / sizeof(TessellationModeTab); ++i) {
1150 if (tessellationModeTab[i].v == mode)
1151 return QLatin1StringView(tessellationModeTab[i].k);
1152 }
1153 return {};
1154}
1155
1156static const struct TessellationWindingOrderTab {
1157 const char k[8];
1158 QShaderDescription::TessellationWindingOrder v;
1159} tessellationWindingOrderTab[] {
1160 { .k: "unknown", .v: QShaderDescription::UnknownTessellationWindingOrder },
1161 { .k: "cw", .v: QShaderDescription::CwTessellationWindingOrder },
1162 { .k: "ccw", .v: QShaderDescription::CcwTessellationWindingOrder }
1163};
1164
1165static QLatin1StringView tessWindStr(QShaderDescription::TessellationWindingOrder w)
1166{
1167 for (size_t i = 0; i < sizeof(tessellationWindingOrderTab) / sizeof(TessellationWindingOrderTab); ++i) {
1168 if (tessellationWindingOrderTab[i].v == w)
1169 return QLatin1StringView(tessellationWindingOrderTab[i].k);
1170 }
1171 return {};
1172}
1173
1174static const struct TessellationPartitioningTab {
1175 const char k[24];
1176 QShaderDescription::TessellationPartitioning v;
1177} tessellationPartitioningTab[] {
1178 { .k: "unknown", .v: QShaderDescription::UnknownTessellationPartitioning },
1179 { .k: "equal_spacing", .v: QShaderDescription::EqualTessellationPartitioning },
1180 { .k: "fractional_even_spacing", .v: QShaderDescription::FractionalEvenTessellationPartitioning },
1181 { .k: "fractional_odd_spacing", .v: QShaderDescription::FractionalOddTessellationPartitioning }
1182};
1183
1184static QLatin1StringView tessPartStr(QShaderDescription::TessellationPartitioning p)
1185{
1186 for (size_t i = 0; i < sizeof(tessellationPartitioningTab) / sizeof(TessellationPartitioningTab); ++i) {
1187 if (tessellationPartitioningTab[i].v == p)
1188 return QLatin1StringView(tessellationPartitioningTab[i].k);
1189 }
1190 return {};
1191}
1192
1193#ifndef QT_NO_DEBUG_STREAM
1194QDebug operator<<(QDebug dbg, const QShaderDescription &sd)
1195{
1196 const QShaderDescriptionPrivate *d = sd.d;
1197 QDebugStateSaver saver(dbg);
1198
1199 if (sd.isValid()) {
1200 dbg.nospace() << "QShaderDescription("
1201 << "inVars " << d->inVars
1202 << " outVars " << d->outVars
1203 << " uniformBlocks " << d->uniformBlocks
1204 << " pcBlocks " << d->pushConstantBlocks
1205 << " storageBlocks " << d->storageBlocks
1206 << " combinedSamplers " << d->combinedImageSamplers
1207 << " storageImages " << d->storageImages
1208 << " separateImages " << d->separateImages
1209 << " separateSamplers " << d->separateSamplers
1210 << " inBuiltins " << d->inBuiltins
1211 << " outBuiltins " << d->outBuiltins
1212 << ')';
1213 } else {
1214 dbg.nospace() << "QShaderDescription(null)";
1215 }
1216
1217 return dbg;
1218}
1219
1220QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var)
1221{
1222 QDebugStateSaver saver(dbg);
1223 dbg.nospace() << "InOutVariable(" << typeStr(t: var.type) << ' ' << var.name;
1224 if (var.perPatch)
1225 dbg.nospace() << " per-patch";
1226 if (var.location >= 0)
1227 dbg.nospace() << " location=" << var.location;
1228 if (var.binding >= 0)
1229 dbg.nospace() << " binding=" << var.binding;
1230 if (var.descriptorSet >= 0)
1231 dbg.nospace() << " set=" << var.descriptorSet;
1232 if (var.imageFormat != QShaderDescription::ImageFormatUnknown)
1233 dbg.nospace() << " imageFormat=" << imageFormatStr(f: var.imageFormat);
1234 if (var.imageFlags)
1235 dbg.nospace() << " imageFlags=" << var.imageFlags;
1236 if (!var.arrayDims.isEmpty())
1237 dbg.nospace() << " array=" << var.arrayDims;
1238 if (!var.structMembers.isEmpty())
1239 dbg.nospace() << " structMembers=" << var.structMembers;
1240 dbg.nospace() << ')';
1241 return dbg;
1242}
1243
1244QDebug operator<<(QDebug dbg, const QShaderDescription::BlockVariable &var)
1245{
1246 QDebugStateSaver saver(dbg);
1247 dbg.nospace() << "BlockVariable(" << typeStr(t: var.type) << ' ' << var.name;
1248 if (var.offset != -1)
1249 dbg.nospace() << " offset=" << var.offset;
1250 dbg.nospace() << " size=" << var.size;
1251 if (!var.arrayDims.isEmpty())
1252 dbg.nospace() << " array=" << var.arrayDims;
1253 if (var.arrayStride)
1254 dbg.nospace() << " arrayStride=" << var.arrayStride;
1255 if (var.matrixStride)
1256 dbg.nospace() << " matrixStride=" << var.matrixStride;
1257 if (var.matrixIsRowMajor)
1258 dbg.nospace() << " [rowmaj]";
1259 if (!var.structMembers.isEmpty())
1260 dbg.nospace() << " structMembers=" << var.structMembers;
1261 dbg.nospace() << ')';
1262 return dbg;
1263}
1264
1265QDebug operator<<(QDebug dbg, const QShaderDescription::UniformBlock &blk)
1266{
1267 QDebugStateSaver saver(dbg);
1268 dbg.nospace() << "UniformBlock(" << blk.blockName << ' ' << blk.structName
1269 << " size=" << blk.size;
1270 if (blk.binding >= 0)
1271 dbg.nospace() << " binding=" << blk.binding;
1272 if (blk.descriptorSet >= 0)
1273 dbg.nospace() << " set=" << blk.descriptorSet;
1274 dbg.nospace() << ' ' << blk.members << ')';
1275 return dbg;
1276}
1277
1278QDebug operator<<(QDebug dbg, const QShaderDescription::PushConstantBlock &blk)
1279{
1280 QDebugStateSaver saver(dbg);
1281 dbg.nospace() << "PushConstantBlock(" << blk.name << " size=" << blk.size << ' ' << blk.members
1282 << ')';
1283 return dbg;
1284}
1285
1286QDebug operator<<(QDebug dbg, const QShaderDescription::StorageBlock &blk)
1287{
1288 QDebugStateSaver saver(dbg);
1289 dbg.nospace() << "StorageBlock(" << blk.blockName << ' ' << blk.instanceName
1290 << " knownSize=" << blk.knownSize;
1291 if (blk.binding >= 0)
1292 dbg.nospace() << " binding=" << blk.binding;
1293 if (blk.descriptorSet >= 0)
1294 dbg.nospace() << " set=" << blk.descriptorSet;
1295 if (blk.runtimeArrayStride)
1296 dbg.nospace() << " runtimeArrayStride=" << blk.runtimeArrayStride;
1297 if (blk.qualifierFlags)
1298 dbg.nospace() << " qualifierFlags=" << blk.qualifierFlags;
1299 dbg.nospace() << ' ' << blk.members << ')';
1300 return dbg;
1301}
1302
1303QDebug operator<<(QDebug dbg, const QShaderDescription::BuiltinVariable &builtin)
1304{
1305 QDebugStateSaver saver(dbg);
1306 dbg.nospace() << "BuiltinVariable(type=" << builtinTypeStr(t: builtin.type);
1307 dbg.nospace() << " varType=" << typeStr(t: builtin.varType);
1308 if (!builtin.arrayDims.isEmpty())
1309 dbg.nospace() << " array=" << builtin.arrayDims;
1310 dbg.nospace() << ")";
1311 return dbg;
1312}
1313#endif
1314
1315#define JSON_KEY(key) static constexpr QLatin1StringView key ## Key() noexcept { return QLatin1StringView( #key ); }
1316JSON_KEY(name)
1317JSON_KEY(type)
1318JSON_KEY(location)
1319JSON_KEY(binding)
1320JSON_KEY(set)
1321JSON_KEY(perPatch)
1322JSON_KEY(imageFormat)
1323JSON_KEY(imageFlags)
1324JSON_KEY(offset)
1325JSON_KEY(arrayDims)
1326JSON_KEY(arrayStride)
1327JSON_KEY(matrixStride)
1328JSON_KEY(matrixRowMajor)
1329JSON_KEY(structMembers)
1330JSON_KEY(members)
1331JSON_KEY(inputs)
1332JSON_KEY(outputs)
1333JSON_KEY(uniformBlocks)
1334JSON_KEY(blockName)
1335JSON_KEY(structName)
1336JSON_KEY(instanceName)
1337JSON_KEY(size)
1338JSON_KEY(knownSize)
1339JSON_KEY(pushConstantBlocks)
1340JSON_KEY(storageBlocks)
1341JSON_KEY(combinedImageSamplers)
1342JSON_KEY(storageImages)
1343JSON_KEY(inBuiltins)
1344JSON_KEY(outBuiltins)
1345JSON_KEY(computeLocalSize)
1346JSON_KEY(tessellationOutputVertexCount)
1347JSON_KEY(tessellationMode)
1348JSON_KEY(tessellationWindingOrder)
1349JSON_KEY(tessellationPartitioning)
1350JSON_KEY(separateImages)
1351JSON_KEY(separateSamplers)
1352JSON_KEY(runtimeArrayStride)
1353JSON_KEY(qualifierFlags)
1354#undef JSON_KEY
1355
1356static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v)
1357{
1358 if (v.location >= 0)
1359 (*obj)[locationKey()] = v.location;
1360 if (v.binding >= 0)
1361 (*obj)[bindingKey()] = v.binding;
1362 if (v.descriptorSet >= 0)
1363 (*obj)[setKey()] = v.descriptorSet;
1364 if (v.perPatch)
1365 (*obj)[perPatchKey()] = v.perPatch;
1366 if (v.imageFormat != QShaderDescription::ImageFormatUnknown)
1367 (*obj)[imageFormatKey()] = imageFormatStr(f: v.imageFormat);
1368 if (v.imageFlags)
1369 (*obj)[imageFlagsKey()] = int(v.imageFlags);
1370 if (!v.arrayDims.isEmpty()) {
1371 QJsonArray dimArr;
1372 for (int dim : v.arrayDims)
1373 dimArr.append(value: dim);
1374 (*obj)[arrayDimsKey()] = dimArr;
1375 }
1376}
1377
1378static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v, int version)
1379{
1380 (*stream) << v.location;
1381 (*stream) << v.binding;
1382 (*stream) << v.descriptorSet;
1383 (*stream) << int(v.imageFormat);
1384 (*stream) << int(v.imageFlags);
1385 (*stream) << int(v.arrayDims.size());
1386 for (int dim : v.arrayDims)
1387 (*stream) << dim;
1388 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO)
1389 (*stream) << quint8(v.perPatch);
1390}
1391
1392static void serializeBuiltinVar(QDataStream *stream, const QShaderDescription::BuiltinVariable &v, int version)
1393{
1394 (*stream) << int(v.type);
1395 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS) {
1396 (*stream) << int(v.varType);
1397 (*stream) << int(v.arrayDims.size());
1398 for (int dim : v.arrayDims)
1399 (*stream) << dim;
1400 }
1401}
1402
1403static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v)
1404{
1405 QJsonObject obj;
1406 obj[nameKey()] = QString::fromUtf8(ba: v.name);
1407 obj[typeKey()] = typeStr(t: v.type);
1408 if (v.offset != -1)
1409 obj[offsetKey()] = v.offset;
1410 obj[sizeKey()] = v.size;
1411 if (!v.arrayDims.isEmpty()) {
1412 QJsonArray dimArr;
1413 for (int dim : v.arrayDims)
1414 dimArr.append(value: dim);
1415 obj[arrayDimsKey()] = dimArr;
1416 }
1417 if (v.arrayStride)
1418 obj[arrayStrideKey()] = v.arrayStride;
1419 if (v.matrixStride)
1420 obj[matrixStrideKey()] = v.matrixStride;
1421 if (v.matrixIsRowMajor)
1422 obj[matrixRowMajorKey()] = true;
1423 if (!v.structMembers.isEmpty()) {
1424 QJsonArray arr;
1425 for (const QShaderDescription::BlockVariable &sv : v.structMembers)
1426 arr.append(value: blockMemberObject(v: sv));
1427 obj[structMembersKey()] = arr;
1428 }
1429 return obj;
1430}
1431
1432static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
1433{
1434 QJsonObject obj;
1435 obj[nameKey()] = QString::fromUtf8(ba: v.name);
1436 obj[typeKey()] = typeStr(t: v.type);
1437 addDeco(obj: &obj, v);
1438 if (!v.structMembers.isEmpty()) {
1439 QJsonArray arr;
1440 for (const QShaderDescription::BlockVariable &sv : v.structMembers)
1441 arr.append(value: blockMemberObject(v: sv));
1442 obj[structMembersKey()] = arr;
1443 }
1444 return obj;
1445}
1446
1447static QJsonObject builtinObject(const QShaderDescription::BuiltinVariable &v)
1448{
1449 QJsonObject obj;
1450
1451 obj[nameKey()] = builtinTypeStr(t: v.type);
1452 obj[typeKey()] = typeStr(t: v.varType);
1453 if (!v.arrayDims.isEmpty()) {
1454 QJsonArray dimArr;
1455 for (int dim : v.arrayDims)
1456 dimArr.append(value: dim);
1457 obj[arrayDimsKey()] = dimArr;
1458 }
1459 return obj;
1460}
1461
1462static void serializeBlockMemberVar(QDataStream *stream, const QShaderDescription::BlockVariable &v)
1463{
1464 (*stream) << QString::fromUtf8(ba: v.name);
1465 (*stream) << int(v.type);
1466 (*stream) << v.offset;
1467 (*stream) << v.size;
1468 (*stream) << int(v.arrayDims.size());
1469 for (int dim : v.arrayDims)
1470 (*stream) << dim;
1471 (*stream) << v.arrayStride;
1472 (*stream) << v.matrixStride;
1473 (*stream) << v.matrixIsRowMajor;
1474 (*stream) << int(v.structMembers.size());
1475 for (const QShaderDescription::BlockVariable &sv : v.structMembers)
1476 serializeBlockMemberVar(stream, v: sv);
1477}
1478
1479static void serializeInOutVar(QDataStream *stream, const QShaderDescription::InOutVariable &v,
1480 int version)
1481{
1482 (*stream) << QString::fromUtf8(ba: v.name);
1483 (*stream) << int(v.type);
1484 serializeDecorations(stream, v, version);
1485 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS) {
1486 (*stream) << int(v.structMembers.size());
1487 for (const QShaderDescription::BlockVariable &sv : v.structMembers)
1488 serializeBlockMemberVar(stream, v: sv);
1489 }
1490}
1491
1492QJsonDocument QShaderDescriptionPrivate::makeDoc()
1493{
1494 QJsonObject root;
1495
1496 QJsonArray jinputs;
1497 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: inVars))
1498 jinputs.append(value: inOutObject(v));
1499 if (!jinputs.isEmpty())
1500 root[inputsKey()] = jinputs;
1501
1502 QJsonArray joutputs;
1503 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: outVars))
1504 joutputs.append(value: inOutObject(v));
1505 if (!joutputs.isEmpty())
1506 root[outputsKey()] = joutputs;
1507
1508 QJsonArray juniformBlocks;
1509 for (const QShaderDescription::UniformBlock &b : uniformBlocks) {
1510 QJsonObject juniformBlock;
1511 juniformBlock[blockNameKey()] = QString::fromUtf8(ba: b.blockName);
1512 juniformBlock[structNameKey()] = QString::fromUtf8(ba: b.structName);
1513 juniformBlock[sizeKey()] = b.size;
1514 if (b.binding >= 0)
1515 juniformBlock[bindingKey()] = b.binding;
1516 if (b.descriptorSet >= 0)
1517 juniformBlock[setKey()] = b.descriptorSet;
1518 QJsonArray members;
1519 for (const QShaderDescription::BlockVariable &v : b.members)
1520 members.append(value: blockMemberObject(v));
1521 juniformBlock[membersKey()] = members;
1522 juniformBlocks.append(value: juniformBlock);
1523 }
1524 if (!juniformBlocks.isEmpty())
1525 root[uniformBlocksKey()] = juniformBlocks;
1526
1527 QJsonArray jpushConstantBlocks;
1528 for (const QShaderDescription::PushConstantBlock &b : pushConstantBlocks) {
1529 QJsonObject jpushConstantBlock;
1530 jpushConstantBlock[nameKey()] = QString::fromUtf8(ba: b.name);
1531 jpushConstantBlock[sizeKey()] = b.size;
1532 QJsonArray members;
1533 for (const QShaderDescription::BlockVariable &v : b.members)
1534 members.append(value: blockMemberObject(v));
1535 jpushConstantBlock[membersKey()] = members;
1536 jpushConstantBlocks.append(value: jpushConstantBlock);
1537 }
1538 if (!jpushConstantBlocks.isEmpty())
1539 root[pushConstantBlocksKey()] = jpushConstantBlocks;
1540
1541 QJsonArray jstorageBlocks;
1542 for (const QShaderDescription::StorageBlock &b : storageBlocks) {
1543 QJsonObject jstorageBlock;
1544 jstorageBlock[blockNameKey()] = QString::fromUtf8(ba: b.blockName);
1545 jstorageBlock[instanceNameKey()] = QString::fromUtf8(ba: b.instanceName);
1546 jstorageBlock[knownSizeKey()] = b.knownSize;
1547 if (b.binding >= 0)
1548 jstorageBlock[bindingKey()] = b.binding;
1549 if (b.descriptorSet >= 0)
1550 jstorageBlock[setKey()] = b.descriptorSet;
1551 if (b.runtimeArrayStride)
1552 jstorageBlock[runtimeArrayStrideKey()] = b.runtimeArrayStride;
1553 if (b.qualifierFlags)
1554 jstorageBlock[qualifierFlagsKey()] = int(b.qualifierFlags);
1555 QJsonArray members;
1556 for (const QShaderDescription::BlockVariable &v : b.members)
1557 members.append(value: blockMemberObject(v));
1558 jstorageBlock[membersKey()] = members;
1559 jstorageBlocks.append(value: jstorageBlock);
1560 }
1561 if (!jstorageBlocks.isEmpty())
1562 root[storageBlocksKey()] = jstorageBlocks;
1563
1564 QJsonArray jcombinedSamplers;
1565 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: combinedImageSamplers)) {
1566 QJsonObject sampler;
1567 sampler[nameKey()] = QString::fromUtf8(ba: v.name);
1568 sampler[typeKey()] = typeStr(t: v.type);
1569 addDeco(obj: &sampler, v);
1570 jcombinedSamplers.append(value: sampler);
1571 }
1572 if (!jcombinedSamplers.isEmpty())
1573 root[combinedImageSamplersKey()] = jcombinedSamplers;
1574
1575 QJsonArray jstorageImages;
1576 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: storageImages)) {
1577 QJsonObject image;
1578 image[nameKey()] = QString::fromUtf8(ba: v.name);
1579 image[typeKey()] = typeStr(t: v.type);
1580 addDeco(obj: &image, v);
1581 jstorageImages.append(value: image);
1582 }
1583 if (!jstorageImages.isEmpty())
1584 root[storageImagesKey()] = jstorageImages;
1585
1586 QJsonArray jinBuiltins;
1587 for (const QShaderDescription::BuiltinVariable &v : std::as_const(t&: inBuiltins))
1588 jinBuiltins.append(value: builtinObject(v));
1589 if (!jinBuiltins.isEmpty())
1590 root[inBuiltinsKey()] = jinBuiltins;
1591
1592 QJsonArray joutBuiltins;
1593 for (const QShaderDescription::BuiltinVariable &v : std::as_const(t&: outBuiltins))
1594 joutBuiltins.append(value: builtinObject(v));
1595 if (!joutBuiltins.isEmpty())
1596 root[outBuiltinsKey()] = joutBuiltins;
1597
1598 if (localSize[0] || localSize[1] || localSize[2]) {
1599 QJsonArray jlocalSize;
1600 for (size_t i = 0; i < 3; ++i)
1601 jlocalSize.append(value: QJsonValue(int(localSize[i])));
1602 root[computeLocalSizeKey()] = jlocalSize;
1603 }
1604
1605 if (tessOutVertCount)
1606 root[tessellationOutputVertexCountKey()] = int(tessOutVertCount);
1607
1608 if (tessMode != QShaderDescription::UnknownTessellationMode)
1609 root[tessellationModeKey()] = tessModeStr(mode: tessMode);
1610
1611 if (tessWind != QShaderDescription::UnknownTessellationWindingOrder)
1612 root[tessellationWindingOrderKey()] = tessWindStr(w: tessWind);
1613
1614 if (tessPart != QShaderDescription::UnknownTessellationPartitioning)
1615 root[tessellationPartitioningKey()] = tessPartStr(p: tessPart);
1616
1617 QJsonArray jseparateImages;
1618 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: separateImages)) {
1619 QJsonObject image;
1620 image[nameKey()] = QString::fromUtf8(ba: v.name);
1621 image[typeKey()] = typeStr(t: v.type);
1622 addDeco(obj: &image, v);
1623 jseparateImages.append(value: image);
1624 }
1625 if (!jseparateImages.isEmpty())
1626 root[separateImagesKey()] = jseparateImages;
1627
1628 QJsonArray jseparateSamplers;
1629 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: separateSamplers)) {
1630 QJsonObject sampler;
1631 sampler[nameKey()] = QString::fromUtf8(ba: v.name);
1632 sampler[typeKey()] = typeStr(t: v.type);
1633 addDeco(obj: &sampler, v);
1634 jseparateSamplers.append(value: sampler);
1635 }
1636 if (!jseparateSamplers.isEmpty())
1637 root[separateSamplersKey()] = jseparateSamplers;
1638
1639 return QJsonDocument(root);
1640}
1641
1642void QShaderDescriptionPrivate::writeToStream(QDataStream *stream, int version)
1643{
1644 (*stream) << int(inVars.size());
1645 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: inVars))
1646 serializeInOutVar(stream, v, version);
1647
1648 (*stream) << int(outVars.size());
1649 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: outVars))
1650 serializeInOutVar(stream, v, version);
1651
1652 (*stream) << int(uniformBlocks.size());
1653 for (const QShaderDescription::UniformBlock &b : uniformBlocks) {
1654 (*stream) << QString::fromUtf8(ba: b.blockName);
1655 (*stream) << QString::fromUtf8(ba: b.structName);
1656 (*stream) << b.size;
1657 (*stream) << b.binding;
1658 (*stream) << b.descriptorSet;
1659 (*stream) << int(b.members.size());
1660 for (const QShaderDescription::BlockVariable &v : b.members)
1661 serializeBlockMemberVar(stream, v);
1662 }
1663
1664 (*stream) << int(pushConstantBlocks.size());
1665 for (const QShaderDescription::PushConstantBlock &b : pushConstantBlocks) {
1666 (*stream) << QString::fromUtf8(ba: b.name);
1667 (*stream) << b.size;
1668 (*stream) << int(b.members.size());
1669 for (const QShaderDescription::BlockVariable &v : b.members)
1670 serializeBlockMemberVar(stream, v);
1671 }
1672
1673 (*stream) << int(storageBlocks.size());
1674 for (const QShaderDescription::StorageBlock &b : storageBlocks) {
1675 (*stream) << QString::fromUtf8(ba: b.blockName);
1676 (*stream) << QString::fromUtf8(ba: b.instanceName);
1677 (*stream) << b.knownSize;
1678 (*stream) << b.binding;
1679 (*stream) << b.descriptorSet;
1680 (*stream) << int(b.members.size());
1681 for (const QShaderDescription::BlockVariable &v : b.members)
1682 serializeBlockMemberVar(stream, v);
1683 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO) {
1684 (*stream) << b.runtimeArrayStride;
1685 (*stream) << b.qualifierFlags;
1686 }
1687 }
1688
1689 (*stream) << int(combinedImageSamplers.size());
1690 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: combinedImageSamplers)) {
1691 (*stream) << QString::fromUtf8(ba: v.name);
1692 (*stream) << int(v.type);
1693 serializeDecorations(stream, v, version);
1694 }
1695
1696 (*stream) << int(storageImages.size());
1697 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: storageImages)) {
1698 (*stream) << QString::fromUtf8(ba: v.name);
1699 (*stream) << int(v.type);
1700 serializeDecorations(stream, v, version);
1701 }
1702
1703 for (size_t i = 0; i < 3; ++i)
1704 (*stream) << quint32(localSize[i]);
1705
1706 (*stream) << int(separateImages.size());
1707 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: separateImages)) {
1708 (*stream) << QString::fromUtf8(ba: v.name);
1709 (*stream) << int(v.type);
1710 serializeDecorations(stream, v, version);
1711 }
1712
1713 (*stream) << int(separateSamplers.size());
1714 for (const QShaderDescription::InOutVariable &v : std::as_const(t&: separateSamplers)) {
1715 (*stream) << QString::fromUtf8(ba: v.name);
1716 (*stream) << int(v.type);
1717 serializeDecorations(stream, v, version);
1718 }
1719
1720 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) {
1721 (*stream) << quint32(tessOutVertCount);
1722 (*stream) << quint32(tessMode);
1723 (*stream) << quint32(tessWind);
1724 (*stream) << quint32(tessPart);
1725
1726 (*stream) << int(inBuiltins.size());
1727 for (const QShaderDescription::BuiltinVariable &v : std::as_const(t&: inBuiltins))
1728 serializeBuiltinVar(stream, v, version);
1729
1730 (*stream) << int(outBuiltins.size());
1731 for (const QShaderDescription::BuiltinVariable &v : std::as_const(t&: outBuiltins))
1732 serializeBuiltinVar(stream, v, version);
1733 }
1734}
1735
1736static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v)
1737{
1738 (*stream) >> v->location;
1739 (*stream) >> v->binding;
1740 (*stream) >> v->descriptorSet;
1741 int f;
1742 (*stream) >> f;
1743 v->imageFormat = QShaderDescription::ImageFormat(f);
1744 (*stream) >> f;
1745 v->imageFlags = QShaderDescription::ImageFlags(f);
1746
1747 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS) {
1748 (*stream) >> f;
1749 v->arrayDims.resize(size: f);
1750 for (int i = 0; i < f; ++i)
1751 (*stream) >> v->arrayDims[i];
1752 }
1753
1754 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) {
1755 quint8 b;
1756 (*stream) >> b;
1757 v->perPatch = b;
1758 }
1759}
1760
1761static QShaderDescription::BuiltinVariable deserializeBuiltinVar(QDataStream *stream, int version)
1762{
1763 QShaderDescription::BuiltinVariable var;
1764 int t;
1765 (*stream) >> t;
1766 var.type = QShaderDescription::BuiltinType(t);
1767 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS) {
1768 (*stream) >> t;
1769 var.varType = QShaderDescription::VariableType(t);
1770 int count;
1771 (*stream) >> count;
1772 var.arrayDims.resize(size: count);
1773 for (int i = 0; i < count; ++i)
1774 (*stream) >> var.arrayDims[i];
1775 }
1776 return var;
1777}
1778
1779static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream, int version)
1780{
1781 QShaderDescription::BlockVariable var;
1782 QString tmp;
1783 (*stream) >> tmp;
1784 var.name = tmp.toUtf8();
1785 int t;
1786 (*stream) >> t;
1787 var.type = QShaderDescription::VariableType(t);
1788 (*stream) >> var.offset;
1789 (*stream) >> var.size;
1790 int count;
1791 (*stream) >> count;
1792 var.arrayDims.resize(size: count);
1793 for (int i = 0; i < count; ++i)
1794 (*stream) >> var.arrayDims[i];
1795 (*stream) >> var.arrayStride;
1796 (*stream) >> var.matrixStride;
1797 (*stream) >> var.matrixIsRowMajor;
1798 (*stream) >> count;
1799 var.structMembers.resize(size: count);
1800 for (int i = 0; i < count; ++i)
1801 var.structMembers[i] = deserializeBlockMemberVar(stream, version);
1802 return var;
1803}
1804
1805static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream, int version)
1806{
1807 QShaderDescription::InOutVariable var;
1808 QString tmp;
1809 (*stream) >> tmp;
1810 var.name = tmp.toUtf8();
1811 int t;
1812 (*stream) >> t;
1813 var.type = QShaderDescription::VariableType(t);
1814 deserializeDecorations(stream, version, v: &var);
1815 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS) {
1816 int count;
1817 (*stream) >> count;
1818 var.structMembers.resize(size: count);
1819 for (int i = 0; i < count; ++i)
1820 var.structMembers[i] = deserializeBlockMemberVar(stream, version);
1821 }
1822 return var;
1823}
1824
1825void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version)
1826{
1827 Q_ASSERT(ref.loadRelaxed() == 1); // must be detached
1828
1829 int count;
1830 (*stream) >> count;
1831 inVars.resize(size: count);
1832 for (int i = 0; i < count; ++i)
1833 inVars[i] = deserializeInOutVar(stream, version);
1834
1835 (*stream) >> count;
1836 outVars.resize(size: count);
1837 for (int i = 0; i < count; ++i)
1838 outVars[i] = deserializeInOutVar(stream, version);
1839
1840 (*stream) >> count;
1841 uniformBlocks.resize(size: count);
1842 for (int i = 0; i < count; ++i) {
1843 QString tmp;
1844 (*stream) >> tmp;
1845 uniformBlocks[i].blockName = tmp.toUtf8();
1846 (*stream) >> tmp;
1847 uniformBlocks[i].structName = tmp.toUtf8();
1848 (*stream) >> uniformBlocks[i].size;
1849 (*stream) >> uniformBlocks[i].binding;
1850 (*stream) >> uniformBlocks[i].descriptorSet;
1851 int memberCount;
1852 (*stream) >> memberCount;
1853 uniformBlocks[i].members.resize(size: memberCount);
1854 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1855 uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
1856 }
1857
1858 (*stream) >> count;
1859 pushConstantBlocks.resize(size: count);
1860 for (int i = 0; i < count; ++i) {
1861 QString tmp;
1862 (*stream) >> tmp;
1863 pushConstantBlocks[i].name = tmp.toUtf8();
1864 (*stream) >> pushConstantBlocks[i].size;
1865 int memberCount;
1866 (*stream) >> memberCount;
1867 pushConstantBlocks[i].members.resize(size: memberCount);
1868 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1869 pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
1870 }
1871
1872 (*stream) >> count;
1873 storageBlocks.resize(size: count);
1874 for (int i = 0; i < count; ++i) {
1875 QString tmp;
1876 (*stream) >> tmp;
1877 storageBlocks[i].blockName = tmp.toUtf8();
1878 (*stream) >> tmp;
1879 storageBlocks[i].instanceName = tmp.toUtf8();
1880 (*stream) >> storageBlocks[i].knownSize;
1881 (*stream) >> storageBlocks[i].binding;
1882 (*stream) >> storageBlocks[i].descriptorSet;
1883 int memberCount;
1884 (*stream) >> memberCount;
1885 storageBlocks[i].members.resize(size: memberCount);
1886 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1887 storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
1888
1889 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO) {
1890 (*stream) >> storageBlocks[i].runtimeArrayStride;
1891 (*stream) >> storageBlocks[i].qualifierFlags;
1892 }
1893 }
1894
1895 (*stream) >> count;
1896 combinedImageSamplers.resize(size: count);
1897 for (int i = 0; i < count; ++i) {
1898 QString tmp;
1899 (*stream) >> tmp;
1900 combinedImageSamplers[i].name = tmp.toUtf8();
1901 int t;
1902 (*stream) >> t;
1903 combinedImageSamplers[i].type = QShaderDescription::VariableType(t);
1904 deserializeDecorations(stream, version, v: &combinedImageSamplers[i]);
1905 }
1906
1907 (*stream) >> count;
1908 storageImages.resize(size: count);
1909 for (int i = 0; i < count; ++i) {
1910 QString tmp;
1911 (*stream) >> tmp;
1912 storageImages[i].name = tmp.toUtf8();
1913 int t;
1914 (*stream) >> t;
1915 storageImages[i].type = QShaderDescription::VariableType(t);
1916 deserializeDecorations(stream, version, v: &storageImages[i]);
1917 }
1918
1919 for (size_t i = 0; i < 3; ++i) {
1920 quint32 v;
1921 (*stream) >> v;
1922 localSize[i] = v;
1923 }
1924
1925 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS) {
1926 (*stream) >> count;
1927 separateImages.resize(size: count);
1928 for (int i = 0; i < count; ++i) {
1929 QString tmp;
1930 (*stream) >> tmp;
1931 separateImages[i].name = tmp.toUtf8();
1932 int t;
1933 (*stream) >> t;
1934 separateImages[i].type = QShaderDescription::VariableType(t);
1935 deserializeDecorations(stream, version, v: &separateImages[i]);
1936 }
1937
1938 (*stream) >> count;
1939 separateSamplers.resize(size: count);
1940 for (int i = 0; i < count; ++i) {
1941 QString tmp;
1942 (*stream) >> tmp;
1943 separateSamplers[i].name = tmp.toUtf8();
1944 int t;
1945 (*stream) >> t;
1946 separateSamplers[i].type = QShaderDescription::VariableType(t);
1947 deserializeDecorations(stream, version, v: &separateSamplers[i]);
1948 }
1949 }
1950
1951 if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) {
1952 quint32 v;
1953 (*stream) >> v;
1954 tessOutVertCount = v;
1955 (*stream) >> v;
1956 tessMode = QShaderDescription::TessellationMode(v);
1957 (*stream) >> v;
1958 tessWind = QShaderDescription::TessellationWindingOrder(v);
1959 (*stream) >> v;
1960 tessPart = QShaderDescription::TessellationPartitioning(v);
1961
1962 (*stream) >> count;
1963 inBuiltins.resize(size: count);
1964 for (int i = 0; i < count; ++i)
1965 inBuiltins[i] = deserializeBuiltinVar(stream, version);
1966
1967 (*stream) >> count;
1968 outBuiltins.resize(size: count);
1969 for (int i = 0; i < count; ++i)
1970 outBuiltins[i] = deserializeBuiltinVar(stream, version);
1971 }
1972}
1973
1974/*!
1975 Returns \c true if the two QShaderDescription objects \a lhs and \a rhs are
1976 equal.
1977
1978 \relates QShaderDescription
1979 */
1980bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept
1981{
1982 if (lhs.d == rhs.d)
1983 return true;
1984
1985 return lhs.d->inVars == rhs.d->inVars
1986 && lhs.d->outVars == rhs.d->outVars
1987 && lhs.d->uniformBlocks == rhs.d->uniformBlocks
1988 && lhs.d->pushConstantBlocks == rhs.d->pushConstantBlocks
1989 && lhs.d->storageBlocks == rhs.d->storageBlocks
1990 && lhs.d->combinedImageSamplers == rhs.d->combinedImageSamplers
1991 && lhs.d->separateImages == rhs.d->separateImages
1992 && lhs.d->separateSamplers == rhs.d->separateSamplers
1993 && lhs.d->storageImages == rhs.d->storageImages
1994 && lhs.d->inBuiltins == rhs.d->inBuiltins
1995 && lhs.d->outBuiltins == rhs.d->outBuiltins
1996 && lhs.d->localSize == rhs.d->localSize
1997 && lhs.d->tessOutVertCount == rhs.d->tessOutVertCount
1998 && lhs.d->tessMode == rhs.d->tessMode
1999 && lhs.d->tessWind == rhs.d->tessWind
2000 && lhs.d->tessPart == rhs.d->tessPart;
2001}
2002
2003/*!
2004 Returns \c true if the two InOutVariable objects \a lhs and \a rhs are
2005 equal.
2006
2007 \relates QShaderDescription::InOutVariable
2008 */
2009bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) noexcept
2010{
2011 return lhs.name == rhs.name
2012 && lhs.type == rhs.type
2013 && lhs.location == rhs.location
2014 && lhs.binding == rhs.binding
2015 && lhs.descriptorSet == rhs.descriptorSet
2016 && lhs.imageFormat == rhs.imageFormat
2017 && lhs.imageFlags == rhs.imageFlags
2018 && lhs.arrayDims == rhs.arrayDims
2019 && lhs.perPatch == rhs.perPatch
2020 && lhs.structMembers == rhs.structMembers;
2021}
2022
2023/*!
2024 Returns \c true if the two BlockVariable objects \a lhs and \a rhs are
2025 equal.
2026
2027 \relates QShaderDescription::BlockVariable
2028 */
2029bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) noexcept
2030{
2031 return lhs.name == rhs.name
2032 && lhs.type == rhs.type
2033 && lhs.offset == rhs.offset
2034 && lhs.size == rhs.size
2035 && lhs.arrayDims == rhs.arrayDims
2036 && lhs.arrayStride == rhs.arrayStride
2037 && lhs.matrixStride == rhs.matrixStride
2038 && lhs.matrixIsRowMajor == rhs.matrixIsRowMajor
2039 && lhs.structMembers == rhs.structMembers;
2040}
2041
2042/*!
2043 Returns \c true if the two UniformBlock objects \a lhs and \a rhs are
2044 equal.
2045
2046 \relates QShaderDescription::UniformBlock
2047 */
2048bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) noexcept
2049{
2050 return lhs.blockName == rhs.blockName
2051 && lhs.structName == rhs.structName
2052 && lhs.size == rhs.size
2053 && lhs.binding == rhs.binding
2054 && lhs.descriptorSet == rhs.descriptorSet
2055 && lhs.members == rhs.members;
2056}
2057
2058/*!
2059 Returns \c true if the two PushConstantBlock objects \a lhs and \a rhs are
2060 equal.
2061
2062 \relates QShaderDescription::PushConstantBlock
2063 */
2064bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) noexcept
2065{
2066 return lhs.name == rhs.name
2067 && lhs.size == rhs.size
2068 && lhs.members == rhs.members;
2069}
2070
2071/*!
2072 Returns \c true if the two StorageBlock objects \a lhs and \a rhs are
2073 equal.
2074
2075 \relates QShaderDescription::StorageBlock
2076 */
2077bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) noexcept
2078{
2079 return lhs.blockName == rhs.blockName
2080 && lhs.instanceName == rhs.instanceName
2081 && lhs.knownSize == rhs.knownSize
2082 && lhs.binding == rhs.binding
2083 && lhs.descriptorSet == rhs.descriptorSet
2084 && lhs.runtimeArrayStride == rhs.runtimeArrayStride
2085 && lhs.qualifierFlags == rhs.qualifierFlags
2086 && lhs.members == rhs.members;
2087}
2088
2089/*!
2090 Returns \c true if the two BuiltinVariable objects \a lhs and \a rhs are
2091 equal.
2092
2093 \relates QShaderDescription::BuiltinVariable
2094 */
2095bool operator==(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept
2096{
2097 return lhs.type == rhs.type
2098 && lhs.varType == rhs.varType
2099 && lhs.arrayDims == rhs.arrayDims;
2100}
2101
2102QT_END_NAMESPACE
2103

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