Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qssgrendershadercodegenerator.cpp
Go to the documentation of this file.
1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
6
7#include <QtQuick3DUtils/private/qssgutils_p.h>
8
9#include <QtQuick3DRuntimeRender/private/qssgrendercontextcore_p.h>
10#include <QtQuick3DRuntimeRender/private/qssgrendershaderlibrarymanager_p.h>
11#include <QtQuick3DRuntimeRender/private/qssgshaderresourcemergecontext_p.h>
12
14
15template<typename T>
16static inline void addStartCond(QByteArray &block, const T &var)
17{
18 // must use #if not #ifdef, as we test for the value, because featureset flags
19 // are written out even when 0, think for example #define QSSG_ENABLE_SSM 0
21 block += QString::asprintf("#if %s\n", var.conditionName.constData()).toUtf8();
22 else if (var.conditionType == QSSGRenderShaderMetadata::Uniform::Negated)
23 block += QString::asprintf("#if !%s\n", var.conditionName.constData()).toUtf8();
24}
25
26template<typename T>
27static inline void addEndCond(QByteArray &block, const T &var)
28{
30 block += QByteArrayLiteral("#endif\n");
31}
32
34{
35 // never null; so safe to call strlen on.
36 const char *m_vertexShader{ "" };
37 const char *m_fragmentShader{ "" };
38
40 QSSGShaderGeneratedProgramOutput(const char *vs, const char *fs)
42 {
43 }
44};
45
47
48 : m_outgoing(nullptr), m_stage(inStage)
49{
50}
51
52void QSSGStageGeneratorBase::begin(QSSGShaderGeneratorStageFlags inEnabledStages)
53{
55 m_outgoing = nullptr;
63 m_enabledStages = inEnabledStages;
66 // the shared buffers will be cleared elsewhere.
67}
68
70{
72}
73
75{
76 if (m_outgoing == nullptr) {
77 Q_ASSERT(false);
78 return;
79 }
81}
82
84{
86}
87
89{
91}
92
94{
96}
97
99{
100 TParamPair theParamPair(paramName, type);
101 TConstantBufferParamPair theBufferParamPair(cbName, theParamPair);
102 m_constantBufferParams.push_back(theBufferParamPair);
103}
104
106{
108 return *this;
109}
110
112{
114 m_codeBuilder.append("\n");
115}
116
118
120{
123}
124
126{
128
130 for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
131 const QByteArray name = iter.key() + inItemSuffix;
132 switch (itemType) {
135 break;
138 break;
141 break;
143 if (iter.value().startsWith(QByteArrayLiteral("sampler")))
145 else
147 break;
148 default:
149 qWarning("Unknown shader item %d", int(itemType));
150 Q_UNREACHABLE();
151 }
152 }
153}
154
156{
159}
160
162{
164 for (TStrTableSizedStrMap::const_iterator iter = m_uniformArrays.begin(), end = m_uniformArrays.end(); iter != end; ++iter) {
165 const QByteArray name = iter.key() +
166 "[" + QByteArray::number(iter.value().first) + "]";
167 if (iter.value().second.startsWith(QByteArrayLiteral("sampler")))
168 m_mergeContext->registerSampler(iter.value().second, name);
169 else
171 }
173}
174
176{
177 if (m_outgoing)
179
181}
182
184{
186
187 // iterate over all constant buffers
188 for (TStrTableStrMap::const_iterator iter = cbMap.begin(), end = cbMap.end(); iter != end; ++iter) {
189 m_finalBuilder.append(iter.value());
191 m_finalBuilder.append(itemType);
194 m_finalBuilder.append(" {\n");
195 // iterate over all param entries and add match
196 for (TConstantBufferParamArray::const_iterator iter1 = cbParamsArray.begin(), end = cbParamsArray.end(); iter1 != end;
197 ++iter1) {
198 if (iter1->first == iter.key()) {
199 m_finalBuilder.append(iter1->second.second);
201 m_finalBuilder.append(iter1->second.first);
202 m_finalBuilder.append(";\n");
203 }
204 }
205
206 m_finalBuilder.append("};\n");
207 }
208}
209
211
213
215{
216 m_mergeContext = mergeContext;
221 m_mergeContext = nullptr;
222
224 iter != end; ++iter) {
225 m_finalBuilder.append("#ifndef ");
228 m_finalBuilder.append("#define ");
230 if (!iter.value().isEmpty())
232 m_finalBuilder.append("\n#endif\n");
233 }
234
235 // Sort for deterministic shader text when printing/debugging
236 QList<QByteArray> sortedIncludes(m_includes.begin(), m_includes.end());
237 std::sort(sortedIncludes.begin(), sortedIncludes.end());
238
239 for (const auto &include : sortedIncludes) {
240 m_finalBuilder.append("#include \"");
241 m_finalBuilder.append(include);
242 m_finalBuilder.append("\"\n");
243 }
244
246}
247
249{
250 static const char *prefix = "//@@";
251 const int prefixLen = 4;
252 const int typeLen = 1;
253 int from = 0;
254 for (; ;) {
255 int pos = m_finalBuilder.indexOf(prefix, from);
256 if (pos >= 0) {
257 from = pos;
258 ShaderItemType itemType = ShaderItemType(m_finalBuilder.mid(pos + prefixLen, typeLen).toInt());
259 switch (itemType) {
262 QByteArray block;
263 for (const QSSGShaderResourceMergeContext::InOutVar &var : mergeContext->m_inOutVars) {
264 if (var.stagesInputIn.testFlag(m_stage))
265 block += QString::asprintf("layout(location = %d) in %s %s;\n", var.location, var.type.constData(), var.name.constData()).toUtf8();
266 }
267 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
268 }
269 break;
271 {
272 QByteArray block;
273 for (const QSSGShaderResourceMergeContext::InOutVar &var : mergeContext->m_inOutVars) {
274 if (var.stagesInputIn.testFlag(m_stage))
275 block += QString::asprintf("layout(location = %d) in %s %s;\n", var.location, var.type.constData(), var.name.constData()).toUtf8();
276 }
277 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
278 }
279 break;
281 {
282 QByteArray block;
283 for (const QSSGShaderResourceMergeContext::InOutVar &var : mergeContext->m_inOutVars) {
284 if (var.stageOutputFrom.testFlag(m_stage))
285 block += QString::asprintf("layout(location = %d) out %s %s;\n", var.location, var.type.constData(), var.name.constData()).toUtf8();
286 }
287 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
288 }
289 break;
291 {
292 QByteArray block;
293
294 for (const auto &sampler : std::as_const(mergeContext->m_samplers)) {
295 addStartCond(block, sampler);
296 block += QString::asprintf("layout(binding = %d) uniform %s %s;\n",
297 sampler.binding,
298 sampler.type.constData(),
299 sampler.name.constData()).toUtf8();
300 addEndCond(block, sampler);
301 }
302
303 if (!mergeContext->m_uniformMembers.isEmpty()) {
304 // The layout (offsets of the members) of the main
305 // uniform block cannot be different in the stages.
306 // (f.ex., a given member must be assumed to be at same
307 // offset both in the vertex and the fragment shader)
308 // Therefore we output everything in all stages.
309 block += QByteArrayLiteral("layout(std140, binding = 0) uniform cbMain {\n");
310 for (auto iter = mergeContext->m_uniformMembers.cbegin(), end = mergeContext->m_uniformMembers.cend();
311 iter != end; ++iter)
312 {
313 addStartCond(block, iter.value());
314 block += QString::asprintf(" %s %s;\n", iter.value().type.constData(), iter.value().name.constData()).toUtf8();
315 addEndCond(block, iter.value());
316 }
317 // No instance name for this uniform block. This is
318 // essential since custom material shader code will not use
319 // any instance name prefix when accessing the members. So
320 // while the internal stuff for default/principled material
321 // could be fixed up with prefixing everything, custom
322 // materials cannot. So leave it out.
323 block += QByteArrayLiteral("};\n");
324 }
325 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
326 }
327 break;
328 default:
329 Q_UNREACHABLE_RETURN(m_finalBuilder);
330 }
331 } else {
332 break;
333 }
334 }
335
336 return m_finalBuilder;
337}
338
340{
341 if (!m_addedFunctions.contains(functionName)) {
342 m_addedFunctions.push_back(functionName);
343 QByteArray includeName;
344 includeName = "func" + functionName + ".glsllib";
345 addInclude(includeName);
346 }
347}
348
350{
352}
353
355{
356 // Link stages incoming to outgoing variables.
357 QSSGStageGeneratorBase *previous = nullptr;
358 quint32 theStageId = 1;
359 for (quint32 idx = 0, end = quint32(QSSGShaderGeneratorStage::StageCount); idx < end; ++idx, theStageId = theStageId << 1) {
360 QSSGStageGeneratorBase *thisStage = nullptr;
361 QSSGShaderGeneratorStage theStageEnum = static_cast<QSSGShaderGeneratorStage>(theStageId);
362 if ((m_enabledStages & theStageEnum)) {
363 thisStage = &internalGetStage(theStageEnum);
364 if (previous)
365 previous->m_outgoing = &thisStage->m_incoming;
366 previous = thisStage;
367 }
368 }
369}
370
371void QSSGProgramGenerator::beginProgram(QSSGShaderGeneratorStageFlags inEnabledStages)
372{
373 m_vs.begin(inEnabledStages);
374 m_fs.begin(inEnabledStages);
375 m_enabledStages = inEnabledStages;
376 linkStages();
377}
378
379QSSGShaderGeneratorStageFlags QSSGProgramGenerator::getEnabledStages() const { return m_enabledStages; }
380
382{
383 switch (inStage) {
385 return m_vs;
387 return m_fs;
388 default:
389 Q_ASSERT(false);
390 break;
391 }
392 return m_vs;
393}
394
396{
397 if ((m_enabledStages & inStage))
398 return &internalGetStage(inStage);
399 return nullptr;
400}
401
403{
405
406 for (const QSSGRenderShaderMetadata::Uniform &u : std::as_const(meta.uniforms)) {
407 if (u.type.startsWith(QByteArrayLiteral("sampler")))
408 mergeContext->registerSampler(u.type, u.name, u.condition, u.conditionName);
409 else
410 mergeContext->registerUniformMember(u.type, u.name, u.condition, u.conditionName);
411 }
412
413 for (const QSSGRenderShaderMetadata::InputOutput &inputVar : std::as_const(meta.inputs)) {
414 if (inputVar.stage == stage)
415 mergeContext->registerInput(stage, inputVar.type, inputVar.name);
416 }
417
418 for (const QSSGRenderShaderMetadata::InputOutput &outputVar : std::as_const(meta.outputs)) {
419 if (outputVar.stage == stage)
420 mergeContext->registerOutput(stage, outputVar.type, outputVar.name);
421 }
422
423 for (auto it = mergeContext->m_inOutVars.cbegin(), end = mergeContext->m_inOutVars.cend(); it != end; ++it) {
424 if (it->stagesInputIn == int(QSSGShaderGeneratorStage::Fragment) && it->stageOutputFrom == 0)
425 qWarning("Fragment stage input %s is not output from vertex stage; expect errors.", it.key().constData());
426 }
427}
428
430 const QSSGShaderFeatures &inFeatureSet,
431 QSSGShaderLibraryManager &shaderLibraryManager,
432 QSSGShaderCache &theCache,
433 QSSGRhiShaderPipeline::StageFlags stageFlags)
434{
435 // No stages enabled
436 if (((quint32)m_enabledStages) == 0) {
437 Q_ASSERT(false);
438 return nullptr;
439 }
440
442
443 for (quint32 stageIdx = 0; stageIdx < static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
444 QSSGShaderGeneratorStage stageName = static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
445 if (m_enabledStages & stageName) {
446 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
447 theStage.buildShaderSourcePass1(&mergeContext);
448 }
449 }
450
451 for (quint32 stageIdx = 0; stageIdx < static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
452 QSSGShaderGeneratorStage stageName = static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
453 if (m_enabledStages & stageName) {
454 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
455 shaderLibraryManager.resolveIncludeFiles(theStage.m_finalBuilder, inMaterialInfoString);
456 registerShaderMetaDataFromSource(&mergeContext, theStage.m_finalBuilder, stageName);
457 }
458 }
459
460 for (quint32 stageIdx = 0; stageIdx < static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
461 QSSGShaderGeneratorStage stageName = static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
462 if (m_enabledStages & stageName) {
463 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
464 theStage.buildShaderSourcePass2(&mergeContext);
465 }
466 }
467
468 // qDebug("VERTEX:\n%s\n\n", m_vs.m_finalBuilder.constData());
469 // qDebug("FRAGMENT:\n%s\n\n", m_fs.m_finalBuilder.constData());
470
471 return theCache.compileForRhi(inMaterialInfoString,
474 inFeatureSet,
475 stageFlags);
476}
477
480{}
481
484{}
485
487{
490}
491
493{
495}
496
\inmodule QtCore
Definition qbytearray.h:57
int toInt(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an int using base base, which is ten by default.
qsizetype indexOf(char c, qsizetype from=0) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
void clear()
Clears the contents of the byte array and makes it null.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray mid(qsizetype index, qsizetype len=-1) const
Returns a byte array containing len bytes from this byte array, starting at position pos.
QByteArray & replace(qsizetype index, qsizetype len, const char *s, qsizetype alen)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:275
Definition qlist.h:74
void push_back(parameter_type t)
Definition qlist.h:672
iterator end()
Definition qlist.h:609
iterator begin()
Definition qlist.h:608
void clear()
Definition qlist.h:417
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
void clear()
Definition qmap.h:288
iterator begin()
Definition qmap.h:597
iterator end()
Definition qmap.h:601
void registerShaderMetaDataFromSource(QSSGShaderResourceMergeContext *mergeContext, const QByteArray &contents, QSSGShaderGeneratorStage stage)
QSSGShaderGeneratorStageFlags m_enabledStages
QSSGRhiShaderPipelinePtr compileGeneratedRhiShader(const QByteArray &inMaterialInfoString, const QSSGShaderFeatures &inFeatureSet, QSSGShaderLibraryManager &shaderLibraryManager, QSSGShaderCache &theCache, QSSGRhiShaderPipeline::StageFlags stageFlags)
QSSGStageGeneratorBase * getStage(QSSGShaderGeneratorStage inStage)
QSSGStageGeneratorBase & internalGetStage(QSSGShaderGeneratorStage inStage)
QSSGShaderGeneratorStageFlags getEnabledStages() const
void beginProgram(QSSGShaderGeneratorStageFlags inEnabledStages=defaultFlags())
QSSGFragmentShaderGenerator m_fs
QSSGRhiShaderPipelinePtr compileForRhi(const QByteArray &inKey, const QByteArray &inVert, const QByteArray &inFrag, const QSSGShaderFeatures &inFeatures, QSSGRhiShaderPipeline::StageFlags stageFlags)
void resolveIncludeFiles(QByteArray &theReadBuffer, const QByteArray &inMaterialInfoString)
void registerInput(QSSGShaderGeneratorStage stage, const QByteArray &type, const QByteArray &name)
void registerOutput(QSSGShaderGeneratorStage stage, const QByteArray &type, const QByteArray &name)
QMap< QByteArray, BlockMember > m_uniformMembers
void registerSampler(const QByteArray &type, const QByteArray &name, QSSGRenderShaderMetadata::Uniform::Condition conditionType=QSSGRenderShaderMetadata::Uniform::None, const QByteArray &conditionName=QByteArray())
void registerUniformMember(const QByteArray &type, const QByteArray &name, QSSGRenderShaderMetadata::Uniform::Condition conditionType=QSSGRenderShaderMetadata::Uniform::None, const QByteArray &conditionName=QByteArray())
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
void clear()
Definition qset.h:61
iterator insert(const T &value)
Definition qset.h:155
QByteArray toUtf8() const &
Definition qstring.h:563
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7005
const void * constData() const
Definition qvariant.h:446
QSet< QString >::iterator it
ShaderMetaData getShaderMetaData(const QByteArray &data)
Combined button and popup list for selecting options.
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:162
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLuint sampler
GLenum type
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static QT_BEGIN_NAMESPACE void addStartCond(QByteArray &block, const T &var)
static void addEndCond(QByteArray &block, const T &var)
std::shared_ptr< QSSGRhiShaderPipeline > QSSGRhiShaderPipelinePtr
unsigned int quint32
Definition qtypes.h:45
QObject::connect nullptr
QVBoxLayout * layout
bool contains(const AT &t) const noexcept
Definition qlist.h:44
QSSGShaderGeneratedProgramOutput(const char *vs, const char *fs)
QSSGStageGeneratorBase(QSSGShaderGeneratorStage inStage)
QSSGShaderGeneratorStage stage() const
TConstantBufferParamArray m_constantBufferParams
QPair< QByteArray, QByteArray > TParamPair
void addShaderPass2Marker(ShaderItemType itemType)
QPair< QByteArray, TParamPair > TConstantBufferParamPair
virtual void addConstantBuffer(const QByteArray &name, const QByteArray &layout)
virtual void addConstantBufferParam(const QByteArray &cbName, const QByteArray &paramName, const QByteArray &type)
virtual void begin(QSSGShaderGeneratorStageFlags inEnabledStages)
virtual void addShaderConstantBufferItemMap(const QByteArray &itemType, const TStrTableStrMap &cbMap, TConstantBufferParamArray cbParamsArray)
QByteArray buildShaderSourcePass2(QSSGShaderResourceMergeContext *mergeContext)
virtual void addUniformArray(const QByteArray &name, const QByteArray &type, quint32 size)
QSSGShaderResourceMergeContext * m_mergeContext
virtual void addFunction(const QByteArray &functionName) final
void buildShaderSourcePass1(QSSGShaderResourceMergeContext *mergeContext)
virtual void addUniform(const QByteArray &name, const QByteArray &type)
virtual void addDefinition(const QByteArray &name, const QByteArray &value) final
QSSGShaderGeneratorStageFlags m_enabledStages
virtual void append(const QByteArray &data)
virtual void addOutgoing(const QByteArray &name, const QByteArray &type)
virtual void addIncoming(const QByteArray &name, const QByteArray &type)
virtual void addInclude(const QByteArray &name) final
void addShaderItemMap(ShaderItemType itemType, const TStrTableStrMap &itemMap, const QByteArray &inItemSuffix=QByteArray())
virtual QSSGStageGeneratorBase & operator<<(const QByteArray &data)
\qmltype MapCircle \instantiates QDeclarativeCircleMapItem \inqmlmodule QtLocation