Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
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
51
52void QSSGStageGeneratorBase::begin(QSSGShaderGeneratorStageFlags inEnabledStages)
53{
55 m_outgoing = nullptr;
57 m_flatOutgoing = nullptr;
65 m_enabledStages = inEnabledStages;
68 // the shared buffers will be cleared elsewhere.
69}
70
76
78{
79 if (m_outgoing == nullptr) {
80 Q_ASSERT(false);
81 return;
82 }
86}
87
93
95{
96 if (m_flatOutgoing == nullptr) {
97 Q_ASSERT(false);
98 return;
99 }
101 if (m_outgoing)
103}
104
109
114
119
121{
122 TParamPair theParamPair(paramName, type);
123 TConstantBufferParamPair theBufferParamPair(cbName, theParamPair);
124 m_constantBufferParams.push_back(theBufferParamPair);
125}
126
132
138
140
146
148{
150
152 for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
153 const QByteArray name = iter.key();
154 switch (itemType) {
157 break;
160 break;
163 break;
165 if (iter.value().startsWith(QByteArrayLiteral("sampler")))
167 else
169 break;
170 default:
171 qWarning("Unknown shader item %d", int(itemType));
172 Q_UNREACHABLE();
173 }
174 }
175}
176
182
184{
186 for (TStrTableSizedStrMap::const_iterator iter = m_uniformArrays.begin(), end = m_uniformArrays.end(); iter != end; ++iter) {
187 const QByteArray name = iter.key() +
188 "[" + QByteArray::number(iter.value().first) + "]";
189 if (iter.value().second.startsWith(QByteArrayLiteral("sampler")))
190 m_mergeContext->registerSampler(iter.value().second, name);
191 else
193 }
195}
196
206
208{
210
211 // iterate over all constant buffers
212 for (TStrTableStrMap::const_iterator iter = cbMap.begin(), end = cbMap.end(); iter != end; ++iter) {
213 m_finalBuilder.append(iter.value());
215 m_finalBuilder.append(itemType);
218 m_finalBuilder.append(" {\n");
219 // iterate over all param entries and add match
220 for (TConstantBufferParamArray::const_iterator iter1 = cbParamsArray.begin(), end = cbParamsArray.end(); iter1 != end;
221 ++iter1) {
222 if (iter1->first == iter.key()) {
223 m_finalBuilder.append(iter1->second.second);
225 m_finalBuilder.append(iter1->second.first);
226 m_finalBuilder.append(";\n");
227 }
228 }
229
230 m_finalBuilder.append("};\n");
231 }
232}
233
235
237
239{
240 m_mergeContext = mergeContext;
245 m_mergeContext = nullptr;
246
248 iter != end; ++iter) {
249 m_finalBuilder.append("#ifndef ");
252 m_finalBuilder.append("#define ");
254 if (!iter.value().isEmpty())
256 m_finalBuilder.append("\n#endif\n");
257 }
258
259 // Sort for deterministic shader text when printing/debugging
260 QList<QByteArray> sortedIncludes(m_includes.begin(), m_includes.end());
261 std::sort(sortedIncludes.begin(), sortedIncludes.end());
262
263 for (const auto &include : sortedIncludes) {
264 m_finalBuilder.append("#include \"");
265 m_finalBuilder.append(include);
266 m_finalBuilder.append("\"\n");
267 }
268
270}
271
273{
274 static const char *prefix = "//@@";
275 const int prefixLen = 4;
276 const int typeLen = 1;
277 int from = 0;
278 for (; ;) {
279 int pos = m_finalBuilder.indexOf(prefix, from);
280 if (pos >= 0) {
281 from = pos;
282 ShaderItemType itemType = ShaderItemType(m_finalBuilder.mid(pos + prefixLen, typeLen).toInt());
283 switch (itemType) {
286 QByteArray block;
287 for (const QSSGShaderResourceMergeContext::InOutVar &var : mergeContext->m_inOutVars) {
288 if (var.stagesInputIn.testFlag(m_stage))
289 block += QString::asprintf("layout(location = %d) in %s %s;\n", var.location, var.type.constData(), var.name.constData()).toUtf8();
290 }
291 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
292 }
293 break;
295 {
296 QByteArray block;
297 for (const QSSGShaderResourceMergeContext::InOutVar &var : mergeContext->m_inOutVars) {
298 if (var.stagesInputIn.testFlag(m_stage))
299 block += QString::asprintf("layout(location = %d) in %s%s %s;\n", var.location, var.flat ? "flat " : "", var.type.constData(), var.name.constData()).toUtf8();
300 }
301 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
302 }
303 break;
305 {
306 QByteArray block;
307 for (const QSSGShaderResourceMergeContext::InOutVar &var : mergeContext->m_inOutVars) {
308 if (var.stageOutputFrom.testFlag(m_stage))
309 block += QString::asprintf("layout(location = %d) out %s%s %s;\n", var.location, var.flat ? "flat " : "", var.type.constData(), var.name.constData()).toUtf8();
310 }
311 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
312 }
313 break;
315 {
316 QByteArray block;
317
318 for (const auto &sampler : std::as_const(mergeContext->m_samplers)) {
319 addStartCond(block, sampler);
320 block += QString::asprintf("layout(binding = %d) uniform %s %s;\n",
321 sampler.binding,
322 sampler.type.constData(),
323 sampler.name.constData()).toUtf8();
324 addEndCond(block, sampler);
325 }
326
327 if (!mergeContext->m_uniformMembers.isEmpty()) {
328 // The layout (offsets of the members) of the main
329 // uniform block cannot be different in the stages.
330 // (f.ex., a given member must be assumed to be at same
331 // offset both in the vertex and the fragment shader)
332 // Therefore we output everything in all stages.
333 block += QByteArrayLiteral("layout(std140, binding = 0) uniform cbMain {\n");
334 for (auto iter = mergeContext->m_uniformMembers.cbegin(), end = mergeContext->m_uniformMembers.cend();
335 iter != end; ++iter)
336 {
337 addStartCond(block, iter.value());
338 block += QString::asprintf(" %s %s;\n", iter.value().type.constData(), iter.value().name.constData()).toUtf8();
339 addEndCond(block, iter.value());
340 }
341 // No instance name for this uniform block. This is
342 // essential since custom material shader code will not use
343 // any instance name prefix when accessing the members. So
344 // while the internal stuff for default/principled material
345 // could be fixed up with prefixing everything, custom
346 // materials cannot. So leave it out.
347 block += QByteArrayLiteral("};\n");
348 }
349 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
350 }
351 break;
352 default:
353 Q_UNREACHABLE_RETURN(m_finalBuilder);
354 }
355 } else {
356 break;
357 }
358 }
359
360 return m_finalBuilder;
361}
362
364{
365 if (!m_addedFunctions.contains(functionName)) {
366 m_addedFunctions.push_back(functionName);
367 QByteArray includeName;
368 includeName = "func" + functionName + ".glsllib";
369 addInclude(includeName);
370 }
371}
372
377
379{
380 // Link stages incoming to outgoing variables.
381 QSSGStageGeneratorBase *previous = nullptr;
382 quint32 theStageId = 1;
383 for (quint32 idx = 0, end = quint32(QSSGShaderGeneratorStage::StageCount); idx < end; ++idx, theStageId = theStageId << 1) {
384 QSSGStageGeneratorBase *thisStage = nullptr;
385 QSSGShaderGeneratorStage theStageEnum = static_cast<QSSGShaderGeneratorStage>(theStageId);
386 if ((m_enabledStages & theStageEnum)) {
387 thisStage = &internalGetStage(theStageEnum);
388 if (previous) {
389 previous->m_outgoing = &thisStage->m_incoming;
390 previous->m_flatOutgoing = &thisStage->m_flatIncoming;
391 }
392 previous = thisStage;
393 }
394 }
395}
396
397void QSSGProgramGenerator::beginProgram(QSSGShaderGeneratorStageFlags inEnabledStages)
398{
399 m_vs.begin(inEnabledStages);
400 m_fs.begin(inEnabledStages);
401 m_enabledStages = inEnabledStages;
402 linkStages();
403}
404
405QSSGShaderGeneratorStageFlags QSSGProgramGenerator::getEnabledStages() const { return m_enabledStages; }
406
408{
409 switch (inStage) {
411 return m_vs;
413 return m_fs;
414 default:
415 Q_ASSERT(false);
416 break;
417 }
418 return m_vs;
419}
420
422{
423 if ((m_enabledStages & inStage))
424 return &internalGetStage(inStage);
425 return nullptr;
426}
427
429{
431
432 for (const QSSGRenderShaderMetadata::Uniform &u : std::as_const(meta.uniforms)) {
433 if (u.type.startsWith(QByteArrayLiteral("sampler"))) {
434 if (u.multiview && mergeContext->viewCount >= 2) {
435 // 'sampler2D qt_screenTexture' becomes 'sampler2DArray qt_screenTextureArray'
436 mergeContext->registerSampler(u.type + QByteArrayLiteral("Array"), u.name + QByteArrayLiteral("Array"), u.condition, u.conditionName);
437 } else {
438 mergeContext->registerSampler(u.type, u.name, u.condition, u.conditionName);
439 }
440 } else {
441 if (u.multiview && mergeContext->viewCount >= 2) {
442 const QByteArray name = u.name + "[" + QByteArray::number(mergeContext->viewCount) + "]";
443 mergeContext->registerUniformMember(u.type, name, u.condition, u.conditionName);
444 } else {
445 mergeContext->registerUniformMember(u.type, u.name, u.condition, u.conditionName);
446 }
447 }
448 }
449
450 for (const QSSGRenderShaderMetadata::InputOutput &inputVar : std::as_const(meta.inputs)) {
451 if (inputVar.stage == stage)
452 mergeContext->registerInput(stage, inputVar.type, inputVar.name, inputVar.flat);
453 }
454
455 for (const QSSGRenderShaderMetadata::InputOutput &outputVar : std::as_const(meta.outputs)) {
456 if (outputVar.stage == stage)
457 mergeContext->registerOutput(stage, outputVar.type, outputVar.name, outputVar.flat);
458 }
459
460 for (auto it = mergeContext->m_inOutVars.cbegin(), end = mergeContext->m_inOutVars.cend(); it != end; ++it) {
461 if (it->stagesInputIn == int(QSSGShaderGeneratorStage::Fragment) && it->stageOutputFrom == 0)
462 qWarning("Fragment stage input %s is not output from vertex stage; expect errors.", it.key().constData());
463 }
464}
465
467 const QSSGShaderFeatures &inFeatureSet,
468 QSSGShaderLibraryManager &shaderLibraryManager,
469 QSSGShaderCache &theCache,
470 QSSGRhiShaderPipeline::StageFlags stageFlags,
471 int viewCount,
472 bool perTargetCompilation)
473{
474 // No stages enabled
475 if (((quint32)m_enabledStages) == 0) {
476 Q_ASSERT(false);
477 return nullptr;
478 }
479
481 mergeContext.viewCount = viewCount;
482
483 for (quint32 stageIdx = 0; stageIdx < static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
484 QSSGShaderGeneratorStage stageName = static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
485 if (m_enabledStages & stageName) {
486 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
487 theStage.buildShaderSourcePass1(&mergeContext);
488 }
489 }
490
491 for (quint32 stageIdx = 0; stageIdx < static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
492 QSSGShaderGeneratorStage stageName = static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
493 if (m_enabledStages & stageName) {
494 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
495 shaderLibraryManager.resolveIncludeFiles(theStage.m_finalBuilder, inMaterialInfoString);
496 registerShaderMetaDataFromSource(&mergeContext, theStage.m_finalBuilder, stageName);
497 }
498 }
499
500 for (quint32 stageIdx = 0; stageIdx < static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
501 QSSGShaderGeneratorStage stageName = static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
502 if (m_enabledStages & stageName) {
503 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
504 theStage.buildShaderSourcePass2(&mergeContext);
505 }
506 }
507
508 // qDebug("VERTEX:\n%s\n\n", m_vs.m_finalBuilder.constData());
509 // qDebug("FRAGMENT:\n%s\n\n", m_fs.m_finalBuilder.constData());
510
511 return theCache.compileForRhi(inMaterialInfoString,
514 inFeatureSet,
515 stageFlags,
516 viewCount,
517 perTargetCompilation);
518}
519
523
527
534
539
\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 &
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:339
Definition qlist.h:75
void push_back(parameter_type t)
Definition qlist.h:675
void clear()
Definition qlist.h:434
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
size_type remove(const Key &key)
Definition qmap.h:300
void clear()
Definition qmap.h:289
iterator begin()
Definition qmap.h:598
iterator end()
Definition qmap.h:602
QSSGRhiShaderPipelinePtr compileGeneratedRhiShader(const QByteArray &inMaterialInfoString, const QSSGShaderFeatures &inFeatureSet, QSSGShaderLibraryManager &shaderLibraryManager, QSSGShaderCache &theCache, QSSGRhiShaderPipeline::StageFlags stageFlags, int viewCount, bool perTargetCompilation)
void registerShaderMetaDataFromSource(QSSGShaderResourceMergeContext *mergeContext, const QByteArray &contents, QSSGShaderGeneratorStage stage)
QSSGShaderGeneratorStageFlags m_enabledStages
QSSGStageGeneratorBase * getStage(QSSGShaderGeneratorStage inStage)
QSSGStageGeneratorBase & internalGetStage(QSSGShaderGeneratorStage inStage)
QSSGShaderGeneratorStageFlags getEnabledStages() const
void beginProgram(QSSGShaderGeneratorStageFlags inEnabledStages=defaultFlags())
QSSGFragmentShaderGenerator m_fs
void resolveIncludeFiles(QByteArray &theReadBuffer, const QByteArray &inMaterialInfoString)
void registerSampler(const QByteArray &type, const QByteArray &name, QSSGRenderShaderMetadata::Uniform::Condition conditionType=QSSGRenderShaderMetadata::Uniform::None, const QByteArray &conditionName=QByteArray())
void registerInput(QSSGShaderGeneratorStage stage, const QByteArray &type, const QByteArray &name, bool flat=false)
void registerOutput(QSSGShaderGeneratorStage stage, const QByteArray &type, const QByteArray &name, bool flat=false)
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
const_iterator cbegin() const noexcept
Definition qset.h:138
iterator insert(const T &value)
Definition qset.h:155
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7263
const void * constData() const
Definition qvariant.h:451
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:166
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLuint sampler
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLbitfield flags
GLuint name
QT_BEGIN_NAMESPACE 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:50
QVBoxLayout * layout
bool contains(const AT &t) const noexcept
Definition qlist.h:45
QSSGShaderGeneratedProgramOutput(const char *vs, const char *fs)
void addShaderItemMap(ShaderItemType itemType, const TStrTableStrMap &itemMap, ShaderItemMapFlags flags={})
virtual void addFlatIncoming(const QByteArray &name, const QByteArray &type)
virtual void addFlatOutgoing(const QByteArray &name, const QByteArray &type)
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
virtual QSSGStageGeneratorBase & operator<<(const QByteArray &data)
\qmltype MapCircle \instantiates QDeclarativeCircleMapItem \inqmlmodule QtLocation