155void QSSGStageGeneratorBase::addShaderItemMap(QSSGStageGeneratorBase::ShaderItemType itemType,
const TStrTableStrMap &itemMap, ShaderItemMapFlags flags)
157 m_finalBuilder.append(
"\n");
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();
163 case ShaderItemType::VertexInput:
164 m_mergeContext->registerInput(QSSGShaderGeneratorStage::Vertex, iter.value(), name);
166 case ShaderItemType::Input:
167 m_mergeContext->registerInput(m_stage, iter.value(), name, flags.testFlag(ShaderItemMapFlag::Flat));
169 case ShaderItemType::Output:
170 m_mergeContext->registerOutput(m_stage, iter.value(), name, flags.testFlag(ShaderItemMapFlag::Flat));
172 case ShaderItemType::Uniform:
173 if (iter.value().startsWith(QByteArrayLiteral(
"sampler")))
174 m_mergeContext->registerSampler(iter.value(), name);
176 m_mergeContext->registerUniformMember(iter.value(), name);
179 qWarning(
"Unknown shader item %d",
int(itemType));
247void QSSGStageGeneratorBase::buildShaderSourcePass1(QSSGShaderResourceMergeContext *mergeContext)
249 m_mergeContext = mergeContext;
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");
258 addShaderIncomingMap();
259 addShaderUniformMap();
260 addShaderConstantBufferItemMap(
"uniform", m_constantBuffers, m_constantBufferParams);
261 addShaderOutgoingMap();
262 m_mergeContext =
nullptr;
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");
276 for (
const auto& value : std::as_const(m_addedTypeDeclarations)) {
277 m_finalBuilder.append(value);
278 m_finalBuilder.append(
"\n");
282 QList<QByteArray> sortedIncludes(m_includes.begin(), m_includes.end());
283 std::sort(sortedIncludes.begin(), sortedIncludes.end());
285 for (
const auto &include : sortedIncludes) {
286 m_finalBuilder.append(
"#include \"");
287 m_finalBuilder.append(include);
288 m_finalBuilder.append(
"\"\n");
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());
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());
311QByteArray QSSGStageGeneratorBase::buildShaderSourcePass2(QSSGShaderResourceMergeContext *mergeContext)
313 static const char *prefix =
"//@@";
314 const int prefixLen = 4;
315 const int typeLen = 1;
318 std::vector<
const QSSGShaderResourceMergeContext::Image *> locationDependentImages;
319 std::vector<
const QSSGShaderResourceMergeContext::Buffer *> locationDependentBuffers;
321 mergeContext->rearrangeResources();
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",
327 image.imgType.constData(),
328 QSSGBaseTypeHelpers::toString(image.qualifiers).constData(),
329 image.type.constData(),
330 image.name.constData()).toUtf8();
331 addEndCond(block, image);
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",
337 QSSGBaseTypeHelpers::toString(buffer.qualifiers).constData(),
338 buffer.name.constData(),
339 buffer.contentType.constData()).toUtf8();
340 addEndCond(block, buffer);
344 int pos = m_finalBuilder.indexOf(prefix, from);
347 ShaderItemType itemType = ShaderItemType(m_finalBuilder.mid(pos + prefixLen, typeLen).toInt());
349 case ShaderItemType::VertexInput:
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();
358 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
361 case ShaderItemType::Input:
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();
368 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
371 case ShaderItemType::Output:
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();
378 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
381 case ShaderItemType::Image:
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);
390 imageDeclaration(block, image);
393 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
395 case ShaderItemType::Uniform:
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",
403 sampler.type.constData(),
404 sampler.name.constData()).toUtf8();
405 addEndCond(block, sampler);
408 if (!mergeContext->m_uniformMembers.isEmpty()) {
414 block += QByteArrayLiteral(
"layout(std140, binding = 0) uniform cbMain {\n");
415 for (
auto iter = mergeContext->m_uniformMembers.cbegin(), end = mergeContext->m_uniformMembers.cend();
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());
428 block += QByteArrayLiteral(
"};\n");
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);
437 bufferDeclaration(block, buffer);
441 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
445 Q_UNREACHABLE_RETURN(m_finalBuilder);
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);
455 imageDeclaration(block, *image);
456 m_finalBuilder.replace(index, atname.length(), block);
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);
462 bufferDeclaration(block, *buffer);
463 m_finalBuilder.replace(index, atname.length(), block);
466 return m_finalBuilder;
565void QSSGProgramGenerator::registerShaderMetaDataFromSource(QSSGShaderResourceMergeContext *mergeContext,
const QByteArray &contents, QSSGShaderGeneratorStage stage)
567 QSSGRenderShaderMetadata::ShaderMetaData meta = QSSGRenderShaderMetadata::getShaderMetaData(contents);
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) {
573 mergeContext->registerSampler(u.type + QByteArrayLiteral(
"Array"), u.name + QByteArrayLiteral(
"Array"), u.condition, u.conditionName);
575 mergeContext->registerSampler(u.type, u.name, u.condition, u.conditionName);
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);
582 mergeContext->registerUniformMember(u.type, u.name, u.condition, u.conditionName);
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);
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);
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);
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());
608QSSGRhiShaderPipelinePtr QSSGProgramGenerator::compileGeneratedRhiShader(
const QByteArray &inMaterialInfoString,
609 const QSSGShaderFeatures &inFeatureSet,
610 QSSGShaderLibraryManager &shaderLibraryManager,
611 QSSGShaderCache &theCache,
612 QSSGRhiShaderPipeline::StageFlags stageFlags,
613 const QSSGUserShaderAugmentation &shaderAugmentation,
615 bool perTargetCompilation,
616 const QByteArray &inCacheKey)
619 if (((quint32)m_enabledStages) == 0) {
624 QSSGShaderResourceMergeContext mergeContext;
625 mergeContext.viewCount = viewCount;
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);
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);
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);
652 QSSGShaderResourceMergeContext::setAdditionalBufferAmount(0);
656 if (m_enabledStages & QSSGShaderGeneratorStage::Compute) {
657 QSSG_ASSERT(inFeatureSet.isNull(),
return {});
658 return theCache.compileComputePipeline(inMaterialInfoString,
661 perTargetCompilation,
664 return theCache.compileGraphicsPipeline(inMaterialInfoString,
671 perTargetCompilation,