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