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