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
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// Qt-Security score:significant reason:default
5
6
8
9#include <QtQuick3DUtils/private/qssgutils_p.h>
10
12#include <QtQuick3DRuntimeRender/private/qssgrendershaderlibrarymanager_p.h>
13#include <QtQuick3DRuntimeRender/private/qssgshaderresourcemergecontext_p.h>
14
16
17template<typename T>
18static inline void addStartCond(QByteArray &block, const T &var)
19{
20 // must use #if not #ifdef, as we test for the value, because featureset flags
21 // are written out even when 0, think for example #define QSSG_ENABLE_SSM 0
22 if (var.conditionType == QSSGRenderShaderMetadata::Uniform::Regular)
23 block += QString::asprintf("#if %s\n", var.conditionName.constData()).toUtf8();
24 else if (var.conditionType == QSSGRenderShaderMetadata::Uniform::Negated)
25 block += QString::asprintf("#if !%s\n", var.conditionName.constData()).toUtf8();
26}
27
28template<typename T>
29static inline void addEndCond(QByteArray &block, const T &var)
30{
31 if (var.conditionType != QSSGRenderShaderMetadata::Uniform::None)
32 block += QByteArrayLiteral("#endif\n");
33}
34
35int QSSGShaderResourceMergeContext::s_additionalBuffers = 0;
36
38{
39 // never null; so safe to call strlen on.
40 const char *m_vertexShader{ "" };
41 const char *m_fragmentShader{ "" };
42
44 QSSGShaderGeneratedProgramOutput(const char *vs, const char *fs)
46 {
47 }
48};
49
50QSSGStageGeneratorBase::QSSGStageGeneratorBase(QSSGShaderGeneratorStage inStage)
51
52 : m_stage(inStage)
53{
54}
55
56void QSSGStageGeneratorBase::begin(QSSGShaderGeneratorStageFlags inEnabledStages)
57{
58 m_incoming.clear();
59 m_outgoing = nullptr;
60 m_flatIncoming.clear();
61 m_flatOutgoing = nullptr;
62 m_includes.clear();
63 m_uniforms.clear();
64 m_uniformArrays.clear();
65 m_constantBuffers.clear();
66 m_constantBufferParams.clear();
67 m_codeBuilder.clear();
68 m_finalBuilder.clear();
69 m_enabledStages = inEnabledStages;
70 m_addedFunctions.clear();
71 m_addedDefinitions.clear();
72 m_addedTypeDeclarations.clear();
73 m_prefixes.clear();
74 m_images.clear();
75 m_buffers.clear();
76 // the shared buffers will be cleared elsewhere.
77}
78
79void QSSGStageGeneratorBase::addIncoming(const QByteArray &name, const QByteArray &type)
80{
81 m_incoming.insert(name, type);
82 m_flatIncoming.remove(name);
83}
84
85void QSSGStageGeneratorBase::addOutgoing(const QByteArray &name, const QByteArray &type)
86{
87 if (m_outgoing == nullptr) {
88 Q_ASSERT(false);
89 return;
90 }
91 m_outgoing->insert(name, type);
92 if (m_flatOutgoing)
93 m_flatOutgoing->remove(name);
94}
95
96void QSSGStageGeneratorBase::addFlatIncoming(const QByteArray &name, const QByteArray &type)
97{
98 m_flatIncoming.insert(name, type);
99 m_incoming.remove(name);
100}
101
102void QSSGStageGeneratorBase::addFlatOutgoing(const QByteArray &name, const QByteArray &type)
103{
104 if (m_flatOutgoing == nullptr) {
105 Q_ASSERT(false);
106 return;
107 }
108 m_flatOutgoing->insert(name, type);
109 if (m_outgoing)
110 m_outgoing->remove(name);
111}
112
113void QSSGStageGeneratorBase::addUniform(const QByteArray &name, const QByteArray &type)
114{
115 m_uniforms.insert(name, type);
116}
117
118void QSSGStageGeneratorBase::addUniformArray(const QByteArray &name, const QByteArray &type, quint32 size)
119{
120 m_uniformArrays.insert(name, qMakePair(size, type));
121}
122
123void QSSGStageGeneratorBase::addConstantBuffer(const QByteArray &name, const QByteArray &layout)
124{
125 m_constantBuffers.insert(name, layout);
126}
127
128void QSSGStageGeneratorBase::addConstantBufferParam(const QByteArray &cbName, const QByteArray &paramName, const QByteArray &type)
129{
130 TParamPair theParamPair(paramName, type);
131 TConstantBufferParamPair theBufferParamPair(cbName, theParamPair);
132 m_constantBufferParams.push_back(theBufferParamPair);
133}
134
135QSSGStageGeneratorBase &QSSGStageGeneratorBase::operator<<(const QByteArray &data)
136{
137 m_codeBuilder.append(data);
138 return *this;
139}
140
141void QSSGStageGeneratorBase::append(const QByteArray &data)
142{
143 m_codeBuilder.append(data);
144 m_codeBuilder.append("\n");
145}
146
147QSSGShaderGeneratorStage QSSGStageGeneratorBase::stage() const { return m_stage; }
148
149void QSSGStageGeneratorBase::addShaderPass2Marker(QSSGStageGeneratorBase::ShaderItemType itemType)
150{
151 Q_ASSERT(m_mergeContext);
152 m_finalBuilder.append(QByteArrayLiteral("//@@") + QByteArray::number(int(itemType)) + QByteArrayLiteral("\n"));
153}
154
155void QSSGStageGeneratorBase::addShaderItemMap(QSSGStageGeneratorBase::ShaderItemType itemType, const TStrTableStrMap &itemMap, ShaderItemMapFlags flags)
156{
157 m_finalBuilder.append("\n");
158
159 Q_ASSERT(m_mergeContext);
160 for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
161 const QByteArray name = iter.key();
162 switch (itemType) {
163 case ShaderItemType::VertexInput:
164 m_mergeContext->registerInput(QSSGShaderGeneratorStage::Vertex, iter.value(), name);
165 break;
166 case ShaderItemType::Input:
167 m_mergeContext->registerInput(m_stage, iter.value(), name, flags.testFlag(ShaderItemMapFlag::Flat));
168 break;
169 case ShaderItemType::Output:
170 m_mergeContext->registerOutput(m_stage, iter.value(), name, flags.testFlag(ShaderItemMapFlag::Flat));
171 break;
172 case ShaderItemType::Uniform:
173 if (iter.value().startsWith(QByteArrayLiteral("sampler")))
174 m_mergeContext->registerSampler(iter.value(), name);
175 else
176 m_mergeContext->registerUniformMember(iter.value(), name);
177 break;
178 default:
179 qWarning("Unknown shader item %d", int(itemType));
180 Q_UNREACHABLE();
181 }
182 }
183}
184
185void QSSGStageGeneratorBase::addShaderIncomingMap()
186{
187 addShaderItemMap(ShaderItemType::VertexInput, m_incoming);
188 addShaderPass2Marker(ShaderItemType::VertexInput);
189}
190
191void QSSGStageGeneratorBase::addShaderUniformMap()
192{
193 addShaderItemMap(ShaderItemType::Uniform, m_uniforms);
194 for (TStrTableSizedStrMap::const_iterator iter = m_uniformArrays.cbegin(), end = m_uniformArrays.cend(); iter != end; ++iter) {
195 const QByteArray name = iter.key() +
196 "[" + QByteArray::number(iter.value().first) + "]";
197 if (iter.value().second.startsWith(QByteArrayLiteral("sampler")))
198 m_mergeContext->registerSampler(iter.value().second, name);
199 else
200 m_mergeContext->registerUniformMember(iter.value().second, name);
201 }
202 addShaderPass2Marker(ShaderItemType::Uniform);
203 addShaderPass2Marker(ShaderItemType::Image);
204}
205
206void QSSGStageGeneratorBase::addShaderOutgoingMap()
207{
208 if (m_outgoing)
209 addShaderItemMap(ShaderItemType::Output, *m_outgoing);
210 if (m_flatOutgoing)
211 addShaderItemMap(ShaderItemType::Output, *m_flatOutgoing, ShaderItemMapFlag::Flat);
212
213 addShaderPass2Marker(ShaderItemType::Output);
214}
215
216void QSSGStageGeneratorBase::addShaderConstantBufferItemMap(const QByteArray &itemType, const TStrTableStrMap &cbMap, TConstantBufferParamArray cbParamsArray)
217{
218 m_finalBuilder.append("\n");
219
220 // iterate over all constant buffers
221 for (TStrTableStrMap::const_iterator iter = cbMap.begin(), end = cbMap.end(); iter != end; ++iter) {
222 m_finalBuilder.append(iter.value());
223 m_finalBuilder.append(" ");
224 m_finalBuilder.append(itemType);
225 m_finalBuilder.append(" ");
226 m_finalBuilder.append(iter.key());
227 m_finalBuilder.append(" {\n");
228 // iterate over all param entries and add match
229 for (TConstantBufferParamArray::const_iterator iter1 = cbParamsArray.cbegin(), end = cbParamsArray.cend(); iter1 != end;
230 ++iter1) {
231 if (iter1->first == iter.key()) {
232 m_finalBuilder.append(iter1->second.second);
233 m_finalBuilder.append(" ");
234 m_finalBuilder.append(iter1->second.first);
235 m_finalBuilder.append(";\n");
236 }
237 }
238
239 m_finalBuilder.append("};\n");
240 }
241}
242
243void QSSGStageGeneratorBase::appendShaderCode() { m_finalBuilder.append(m_codeBuilder); }
244
245void QSSGStageGeneratorBase::addInclude(const QByteArray &name) { m_includes.insert(name); }
246
247void QSSGStageGeneratorBase::buildShaderSourcePass1(QSSGShaderResourceMergeContext *mergeContext)
248{
249 m_mergeContext = mergeContext;
250
251 if (m_prefixes.size())
252 m_finalBuilder.append("\n");
253 for (const auto &prefix : std::as_const(m_prefixes)) {
254 m_finalBuilder.append(prefix);
255 m_finalBuilder.append("\n");
256 }
257
258 addShaderIncomingMap();
259 addShaderUniformMap();
260 addShaderConstantBufferItemMap("uniform", m_constantBuffers, m_constantBufferParams);
261 addShaderOutgoingMap();
262 m_mergeContext = nullptr;
263
264 for (auto iter = m_addedDefinitions.begin(), end = m_addedDefinitions.end();
265 iter != end; ++iter) {
266 m_finalBuilder.append("#ifndef ");
267 m_finalBuilder.append(iter.key());
268 m_finalBuilder.append("\n");
269 m_finalBuilder.append("#define ");
270 m_finalBuilder.append(iter.key());
271 if (!iter.value().isEmpty())
272 m_finalBuilder.append(QByteArrayLiteral(" ") + iter.value());
273 m_finalBuilder.append("\n#endif\n");
274 }
275
276 for (const auto& value : std::as_const(m_addedTypeDeclarations)) {
277 m_finalBuilder.append(value);
278 m_finalBuilder.append("\n");
279 }
280
281 // Sort for deterministic shader text when printing/debugging
282 QList<QByteArray> sortedIncludes(m_includes.begin(), m_includes.end());
283 std::sort(sortedIncludes.begin(), sortedIncludes.end());
284
285 for (const auto &include : sortedIncludes) {
286 m_finalBuilder.append("#include \"");
287 m_finalBuilder.append(include);
288 m_finalBuilder.append("\"\n");
289 }
290
291 for (const auto &image : std::as_const(m_images)) {
292 auto strcond = QString::fromUtf8(image.condition);
293 auto condition = QSSGRenderShaderMetadata::Uniform::conditionFromString(strcond);
294 if (condition == QSSGRenderShaderMetadata::Uniform::Negated)
295 strcond = strcond.mid(1);
296 mergeContext->registerImage(m_stage, image.imageType, image.name, image.format, image.qualifiers,
297 condition, strcond.toUtf8());
298 }
299 for (const auto &buffer : std::as_const(m_buffers)) {
300 auto strcond = QString::fromUtf8(buffer.condition);
301 auto condition = QSSGRenderShaderMetadata::Uniform::conditionFromString(strcond);
302 if (condition == QSSGRenderShaderMetadata::Uniform::Negated)
303 strcond = strcond.mid(1);
304 mergeContext->registerBuffer(m_stage, buffer.contentType, buffer.name, buffer.qualifiers,
305 condition, strcond.toUtf8());
306 }
307
308 appendShaderCode();
309}
310
311QByteArray QSSGStageGeneratorBase::buildShaderSourcePass2(QSSGShaderResourceMergeContext *mergeContext)
312{
313 static const char *prefix = "//@@";
314 const int prefixLen = 4;
315 const int typeLen = 1;
316 int from = 0;
317
318 std::vector<const QSSGShaderResourceMergeContext::Image *> locationDependentImages;
319 std::vector<const QSSGShaderResourceMergeContext::Buffer *> locationDependentBuffers;
320
321 mergeContext->rearrangeResources();
322
323 const auto imageDeclaration = [](QByteArray &block, const QSSGShaderResourceMergeContext::Image &image) {
324 addStartCond(block, image);
325 block += QString::asprintf("layout(binding = %d, %s) uniform %s %s %s;\n",
326 image.binding,
327 image.imgType.constData(),
328 QSSGBaseTypeHelpers::toString(image.qualifiers).constData(),
329 image.type.constData(),
330 image.name.constData()).toUtf8();
331 addEndCond(block, image);
332 };
333 const auto bufferDeclaration = [](QByteArray &block, const QSSGShaderResourceMergeContext::Buffer &buffer) {
334 addStartCond(block, buffer);
335 block += QString::asprintf("layout(std430, binding = %d) %s buffer %s {\n %s\n};\n",
336 buffer.binding,
337 QSSGBaseTypeHelpers::toString(buffer.qualifiers).constData(),
338 buffer.name.constData(),
339 buffer.contentType.constData()).toUtf8();
340 addEndCond(block, buffer);
341 };
342
343 for (; ;) {
344 int pos = m_finalBuilder.indexOf(prefix, from);
345 if (pos >= 0) {
346 from = pos;
347 ShaderItemType itemType = ShaderItemType(m_finalBuilder.mid(pos + prefixLen, typeLen).toInt());
348 switch (itemType) {
349 case ShaderItemType::VertexInput:
350 {
351 QByteArray block;
352 if (m_stage == QSSGShaderGeneratorStage::Vertex) {
353 for (const QSSGShaderResourceMergeContext::InOutVar &var : std::as_const(mergeContext->m_inOutVars)) {
354 if (var.stagesInputIn.testFlag(m_stage))
355 block += QString::asprintf("layout(location = %d) in %s %s;\n", var.location, var.type.constData(), var.name.constData()).toUtf8();
356 }
357 }
358 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
359 }
360 break;
361 case ShaderItemType::Input:
362 {
363 QByteArray block;
364 for (const QSSGShaderResourceMergeContext::InOutVar &var : std::as_const(mergeContext->m_inOutVars)) {
365 if (var.stagesInputIn.testFlag(m_stage))
366 block += QString::asprintf("layout(location = %d) in %s%s %s;\n", var.location, var.flat ? "flat " : "", var.type.constData(), var.name.constData()).toUtf8();
367 }
368 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
369 }
370 break;
371 case ShaderItemType::Output:
372 {
373 QByteArray block;
374 for (const QSSGShaderResourceMergeContext::InOutVar &var : std::as_const(mergeContext->m_inOutVars)) {
375 if (var.stageOutputFrom.testFlag(m_stage))
376 block += QString::asprintf("layout(location = %d) out %s%s %s;\n", var.location, var.flat ? "flat " : "", var.type.constData(), var.name.constData()).toUtf8();
377 }
378 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
379 }
380 break;
381 case ShaderItemType::Image:
382 {
383 QByteArray block;
384 for (const auto &image : std::as_const(mergeContext->m_images)) {
385 if (image.stages & m_stage) {
386 const QByteArray atname = QByteArrayLiteral("@") + image.name + QByteArrayLiteral("@");
387 if (m_finalBuilder.indexOf(atname) >= 0)
388 locationDependentImages.push_back(&image);
389 else
390 imageDeclaration(block, image);
391 }
392 }
393 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
394 } break;
395 case ShaderItemType::Uniform:
396 {
397 QByteArray block;
398
399 for (const auto &sampler : std::as_const(mergeContext->m_samplers)) {
400 addStartCond(block, sampler);
401 block += QString::asprintf("layout(binding = %d) uniform %s %s;\n",
402 sampler.binding,
403 sampler.type.constData(),
404 sampler.name.constData()).toUtf8();
405 addEndCond(block, sampler);
406 }
407
408 if (!mergeContext->m_uniformMembers.isEmpty()) {
409 // The layout (offsets of the members) of the main
410 // uniform block cannot be different in the stages.
411 // (f.ex., a given member must be assumed to be at same
412 // offset both in the vertex and the fragment shader)
413 // Therefore we output everything in all stages.
414 block += QByteArrayLiteral("layout(std140, binding = 0) uniform cbMain {\n");
415 for (auto iter = mergeContext->m_uniformMembers.cbegin(), end = mergeContext->m_uniformMembers.cend();
416 iter != end; ++iter)
417 {
418 addStartCond(block, iter.value());
419 block += QString::asprintf(" %s %s;\n", iter.value().type.constData(), iter.value().name.constData()).toUtf8();
420 addEndCond(block, iter.value());
421 }
422 // No instance name for this uniform block. This is
423 // essential since custom material shader code will not use
424 // any instance name prefix when accessing the members. So
425 // while the internal stuff for default/principled material
426 // could be fixed up with prefixing everything, custom
427 // materials cannot. So leave it out.
428 block += QByteArrayLiteral("};\n");
429 }
430
431 for (const auto &buffer : std::as_const(mergeContext->m_buffers)) {
432 if (buffer.stages & m_stage) {
433 const QByteArray atname = QByteArrayLiteral("@") + buffer.name + QByteArrayLiteral("@");
434 if (m_finalBuilder.indexOf(atname, 0) >= 0)
435 locationDependentBuffers.push_back(&buffer);
436 else
437 bufferDeclaration(block, buffer);
438 }
439 }
440
441 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
442 }
443 break;
444 default:
445 Q_UNREACHABLE_RETURN(m_finalBuilder);
446 }
447 } else {
448 break;
449 }
450 }
451 for (const auto *image : std::as_const(locationDependentImages)) {
452 const QByteArray atname = QByteArrayLiteral("@") + image->name + QByteArrayLiteral("@");
453 qsizetype index = m_finalBuilder.indexOf(atname, 0);
454 QByteArray block;
455 imageDeclaration(block, *image);
456 m_finalBuilder.replace(index, atname.length(), block);
457 }
458 for (const auto *buffer : std::as_const(locationDependentBuffers)) {
459 const QByteArray atname = QByteArrayLiteral("@") + buffer->name + QByteArrayLiteral("@");
460 qsizetype index = m_finalBuilder.indexOf(atname, 0);
461 QByteArray block;
462 bufferDeclaration(block, *buffer);
463 m_finalBuilder.replace(index, atname.length(), block);
464 }
465
466 return m_finalBuilder;
467}
468
469void QSSGStageGeneratorBase::addFunction(const QByteArray &functionName)
470{
471 if (!m_addedFunctions.contains(functionName)) {
472 m_addedFunctions.push_back(functionName);
473 QByteArray includeName;
474 includeName = "func" + functionName + ".glsllib";
475 addInclude(includeName);
476 }
477}
478
479void QSSGStageGeneratorBase::addPrefix(const QByteArray &data)
480{
481 m_prefixes.append(data);
482}
483
484void QSSGStageGeneratorBase::addImage(const QByteArray &name, const QByteArray &imageType,
485 const QByteArray &format, QSSGMemoryQualifiers qualifiers,
486 const QByteArray &condition)
487{
488 m_images.emplace_back(name, imageType, format, qualifiers, condition);
489}
490
491void QSSGStageGeneratorBase::addBuffer(const QByteArray &name, const QByteArray &contentType,
492 QSSGMemoryQualifiers qualifiers, const QByteArray &condition)
493{
494 m_buffers.emplace_back(name, contentType, qualifiers, condition);
495}
496
497void QSSGStageGeneratorBase::addDefinition(const QByteArray &name, const QByteArray &value)
498{
499 m_addedDefinitions.insert(name, value);
500}
501
502void QSSGStageGeneratorBase::addTypeDeclaration(const QByteArray &typeName, const QByteArray &snippet)
503{
504 if (snippet.isEmpty())
505 return;
506 m_addedTypeDeclarations.insert(typeName, snippet);
507}
508
509void QSSGProgramGenerator::linkStages()
510{
511 // Link stages incoming to outgoing variables.
512 QSSGStageGeneratorBase *previous = nullptr;
513 quint32 theStageId = 1;
514 for (quint32 idx = 0, end = quint32(QSSGShaderGeneratorStage::StageCount); idx < end; ++idx, theStageId = theStageId << 1) {
515 QSSGStageGeneratorBase *thisStage = nullptr;
516 QSSGShaderGeneratorStage theStageEnum = static_cast<QSSGShaderGeneratorStage>(theStageId);
517 if ((m_enabledStages & theStageEnum)) {
518 thisStage = &internalGetStage(theStageEnum);
519 if (previous) {
520 previous->m_outgoing = &thisStage->m_incoming;
521 previous->m_flatOutgoing = &thisStage->m_flatIncoming;
522 }
523 previous = thisStage;
524 }
525 }
526}
527
528void QSSGProgramGenerator::beginProgram(QSSGShaderGeneratorStageFlags inEnabledStages)
529{
530 // If compute is enabled it must be the only stage
531 QSSG_ASSERT(!inEnabledStages.testFlag(QSSGShaderGeneratorStage::Compute)
532 || inEnabledStages == QSSGShaderGeneratorStage::Compute, m_enabledStages = {}; return);
533 m_vs.begin(inEnabledStages);
534 m_fs.begin(inEnabledStages);
535 m_cs.begin(inEnabledStages);
536 m_enabledStages = inEnabledStages;
537 linkStages();
538}
539
540QSSGShaderGeneratorStageFlags QSSGProgramGenerator::getEnabledStages() const { return m_enabledStages; }
541
542QSSGStageGeneratorBase &QSSGProgramGenerator::internalGetStage(QSSGShaderGeneratorStage inStage)
543{
544 switch (inStage) {
545 case QSSGShaderGeneratorStage::Vertex:
546 return m_vs;
547 case QSSGShaderGeneratorStage::Fragment:
548 return m_fs;
549 case QSSGShaderGeneratorStage::Compute:
550 return m_cs;
551 default:
552 Q_ASSERT(false);
553 break;
554 }
555 return m_vs;
556}
557
558QSSGStageGeneratorBase *QSSGProgramGenerator::getStage(QSSGShaderGeneratorStage inStage)
559{
560 if ((m_enabledStages & inStage))
561 return &internalGetStage(inStage);
562 return nullptr;
563}
564
565void QSSGProgramGenerator::registerShaderMetaDataFromSource(QSSGShaderResourceMergeContext *mergeContext, const QByteArray &contents, QSSGShaderGeneratorStage stage)
566{
567 QSSGRenderShaderMetadata::ShaderMetaData meta = QSSGRenderShaderMetadata::getShaderMetaData(contents);
568
569 for (const QSSGRenderShaderMetadata::Uniform &u : std::as_const(meta.uniforms)) {
570 if (u.type.startsWith(QByteArrayLiteral("sampler"))) {
571 if (u.multiview && mergeContext->viewCount >= 2) {
572 // 'sampler2D qt_screenTexture' becomes 'sampler2DArray qt_screenTextureArray'
573 mergeContext->registerSampler(u.type + QByteArrayLiteral("Array"), u.name + QByteArrayLiteral("Array"), u.condition, u.conditionName);
574 } else {
575 mergeContext->registerSampler(u.type, u.name, u.condition, u.conditionName);
576 }
577 } else {
578 if (u.multiview && mergeContext->viewCount >= 2) {
579 const QByteArray name = u.name + "[" + QByteArray::number(mergeContext->viewCount) + "]";
580 mergeContext->registerUniformMember(u.type, name, u.condition, u.conditionName);
581 } else {
582 mergeContext->registerUniformMember(u.type, u.name, u.condition, u.conditionName);
583 }
584 }
585 }
586
587 for (const QSSGRenderShaderMetadata::Image &img : std::as_const(meta.images))
588 mergeContext->registerImage(stage, img.type, img.name, img.imageType, img.qualifiers, img.condition, img.conditionName);
589 for (const QSSGRenderShaderMetadata::Buffer &buf : std::as_const(meta.buffers))
590 mergeContext->registerBuffer(stage, buf.contentType, buf.name, buf.qualifiers, buf.condition, buf.conditionName);
591
592 for (const QSSGRenderShaderMetadata::InputOutput &inputVar : std::as_const(meta.inputs)) {
593 if (inputVar.stage == stage)
594 mergeContext->registerInput(stage, inputVar.type, inputVar.name, inputVar.flat);
595 }
596
597 for (const QSSGRenderShaderMetadata::InputOutput &outputVar : std::as_const(meta.outputs)) {
598 if (outputVar.stage == stage)
599 mergeContext->registerOutput(stage, outputVar.type, outputVar.name, outputVar.flat);
600 }
601
602 for (auto it = mergeContext->m_inOutVars.cbegin(), end = mergeContext->m_inOutVars.cend(); it != end; ++it) {
603 if (it->stagesInputIn == int(QSSGShaderGeneratorStage::Fragment) && it->stageOutputFrom == 0)
604 qWarning("Fragment stage input %s is not output from vertex stage; expect errors.", it.key().constData());
605 }
606}
607
608QSSGRhiShaderPipelinePtr QSSGProgramGenerator::compileGeneratedRhiShader(const QByteArray &inMaterialInfoString,
609 const QSSGShaderFeatures &inFeatureSet,
610 QSSGShaderLibraryManager &shaderLibraryManager,
611 QSSGShaderCache &theCache,
612 QSSGRhiShaderPipeline::StageFlags stageFlags,
613 const QSSGUserShaderAugmentation &shaderAugmentation,
614 int viewCount,
615 bool perTargetCompilation,
616 const QByteArray &inCacheKey)
617{
618 // No stages enabled
619 if (((quint32)m_enabledStages) == 0) {
620 Q_ASSERT(false);
621 return nullptr;
622 }
623
624 QSSGShaderResourceMergeContext mergeContext;
625 mergeContext.viewCount = viewCount;
626
627 for (quint32 stageIdx = 0; stageIdx < static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
628 QSSGShaderGeneratorStage stageName = static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
629 if (m_enabledStages & stageName) {
630 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
631 theStage.buildShaderSourcePass1(&mergeContext);
632 }
633 }
634
635 for (quint32 stageIdx = 0; stageIdx < static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
636 QSSGShaderGeneratorStage stageName = static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
637 if (m_enabledStages & stageName) {
638 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
639 shaderLibraryManager.resolveIncludeFiles(theStage.m_finalBuilder, inMaterialInfoString);
640 registerShaderMetaDataFromSource(&mergeContext, theStage.m_finalBuilder, stageName);
641 }
642 }
643
644 for (quint32 stageIdx = 0; stageIdx < static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
645 QSSGShaderGeneratorStage stageName = static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
646 if (m_enabledStages & stageName) {
647 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
648 theStage.buildShaderSourcePass2(&mergeContext);
649 }
650 }
651
652 QSSGShaderResourceMergeContext::setAdditionalBufferAmount(0);
653
654 // qDebug("VERTEX:\n%s\n\n", m_vs.m_finalBuilder.constData());
655 // qDebug("FRAGMENT:\n%s\n\n", m_fs.m_finalBuilder.constData());
656 if (m_enabledStages & QSSGShaderGeneratorStage::Compute) {
657 QSSG_ASSERT(inFeatureSet.isNull(), return {});
658 return theCache.compileComputePipeline(inMaterialInfoString,
659 m_cs.m_finalBuilder,
660 viewCount,
661 perTargetCompilation,
662 inCacheKey);
663 }
664 return theCache.compileGraphicsPipeline(inMaterialInfoString,
665 m_vs.m_finalBuilder,
666 m_fs.m_finalBuilder,
667 inFeatureSet,
668 stageFlags,
669 shaderAugmentation,
670 viewCount,
671 perTargetCompilation,
672 inCacheKey);
673}
674
675QSSGVertexShaderGenerator::QSSGVertexShaderGenerator()
676 : QSSGStageGeneratorBase(QSSGShaderGeneratorStage::Vertex)
677{}
678
679QSSGFragmentShaderGenerator::QSSGFragmentShaderGenerator()
680 : QSSGStageGeneratorBase(QSSGShaderGeneratorStage::Fragment)
681{}
682
683QSSGComputeShaderGenerator::QSSGComputeShaderGenerator()
684 : QSSGStageGeneratorBase(QSSGShaderGeneratorStage::Compute)
685{}
686
687void QSSGFragmentShaderGenerator::addShaderIncomingMap()
688{
689 addShaderItemMap(ShaderItemType::Input, m_incoming);
690 addShaderItemMap(ShaderItemType::Input, m_flatIncoming, ShaderItemMapFlag::Flat);
691 addShaderPass2Marker(ShaderItemType::Input);
692}
693
694void QSSGFragmentShaderGenerator::addShaderOutgoingMap()
695{
696 addShaderPass2Marker(ShaderItemType::Output);
697}
698
699QT_END_NAMESPACE
Combined button and popup list for selecting options.
static void addEndCond(QByteArray &block, const T &var)
QSSGShaderGeneratedProgramOutput(const char *vs, const char *fs)