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
4#ifndef QSSGRHICONTEXT_P_H
5#define QSSGRHICONTEXT_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtGui/rhi/qrhi.h>
19
20#include <QtQuick3DRuntimeRender/qtquick3druntimerenderexports.h>
21#include <QtQuick3DUtils/private/qssgrenderbasetypes_p.h>
22#include <ssg/qssgrhicontext.h>
23
24QT_BEGIN_NAMESPACE
25
26struct QSSGRenderLayer;
27struct QSSGRenderInstanceTable;
28struct QSSGRenderModel;
29struct QSSGRenderMesh;
30class QSSGRenderGraphObject;
31
33{
35 static const InputAssemblerState &get(const QSSGRhiGraphicsPipelineState &ps) { return ps.ia; }
36 static InputAssemblerState &get(QSSGRhiGraphicsPipelineState &ps) { return ps.ia; }
37};
38
39using QSSGRhiInputAssemblerState = QSSGRhiInputAssemblerStatePrivate::InputAssemblerState;
40
42{
43 static void setShaderPipeline(QSSGRhiGraphicsPipelineState &ps, const QSSGRhiShaderPipeline *pipeline)
44 {
45 ps.shaderPipeline = pipeline;
46 }
47
48 static constexpr const QSSGRhiShaderPipeline *getShaderPipeline(const QSSGRhiGraphicsPipelineState &ps)
49 {
50 return ps.shaderPipeline;
51 }
52};
53
54namespace QSSGRhiHelpers
55{
56
57inline QRhiSampler::Filter toRhi(QSSGRenderTextureFilterOp op)
58{
59 switch (op) {
60 case QSSGRenderTextureFilterOp::Nearest:
61 return QRhiSampler::Nearest;
62 case QSSGRenderTextureFilterOp::Linear:
63 return QRhiSampler::Linear;
64 case QSSGRenderTextureFilterOp::None:
65 return QRhiSampler::Linear;
66 }
67
68 Q_UNREACHABLE_RETURN(QRhiSampler::Linear);
69}
70
71inline QRhiSampler::AddressMode toRhi(QSSGRenderTextureCoordOp tiling)
72{
73 switch (tiling) {
74 case QSSGRenderTextureCoordOp::Repeat:
75 return QRhiSampler::Repeat;
76 case QSSGRenderTextureCoordOp::MirroredRepeat:
77 return QRhiSampler::Mirror;
78 case QSSGRenderTextureCoordOp::ClampToEdge:
79 return QRhiSampler::ClampToEdge;
80 case QSSGRenderTextureCoordOp::Unknown:
81 return QRhiSampler::ClampToEdge;
82 }
83
84 Q_UNREACHABLE_RETURN(QRhiSampler::ClampToEdge);
85}
86
87inline QRhiGraphicsPipeline::CullMode toCullMode(QSSGCullFaceMode cullFaceMode)
88{
89 switch (cullFaceMode) {
90 case QSSGCullFaceMode::Back:
91 return QRhiGraphicsPipeline::Back;
92 case QSSGCullFaceMode::Front:
93 return QRhiGraphicsPipeline::Front;
94 case QSSGCullFaceMode::Disabled:
95 return QRhiGraphicsPipeline::None;
96 case QSSGCullFaceMode::FrontAndBack:
97 qWarning("FrontAndBack cull mode not supported");
98 return QRhiGraphicsPipeline::None;
99 case QSSGCullFaceMode::Unknown:
100 return QRhiGraphicsPipeline::None;
101 }
102
103 Q_UNREACHABLE_RETURN(QRhiGraphicsPipeline::None);
104}
105
106QRhiVertexInputAttribute::Format toVertexInputFormat(QSSGRenderComponentType compType, quint32 numComps);
107QRhiGraphicsPipeline::Topology toTopology(QSSGRenderDrawMode drawMode);
108// Fills out inputLayout.attributes[].location based on
109// inputLayoutInputNames and the provided shader reflection info.
110void bakeVertexInputLocations(QSSGRhiInputAssemblerState *ia, const QSSGRhiShaderPipeline &shaders, int instanceBufferBinding = 0);
111
112} // namespace QSSGRhiHelpers
113
114inline bool operator==(const QSSGRhiGraphicsPipelineState &a, const QSSGRhiGraphicsPipelineState &b) Q_DECL_NOTHROW
115{
116 const auto &ia_a = QSSGRhiInputAssemblerStatePrivate::get(a);
117 const auto &ia_b = QSSGRhiInputAssemblerStatePrivate::get(b);
118 const auto compareTargetBlend = [](const std::array<QRhiGraphicsPipeline::TargetBlend, 8> &a,
119 const std::array<QRhiGraphicsPipeline::TargetBlend, 8> &b,
120 const int count) -> bool {
121 for (int i = 0; i < count; i++) {
122 if (a[i].colorWrite != b[i].colorWrite
123 || a[i].srcColor != b[i].srcColor
124 || a[i].dstColor != b[i].dstColor
125 || a[i].opColor != b[i].opColor
126 || a[i].srcAlpha != b[i].srcAlpha
127 || a[i].dstAlpha != b[i].dstAlpha
128 || a[i].opAlpha != b[i].opAlpha) {
129 return false;
130 }
131 }
132 return true;
133 };
134 return QSSGRhiGraphicsPipelineStatePrivate::getShaderPipeline(a) == QSSGRhiGraphicsPipelineStatePrivate::getShaderPipeline(b)
135 && a.samples == b.samples
136 && a.flags == b.flags
137 && a.stencilRef == b.stencilRef
138 && (std::memcmp(&a.stencilOpFrontState, &b.stencilOpFrontState, sizeof(QRhiGraphicsPipeline::StencilOpState)) == 0)
139 && a.stencilWriteMask == b.stencilWriteMask
140 && a.depthFunc == b.depthFunc
141 && a.cullMode == b.cullMode
142 && a.depthBias == b.depthBias
143 && a.slopeScaledDepthBias == b.slopeScaledDepthBias
144 && a.viewport == b.viewport
145 && a.scissor == b.scissor
146 && ia_a.topology == ia_b.topology
147 && ia_a.inputLayout == ia_b.inputLayout
148 && a.colorAttachmentCount == b.colorAttachmentCount
149 && compareTargetBlend(a.targetBlend, b.targetBlend, a.colorAttachmentCount)
150 && a.lineWidth == b.lineWidth
151 && a.polygonMode == b.polygonMode
152 && a.viewCount == b.viewCount;
153}
154
155inline bool operator!=(const QSSGRhiGraphicsPipelineState &a, const QSSGRhiGraphicsPipelineState &b) Q_DECL_NOTHROW
156{
157 return !(a == b);
158}
159
160inline size_t qHash(const QSSGRhiGraphicsPipelineState &s, size_t seed) Q_DECL_NOTHROW
161{
162 // do not bother with all fields
163 return qHash(QSSGRhiGraphicsPipelineStatePrivate::getShaderPipeline(s), seed)
164 ^ qHash(s.samples)
165 ^ qHash(s.viewCount)
166 ^ qHash(s.targetBlend[0].dstColor)
167 ^ qHash(s.depthFunc)
168 ^ qHash(s.cullMode)
169 ^ qHash(s.colorAttachmentCount)
170 ^ qHash(s.lineWidth)
171 ^ qHash(s.polygonMode)
172 ^ qHashBits(&s.stencilOpFrontState, sizeof(QRhiGraphicsPipeline::StencilOpState))
173 ^ (s.flags)
174 ^ (s.stencilRef << 6)
175 ^ (s.stencilWriteMask << 7);
176}
177
178// The lookup keys can be somewhat complicated due to having to handle cases
179// like "render a model in a shared scene between multiple View3Ds" (here both
180// the View3D ('layer/cid') and the model ('model') act as the lookup key since
181// while the model is the same, we still want different uniform buffers per
182// View3D), or the case of shadow maps where the shadow map (there can be as
183// many as lights) is taken into account too ('entry') together with an entry index
184// where more resolution is needed (e.g., cube maps).
185//
186struct QSSGRhiDrawCallDataKey
187{
188 const void *cid = nullptr; // Usually the sub-pass (see usage of QSSGPassKey)
189 const void *model = nullptr;
190 const void *entry = nullptr;
191 quintptr entryIdx = 0;
192};
193
194class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiBuffer
195{
196 Q_DISABLE_COPY(QSSGRhiBuffer)
197public:
198 QSSGRhiBuffer(QSSGRhiContext &context,
199 QRhiBuffer::Type type,
200 QRhiBuffer::UsageFlags usageMask,
201 quint32 stride,
202 qsizetype size,
203 QRhiCommandBuffer::IndexFormat indexFormat = QRhiCommandBuffer::IndexUInt16);
204
205 virtual ~QSSGRhiBuffer();
206
207 QRhiBuffer *buffer() const { return m_buffer; }
208 quint32 stride() const { return m_stride; }
210 const quint32 sz = quint32(m_buffer->size());
211 Q_ASSERT((sz % m_stride) == 0);
212 return sz / m_stride;
213 }
214 QRhiCommandBuffer::IndexFormat indexFormat() const { return m_indexFormat; }
215
216private:
217 QSSGRhiContext &m_context;
218 QRhiBuffer *m_buffer = nullptr;
219 quint32 m_stride;
220 QRhiCommandBuffer::IndexFormat m_indexFormat;
221};
222
224{
225 char name[64];
227
228private:
229 size_t offset = SIZE_MAX;
230 bool maybeExists = true;
231 friend class QSSGRhiShaderPipeline;
232};
233
235{
236 char name[64];
239
240private:
241 size_t offset = SIZE_MAX;
242 size_t size = 0;
243 bool maybeExists = true;
244 friend class QSSGRhiShaderPipeline;
245};
246
247using QSSGRhiBufferPtr = std::shared_ptr<QSSGRhiBuffer>;
248
249inline bool operator==(const QSSGRhiSamplerDescription &a, const QSSGRhiSamplerDescription &b) Q_DECL_NOTHROW
250{
251 return a.hTiling == b.hTiling && a.vTiling == b.vTiling && a.zTiling == b.zTiling
252 && a.minFilter == b.minFilter && a.magFilter == b.magFilter
253 && a.mipmap == b.mipmap;
254}
255
256inline bool operator!=(const QSSGRhiSamplerDescription &a, const QSSGRhiSamplerDescription &b) Q_DECL_NOTHROW
257{
258 return !(a == b);
259}
260
261struct QSSGRhiTexture
262{
263 QByteArray name;
264 QRhiTexture *texture = nullptr;
265 QSSGRhiSamplerDescription samplerDesc;
266};
267
282
283// these are our current shader limits
284#define QSSG_MAX_NUM_LIGHTS 16
285#define QSSG_MAX_NUM_DIRECTIONAL_LIGHTS 4
286#define QSSG_REDUCED_MAX_NUM_LIGHTS 8
287#define QSSG_REDUCED_MAX_NUM_DIRECTIONAL_LIGHTS 2
288
322
348
352
356
357class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiShaderPipeline
358{
359 Q_DISABLE_COPY(QSSGRhiShaderPipeline)
360public:
361 explicit QSSGRhiShaderPipeline(QSSGRhiContext &context) : m_context(context) { }
362
363 QSSGRhiContext &context() const { return m_context; }
364 bool isNull() const { return m_stages.isEmpty(); }
365
366 enum StageFlag {
367 // Indicates that this shaderpipeline object is not going to be used with
368 // a QSSGRhiInputAssemblerState, i.e. bakeVertexInputLocations() will
369 // not be called.
370 UsedWithoutIa = 0x01
371 };
372 Q_DECLARE_FLAGS(StageFlags, StageFlag)
373
374 void addStage(const QRhiShaderStage &stage, StageFlags flags = {});
375 const QRhiShaderStage *cbeginStages() const { return m_stages.cbegin(); }
376 const QRhiShaderStage *cendStages() const { return m_stages.cend(); }
377
379 for (const QRhiShaderStage &s : m_stages) {
380 if (s.type() == QRhiShaderStage::Vertex)
381 return &s;
382 }
383 return nullptr;
384 }
386 for (const QRhiShaderStage &s : m_stages) {
387 if (s.type() == QRhiShaderStage::Fragment)
388 return &s;
389 }
390 return nullptr;
391 }
392
393 int ub0Size() const { return m_ub0Size; }
394 int ub0LightDataOffset() const { return m_ub0NextUBufOffset; }
396
398
399 // This struct is used purely for performance. It is used to quickly store
400 // and index common uniform names using the storeIndex argument in the
401 // setUniform method.
403 {
434 int pointSizeIdx = -1;
441 int fogColorIdx = -1;
447
454 } commonUniformIndices;
455
457 int transform0 = -1;
458 int transform1 = -1;
459 int transform2 = -1;
460 int color = -1;
461 int data = -1;
462 } instanceLocations;
463
464 enum class UniformFlag {
465 Mat3 = 0x01
466 };
467 Q_DECLARE_FLAGS(UniformFlags, UniformFlag)
468
469 void setUniformValue(char *ubufData, const char *name, const QVariant &value, QSSGRenderShaderValue::Type type);
470 void setUniform(char *ubufData, const char *name, const void *data, size_t size, int *storeIndex = nullptr, UniformFlags flags = {});
471 void setUniformArray(char *ubufData, const char *name, const void *data, size_t itemCount, QSSGRenderShaderValue::Type type, int *storeIndex = nullptr);
472 int bindingForTexture(const char *name, int hint = -1);
473
474 void setLightsEnabled(bool enable) { m_lightsEnabled = enable; }
475 bool isLightingEnabled() const { return m_lightsEnabled; }
476
477 void ensureCombinedUniformBuffer(QRhiBuffer **ubuf);
478 void ensureUniformBuffer(QRhiBuffer **ubuf);
479
480 void setLightProbeTexture(QRhiTexture *texture,
481 QSSGRenderTextureCoordOp hTile = QSSGRenderTextureCoordOp::ClampToEdge,
482 QSSGRenderTextureCoordOp vTile = QSSGRenderTextureCoordOp::ClampToEdge)
483 {
484 m_lightProbeTexture = texture; m_lightProbeHorzTile = hTile; m_lightProbeVertTile = vTile;
485 }
486 QRhiTexture *lightProbeTexture() const { return m_lightProbeTexture; }
488 {
489 return {m_lightProbeHorzTile, m_lightProbeVertTile};
490 }
491
492 void setScreenTexture(QRhiTexture *texture) { m_screenTexture = texture; }
493 QRhiTexture *screenTexture() const { return m_screenTexture; }
494
495 void setDepthTexture(QRhiTexture *texture) { m_depthTexture = texture; }
496 QRhiTexture *depthTexture() const { return m_depthTexture; }
497
498 void setNormalTexture(QRhiTexture *texture) { m_normalTexture = texture; }
499 QRhiTexture *normalTexture() const { return m_normalTexture; }
500
501 void setSsaoTexture(QRhiTexture *texture) { m_ssaoTexture = texture; }
502 QRhiTexture *ssaoTexture() const { return m_ssaoTexture; }
503
504 void setLightmapTexture(QRhiTexture *texture) { m_lightmapTexture = texture; }
505 QRhiTexture *lightmapTexture() const { return m_lightmapTexture; }
506
507 void setShadowMapAtlasTexture(QRhiTexture *texture) { m_shadowMapAtlasTexture = texture; }
508 QRhiTexture *shadowMapAtlasTexture() const { return m_shadowMapAtlasTexture; }
509
510 void resetExtraTextures() { m_extraTextures.clear(); }
511 void addExtraTexture(const QSSGRhiTexture &t) { m_extraTextures.append(t); }
512 int extraTextureCount() const { return m_extraTextures.size(); }
513 const QSSGRhiTexture &extraTextureAt(int index) const { return m_extraTextures[index]; }
514 QSSGRhiTexture &extraTextureAt(int index) { return m_extraTextures[index]; }
515
516 QSSGShaderLightsUniformData &lightsUniformData() { return m_lightsUniformData; }
517 QSSGShaderDirectionalLightsUniformData &directionalLightsUniformData() { return m_directionalLightsUniformData; }
518 InstanceLocations instanceBufferLocations() const { return instanceLocations; }
519
520 int offsetOfUniform(const QByteArray &name);
521
522private:
523 QSSGRhiContext &m_context;
524 QVarLengthArray<QRhiShaderStage, 2> m_stages;
525 int m_ub0Size = 0;
526 int m_ub0NextUBufOffset = 0;
527 QHash<QByteArray, QShaderDescription::BlockVariable> m_ub0;
528 QHash<QSSGRhiInputAssemblerState::InputSemantic, QShaderDescription::InOutVariable> m_vertexInputs;
529 QHash<QByteArray, QShaderDescription::InOutVariable> m_combinedImageSamplers;
530 int m_materialImageSamplerBindings[size_t(QSSGRhiSamplerBindingHints::BindingMapSize)];
531
532 QVarLengthArray<QSSGRhiShaderUniform, 32> m_uniforms; // members of the main (binding 0) uniform buffer
533 QVarLengthArray<QSSGRhiShaderUniformArray, 8> m_uniformArrays;
534 QHash<QByteArray, size_t> m_uniformIndex; // Maps uniform name to index in m_uniforms and m_uniformArrays
535
536 // transient (per-object) data; pointers are all non-owning
537 bool m_lightsEnabled = false;
538 QSSGShaderLightsUniformData m_lightsUniformData;
539 QSSGShaderDirectionalLightsUniformData m_directionalLightsUniformData;
540 QRhiTexture *m_shadowMapAtlasTexture = nullptr;
541 QRhiTexture *m_lightProbeTexture = nullptr;
542 QSSGRenderTextureCoordOp m_lightProbeHorzTile = QSSGRenderTextureCoordOp::ClampToEdge;
543 QSSGRenderTextureCoordOp m_lightProbeVertTile = QSSGRenderTextureCoordOp::ClampToEdge;
544 QRhiTexture *m_screenTexture = nullptr;
545 QRhiTexture *m_depthTexture = nullptr;
546 QRhiTexture *m_normalTexture = nullptr;
547 QRhiTexture *m_ssaoTexture = nullptr;
548 QRhiTexture *m_lightmapTexture = nullptr;
549 QVarLengthArray<QSSGRhiTexture, 8> m_extraTextures;
550};
551
552Q_DECLARE_OPERATORS_FOR_FLAGS(QSSGRhiShaderPipeline::StageFlags)
553Q_DECLARE_OPERATORS_FOR_FLAGS(QSSGRhiShaderPipeline::UniformFlags)
554
555using QSSGRhiShaderPipelinePtr = std::shared_ptr<QSSGRhiShaderPipeline>;
556
557class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiShaderResourceBindingList
558{
559public:
560 static const int MAX_SIZE = 32;
561
562 int p = 0;
563 size_t h = 0;
564 QRhiShaderResourceBinding v[MAX_SIZE];
565
566 void clear() { p = 0; h = 0; }
567
568 QSSGRhiShaderResourceBindingList() { }
569
570 QSSGRhiShaderResourceBindingList(const QSSGRhiShaderResourceBindingList &other)
571 : p(other.p),
572 h(other.h)
573 {
574 for (int i = 0; i < p; ++i)
575 v[i] = other.v[i];
576 }
577
578 QSSGRhiShaderResourceBindingList &operator=(const QSSGRhiShaderResourceBindingList &other) Q_DECL_NOTHROW
579 {
580 if (this != &other) {
581 p = other.p;
582 h = other.h;
583 for (int i = 0; i < p; ++i)
584 v[i] = other.v[i];
585 }
586 return *this;
587 }
588
589 void addUniformBuffer(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiBuffer *buf, int offset = 0 , int size = 0);
590 void addTexture(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler);
591};
592
593inline bool operator==(const QSSGRhiShaderResourceBindingList &a, const QSSGRhiShaderResourceBindingList &b) Q_DECL_NOTHROW
594{
595 if (a.h != b.h)
596 return false;
597 if (a.p != b.p)
598 return false;
599 for (int i = 0; i < a.p; ++i) {
600 if (a.v[i] != b.v[i])
601 return false;
602 }
603 return true;
604}
605
606inline bool operator!=(const QSSGRhiShaderResourceBindingList &a, const QSSGRhiShaderResourceBindingList &b) Q_DECL_NOTHROW
607{
608 return !(a == b);
609}
610
611inline size_t qHash(const QSSGRhiShaderResourceBindingList &bl, size_t seed) Q_DECL_NOTHROW
612{
613 return bl.h ^ seed;
614}
615
616struct QSSGRhiDrawCallData
617{
618 QRhiBuffer *ubuf = nullptr; // owned
619 QRhiShaderResourceBindings *srb = nullptr; // not owned
620 QSSGRhiShaderResourceBindingList bindings;
621 QRhiGraphicsPipeline *pipeline = nullptr; // not owned
622 size_t renderTargetDescriptionHash = 0;
623 QVector<quint32> renderTargetDescription;
624 QSSGRhiGraphicsPipelineState ps;
625
626 void reset()
627 {
628 delete ubuf;
629 ubuf = nullptr;
630 srb = nullptr;
631 pipeline = nullptr;
632 }
633};
634
636{
639 QRhiTexture *depthTexture = nullptr; // either depthStencil or depthTexture are valid, never both
642 bool isValid() const { return texture && rpDesc && rt; }
644 delete rt;
645 rt = nullptr;
646 delete rpDesc;
647 rpDesc = nullptr;
648 }
649 void reset() {
651 delete texture;
652 delete depthStencil;
653 delete depthTexture;
654 *this = QSSGRhiRenderableTexture();
655 }
656};
657
659{
660 float d = 0.0f;
662};
663
676
687
689{
690public:
693 struct {
695 } extra;
696 static QSSGComputePipelineStateKey create(const QShader &shader,
697 const QRhiShaderResourceBindings *srb)
698 {
699 const QVector<quint32> srbDesc = srb->serializedLayoutDescription();
700 return { shader, srbDesc, { qHash(srbDesc) } };
701 }
702};
703
704inline bool operator==(const QSSGComputePipelineStateKey &a, const QSSGComputePipelineStateKey &b) Q_DECL_NOTHROW
705{
706 return a.shader == b.shader && a.srbLayoutDescription == b.srbLayoutDescription;
707}
708
709inline bool operator!=(const QSSGComputePipelineStateKey &a, const QSSGComputePipelineStateKey &b) Q_DECL_NOTHROW
710{
711 return !(a == b);
712}
713
714inline size_t qHash(const QSSGComputePipelineStateKey &k, size_t seed = 0) Q_DECL_NOTHROW
715{
716 return qHash(k.shader, seed) ^ k.extra.srbLayoutDescriptionHash;
717}
718
719struct QSSGRhiDummyTextureKey
720{
721 QRhiTexture::Flags flags;
722 QSize size;
723 QColor color;
724 int arraySize;
725};
726
727inline size_t qHash(const QSSGRhiDummyTextureKey &k, size_t seed) Q_DECL_NOTHROW
728{
729 return qHash(k.flags, seed)
730 ^ qHash(k.size.width() ^ k.size.height() ^ k.color.red() ^ k.color.green()
731 ^ k.color.blue() ^ k.color.alpha() ^ k.arraySize);
732}
733
734inline bool operator==(const QSSGRhiDummyTextureKey &a, const QSSGRhiDummyTextureKey &b) Q_DECL_NOTHROW
735{
736 return a.flags == b.flags && a.size == b.size && a.color == b.color && a.arraySize == b.arraySize;
737}
738
739inline bool operator!=(const QSSGRhiDummyTextureKey &a, const QSSGRhiDummyTextureKey &b) Q_DECL_NOTHROW
740{
741 return !(a == b);
742}
743
744class QSSGGraphicsPipelineStateKey
745{
746public:
747 QSSGRhiGraphicsPipelineState state;
748 QVector<quint32> renderTargetDescription;
749 QVector<quint32> srbLayoutDescription;
750 struct {
751 size_t renderTargetDescriptionHash;
752 size_t srbLayoutDescriptionHash;
753 } extra;
754 static QSSGGraphicsPipelineStateKey create(const QSSGRhiGraphicsPipelineState &state,
755 const QRhiRenderPassDescriptor *rpDesc,
756 const QRhiShaderResourceBindings *srb)
757 {
758 const QVector<quint32> rtDesc = rpDesc->serializedFormat();
759 const QVector<quint32> srbDesc = srb->serializedLayoutDescription();
760 return { state, rtDesc, srbDesc, { qHash(rtDesc), qHash(srbDesc) } };
761 }
762};
763
764inline bool operator==(const QSSGGraphicsPipelineStateKey &a, const QSSGGraphicsPipelineStateKey &b) Q_DECL_NOTHROW
765{
766 return a.state == b.state
767 && a.renderTargetDescription == b.renderTargetDescription
768 && a.srbLayoutDescription == b.srbLayoutDescription;
769}
770
771inline bool operator!=(const QSSGGraphicsPipelineStateKey &a, const QSSGGraphicsPipelineStateKey &b) Q_DECL_NOTHROW
772{
773 return !(a == b);
774}
775
776inline size_t qHash(const QSSGGraphicsPipelineStateKey &k, size_t seed) Q_DECL_NOTHROW
777{
778 return qHash(k.state, seed)
779 ^ k.extra.renderTargetDescriptionHash
780 ^ k.extra.srbLayoutDescriptionHash;
781}
782
783#define QSSGRHICTX_STAT(ctx, f)
784 for (bool qssgrhictxlog_enabled = QSSGRhiContextStats::get(*ctx).isEnabled(); qssgrhictxlog_enabled; qssgrhictxlog_enabled = false)
785 QSSGRhiContextStats::get(*ctx).f
786
787class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiContextStats
788{
789public:
790 [[nodiscard]] static QSSGRhiContextStats &get(QSSGRhiContext &rhiCtx);
791 [[nodiscard]] static const QSSGRhiContextStats &get(const QSSGRhiContext &rhiCtx);
792
793 struct DrawInfo {
794 quint64 callCount = 0;
795 quint64 vertexOrIndexCount = 0;
796 };
797 struct InstancedDrawInfo {
798 quint64 callCount = 0;
799 quint64 vertexOrIndexCount = 0;
800 quint64 instanceCount = 0;
801 };
802 struct RenderPassInfo {
803 QByteArray rtName;
804 QSize pixelSize;
805 DrawInfo indexedDraws;
806 DrawInfo draws;
807 InstancedDrawInfo instancedIndexedDraws;
808 InstancedDrawInfo instancedDraws;
809 };
810 struct PerLayerInfo {
811 PerLayerInfo()
812 {
813 externalRenderPass.rtName = QByteArrayLiteral("Qt Quick");
814 }
815
816 // The main render pass if renderMode==Offscreen, plus render passes
817 // for shadow maps, postprocessing effects, etc.
818 QVector<RenderPassInfo> renderPasses;
819
820 // An Underlay/Overlay/Inline renderMode will make the View3D add stuff
821 // to a render pass managed by Qt Quick. (external == not under the
822 // control of Qt Quick 3D)
823 RenderPassInfo externalRenderPass;
824
825 int currentRenderPassIndex = -1;
826 };
827 struct GlobalInfo { // global as in per QSSGRhiContext which is per-QQuickWindow
828 quint64 meshDataSize = 0;
829 quint64 imageDataSize = 0;
830 qint64 materialGenerationTime = 0;
831 qint64 effectGenerationTime = 0;
832 };
833
834 QHash<QSSGRenderLayer *, PerLayerInfo> perLayerInfo;
835 GlobalInfo globalInfo;
836
837 QSSGRhiContextStats(QSSGRhiContext &context)
838 : rhiCtx(&context)
839 {
840 }
841
842 // The data collected have four consumers:
843 //
844 // - Printed on debug output when QSG_RENDERER_DEBUG has the relevant key.
845 // (this way the debug output from the 2D scenegraph renderer and these 3D
846 // statistics appear nicely intermixed)
847 // - Passed on to the QML profiler when profiling is enabled.
848 // - DebugView via QQuick3DRenderStats.
849 // - When tracing is enabled
850 //
851 // The first two are enabled globally, but DebugView needs a dynamic
852 // enable/disable since we want to collect data when a DebugView item
853 // becomes visible, but not otherwise.
854
855 static bool profilingEnabled();
856 static bool rendererDebugEnabled();
857
858 bool isEnabled() const;
859 void drawIndexed(quint32 indexCount, quint32 instanceCount);
860 void draw(quint32 vertexCount, quint32 instanceCount);
861
862 void meshDataSizeChanges(quint64 newSize) // can be called outside start-stop
863 {
864 globalInfo.meshDataSize = newSize;
865 }
866
867 void imageDataSizeChanges(quint64 newSize) // can be called outside start-stop
868 {
869 globalInfo.imageDataSize = newSize;
870 }
871
872 void registerMaterialShaderGenerationTime(qint64 ms)
873 {
874 globalInfo.materialGenerationTime += ms;
875 }
876
877 void registerEffectShaderGenerationTime(qint64 ms)
878 {
879 globalInfo.effectGenerationTime += ms;
880 }
881
882 static quint64 totalDrawCallCountForPass(const QSSGRhiContextStats::RenderPassInfo &pass)
883 {
884 return pass.draws.callCount
885 + pass.indexedDraws.callCount
886 + pass.instancedDraws.callCount
887 + pass.instancedIndexedDraws.callCount;
888 }
889
890 static quint64 totalVertexCountForPass(const QSSGRhiContextStats::RenderPassInfo &pass)
891 {
892 return pass.draws.vertexOrIndexCount
893 + pass.indexedDraws.vertexOrIndexCount
894 + pass.instancedDraws.vertexOrIndexCount
895 + pass.instancedIndexedDraws.vertexOrIndexCount;
896 }
897
898 void start(QSSGRenderLayer *layer);
899 void stop(QSSGRenderLayer *layer);
900 void beginRenderPass(QRhiTextureRenderTarget *rt);
901 void endRenderPass();
902 void printRenderPass(const RenderPassInfo &rp);
903 void cleanupLayerInfo(QSSGRenderLayer *layer);
904
905 QSSGRhiContext *rhiCtx;
906 QSSGRenderLayer *layerKey = nullptr;
907 QSet<QSSGRenderLayer *> dynamicDataSources;
908};
909
910class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRhiContextPrivate
911{
912 Q_DECLARE_PUBLIC(QSSGRhiContext)
913
914 explicit QSSGRhiContextPrivate(QSSGRhiContext &rhiCtx, QRhi *rhi_)
915 : q_ptr(&rhiCtx)
916 , m_rhi(rhi_)
917 , m_stats(rhiCtx)
918 {}
919
920public:
921 using Textures = QSet<QRhiTexture *>;
922 using Meshes = QSet<QSSGRenderMesh *>;
923
924 [[nodiscard]] static QSSGRhiContextPrivate *get(QSSGRhiContext *q) { return q->d_ptr.get(); }
925 [[nodiscard]] static const QSSGRhiContextPrivate *get(const QSSGRhiContext *q) { return q->d_ptr.get(); }
926
927 [[nodiscard]] static bool shaderDebuggingEnabled();
928 [[nodiscard]] static bool editorMode();
929
930 void setMainRenderPassDescriptor(QRhiRenderPassDescriptor *rpDesc);
931 void setCommandBuffer(QRhiCommandBuffer *cb);
932 void setRenderTarget(QRhiRenderTarget *rt);
933 void setMainPassSampleCount(int samples);
934 void setMainPassViewCount(int viewCount);
935
936 void releaseCachedResources();
937
938 void registerTexture(QRhiTexture *texture);
939 void releaseTexture(QRhiTexture *texture);
940
941 void registerMesh(QSSGRenderMesh *mesh);
942 void releaseMesh(QSSGRenderMesh *mesh);
943
944 QRhiShaderResourceBindings *srb(const QSSGRhiShaderResourceBindingList &bindings);
945 void releaseCachedSrb(QSSGRhiShaderResourceBindingList &bindings);
946
947 QRhiGraphicsPipeline *pipeline(const QSSGRhiGraphicsPipelineState &ps,
948 QRhiRenderPassDescriptor *rpDesc,
949 QRhiShaderResourceBindings *srb);
950
951 QRhiGraphicsPipeline *pipeline(const QSSGGraphicsPipelineStateKey &key,
952 QRhiRenderPassDescriptor *rpDesc,
953 QRhiShaderResourceBindings *srb);
954
955 QRhiComputePipeline *computePipeline(const QShader &shader,
956 QRhiShaderResourceBindings *srb);
957
958 QRhiComputePipeline *computePipeline(const QSSGComputePipelineStateKey &key,
959 QRhiShaderResourceBindings *srb);
960
961 QSSGRhiDrawCallData &drawCallData(const QSSGRhiDrawCallDataKey &key);
962 void releaseDrawCallData(QSSGRhiDrawCallData &dcd);
963 void cleanupDrawCallData(const QSSGRenderModel *model);
964
965 QSSGRhiInstanceBufferData &instanceBufferData(QSSGRenderInstanceTable *instanceTable);
966 void releaseInstanceBuffer(QSSGRenderInstanceTable *instanceTable);
967
968 QSSGRhiInstanceBufferData &instanceBufferData(const QSSGRenderModel *model);
969
970 QSSGRhiParticleData &particleData(const QSSGRenderGraphObject *particlesOrModel);
971
972 QSSGRhiContext *q_ptr = nullptr;
973 QRhi *m_rhi = nullptr;
974
975 QRhiRenderPassDescriptor *m_mainRpDesc = nullptr;
976 QRhiCommandBuffer *m_cb = nullptr;
977 QRhiRenderTarget *m_rt = nullptr;
978 Textures m_textures;
979 Meshes m_meshes;
980 int m_mainSamples = 1;
981 int m_mainViewCount = 1;
982
983 QVector<QPair<QSSGRhiSamplerDescription, QRhiSampler*>> m_samplers;
984
985 QHash<QSSGRhiDrawCallDataKey, QSSGRhiDrawCallData> m_drawCallData;
986 QHash<QSSGRhiShaderResourceBindingList, QRhiShaderResourceBindings *> m_srbCache;
987 QHash<QSSGGraphicsPipelineStateKey, QRhiGraphicsPipeline *> m_pipelines;
988 QHash<QSSGComputePipelineStateKey, QRhiComputePipeline *> m_computePipelines;
989 QHash<QSSGRhiDummyTextureKey, QRhiTexture *> m_dummyTextures;
990 QHash<QSSGRenderInstanceTable *, QSSGRhiInstanceBufferData> m_instanceBuffers;
991 QHash<const QSSGRenderModel *, QSSGRhiInstanceBufferData> m_instanceBuffersLod;
992 QHash<const QSSGRenderGraphObject *, QSSGRhiParticleData> m_particleData;
993 QSSGRhiContextStats m_stats;
994};
995
996inline bool operator==(const QSSGRhiDrawCallDataKey &a, const QSSGRhiDrawCallDataKey &b) noexcept
997{
998 return a.cid == b.cid && a.model == b.model && a.entry == b.entry && a.entryIdx == b.entryIdx;
999}
1000
1001inline bool operator!=(const QSSGRhiDrawCallDataKey &a, const QSSGRhiDrawCallDataKey &b) noexcept
1002{
1003 return !(a == b);
1004}
1005
1006inline size_t qHash(const QSSGRhiDrawCallDataKey &k, size_t seed = 0) noexcept
1007{
1008 return qHash(quintptr(k.cid)
1009 ^ quintptr(k.model)
1010 ^ quintptr(k.entry)
1011 ^ quintptr(k.entryIdx), seed);
1012}
1013
1014QT_END_NAMESPACE
1015
1016#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:801
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:812
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 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
QPair< QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp > lightProbeTiling() const
void setLightProbeTexture(QRhiTexture *texture, QSSGRenderTextureCoordOp hTile=QSSGRenderTextureCoordOp::ClampToEdge, QSSGRenderTextureCoordOp vTile=QSSGRenderTextureCoordOp::ClampToEdge)
void setLightmapTexture(QRhiTexture *texture)
InstanceLocations instanceBufferLocations() const
void setDepthTexture(QRhiTexture *texture)
void addStage(const QRhiShaderStage &stage, StageFlags flags={})
QRhiTexture * screenTexture() const
void ensureUniformBuffer(QRhiBuffer **ubuf)
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 setScreenTexture(QRhiTexture *texture)
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 setShadowMapAtlasTexture(QRhiTexture *texture)
void setUniform(char *ubufData, const char *name, const void *data, size_t size, int *storeIndex=nullptr, UniformFlags flags={})
QRhiTexture * lightmapTexture() const
void setNormalTexture(QRhiTexture *texture)
void setSsaoTexture(QRhiTexture *texture)
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(qtquick3d, QSSG_renderFrame_entry, int width, int height)
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept
Definition qsize.h:191
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]