Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssgrhicontext_p.h
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
6#ifndef QSSGRHICONTEXT_P_H
7#define QSSGRHICONTEXT_P_H
8
9//
10// W A R N I N G
11// -------------
12//
13// This file is not part of the Qt API. It exists purely as an
14// implementation detail. This header file may change from version to
15// version without notice, or even be removed.
16//
17// We mean it.
18//
19
20#include <QtGui/rhi/qrhi.h>
21
22#include <QtQuick3DRuntimeRender/qtquick3druntimerenderexports.h>
23#include <QtQuick3DUtils/private/qssgrenderbasetypes_p.h>
24#include <QtQuick3DUtils/private/qssgutils_p.h>
25#include <ssg/qssgrhicontext.h>
26
27QT_BEGIN_NAMESPACE
28
29struct QSSGRenderLayer;
30struct QSSGRenderInstanceTable;
31struct QSSGRenderModel;
32struct QSSGRenderMesh;
33class QSSGRenderGraphObject;
34class QSSGBufferManager;
35class QSSGUserRenderPassManager;
36
38{
40 static const InputAssemblerState &get(const QSSGRhiGraphicsPipelineState &ps) { return ps.ia; }
41 static InputAssemblerState &get(QSSGRhiGraphicsPipelineState &ps) { return ps.ia; }
42};
43
44using QSSGRhiInputAssemblerState = QSSGRhiInputAssemblerStatePrivate::InputAssemblerState;
45
47{
48 static void setShaderPipeline(QSSGRhiGraphicsPipelineState &ps, const QSSGRhiShaderPipeline *pipeline)
49 {
50 ps.shaderPipeline = pipeline;
51 }
52
53 static constexpr const QSSGRhiShaderPipeline *getShaderPipeline(const QSSGRhiGraphicsPipelineState &ps)
54 {
55 return ps.shaderPipeline;
56 }
57};
58
59namespace QSSGRhiHelpers
60{
61
62inline QRhiSampler::Filter toRhi(QSSGRenderTextureFilterOp op)
63{
64 switch (op) {
65 case QSSGRenderTextureFilterOp::Nearest:
66 return QRhiSampler::Nearest;
67 case QSSGRenderTextureFilterOp::Linear:
68 return QRhiSampler::Linear;
69 case QSSGRenderTextureFilterOp::None:
70 return QRhiSampler::Linear;
71 }
72
73 Q_UNREACHABLE_RETURN(QRhiSampler::Linear);
74}
75
76inline QRhiSampler::AddressMode toRhi(QSSGRenderTextureCoordOp tiling)
77{
78 switch (tiling) {
79 case QSSGRenderTextureCoordOp::Repeat:
80 return QRhiSampler::Repeat;
81 case QSSGRenderTextureCoordOp::MirroredRepeat:
82 return QRhiSampler::Mirror;
83 case QSSGRenderTextureCoordOp::ClampToEdge:
84 return QRhiSampler::ClampToEdge;
85 case QSSGRenderTextureCoordOp::Unknown:
86 return QRhiSampler::ClampToEdge;
87 }
88
89 Q_UNREACHABLE_RETURN(QRhiSampler::ClampToEdge);
90}
91
92inline QRhiGraphicsPipeline::CullMode toCullMode(QSSGCullFaceMode cullFaceMode)
93{
94 switch (cullFaceMode) {
95 case QSSGCullFaceMode::Back:
96 return QRhiGraphicsPipeline::Back;
97 case QSSGCullFaceMode::Front:
98 return QRhiGraphicsPipeline::Front;
99 case QSSGCullFaceMode::Disabled:
100 return QRhiGraphicsPipeline::None;
101 case QSSGCullFaceMode::FrontAndBack:
102 qWarning("FrontAndBack cull mode not supported");
103 return QRhiGraphicsPipeline::None;
104 case QSSGCullFaceMode::Unknown:
105 return QRhiGraphicsPipeline::None;
106 }
107
108 Q_UNREACHABLE_RETURN(QRhiGraphicsPipeline::None);
109}
110
111QRhiVertexInputAttribute::Format toVertexInputFormat(QSSGRenderComponentType compType, quint32 numComps);
112QRhiGraphicsPipeline::Topology toTopology(QSSGRenderDrawMode drawMode);
113// Fills out inputLayout.attributes[].location based on
114// inputLayoutInputNames and the provided shader reflection info.
115void bakeVertexInputLocations(QSSGRhiInputAssemblerState *ia, const QSSGRhiShaderPipeline &shaders, int instanceBufferBinding = 0);
116
117} // namespace QSSGRhiHelpers
118
119inline bool operator==(const QSSGRhiGraphicsPipelineState &a, const QSSGRhiGraphicsPipelineState &b) Q_DECL_NOTHROW
120{
121 const auto &ia_a = QSSGRhiInputAssemblerStatePrivate::get(a);
122 const auto &ia_b = QSSGRhiInputAssemblerStatePrivate::get(b);
123 const auto compareTargetBlend = [](const std::array<QRhiGraphicsPipeline::TargetBlend, 8> &a,
124 const std::array<QRhiGraphicsPipeline::TargetBlend, 8> &b,
125 const int count) -> bool {
126 for (int i = 0; i < count; i++) {
127 if (a[i].colorWrite != b[i].colorWrite
128 || a[i].srcColor != b[i].srcColor
129 || a[i].dstColor != b[i].dstColor
130 || a[i].opColor != b[i].opColor
131 || a[i].srcAlpha != b[i].srcAlpha
132 || a[i].dstAlpha != b[i].dstAlpha
133 || a[i].opAlpha != b[i].opAlpha) {
134 return false;
135 }
136 }
137 return true;
138 };
139 return QSSGRhiGraphicsPipelineStatePrivate::getShaderPipeline(a) == QSSGRhiGraphicsPipelineStatePrivate::getShaderPipeline(b)
140 && a.samples == b.samples
141 && a.flags == b.flags
142 && a.stencilRef == b.stencilRef
143 && (std::memcmp(&a.stencilOpFrontState, &b.stencilOpFrontState, sizeof(QRhiGraphicsPipeline::StencilOpState)) == 0)
144 && a.stencilWriteMask == b.stencilWriteMask
145 && a.depthFunc == b.depthFunc
146 && a.cullMode == b.cullMode
147 && a.depthBias == b.depthBias
148 && a.slopeScaledDepthBias == b.slopeScaledDepthBias
149 && a.viewport == b.viewport
150 && a.scissor == b.scissor
151 && ia_a.topology == ia_b.topology
152 && ia_a.inputLayout == ia_b.inputLayout
153 && a.colorAttachmentCount == b.colorAttachmentCount
154 && compareTargetBlend(a.targetBlend, b.targetBlend, a.colorAttachmentCount)
155 && a.lineWidth == b.lineWidth
156 && a.polygonMode == b.polygonMode
157 && a.viewCount == b.viewCount;
158}
159
160inline bool operator!=(const QSSGRhiGraphicsPipelineState &a, const QSSGRhiGraphicsPipelineState &b) Q_DECL_NOTHROW
161{
162 return !(a == b);
163}
164
165inline size_t qHash(const QSSGRhiGraphicsPipelineState &s, size_t seed) Q_DECL_NOTHROW
166{
167 // do not bother with all fields
168 return qHash(QSSGRhiGraphicsPipelineStatePrivate::getShaderPipeline(s), seed)
169 ^ qHash(s.samples)
170 ^ qHash(s.viewCount)
171 ^ qHash(s.targetBlend[0].dstColor)
172 ^ qHash(s.depthFunc)
173 ^ qHash(s.cullMode)
174 ^ qHash(s.colorAttachmentCount)
175 ^ qHash(s.lineWidth)
176 ^ qHash(s.polygonMode)
177 ^ qHashBits(&s.stencilOpFrontState, sizeof(QRhiGraphicsPipeline::StencilOpState))
178 ^ (s.flags)
179 ^ (s.stencilRef << 6)
180 ^ (s.stencilWriteMask << 7);
181}
182
183// The lookup keys can be somewhat complicated due to having to handle cases
184// like "render a model in a shared scene between multiple View3Ds" (here both
185// the View3D ('layer/cid') and the model ('model') act as the lookup key since
186// while the model is the same, we still want different uniform buffers per
187// View3D), or the case of shadow maps where the shadow map (there can be as
188// many as lights) is taken into account too ('entry') together with an entry index
189// where more resolution is needed (e.g., cube maps).
190//
191struct QSSGRhiDrawCallDataKey
192{
193 const void *cid = nullptr; // Usually the sub-pass (see usage of QSSGPassKey)
194 const void *model = nullptr;
195 const void *entry = nullptr;
196 quintptr entryIdx = 0;
197};
198
199class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiBuffer
200{
201 Q_DISABLE_COPY(QSSGRhiBuffer)
202public:
203 QSSGRhiBuffer(QSSGRhiContext &context,
204 QRhiBuffer::Type type,
205 QRhiBuffer::UsageFlags usageMask,
206 quint32 stride,
207 qsizetype size,
208 QRhiCommandBuffer::IndexFormat indexFormat = QRhiCommandBuffer::IndexUInt16);
209
210 virtual ~QSSGRhiBuffer();
211
212 QRhiBuffer *buffer() const { return m_buffer; }
213 quint32 stride() const { return m_stride; }
215 const quint32 sz = quint32(m_buffer->size());
216 Q_ASSERT((sz % m_stride) == 0);
217 return sz / m_stride;
218 }
219 QRhiCommandBuffer::IndexFormat indexFormat() const { return m_indexFormat; }
220
221private:
222 QSSGRhiContext &m_context;
223 QRhiBuffer *m_buffer = nullptr;
224 quint32 m_stride;
225 QRhiCommandBuffer::IndexFormat m_indexFormat;
226};
227
229{
230 char name[64];
232
233private:
234 size_t offset = SIZE_MAX;
235 bool maybeExists = true;
236 friend class QSSGRhiShaderPipeline;
237};
238
240{
241 char name[64];
244
245private:
246 size_t offset = SIZE_MAX;
247 size_t size = 0;
248 bool maybeExists = true;
249 friend class QSSGRhiShaderPipeline;
250};
251
252using QSSGRhiBufferPtr = std::shared_ptr<QSSGRhiBuffer>;
253
254inline bool operator==(const QSSGRhiSamplerDescription &a, const QSSGRhiSamplerDescription &b) Q_DECL_NOTHROW
255{
256 return a.hTiling == b.hTiling && a.vTiling == b.vTiling && a.zTiling == b.zTiling
257 && a.minFilter == b.minFilter && a.magFilter == b.magFilter
258 && a.mipmap == b.mipmap;
259}
260
261inline bool operator!=(const QSSGRhiSamplerDescription &a, const QSSGRhiSamplerDescription &b) Q_DECL_NOTHROW
262{
263 return !(a == b);
264}
265
266struct QSSGRhiTexture
267{
268 QByteArray name;
269 QRhiTexture *texture = nullptr;
270 QSSGRhiSamplerDescription samplerDesc;
271};
272
288
289// these are our current shader limits
290#define QSSG_MAX_NUM_LIGHTS 16
291#define QSSG_MAX_NUM_DIRECTIONAL_LIGHTS 4
292#define QSSG_REDUCED_MAX_NUM_LIGHTS 8
293#define QSSG_REDUCED_MAX_NUM_DIRECTIONAL_LIGHTS 2
294
328
354
358
362
363class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiShaderPipeline
364{
365 Q_DISABLE_COPY(QSSGRhiShaderPipeline)
366public:
367 explicit QSSGRhiShaderPipeline(QSSGRhiContext &context) : m_context(context) { }
368
369 QSSGRhiContext &context() const { return m_context; }
370 bool isNull() const { return m_stages.isEmpty(); }
371
372 enum StageFlag {
373 // Indicates that this shaderpipeline object is not going to be used with
374 // a QSSGRhiInputAssemblerState, i.e. bakeVertexInputLocations() will
375 // not be called.
376 UsedWithoutIa = 0x01
377 };
379
380 void addStage(const QRhiShaderStage &stage, StageFlags flags = {});
381 const QRhiShaderStage *cbeginStages() const { return m_stages.cbegin(); }
382 const QRhiShaderStage *cendStages() const { return m_stages.cend(); }
383
385 for (const QRhiShaderStage &s : m_stages) {
386 if (s.type() == QRhiShaderStage::Vertex)
387 return &s;
388 }
389 return nullptr;
390 }
392 for (const QRhiShaderStage &s : m_stages) {
393 if (s.type() == QRhiShaderStage::Fragment)
394 return &s;
395 }
396 return nullptr;
397 }
398
399 int ub0Size() const { return m_ub0Size; }
400 int ub0LightDataOffset() const { return m_ub0NextUBufOffset; }
402
404
405 // This struct is used purely for performance. It is used to quickly store
406 // and index common uniform names using the storeIndex argument in the
407 // setUniform method.
409 {
440 int pointSizeIdx = -1;
447 int fogColorIdx = -1;
455 int viewSize = -1;
456 int samples = -1;
457
464 } commonUniformIndices;
465
467 int transform0 = -1;
468 int transform1 = -1;
469 int transform2 = -1;
470 int color = -1;
471 int data = -1;
472 } instanceLocations;
473
474 enum class UniformFlag {
475 Mat3 = 0x01
476 };
477 Q_DECLARE_FLAGS(UniformFlags, UniformFlag)
478
479 void setUniformValue(char *ubufData, const char *name, const QVariant &value, QSSGRenderShaderValue::Type type);
480 void setUniform(char *ubufData, const char *name, const void *data, size_t size, int *storeIndex = nullptr, UniformFlags flags = {});
481 void setUniformArray(char *ubufData, const char *name, const void *data, size_t itemCount, QSSGRenderShaderValue::Type type, int *storeIndex = nullptr);
482 int bindingForTexture(const char *name, int hint = -1);
483 int bindingForImage(const char *name);
484
485 void setShaderResources(char *ubufData,
486 QSSGBufferManager &theBufferManager,
487 const QByteArray &inPropertyName,
488 const QVariant &propertyValue,
489 QSSGRenderShaderValue::Type inPropertyType);
490
491 void setLightsEnabled(bool enable) { m_lightsEnabled = enable; }
492 bool isLightingEnabled() const { return m_lightsEnabled; }
493
494 void ensureCombinedUniformBuffer(QRhiBuffer **ubuf);
495 void ensureUniformBuffer(QRhiBuffer **ubuf);
496
497 void setLightProbeTexture(QRhiTexture *texture,
498 QSSGRenderTextureCoordOp hTile = QSSGRenderTextureCoordOp::ClampToEdge,
499 QSSGRenderTextureCoordOp vTile = QSSGRenderTextureCoordOp::ClampToEdge)
500 {
501 m_lightProbeTexture = texture; m_lightProbeHorzTile = hTile; m_lightProbeVertTile = vTile;
502 }
503 QRhiTexture *lightProbeTexture() const { return m_lightProbeTexture; }
505 {
506 return {m_lightProbeHorzTile, m_lightProbeVertTile};
507 }
508
509 void setScreenTexture(QRhiTexture *texture) { m_screenTexture = texture; }
510 QRhiTexture *screenTexture() const { return m_screenTexture; }
511
512 void setDepthTexture(QRhiTexture *texture) { m_depthTexture = texture; }
513 QRhiTexture *depthTexture() const { return m_depthTexture; }
514
515 void setNormalTexture(QRhiTexture *texture) { m_normalTexture = texture; }
516 QRhiTexture *normalTexture() const { return m_normalTexture; }
517
518 void setSsaoTexture(QRhiTexture *texture) { m_ssaoTexture = texture; }
519 QRhiTexture *ssaoTexture() const { return m_ssaoTexture; }
520
521 void setLightmapTexture(QRhiTexture *texture) { m_lightmapTexture = texture; }
522 QRhiTexture *lightmapTexture() const { return m_lightmapTexture; }
523
524 void setMotionVectorTexture(QRhiTexture *texture) { m_motionVectorTexture = texture; }
525 QRhiTexture *MotionVectorTexture() const { return m_motionVectorTexture; }
526 void setShadowMapAtlasTexture(QRhiTexture *texture) { m_shadowMapAtlasTexture = texture; }
527 QRhiTexture *shadowMapAtlasTexture() const { return m_shadowMapAtlasTexture; }
528
529 void setShadowMapBlueNoiseTexture(QRhiTexture *texture) { m_shadowMapBlueNoiseTexture = texture; }
530 QRhiTexture *shadowMapBlueNoiseTexture() const { return m_shadowMapBlueNoiseTexture; }
531
532 void setOITImages(QRhiTexture *accumulator, QRhiTexture *auxiliary, QRhiTexture *counter)
533 {
534 m_oitImages[0] = accumulator;
535 m_oitImages[1] = auxiliary;
536 m_oitImages[2] = counter;
537 }
538 QRhiTexture **oitImages() { return m_oitImages; }
539
540 void resetExtraTextures() { m_extraTextures.clear(); }
541 void addExtraTexture(const QSSGRhiTexture &t) { m_extraTextures.append(t); }
542 int extraTextureCount() const { return m_extraTextures.size(); }
543 const QSSGRhiTexture &extraTextureAt(int index) const { return m_extraTextures[index]; }
544 QSSGRhiTexture &extraTextureAt(int index) { return m_extraTextures[index]; }
545
546 QSSGShaderLightsUniformData &lightsUniformData() { return m_lightsUniformData; }
547 QSSGShaderDirectionalLightsUniformData &directionalLightsUniformData() { return m_directionalLightsUniformData; }
548 InstanceLocations instanceBufferLocations() const { return instanceLocations; }
549
550 int offsetOfUniform(const QByteArray &name);
551
552private:
553 QSSGRhiContext &m_context;
554 QVarLengthArray<QRhiShaderStage, 2> m_stages;
555 int m_ub0Size = 0;
556 int m_ub0NextUBufOffset = 0;
557 QHash<QByteArray, QShaderDescription::BlockVariable> m_ub0;
558 QHash<QSSGRhiInputAssemblerState::InputSemantic, QShaderDescription::InOutVariable> m_vertexInputs;
559 QHash<QByteArray, QShaderDescription::InOutVariable> m_combinedImageSamplers;
560 QHash<QByteArray, QShaderDescription::InOutVariable> m_storageImages;
561 int m_materialImageSamplerBindings[size_t(QSSGRhiSamplerBindingHints::BindingMapSize)];
562
563 QVarLengthArray<QSSGRhiShaderUniform, 32> m_uniforms; // members of the main (binding 0) uniform buffer
564 QVarLengthArray<QSSGRhiShaderUniformArray, 8> m_uniformArrays;
565 QHash<QByteArray, size_t> m_uniformIndex; // Maps uniform name to index in m_uniforms and m_uniformArrays
566
567 // transient (per-object) data; pointers are all non-owning
568 bool m_lightsEnabled = false;
569 QSSGShaderLightsUniformData m_lightsUniformData;
570 QSSGShaderDirectionalLightsUniformData m_directionalLightsUniformData;
571 QRhiTexture *m_shadowMapAtlasTexture = nullptr;
572 QRhiTexture *m_shadowMapBlueNoiseTexture = nullptr;
573 QRhiTexture *m_lightProbeTexture = nullptr;
574 QSSGRenderTextureCoordOp m_lightProbeHorzTile = QSSGRenderTextureCoordOp::ClampToEdge;
575 QSSGRenderTextureCoordOp m_lightProbeVertTile = QSSGRenderTextureCoordOp::ClampToEdge;
576 QRhiTexture *m_screenTexture = nullptr;
577 QRhiTexture *m_depthTexture = nullptr;
578 QRhiTexture *m_normalTexture = nullptr;
579 QRhiTexture *m_ssaoTexture = nullptr;
580 QRhiTexture *m_lightmapTexture = nullptr;
581 QRhiTexture *m_oitImages[3] = {nullptr};
582 QRhiTexture *m_motionVectorTexture = nullptr;
583 QVarLengthArray<QSSGRhiTexture, 8> m_extraTextures;
584};
585
586Q_DECLARE_OPERATORS_FOR_FLAGS(QSSGRhiShaderPipeline::StageFlags)
587Q_DECLARE_OPERATORS_FOR_FLAGS(QSSGRhiShaderPipeline::UniformFlags)
588
589using QSSGRhiShaderPipelinePtr = std::shared_ptr<QSSGRhiShaderPipeline>;
590
591class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiShaderResourceBindingList
592{
593public:
594 static const int MAX_SIZE = 32;
595
596 int p = 0;
597 size_t h = 0;
598 QRhiShaderResourceBinding v[MAX_SIZE];
599
600 void clear() { p = 0; h = 0; }
601
602 QSSGRhiShaderResourceBindingList() { }
603
604 QSSGRhiShaderResourceBindingList(const QSSGRhiShaderResourceBindingList &other)
605 : p(other.p),
606 h(other.h)
607 {
608 for (int i = 0; i < p; ++i)
609 v[i] = other.v[i];
610 }
611
612 QSSGRhiShaderResourceBindingList &operator=(const QSSGRhiShaderResourceBindingList &other) Q_DECL_NOTHROW
613 {
614 if (this != &other) {
615 p = other.p;
616 h = other.h;
617 for (int i = 0; i < p; ++i)
618 v[i] = other.v[i];
619 }
620 return *this;
621 }
622
623 void addUniformBuffer(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiBuffer *buf, int offset = 0 , int size = 0);
624 void addTexture(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler);
625 void addImageLoad(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, int level);
626 void addImageStore(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, int level);
627 void addImageLoadStore(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, int level);
628 void addStorageBuffer(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiBuffer *buf, int offset = 0 , int size = 0);
629};
630
631inline bool operator==(const QSSGRhiShaderResourceBindingList &a, const QSSGRhiShaderResourceBindingList &b) Q_DECL_NOTHROW
632{
633 if (a.h != b.h)
634 return false;
635 if (a.p != b.p)
636 return false;
637 for (int i = 0; i < a.p; ++i) {
638 if (a.v[i] != b.v[i])
639 return false;
640 }
641 return true;
642}
643
644inline bool operator!=(const QSSGRhiShaderResourceBindingList &a, const QSSGRhiShaderResourceBindingList &b) Q_DECL_NOTHROW
645{
646 return !(a == b);
647}
648
649inline size_t qHash(const QSSGRhiShaderResourceBindingList &bl, size_t seed) Q_DECL_NOTHROW
650{
651 return bl.h ^ seed;
652}
653
654struct QSSGRhiDrawCallData
655{
656 QRhiBuffer *ubuf = nullptr; // owned
657 QRhiShaderResourceBindings *srb = nullptr; // not owned
658 QSSGRhiShaderResourceBindingList bindings;
659 QRhiGraphicsPipeline *pipeline = nullptr; // not owned
660 size_t renderTargetDescriptionHash = 0;
661 QVector<quint32> renderTargetDescription;
662 QSSGRhiGraphicsPipelineState ps;
663
664 void reset()
665 {
666 delete ubuf;
667 ubuf = nullptr;
668 srb = nullptr;
669 pipeline = nullptr;
670 }
671};
672
673class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGManagedRhiTexture
674{
675 enum class Private { Initialize };
676 Q_DISABLE_COPY(QSSGManagedRhiTexture)
677public:
678 using Ptr = std::unique_ptr<QSSGManagedRhiTexture>;
679
680 const std::unique_ptr<QRhiTexture> &texture() const { return m_texture; }
681
682 [[nodiscard]] bool isValid() const { return m_texture != nullptr; }
683
684 QSSGManagedRhiTexture() = default;
685 QSSGManagedRhiTexture(const std::shared_ptr<QSSGUserRenderPassManager> &manager, QRhiTexture *texture, Private);
686 QSSGManagedRhiTexture(const std::shared_ptr<QSSGUserRenderPassManager> &manager, std::unique_ptr<QRhiTexture> texture);
687 ~QSSGManagedRhiTexture();
688
689 [[nodiscard]] static Ptr make_copy(const Ptr &other)
690 {
691 return std::make_unique<QSSGManagedRhiTexture>(other->m_manager, other->m_texture.get(), Private::Initialize);
692 }
693
694private:
695 friend class QSSGRhiRenderableTextureV2;
696 friend class QSSGUserRenderPassManager;
697
698 void invalidate();
699
700 std::shared_ptr<QSSGUserRenderPassManager> m_manager;
701 std::unique_ptr<QRhiTexture> m_texture;
702};
703
704using QSSGManagedRhiTexturePtr = QSSGManagedRhiTexture::Ptr;
705
707{
708 enum class Private { Initialize };
709public:
710 QSSGRhiRenderableTextureV2(const std::shared_ptr<QSSGUserRenderPassManager> &manager, Private)
712 {
713 }
715
716 void setDescription(QRhi *rhi, QRhiTextureRenderTargetDescription rtDesc, QRhiTextureRenderTarget::Flags = {});
717
718 void setName(const QByteArray &name) { rtName = name; }
719 const QByteArray &getName() const { return rtName; }
720
721 const QSSGManagedRhiTexturePtr &getDepthTexture() const { return depthTexture; }
722 const std::unique_ptr<QRhiRenderBuffer> &getDepthStencil() const { return depthStencil; }
725
726 size_t colorAttachmentCount() const { return textures.size(); }
727 const QSSGManagedRhiTexturePtr &getColorTexture(int index) const { return textures[index]; }
728
729 bool isValid() const { return (textures.size() > 0) && rt && rpDesc; }
730
731 void finialize(QRhi *rhi);
732
733 void resetRenderTarget();
734 void reset();
735
736private:
737 friend class QSSGUserRenderPassManager;
738
739 enum Dirty : quint32
740 {
741 ColorTextureDirty = 0x1,
742 DepthStencilDirty = 0x2,
743 DepthTextureDirty = 0x4,
744 };
745
746 void invalidate();
747
749
750 std::shared_ptr<QSSGUserRenderPassManager> m_manager;
751
752 QVarLengthArray<QSSGManagedRhiTexturePtr, 4> textures {};
753 std::unique_ptr<QRhiRenderBuffer> depthStencil;
754 QSSGManagedRhiTexturePtr depthTexture; // either depthStencil or depthTexture are valid, never both
755
756 std::unique_ptr<QRhiRenderPassDescriptor> rpDesc;
757 std::unique_ptr<QRhiTextureRenderTarget> rt;
758 QByteArray rtName;
759 DirtyT dirty = 0;
760};
761
762using QSSGRhiRenderableTextureV2Ptr = std::shared_ptr<QSSGRhiRenderableTextureV2>;
763
765{
768 QRhiTexture *depthTexture = nullptr; // either depthStencil or depthTexture are valid, never both
771 bool isValid() const { return texture && rpDesc && rt; }
773 delete rt;
774 rt = nullptr;
775 delete rpDesc;
776 rpDesc = nullptr;
777 }
778 void reset() {
780 delete texture;
781 delete depthStencil;
782 delete depthTexture;
783 *this = QSSGRhiRenderableTexture();
784 }
785};
786
788{
789 float d = 0.0f;
791};
792
805
816
818{
819public:
822 struct {
824 } extra;
825 static QSSGComputePipelineStateKey create(const QShader &shader,
826 const QRhiShaderResourceBindings *srb)
827 {
828 const QVector<quint32> srbDesc = srb->serializedLayoutDescription();
829 return { shader, srbDesc, { qHash(srbDesc) } };
830 }
831};
832
833inline bool operator==(const QSSGComputePipelineStateKey &a, const QSSGComputePipelineStateKey &b) Q_DECL_NOTHROW
834{
835 return a.shader == b.shader && a.srbLayoutDescription == b.srbLayoutDescription;
836}
837
838inline bool operator!=(const QSSGComputePipelineStateKey &a, const QSSGComputePipelineStateKey &b) Q_DECL_NOTHROW
839{
840 return !(a == b);
841}
842
843inline size_t qHash(const QSSGComputePipelineStateKey &k, size_t seed = 0) Q_DECL_NOTHROW
844{
845 return qHash(k.shader, seed) ^ k.extra.srbLayoutDescriptionHash;
846}
847
848struct QSSGRhiDummyTextureKey
849{
850 QRhiTexture::Flags flags;
851 QSize size;
852 QColor color;
853 int arraySize;
854};
855
856inline size_t qHash(const QSSGRhiDummyTextureKey &k, size_t seed) Q_DECL_NOTHROW
857{
858 return qHash(k.flags, seed)
859 ^ qHash(k.size.width() ^ k.size.height() ^ k.color.red() ^ k.color.green()
860 ^ k.color.blue() ^ k.color.alpha() ^ k.arraySize);
861}
862
863inline bool operator==(const QSSGRhiDummyTextureKey &a, const QSSGRhiDummyTextureKey &b) Q_DECL_NOTHROW
864{
865 return a.flags == b.flags && a.size == b.size && a.color == b.color && a.arraySize == b.arraySize;
866}
867
868inline bool operator!=(const QSSGRhiDummyTextureKey &a, const QSSGRhiDummyTextureKey &b) Q_DECL_NOTHROW
869{
870 return !(a == b);
871}
872
873class QSSGGraphicsPipelineStateKey
874{
875public:
876 QSSGRhiGraphicsPipelineState state;
877 QVector<quint32> renderTargetDescription;
878 QVector<quint32> srbLayoutDescription;
879 struct {
880 size_t renderTargetDescriptionHash;
881 size_t srbLayoutDescriptionHash;
882 } extra;
883 static QSSGGraphicsPipelineStateKey create(const QSSGRhiGraphicsPipelineState &state,
884 const QRhiRenderPassDescriptor *rpDesc,
885 const QRhiShaderResourceBindings *srb)
886 {
887 const QVector<quint32> rtDesc = rpDesc->serializedFormat();
888 const QVector<quint32> srbDesc = srb->serializedLayoutDescription();
889 return { state, rtDesc, srbDesc, { qHash(rtDesc), qHash(srbDesc) } };
890 }
891};
892
893inline bool operator==(const QSSGGraphicsPipelineStateKey &a, const QSSGGraphicsPipelineStateKey &b) Q_DECL_NOTHROW
894{
895 return a.state == b.state
896 && a.renderTargetDescription == b.renderTargetDescription
897 && a.srbLayoutDescription == b.srbLayoutDescription;
898}
899
900inline bool operator!=(const QSSGGraphicsPipelineStateKey &a, const QSSGGraphicsPipelineStateKey &b) Q_DECL_NOTHROW
901{
902 return !(a == b);
903}
904
905inline size_t qHash(const QSSGGraphicsPipelineStateKey &k, size_t seed) Q_DECL_NOTHROW
906{
907 return qHash(k.state, seed)
908 ^ k.extra.renderTargetDescriptionHash
909 ^ k.extra.srbLayoutDescriptionHash;
910}
911
912#define QSSGRHICTX_STAT(ctx, f)
913 for (bool qssgrhictxlog_enabled = QSSGRhiContextStats::get(*ctx).isEnabled(); qssgrhictxlog_enabled; qssgrhictxlog_enabled = false)
914 QSSGRhiContextStats::get(*ctx).f
915
916class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiContextStats
917{
918public:
919 [[nodiscard]] static QSSGRhiContextStats &get(QSSGRhiContext &rhiCtx);
920 [[nodiscard]] static const QSSGRhiContextStats &get(const QSSGRhiContext &rhiCtx);
921
922 struct DrawInfo {
923 quint64 callCount = 0;
924 quint64 vertexOrIndexCount = 0;
925 };
926 struct InstancedDrawInfo {
927 quint64 callCount = 0;
928 quint64 vertexOrIndexCount = 0;
929 quint64 instanceCount = 0;
930 };
931 struct RenderPassInfo {
932 QByteArray rtName;
933 QSize pixelSize;
934 DrawInfo indexedDraws;
935 DrawInfo draws;
936 InstancedDrawInfo instancedIndexedDraws;
937 InstancedDrawInfo instancedDraws;
938 };
939 struct PerLayerInfo {
940 PerLayerInfo()
941 {
942 externalRenderPass.rtName = QByteArrayLiteral("Qt Quick");
943 }
944
945 // The main render pass if renderMode==Offscreen, plus render passes
946 // for shadow maps, postprocessing effects, etc.
947 QVector<RenderPassInfo> renderPasses;
948
949 // An Underlay/Overlay/Inline renderMode will make the View3D add stuff
950 // to a render pass managed by Qt Quick. (external == not under the
951 // control of Qt Quick 3D)
952 RenderPassInfo externalRenderPass;
953
954 int currentRenderPassIndex = -1;
955 };
956 struct GlobalInfo { // global as in per QSSGRhiContext which is per-QQuickWindow
957 quint64 meshDataSize = 0;
958 quint64 imageDataSize = 0;
959 qint64 materialGenerationTime = 0;
960 qint64 effectGenerationTime = 0;
961 };
962
963 QHash<QSSGRenderLayer *, PerLayerInfo> perLayerInfo;
964 GlobalInfo globalInfo;
965
966 QSSGRhiContextStats(QSSGRhiContext &context)
967 : rhiCtx(&context)
968 {
969 }
970
971 // The data collected have four consumers:
972 //
973 // - Printed on debug output when QSG_RENDERER_DEBUG has the relevant key.
974 // (this way the debug output from the 2D scenegraph renderer and these 3D
975 // statistics appear nicely intermixed)
976 // - Passed on to the QML profiler when profiling is enabled.
977 // - DebugView via QQuick3DRenderStats.
978 // - When tracing is enabled
979 //
980 // The first two are enabled globally, but DebugView needs a dynamic
981 // enable/disable since we want to collect data when a DebugView item
982 // becomes visible, but not otherwise.
983
984 static bool profilingEnabled();
985 static bool rendererDebugEnabled();
986
987 bool isEnabled() const;
988 void drawIndexed(quint32 indexCount, quint32 instanceCount);
989 void draw(quint32 vertexCount, quint32 instanceCount);
990
991 void meshDataSizeChanges(quint64 newSize) // can be called outside start-stop
992 {
993 globalInfo.meshDataSize = newSize;
994 }
995
996 void imageDataSizeChanges(quint64 newSize) // can be called outside start-stop
997 {
998 globalInfo.imageDataSize = newSize;
999 }
1000
1001 void registerMaterialShaderGenerationTime(qint64 ms)
1002 {
1003 globalInfo.materialGenerationTime += ms;
1004 }
1005
1006 void registerEffectShaderGenerationTime(qint64 ms)
1007 {
1008 globalInfo.effectGenerationTime += ms;
1009 }
1010
1011 static quint64 totalDrawCallCountForPass(const QSSGRhiContextStats::RenderPassInfo &pass)
1012 {
1013 return pass.draws.callCount
1014 + pass.indexedDraws.callCount
1015 + pass.instancedDraws.callCount
1016 + pass.instancedIndexedDraws.callCount;
1017 }
1018
1019 static quint64 totalVertexCountForPass(const QSSGRhiContextStats::RenderPassInfo &pass)
1020 {
1021 return pass.draws.vertexOrIndexCount
1022 + pass.indexedDraws.vertexOrIndexCount
1023 + pass.instancedDraws.vertexOrIndexCount
1024 + pass.instancedIndexedDraws.vertexOrIndexCount;
1025 }
1026
1027 void start(QSSGRenderLayer *layer);
1028 void stop(QSSGRenderLayer *layer);
1029 void beginRenderPass(QRhiTextureRenderTarget *rt);
1030 void endRenderPass();
1031 void printRenderPass(const RenderPassInfo &rp);
1032 void cleanupLayerInfo(QSSGRenderLayer *layer);
1033
1034 QSSGRhiContext *rhiCtx;
1035 QSSGRenderLayer *layerKey = nullptr;
1036 QSet<QSSGRenderLayer *> dynamicDataSources;
1037};
1038
1039class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiContextPrivate
1040{
1041 Q_DECLARE_PUBLIC(QSSGRhiContext)
1042
1043 explicit QSSGRhiContextPrivate(QSSGRhiContext &rhiCtx, QRhi *rhi_)
1044 : q_ptr(&rhiCtx)
1045 , m_rhi(rhi_)
1046 , m_stats(rhiCtx)
1047 {}
1048
1049public:
1050 using Textures = QSet<QRhiTexture *>;
1051 using Meshes = QSet<QSSGRenderMesh *>;
1052
1053 [[nodiscard]] static QSSGRhiContextPrivate *get(QSSGRhiContext *q) { return q->d_ptr.get(); }
1054 [[nodiscard]] static const QSSGRhiContextPrivate *get(const QSSGRhiContext *q) { return q->d_ptr.get(); }
1055
1056 [[nodiscard]] static bool shaderDebuggingEnabled();
1057 [[nodiscard]] static bool editorMode();
1058
1059 void setMainRenderPassDescriptor(QRhiRenderPassDescriptor *rpDesc);
1060 void setCommandBuffer(QRhiCommandBuffer *cb);
1061 void setRenderTarget(QRhiRenderTarget *rt);
1062 void setMainPassSampleCount(int samples);
1063 void setMainPassViewCount(int viewCount);
1064
1065 void releaseCachedResources();
1066
1067 void registerTexture(QRhiTexture *texture);
1068 void releaseTexture(QRhiTexture *texture);
1069
1070 void registerMesh(QSSGRenderMesh *mesh);
1071 void releaseMesh(QSSGRenderMesh *mesh);
1072
1073 QRhiShaderResourceBindings *srb(const QSSGRhiShaderResourceBindingList &bindings);
1074 void releaseCachedSrb(QSSGRhiShaderResourceBindingList &bindings);
1075
1076 QRhiGraphicsPipeline *pipeline(const QSSGRhiGraphicsPipelineState &ps,
1077 QRhiRenderPassDescriptor *rpDesc,
1078 QRhiShaderResourceBindings *srb);
1079
1080 QRhiGraphicsPipeline *pipeline(const QSSGGraphicsPipelineStateKey &key,
1081 QRhiRenderPassDescriptor *rpDesc,
1082 QRhiShaderResourceBindings *srb);
1083
1084 QRhiComputePipeline *computePipeline(const QShader &shader,
1085 QRhiShaderResourceBindings *srb);
1086
1088 QRhiShaderResourceBindings *srb);
1089
1090 QSSGRhiDrawCallData &drawCallData(const QSSGRhiDrawCallDataKey &key);
1091 void releaseDrawCallData(QSSGRhiDrawCallData &dcd);
1092 void cleanupDrawCallData(const QSSGRenderModel *model);
1093
1094 QSSGRhiInstanceBufferData &instanceBufferData(QSSGRenderInstanceTable *instanceTable);
1095 void releaseInstanceBuffer(QSSGRenderInstanceTable *instanceTable);
1096
1097 QSSGRhiInstanceBufferData &instanceBufferData(const QSSGRenderModel *model);
1098
1099 QSSGRhiParticleData &particleData(const QSSGRenderGraphObject *particlesOrModel);
1100
1102 QRhi *m_rhi = nullptr;
1103
1111
1113
1123};
1124
1125inline bool operator==(const QSSGRhiDrawCallDataKey &a, const QSSGRhiDrawCallDataKey &b) noexcept
1126{
1127 return a.cid == b.cid && a.model == b.model && a.entry == b.entry && a.entryIdx == b.entryIdx;
1128}
1129
1130inline bool operator!=(const QSSGRhiDrawCallDataKey &a, const QSSGRhiDrawCallDataKey &b) noexcept
1131{
1132 return !(a == b);
1133}
1134
1135inline size_t qHash(const QSSGRhiDrawCallDataKey &k, size_t seed = 0) noexcept
1136{
1137 return qHash(quintptr(k.cid)
1138 ^ quintptr(k.model)
1139 ^ quintptr(k.entry)
1140 ^ quintptr(k.entryIdx), seed);
1141}
1142
1143QT_END_NAMESPACE
1144
1145#endif // QSSGRHICONTEXT_P_H
friend bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are equal, otherwise returns false.
Definition qbytearray.h:807
friend bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are different, otherwise returns false.
Definition qbytearray.h:818
QObject * q_ptr
Definition qobject.h:72
Q_DECLARE_FLAGS(InitFlags, InitFlag)
static QSSGComputePipelineStateKey create(const QShader &shader, const QRhiShaderResourceBindings *srb)
QVector< quint32 > srbLayoutDescription
QRhiBuffer * buffer() const
QRhiCommandBuffer::IndexFormat indexFormat() const
quint32 stride() const
quint32 numVertices() const
void setMainRenderPassDescriptor(QRhiRenderPassDescriptor *rpDesc)
void releaseInstanceBuffer(QSSGRenderInstanceTable *instanceTable)
QSSGRhiInstanceBufferData & instanceBufferData(const QSSGRenderModel *model)
void releaseDrawCallData(QSSGRhiDrawCallData &dcd)
QRhiRenderPassDescriptor * m_mainRpDesc
QRhiShaderResourceBindings * srb(const QSSGRhiShaderResourceBindingList &bindings)
QSSGRhiDrawCallData & drawCallData(const QSSGRhiDrawCallDataKey &key)
QRhiGraphicsPipeline * pipeline(const QSSGRhiGraphicsPipelineState &ps, QRhiRenderPassDescriptor *rpDesc, QRhiShaderResourceBindings *srb)
void releaseCachedSrb(QSSGRhiShaderResourceBindingList &bindings)
static const QSSGRhiContextPrivate * get(const QSSGRhiContext *q)
void releaseMesh(QSSGRenderMesh *mesh)
QRhiComputePipeline * computePipeline(const QSSGComputePipelineStateKey &key, QRhiShaderResourceBindings *srb)
QHash< QSSGRenderInstanceTable *, QSSGRhiInstanceBufferData > m_instanceBuffers
void setCommandBuffer(QRhiCommandBuffer *cb)
QVector< QPair< QSSGRhiSamplerDescription, QRhiSampler * > > m_samplers
void setMainPassSampleCount(int samples)
QRhiRenderTarget * m_rt
void cleanupDrawCallData(const QSSGRenderModel *model)
QHash< const QSSGRenderGraphObject *, QSSGRhiParticleData > m_particleData
QSSGRhiContextStats m_stats
QHash< const QSSGRenderModel *, QSSGRhiInstanceBufferData > m_instanceBuffersLod
QHash< QSSGRhiDummyTextureKey, QRhiTexture * > m_dummyTextures
void registerMesh(QSSGRenderMesh *mesh)
static bool shaderDebuggingEnabled()
QSSGRhiParticleData & particleData(const QSSGRenderGraphObject *particlesOrModel)
void setRenderTarget(QRhiRenderTarget *rt)
QHash< QSSGRhiShaderResourceBindingList, QRhiShaderResourceBindings * > m_srbCache
QHash< QSSGRhiDrawCallDataKey, QSSGRhiDrawCallData > m_drawCallData
void setMainPassViewCount(int viewCount)
QRhiCommandBuffer * m_cb
static QSSGRhiContextPrivate * get(QSSGRhiContext *q)
QRhiComputePipeline * computePipeline(const QShader &shader, QRhiShaderResourceBindings *srb)
QHash< QSSGComputePipelineStateKey, QRhiComputePipeline * > m_computePipelines
QHash< QSSGGraphicsPipelineStateKey, QRhiGraphicsPipeline * > m_pipelines
QSSGRhiInstanceBufferData & instanceBufferData(QSSGRenderInstanceTable *instanceTable)
const QSSGManagedRhiTexturePtr & getColorTexture(int index) const
const std::unique_ptr< QRhiRenderPassDescriptor > & getRenderPassDescriptor() const
void setName(const QByteArray &name)
void finialize(QRhi *rhi)
const std::unique_ptr< QRhiTextureRenderTarget > & getRenderTarget() const
const std::unique_ptr< QRhiRenderBuffer > & getDepthStencil() const
void setDescription(QRhi *rhi, QRhiTextureRenderTargetDescription rtDesc, QRhiTextureRenderTarget::Flags={})
const QByteArray & getName() const
const QSSGManagedRhiTexturePtr & getDepthTexture() const
QSSGRhiRenderableTextureV2(const std::shared_ptr< QSSGUserRenderPassManager > &manager, Private)
void setUniformValue(char *ubufData, const char *name, const QVariant &value, QSSGRenderShaderValue::Type type)
const QRhiShaderStage * cendStages() const
QRhiTexture * ssaoTexture() const
const QHash< QSSGRhiInputAssemblerState::InputSemantic, QShaderDescription::InOutVariable > & vertexInputs() const
QRhiTexture * lightProbeTexture() const
QRhiTexture * shadowMapAtlasTexture() const
int bindingForImage(const char *name)
QPair< QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp > lightProbeTiling() const
InstanceLocations instanceBufferLocations() const
void addStage(const QRhiShaderStage &stage, StageFlags flags={})
QRhiTexture * screenTexture() const
void ensureUniformBuffer(QRhiBuffer **ubuf)
QRhiTexture * MotionVectorTexture() const
QRhiTexture * shadowMapBlueNoiseTexture() const
const QRhiShaderStage * cbeginStages() const
const QRhiShaderStage * fragmentStage() const
QRhiTexture * depthTexture() const
void addExtraTexture(const QSSGRhiTexture &t)
void setLightsEnabled(bool enable)
QSSGShaderDirectionalLightsUniformData & directionalLightsUniformData()
int offsetOfUniform(const QByteArray &name)
int bindingForTexture(const char *name, int hint=-1)
void ensureCombinedUniformBuffer(QRhiBuffer **ubuf)
void setShaderResources(char *ubufData, QSSGBufferManager &theBufferManager, const QByteArray &inPropertyName, const QVariant &propertyValue, QSSGRenderShaderValue::Type inPropertyType)
QRhiTexture ** oitImages()
void setUniformArray(char *ubufData, const char *name, const void *data, size_t itemCount, QSSGRenderShaderValue::Type type, int *storeIndex=nullptr)
QRhiTexture * normalTexture() const
int ub0DirectionalLightDataOffset() const
const QRhiShaderStage * vertexStage() const
QSSGShaderLightsUniformData & lightsUniformData()
void setUniform(char *ubufData, const char *name, const void *data, size_t size, int *storeIndex=nullptr, UniformFlags flags={})
QRhiTexture * lightmapTexture() const
const QSSGRhiTexture & extraTextureAt(int index) const
QRhiVertexInputAttribute::Format toVertexInputFormat(QSSGRenderComponentType compType, quint32 numComps)
QRhiGraphicsPipeline::CullMode toCullMode(QSSGCullFaceMode cullFaceMode)
QRhiGraphicsPipeline::Topology toTopology(QSSGRenderDrawMode drawMode)
void bakeVertexInputLocations(QSSGRhiInputAssemblerState *ia, const QSSGRhiShaderPipeline &shaders, int instanceBufferBinding)
QRhiSampler::Filter toRhi(QSSGRenderTextureFilterOp op)
Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_exit)
Q_TRACE_POINT(qtcore, QFactoryLoader_update, const QString &fileName)
Q_TRACE_POINT(qtquick3d, QSSG_renderFrame_entry, int width, int height)
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept
Definition qsize.h:192
static QString getUBMemberSizeWarning(QLatin1StringView name, qsizetype correctedSize, qsizetype requestedSize)
#define QSSG_MAX_NUM_LIGHTS
#define QSSG_MAX_NUM_DIRECTIONAL_LIGHTS
QSSGRhiSamplerBindingHints
static constexpr const QSSGRhiShaderPipeline * getShaderPipeline(const QSSGRhiGraphicsPipelineState &ps)
static void setShaderPipeline(QSSGRhiGraphicsPipelineState &ps, const QSSGRhiShaderPipeline *pipeline)
static const InputAssemblerState & get(const QSSGRhiGraphicsPipelineState &ps)
static InputAssemblerState & get(QSSGRhiGraphicsPipelineState &ps)
QList< QSSGRhiSortData > sortData
QList< QSSGRhiSortData > sortData
QRhiTextureRenderTarget * rt
QRhiRenderPassDescriptor * rpDesc
QRhiRenderBuffer * depthStencil
QVarLengthArray< ImageIndices, 16 > imageIndices
QSSGShaderDirectionalLightData directionalLightData[QSSG_MAX_NUM_DIRECTIONAL_LIGHTS]
QSSGShaderLightData lightData[QSSG_MAX_NUM_LIGHTS]