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 | |
11 | QT_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 | */ |
551 | QShaderDescription::QShaderDescription() |
552 | : d(new QShaderDescriptionPrivate) |
553 | { |
554 | } |
555 | |
556 | /*! |
557 | \internal |
558 | */ |
559 | void QShaderDescription::detach() |
560 | { |
561 | qAtomicDetach(d); |
562 | } |
563 | |
564 | /*! |
565 | Constructs a copy of \a other. |
566 | */ |
567 | QShaderDescription::QShaderDescription(const QShaderDescription &other) |
568 | : d(other.d) |
569 | { |
570 | d->ref.ref(); |
571 | } |
572 | |
573 | /*! |
574 | Assigns \a other to this object. |
575 | */ |
576 | QShaderDescription &QShaderDescription::operator=(const QShaderDescription &other) |
577 | { |
578 | qAtomicAssign(d, x: other.d); |
579 | return *this; |
580 | } |
581 | |
582 | /*! |
583 | Destructor. |
584 | */ |
585 | QShaderDescription::~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 | */ |
595 | bool 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 | */ |
611 | QByteArray 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 | */ |
622 | void 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 | */ |
633 | QShaderDescription 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 | */ |
645 | QList<QShaderDescription::InOutVariable> QShaderDescription::inputVariables() const |
646 | { |
647 | return d->inVars; |
648 | } |
649 | |
650 | /*! |
651 | \return the list of output variables. |
652 | */ |
653 | QList<QShaderDescription::InOutVariable> QShaderDescription::outputVariables() const |
654 | { |
655 | return d->outVars; |
656 | } |
657 | |
658 | /*! |
659 | \return the list of uniform blocks. |
660 | */ |
661 | QList<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 | */ |
673 | QList<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 | */ |
748 | QList<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 | */ |
775 | QList<QShaderDescription::InOutVariable> QShaderDescription::combinedImageSamplers() const |
776 | { |
777 | return d->combinedImageSamplers; |
778 | } |
779 | |
780 | QList<QShaderDescription::InOutVariable> QShaderDescription::separateImages() const |
781 | { |
782 | return d->separateImages; |
783 | } |
784 | |
785 | QList<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 | */ |
812 | QList<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 | */ |
822 | QVector<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 | */ |
831 | QVector<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 | */ |
846 | std::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 | */ |
861 | uint 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 | */ |
888 | QShaderDescription::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 | */ |
914 | QShaderDescription::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 | */ |
941 | QShaderDescription::TessellationPartitioning QShaderDescription::tessellationPartitioning() const |
942 | { |
943 | return d->tessPart; |
944 | } |
945 | |
946 | static 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 | |
1029 | static 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 | |
1038 | static 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 | |
1084 | static 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 | |
1093 | static 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 | |
1128 | static 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 | |
1137 | static 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 | |
1147 | static 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 | |
1156 | static 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 | |
1165 | static 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 | |
1174 | static 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 | |
1184 | static 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 |
1194 | QDebug 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 | |
1220 | QDebug 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 | |
1244 | QDebug 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 | |
1265 | QDebug 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 | |
1278 | QDebug 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 | |
1286 | QDebug 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 | |
1303 | QDebug 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 ); } |
1316 | JSON_KEY(name) |
1317 | JSON_KEY(type) |
1318 | JSON_KEY(location) |
1319 | JSON_KEY(binding) |
1320 | JSON_KEY(set) |
1321 | JSON_KEY(perPatch) |
1322 | JSON_KEY(imageFormat) |
1323 | JSON_KEY(imageFlags) |
1324 | JSON_KEY(offset) |
1325 | JSON_KEY(arrayDims) |
1326 | JSON_KEY(arrayStride) |
1327 | JSON_KEY(matrixStride) |
1328 | JSON_KEY(matrixRowMajor) |
1329 | JSON_KEY(structMembers) |
1330 | JSON_KEY(members) |
1331 | JSON_KEY(inputs) |
1332 | JSON_KEY(outputs) |
1333 | JSON_KEY(uniformBlocks) |
1334 | JSON_KEY(blockName) |
1335 | JSON_KEY(structName) |
1336 | JSON_KEY(instanceName) |
1337 | JSON_KEY(size) |
1338 | JSON_KEY(knownSize) |
1339 | JSON_KEY(pushConstantBlocks) |
1340 | JSON_KEY(storageBlocks) |
1341 | JSON_KEY(combinedImageSamplers) |
1342 | JSON_KEY(storageImages) |
1343 | JSON_KEY(inBuiltins) |
1344 | JSON_KEY(outBuiltins) |
1345 | JSON_KEY(computeLocalSize) |
1346 | JSON_KEY(tessellationOutputVertexCount) |
1347 | JSON_KEY(tessellationMode) |
1348 | JSON_KEY(tessellationWindingOrder) |
1349 | JSON_KEY(tessellationPartitioning) |
1350 | JSON_KEY(separateImages) |
1351 | JSON_KEY(separateSamplers) |
1352 | JSON_KEY(runtimeArrayStride) |
1353 | JSON_KEY(qualifierFlags) |
1354 | #undef JSON_KEY |
1355 | |
1356 | static 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 | |
1378 | static 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 | |
1392 | static 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 | |
1403 | static 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 | |
1432 | static 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 | |
1447 | static 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 | |
1462 | static 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 | |
1479 | static 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 | |
1492 | QJsonDocument 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 | |
1642 | void 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 | |
1736 | static 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 | |
1761 | static 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 | |
1779 | static 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 | |
1805 | static 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 | |
1825 | void 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 | */ |
1980 | bool 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 | */ |
2009 | bool 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 | */ |
2029 | bool 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 | */ |
2048 | bool 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 | */ |
2064 | bool 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 | */ |
2077 | bool 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 | */ |
2095 | bool 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 | |
2102 | QT_END_NAMESPACE |
2103 | |