16static inline void addStartCond(QByteArray &block,
const T &var)
20 if (var.conditionType == QSSGRenderShaderMetadata::Uniform::Regular)
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();
148void QSSGStageGeneratorBase::addShaderItemMap(QSSGStageGeneratorBase::ShaderItemType itemType,
const TStrTableStrMap &itemMap, ShaderItemMapFlags flags)
150 m_finalBuilder.append(
"\n");
152 Q_ASSERT(m_mergeContext);
153 for (TStrTableStrMap::const_iterator iter = itemMap.begin(), end = itemMap.end(); iter != end; ++iter) {
154 const QByteArray name = iter.key();
156 case ShaderItemType::VertexInput:
157 m_mergeContext->registerInput(QSSGShaderGeneratorStage::Vertex, iter.value(), name);
159 case ShaderItemType::Input:
160 m_mergeContext->registerInput(m_stage, iter.value(), name, flags.testFlag(ShaderItemMapFlag::Flat));
162 case ShaderItemType::Output:
163 m_mergeContext->registerOutput(m_stage, iter.value(), name, flags.testFlag(ShaderItemMapFlag::Flat));
165 case ShaderItemType::Uniform:
166 if (iter.value().startsWith(QByteArrayLiteral(
"sampler")))
167 m_mergeContext->registerSampler(iter.value(), name);
169 m_mergeContext->registerUniformMember(iter.value(), name);
172 qWarning(
"Unknown shader item %d",
int(itemType));
184void QSSGStageGeneratorBase::addShaderUniformMap()
186 addShaderItemMap(ShaderItemType::Uniform, m_uniforms);
187 for (TStrTableSizedStrMap::const_iterator iter = m_uniformArrays.begin(), end = m_uniformArrays.end(); iter != end; ++iter) {
188 const QByteArray name = iter.key() +
189 "[" + QByteArray::number(iter.value().first) +
"]";
190 if (iter.value().second.startsWith(QByteArrayLiteral(
"sampler")))
191 m_mergeContext->registerSampler(iter.value().second, name);
193 m_mergeContext->registerUniformMember(iter.value().second, name);
195 addShaderPass2Marker(ShaderItemType::Uniform);
208void QSSGStageGeneratorBase::addShaderConstantBufferItemMap(
const QByteArray &itemType,
const TStrTableStrMap &cbMap, TConstantBufferParamArray cbParamsArray)
210 m_finalBuilder.append(
"\n");
213 for (TStrTableStrMap::const_iterator iter = cbMap.begin(), end = cbMap.end(); iter != end; ++iter) {
214 m_finalBuilder.append(iter.value());
215 m_finalBuilder.append(
" ");
216 m_finalBuilder.append(itemType);
217 m_finalBuilder.append(
" ");
218 m_finalBuilder.append(iter.key());
219 m_finalBuilder.append(
" {\n");
221 for (TConstantBufferParamArray::const_iterator iter1 = cbParamsArray.begin(), end = cbParamsArray.end(); iter1 != end;
223 if (iter1->first == iter.key()) {
224 m_finalBuilder.append(iter1->second.second);
225 m_finalBuilder.append(
" ");
226 m_finalBuilder.append(iter1->second.first);
227 m_finalBuilder.append(
";\n");
231 m_finalBuilder.append(
"};\n");
239void QSSGStageGeneratorBase::buildShaderSourcePass1(QSSGShaderResourceMergeContext *mergeContext)
241 m_mergeContext = mergeContext;
242 addShaderIncomingMap();
243 addShaderUniformMap();
244 addShaderConstantBufferItemMap(
"uniform", m_constantBuffers, m_constantBufferParams);
245 addShaderOutgoingMap();
246 m_mergeContext =
nullptr;
248 for (
auto iter = m_addedDefinitions.begin(), end = m_addedDefinitions.end();
249 iter != end; ++iter) {
250 m_finalBuilder.append(
"#ifndef ");
251 m_finalBuilder.append(iter.key());
252 m_finalBuilder.append(
"\n");
253 m_finalBuilder.append(
"#define ");
254 m_finalBuilder.append(iter.key());
255 if (!iter.value().isEmpty())
256 m_finalBuilder.append(QByteArrayLiteral(
" ") + iter.value());
257 m_finalBuilder.append(
"\n#endif\n");
260 for (
const auto& value : std::as_const(m_addedTypeDeclarations)) {
261 m_finalBuilder.append(value);
262 m_finalBuilder.append(
"\n");
266 QList<QByteArray> sortedIncludes(m_includes.begin(), m_includes.end());
267 std::sort(sortedIncludes.begin(), sortedIncludes.end());
269 for (
const auto &include : sortedIncludes) {
270 m_finalBuilder.append(
"#include \"");
271 m_finalBuilder.append(include);
272 m_finalBuilder.append(
"\"\n");
278QByteArray QSSGStageGeneratorBase::buildShaderSourcePass2(QSSGShaderResourceMergeContext *mergeContext)
280 static const char *prefix =
"//@@";
281 const int prefixLen = 4;
282 const int typeLen = 1;
285 int pos = m_finalBuilder.indexOf(prefix, from);
288 ShaderItemType itemType = ShaderItemType(m_finalBuilder.mid(pos + prefixLen, typeLen).toInt());
290 case ShaderItemType::VertexInput:
291 if (m_stage == QSSGShaderGeneratorStage::Vertex) {
293 for (
const QSSGShaderResourceMergeContext::InOutVar &var : mergeContext->m_inOutVars) {
294 if (var.stagesInputIn.testFlag(m_stage))
295 block += QString::asprintf(
"layout(location = %d) in %s %s;\n", var.location, var.type.constData(), var.name.constData()).toUtf8();
297 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
300 case ShaderItemType::Input:
303 for (
const QSSGShaderResourceMergeContext::InOutVar &var : mergeContext->m_inOutVars) {
304 if (var.stagesInputIn.testFlag(m_stage))
305 block += QString::asprintf(
"layout(location = %d) in %s%s %s;\n", var.location, var.flat ?
"flat " :
"", var.type.constData(), var.name.constData()).toUtf8();
307 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
310 case ShaderItemType::Output:
313 for (
const QSSGShaderResourceMergeContext::InOutVar &var : mergeContext->m_inOutVars) {
314 if (var.stageOutputFrom.testFlag(m_stage))
315 block += QString::asprintf(
"layout(location = %d) out %s%s %s;\n", var.location, var.flat ?
"flat " :
"", var.type.constData(), var.name.constData()).toUtf8();
317 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
320 case ShaderItemType::Uniform:
324 for (
const auto &sampler : std::as_const(mergeContext->m_samplers)) {
325 addStartCond(block, sampler);
326 block += QString::asprintf(
"layout(binding = %d) uniform %s %s;\n",
328 sampler.type.constData(),
329 sampler.name.constData()).toUtf8();
330 addEndCond(block, sampler);
333 if (!mergeContext->m_uniformMembers.isEmpty()) {
339 block += QByteArrayLiteral(
"layout(std140, binding = 0) uniform cbMain {\n");
340 for (
auto iter = mergeContext->m_uniformMembers.cbegin(), end = mergeContext->m_uniformMembers.cend();
343 addStartCond(block, iter.value());
344 block += QString::asprintf(
" %s %s;\n", iter.value().type.constData(), iter.value().name.constData()).toUtf8();
345 addEndCond(block, iter.value());
353 block += QByteArrayLiteral(
"};\n");
355 m_finalBuilder.replace(pos, prefixLen + typeLen, block);
359 Q_UNREACHABLE_RETURN(m_finalBuilder);
366 return m_finalBuilder;
391void QSSGProgramGenerator::linkStages()
394 QSSGStageGeneratorBase *previous =
nullptr;
395 quint32 theStageId = 1;
396 for (quint32 idx = 0, end = quint32(QSSGShaderGeneratorStage::StageCount); idx < end; ++idx, theStageId = theStageId << 1) {
397 QSSGStageGeneratorBase *thisStage =
nullptr;
398 QSSGShaderGeneratorStage theStageEnum =
static_cast<QSSGShaderGeneratorStage>(theStageId);
399 if ((m_enabledStages & theStageEnum)) {
400 thisStage = &internalGetStage(theStageEnum);
402 previous->m_outgoing = &thisStage->m_incoming;
403 previous->m_flatOutgoing = &thisStage->m_flatIncoming;
405 previous = thisStage;
441void QSSGProgramGenerator::registerShaderMetaDataFromSource(QSSGShaderResourceMergeContext *mergeContext,
const QByteArray &contents, QSSGShaderGeneratorStage stage)
443 QSSGRenderShaderMetadata::ShaderMetaData meta = QSSGRenderShaderMetadata::getShaderMetaData(contents);
445 for (
const QSSGRenderShaderMetadata::Uniform &u : std::as_const(meta.uniforms)) {
446 if (u.type.startsWith(QByteArrayLiteral(
"sampler"))) {
447 if (u.multiview && mergeContext->viewCount >= 2) {
449 mergeContext->registerSampler(u.type + QByteArrayLiteral(
"Array"), u.name + QByteArrayLiteral(
"Array"), u.condition, u.conditionName);
451 mergeContext->registerSampler(u.type, u.name, u.condition, u.conditionName);
454 if (u.multiview && mergeContext->viewCount >= 2) {
455 const QByteArray name = u.name +
"[" + QByteArray::number(mergeContext->viewCount) +
"]";
456 mergeContext->registerUniformMember(u.type, name, u.condition, u.conditionName);
458 mergeContext->registerUniformMember(u.type, u.name, u.condition, u.conditionName);
463 for (
const QSSGRenderShaderMetadata::InputOutput &inputVar : std::as_const(meta.inputs)) {
464 if (inputVar.stage == stage)
465 mergeContext->registerInput(stage, inputVar.type, inputVar.name, inputVar.flat);
468 for (
const QSSGRenderShaderMetadata::InputOutput &outputVar : std::as_const(meta.outputs)) {
469 if (outputVar.stage == stage)
470 mergeContext->registerOutput(stage, outputVar.type, outputVar.name, outputVar.flat);
473 for (
auto it = mergeContext->m_inOutVars.cbegin(), end = mergeContext->m_inOutVars.cend(); it != end; ++it) {
474 if (it->stagesInputIn ==
int(QSSGShaderGeneratorStage::Fragment) && it->stageOutputFrom == 0)
475 qWarning(
"Fragment stage input %s is not output from vertex stage; expect errors.", it.key().constData());
479QSSGRhiShaderPipelinePtr QSSGProgramGenerator::compileGeneratedRhiShader(
const QByteArray &inMaterialInfoString,
480 const QSSGShaderFeatures &inFeatureSet,
481 QSSGShaderLibraryManager &shaderLibraryManager,
482 QSSGShaderCache &theCache,
483 QSSGRhiShaderPipeline::StageFlags stageFlags,
485 bool perTargetCompilation)
488 if (((quint32)m_enabledStages) == 0) {
493 QSSGShaderResourceMergeContext mergeContext;
494 mergeContext.viewCount = viewCount;
496 for (quint32 stageIdx = 0; stageIdx <
static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
497 QSSGShaderGeneratorStage stageName =
static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
498 if (m_enabledStages & stageName) {
499 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
500 theStage.buildShaderSourcePass1(&mergeContext);
504 for (quint32 stageIdx = 0; stageIdx <
static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
505 QSSGShaderGeneratorStage stageName =
static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
506 if (m_enabledStages & stageName) {
507 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
508 shaderLibraryManager.resolveIncludeFiles(theStage.m_finalBuilder, inMaterialInfoString);
509 registerShaderMetaDataFromSource(&mergeContext, theStage.m_finalBuilder, stageName);
513 for (quint32 stageIdx = 0; stageIdx <
static_cast<quint32>(QSSGShaderGeneratorStage::StageCount); ++stageIdx) {
514 QSSGShaderGeneratorStage stageName =
static_cast<QSSGShaderGeneratorStage>(1 << stageIdx);
515 if (m_enabledStages & stageName) {
516 QSSGStageGeneratorBase &theStage(internalGetStage(stageName));
517 theStage.buildShaderSourcePass2(&mergeContext);
524 return theCache.compileForRhi(inMaterialInfoString,
530 perTargetCompilation);