153void QSSGStageGeneratorBase::addShaderItemMap(QSSGStageGeneratorBase::ShaderItemType itemType,
const TStrTableStrMap &itemMap, ShaderItemMapFlags flags)
155 m_finalBuilder.append(
"\n");
157 Q_ASSERT(m_mergeContext);
158 for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
159 const QByteArray name = iter.key();
161 case ShaderItemType::VertexInput:
162 m_mergeContext->registerInput(QSSGShaderGeneratorStage::Vertex, iter.value(), name);
164 case ShaderItemType::Input:
165 m_mergeContext->registerInput(m_stage, iter.value(), name, flags.testFlag(ShaderItemMapFlag::Flat));
167 case ShaderItemType::Output:
168 m_mergeContext->registerOutput(m_stage, iter.value(), name, flags.testFlag(ShaderItemMapFlag::Flat));
170 case ShaderItemType::Uniform:
171 if (iter.value().startsWith(QByteArrayLiteral(
"sampler")))
172 m_mergeContext->registerSampler(iter.value(), name);
174 m_mergeContext->registerUniformMember(iter.value(), name);
177 qWarning(
"Unknown shader item %d",
int(itemType));
189void QSSGStageGeneratorBase::addShaderUniformMap()
191 addShaderItemMap(ShaderItemType::Uniform, m_uniforms);
192 for (TStrTableSizedStrMap::const_iterator iter = m_uniformArrays.begin(), end = m_uniformArrays.end(); iter != end; ++iter) {
193 const QByteArray name = iter.key() +
194 "[" + QByteArray::number(iter.value().first) +
"]";
195 if (iter.value().second.startsWith(QByteArrayLiteral(
"sampler")))
196 m_mergeContext->registerSampler(iter.value().second, name);
198 m_mergeContext->registerUniformMember(iter.value().second, name);
200 addShaderPass2Marker(ShaderItemType::Uniform);
201 addShaderPass2Marker(ShaderItemType::Image);
214void QSSGStageGeneratorBase::addShaderConstantBufferItemMap(
const QByteArray &itemType,
const TStrTableStrMap &cbMap, TConstantBufferParamArray cbParamsArray)
216 m_finalBuilder.append(
"\n");
219 for (TStrTableStrMap::const_iterator iter = cbMap.begin(), end = cbMap.end(); iter != end; ++iter) {
220 m_finalBuilder.append(iter.value());
221 m_finalBuilder.append(
" ");
222 m_finalBuilder.append(itemType);
223 m_finalBuilder.append(
" ");
224 m_finalBuilder.append(iter.key());
225 m_finalBuilder.append(
" {\n");
227 for (TConstantBufferParamArray::const_iterator iter1 = cbParamsArray.begin(), end = cbParamsArray.end(); iter1 != end;
229 if (iter1->first == iter.key()) {
230 m_finalBuilder.append(iter1->second.second);
231 m_finalBuilder.append(
" ");
232 m_finalBuilder.append(iter1->second.first);
233 m_finalBuilder.append(
";\n");
237 m_finalBuilder.append(
"};\n");
245void QSSGStageGeneratorBase::buildShaderSourcePass1(QSSGShaderResourceMergeContext *mergeContext)
247 m_mergeContext = mergeContext;
249 if (m_prefixes.size())
250 m_finalBuilder.append(
"\n");
251 for (
const auto &prefix : std::as_const(m_prefixes)) {
252 m_finalBuilder.append(prefix);
253 m_finalBuilder.append(
"\n");
256 addShaderIncomingMap();
257 addShaderUniformMap();
258 addShaderConstantBufferItemMap(
"uniform", m_constantBuffers, m_constantBufferParams);
259 addShaderOutgoingMap();
260 m_mergeContext =
nullptr;
262 for (
auto iter = m_addedDefinitions.begin(), end = m_addedDefinitions.end();
263 iter != end; ++iter) {
264 m_finalBuilder.append(
"#ifndef ");
265 m_finalBuilder.append(iter.key());
266 m_finalBuilder.append(
"\n");
267 m_finalBuilder.append(
"#define ");
268 m_finalBuilder.append(iter.key());
269 if (!iter.value().isEmpty())
270 m_finalBuilder.append(QByteArrayLiteral(
" ") + iter.value());
271 m_finalBuilder.append(
"\n#endif\n");
274 for (
const auto& value : std::as_const(m_addedTypeDeclarations)) {
275 m_finalBuilder.append(value);
276 m_finalBuilder.append(
"\n");
280 QList<QByteArray> sortedIncludes(m_includes.begin(), m_includes.end());
281 std::sort(sortedIncludes.begin(), sortedIncludes.end());
283 for (
const auto &include : sortedIncludes) {
284 m_finalBuilder.append(
"#include \"");
285 m_finalBuilder.append(include);
286 m_finalBuilder.append(
"\"\n");
292QByteArray QSSGStageGeneratorBase::buildShaderSourcePass2(QSSGShaderResourceMergeContext *mergeContext)
294 static const char *prefix =
"//@@";
295 const int prefixLen = 4;
296 const int typeLen = 1;
299 mergeContext->rearrangeResources();
302 int pos = m_finalBuilder.indexOf(prefix, from);
305 ShaderItemType itemType = ShaderItemType(m_finalBuilder.mid(pos + prefixLen, typeLen).toInt());
307 case ShaderItemType::VertexInput:
308 if (m_stage == QSSGShaderGeneratorStage::Vertex) {
310 for (
const QSSGShaderResourceMergeContext::InOutVar &var : std::as_const(mergeContext->m_inOutVars)) {
311 if (var.stagesInputIn.testFlag(m_stage))
312 block += QString::asprintf(
"layout(location = %d) in %s %s;\n", var.location, var.type.constData(), var.name.constData()).toUtf8();
314 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
317 case ShaderItemType::Input:
320 for (
const QSSGShaderResourceMergeContext::InOutVar &var : std::as_const(mergeContext->m_inOutVars)) {
321 if (var.stagesInputIn.testFlag(m_stage))
322 block += QString::asprintf(
"layout(location = %d) in %s%s %s;\n", var.location, var.flat ?
"flat " :
"", var.type.constData(), var.name.constData()).toUtf8();
324 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
327 case ShaderItemType::Output:
330 for (
const QSSGShaderResourceMergeContext::InOutVar &var : std::as_const(mergeContext->m_inOutVars)) {
331 if (var.stageOutputFrom.testFlag(m_stage))
332 block += QString::asprintf(
"layout(location = %d) out %s%s %s;\n", var.location, var.flat ?
"flat " :
"", var.type.constData(), var.name.constData()).toUtf8();
334 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
337 case ShaderItemType::Image:
341 for (
const auto &image : std::as_const(mergeContext->m_images)) {
342 addStartCond(block, image);
343 block += QString::asprintf(
"layout(binding = %d, %s) uniform %s %s %s;\n",
345 image.imgType.constData(),
346 image.qualifiers.constData(),
347 image.type.constData(),
348 image.name.constData()).toUtf8();
349 addEndCond(block, image);
351 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
353 case ShaderItemType::Uniform:
357 for (
const auto &sampler : std::as_const(mergeContext->m_samplers)) {
358 addStartCond(block, sampler);
359 block += QString::asprintf(
"layout(binding = %d) uniform %s %s;\n",
361 sampler.type.constData(),
362 sampler.name.constData()).toUtf8();
363 addEndCond(block, sampler);
366 if (!mergeContext->m_uniformMembers.isEmpty()) {
372 block += QByteArrayLiteral(
"layout(std140, binding = 0) uniform cbMain {\n");
373 for (
auto iter = mergeContext->m_uniformMembers.cbegin(), end = mergeContext->m_uniformMembers.cend();
376 addStartCond(block, iter.value());
377 block += QString::asprintf(
" %s %s;\n", iter.value().type.constData(), iter.value().name.constData()).toUtf8();
378 addEndCond(block, iter.value());
386 block += QByteArrayLiteral(
"};\n");
388 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
392 Q_UNREACHABLE_RETURN(m_finalBuilder);
399 return m_finalBuilder;
429void QSSGProgramGenerator::linkStages()
432 QSSGStageGeneratorBase *previous =
nullptr;
433 quint32 theStageId = 1;
434 for (quint32 idx = 0, end = quint32(QSSGShaderGeneratorStage::StageCount); idx < end; ++idx, theStageId = theStageId << 1) {
435 QSSGStageGeneratorBase *thisStage =
nullptr;
436 QSSGShaderGeneratorStage theStageEnum =
static_cast<QSSGShaderGeneratorStage>(theStageId);
437 if ((m_enabledStages & theStageEnum)) {
438 thisStage = &internalGetStage(theStageEnum);
440 previous->m_outgoing = &thisStage->m_incoming;
441 previous->m_flatOutgoing = &thisStage->m_flatIncoming;
443 previous = thisStage;
479void QSSGProgramGenerator::registerShaderMetaDataFromSource(QSSGShaderResourceMergeContext *mergeContext,
const QByteArray &contents, QSSGShaderGeneratorStage stage)
481 QSSGRenderShaderMetadata::ShaderMetaData meta = QSSGRenderShaderMetadata::getShaderMetaData(contents);
483 for (
const QSSGRenderShaderMetadata::Uniform &u : std::as_const(meta.uniforms)) {
484 if (u.type.startsWith(QByteArrayLiteral(
"sampler"))) {
485 if (u.multiview && mergeContext->viewCount >= 2) {
487 mergeContext->registerSampler(u.type + QByteArrayLiteral(
"Array"), u.name + QByteArrayLiteral(
"Array"), u.condition, u.conditionName);
489 mergeContext->registerSampler(u.type, u.name, u.condition, u.conditionName);
492 if (u.multiview && mergeContext->viewCount >= 2) {
493 const QByteArray name = u.name +
"[" + QByteArray::number(mergeContext->viewCount) +
"]";
494 mergeContext->registerUniformMember(u.type, name, u.condition, u.conditionName);
496 mergeContext->registerUniformMember(u.type, u.name, u.condition, u.conditionName);
501 for (
const QSSGRenderShaderMetadata::Image &img : std::as_const(meta.images))
502 mergeContext->registerImage(img.type, img.name, img.imageType, img.qualifiers, img.condition, img.conditionName);
504 for (
const QSSGRenderShaderMetadata::InputOutput &inputVar : std::as_const(meta.inputs)) {
505 if (inputVar.stage == stage)
506 mergeContext->registerInput(stage, inputVar.type, inputVar.name, inputVar.flat);
509 for (
const QSSGRenderShaderMetadata::InputOutput &outputVar : std::as_const(meta.outputs)) {
510 if (outputVar.stage == stage)
511 mergeContext->registerOutput(stage, outputVar.type, outputVar.name, outputVar.flat);
514 for (
auto it = mergeContext->m_inOutVars.cbegin(), end = mergeContext->m_inOutVars.cend(); it != end; ++it) {
515 if (it->stagesInputIn ==
int(QSSGShaderGeneratorStage::Fragment) && it->stageOutputFrom == 0)
516 qWarning(
"Fragment stage input %s is not output from vertex stage; expect errors.", it.key().constData());
520QSSGRhiShaderPipelinePtr QSSGProgramGenerator::compileGeneratedRhiShader(
const QByteArray &inMaterialInfoString,
521 const QSSGShaderFeatures &inFeatureSet,
522 QSSGShaderLibraryManager &shaderLibraryManager,
523 QSSGShaderCache &theCache,
524 QSSGRhiShaderPipeline::StageFlags stageFlags,
525 const QSSGUserShaderAugmentation &shaderAugmentation,
527 bool perTargetCompilation)
530 if (((quint32)m_enabledStages) == 0) {
535 QSSGShaderResourceMergeContext mergeContext;
536 mergeContext.viewCount = viewCount;
538 for (quint32 stageIdx = 0; stageIdx <
static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
539 QSSGShaderGeneratorStage stageName =
static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
540 if (m_enabledStages & stageName) {
541 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
542 theStage.buildShaderSourcePass1(&mergeContext);
546 for (quint32 stageIdx = 0; stageIdx <
static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
547 QSSGShaderGeneratorStage stageName =
static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
548 if (m_enabledStages & stageName) {
549 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
550 shaderLibraryManager.resolveIncludeFiles(theStage.m_finalBuilder, inMaterialInfoString);
551 registerShaderMetaDataFromSource(&mergeContext, theStage.m_finalBuilder, stageName);
555 for (quint32 stageIdx = 0; stageIdx <
static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
556 QSSGShaderGeneratorStage stageName =
static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
557 if (m_enabledStages & stageName) {
558 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
559 theStage.buildShaderSourcePass2(&mergeContext);
563 QSSGShaderResourceMergeContext::setAdditionalBufferAmount(0);
568 return theCache.compileForRhi(inMaterialInfoString,
575 perTargetCompilation);