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
qssgshaderresourcemergecontext_p.h
Go to the documentation of this file.
1// Copyright (C) 2019 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 QSSGSHADERRESOURCEMERGECONTEXT_P_H
7#define QSSGSHADERRESOURCEMERGECONTEXT_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
22
23QT_BEGIN_NAMESPACE
24
25class QSSGShaderResourceMergeContext
26{
27public:
28
29 QSSGShaderResourceMergeContext()
30 : m_nextFreeResourceBinding(FIRST_CUSTOM_RESOURCE_BINDING_POINT + s_additionalBuffers)
31 {
32 }
33 // Resource bindings 0..2 are reserved for uniform buffers.
34 // (0 is cbMain, 1 is cbLights)
35 static const int FIRST_CUSTOM_RESOURCE_BINDING_POINT = 3;
36
37 struct InOutVar {
38 QSSGShaderGeneratorStageFlags stageOutputFrom;
39 QSSGShaderGeneratorStageFlags stagesInputIn;
40 QByteArray type;
41 QByteArray name;
42 int location;
43 bool output;
44 bool flat;
45 };
46
47 struct Sampler {
48 QByteArray type;
49 QByteArray name;
50 QSSGRenderShaderMetadata::Uniform::Condition conditionType;
51 QByteArray conditionName;
52 int binding;
53 };
54
55 struct Image : public Sampler
56 {
57 QByteArray imgType;
58 QSSGMemoryQualifiers qualifiers;
59 QSSGShaderGeneratorStageFlags stages;
60 };
61
62 struct BlockMember {
63 QByteArray type;
64 QByteArray name;
65 QSSGRenderShaderMetadata::Uniform::Condition conditionType;
66 QByteArray conditionName;
67 };
68
69 struct Buffer : public BlockMember
70 {
71 int binding;
72 QByteArray contentType;
73 QSSGMemoryQualifiers qualifiers;
74 QSSGShaderGeneratorStageFlags stages;
75 };
76
77 // Using QMap intentionally - while it is not strictly required to use an
78 // ordered map, being sorted by key when iterating is helpful to get the
79 // same ordered list of vertex inputs, uniforms, etc. on every run, which
80 // in turn helps shader (disk) cache efficiency due to not generating a
81 // different shader string just because QHash decided to iterate entries in
82 // a different order.
83 QMap<QByteArray, InOutVar> m_inOutVars;
84 QMap<QByteArray, Sampler> m_samplers;
85 QMap<QByteArray, Image> m_images;
86 QMap<QByteArray, Buffer> m_buffers;
87 QMap<QByteArray, BlockMember> m_uniformMembers;
88
89 int m_nextFreeResourceBinding = FIRST_CUSTOM_RESOURCE_BINDING_POINT;
90 int m_nextFreeImageBinding = 0;
91 QHash<int, int> m_nextFreeInLocation;
92 QHash<int, int> m_nextFreeOutLocation;
93
94 int viewCount = 1;
95
96 void rearrangeResources()
97 {
98 // Put images and storage buffers before samplers. QRhi's OpenGL
99 // backend uses the binding number directly as the image unit and as
100 // the shader storage buffer binding point, and the guaranteed minimum
101 // for both is only 8 (GL_MAX_IMAGE_UNITS, GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS).
102 // These are separate namespaces in OpenGL, but QRhi needs unique binding
103 // numbers across all resource types, so the numbers used by uniform buffers (0..2),
104 // images and buffers all count against both limits. Linked list OIT adds three
105 // images, which leaves two bindings for custom images and buffers.
106 // Samplers and uniform buffers are not affected: QRhi assigns texture
107 // units itself and sets uniform block members as plain uniforms.
108 int binding = FIRST_CUSTOM_RESOURCE_BINDING_POINT + s_additionalBuffers;
109 for (auto &image : m_images)
110 image.binding = binding++;
111 for (auto &buffer : m_buffers)
112 buffer.binding = binding++;
113 for (auto &sampler : m_samplers)
114 sampler.binding = binding++;
115 }
116
117 void registerInput(QSSGShaderGeneratorStage stage, const QByteArray &type, const QByteArray &name, bool flat = false)
118 {
119 auto it = m_inOutVars.find(name);
120 if (it != m_inOutVars.end()) {
121 it->stagesInputIn |= stage;
122 return;
123 }
124 InOutVar var { {}, stage, type, name, m_nextFreeInLocation[int(stage)]++, false, flat };
125 m_inOutVars.insert(name, var);
126 }
127
128 void registerOutput(QSSGShaderGeneratorStage stage, const QByteArray &type, const QByteArray &name, bool flat = false)
129 {
130 auto it = m_inOutVars.find(name);
131 if (it != m_inOutVars.end()) {
132 it->stageOutputFrom |= stage;
133 return;
134 }
135 InOutVar var { stage, {}, type, name, m_nextFreeOutLocation[int(stage)]++, true, flat };
136 m_inOutVars.insert(name, var);
137 }
138
139 void registerSampler(const QByteArray &type,
140 const QByteArray &name,
141 QSSGRenderShaderMetadata::Uniform::Condition conditionType = QSSGRenderShaderMetadata::Uniform::None,
142 const QByteArray &conditionName = QByteArray())
143 {
144 if (m_images.contains(name) || m_buffers.contains(name)) {
145 qWarning("Sampler %s name conflicts with existing image or buffer.", name.constData());
146 return;
147 }
148 if (m_samplers.contains(name))
149 return;
150 Sampler var { type, name, conditionType, conditionName, m_nextFreeResourceBinding++ };
151 m_samplers.insert(name, var);
152 }
153
154 void registerImage(QSSGShaderGeneratorStage stage,
155 const QByteArray &type,
156 const QByteArray &name,
157 const QByteArray &imgtype,
158 QSSGMemoryQualifiers qualifiers,
159 QSSGRenderShaderMetadata::Uniform::Condition conditionType = QSSGRenderShaderMetadata::Uniform::None,
160 const QByteArray &conditionName = QByteArray())
161 {
162 if (m_samplers.contains(name) || m_buffers.contains(name)) {
163 qWarning("Image %s name conflicts with existing sampler or buffer.", name.constData());
164 return;
165 }
166 auto iter = m_images.find(name);
167 if (iter != m_images.end()) {
168 auto &img = *iter;
169 if (img.type != type || img.imgType != imgtype || img.qualifiers != qualifiers)
170 qWarning("Image %s is declared differently between shader stages.", name.constData());
171 if (img.conditionType != conditionType || img.conditionName != conditionName)
172 qWarning("Image %s condition doesn't match between shader stages.", name.constData());
173 img.stages |= stage;
174 return;
175 }
176 Image var {{type, name, conditionType, conditionName, m_nextFreeResourceBinding++}, imgtype, qualifiers, stage};
177 m_images.insert(name, var);
178 }
179 void registerBuffer(QSSGShaderGeneratorStage stage,
180 const QByteArray &contentType,
181 const QByteArray &name,
182 QSSGMemoryQualifiers qualifiers,
183 QSSGRenderShaderMetadata::Uniform::Condition conditionType = QSSGRenderShaderMetadata::Uniform::None,
184 const QByteArray &conditionName = QByteArray())
185 {
186 if (m_samplers.contains(name) || m_images.contains(name)) {
187 qWarning("Buffer %s name conflicts with existing sampler or image.", name.constData());
188 return;
189 }
190 auto iter = m_buffers.find(name);
191 if (iter != m_buffers.end()) {
192 auto &buf = *iter;
193 if (buf.contentType.simplified() != contentType.simplified() || buf.qualifiers != qualifiers)
194 qWarning("Storage buffer %s is declared differently between shader stages.", name.constData());
195 if (buf.conditionType != conditionType || buf.conditionName != conditionName)
196 qWarning("Storage buffer %s condition doesn't match between shader stages.", name.constData());
197 buf.stages |= stage;
198 return;
199 }
200 Buffer var {{"buffer", name, conditionType, conditionName}, m_nextFreeResourceBinding++, contentType, qualifiers, stage};
201 m_buffers.insert(name, var);
202 }
203
204 void registerUniformMember(const QByteArray &type,
205 const QByteArray &name,
206 QSSGRenderShaderMetadata::Uniform::Condition conditionType = QSSGRenderShaderMetadata::Uniform::None,
207 const QByteArray &conditionName = QByteArray())
208 {
209 auto it = m_uniformMembers.constFind(name);
210 if (it != m_uniformMembers.constEnd()) {
211 if (it->conditionType != conditionType) {
212 qWarning("Encountered uniform %s with different conditions, this is not supported.",
213 name.constData());
214 }
215 return;
216 }
217 BlockMember var { type, name, conditionType, conditionName };
218 m_uniformMembers.insert(name, var);
219 }
220 static int s_additionalBuffers;
221 static void setAdditionalBufferAmount(int amount)
222 {
223 s_additionalBuffers = amount;
224 }
225};
226
227QT_END_NAMESPACE
228
229#endif