diff options
| author | Yong He <yonghe@outlook.com> | 2023-11-01 21:42:12 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-01 21:42:12 -0700 |
| commit | 6aca3813c4ccc496c0f9b2db293acb546aa11d2d (patch) | |
| tree | 5281f0ac62946787db90409c1ab3da5ed3f0fc5c | |
| parent | 532c4322c9d9ab2c95a5bb573c89062456b59236 (diff) | |
Parameter binding and gfx fixes. (#3302)
* Parameter binding and gfx fixes.
* Add diagnostics on entry point parameters.
* Fix.
---------
Co-authored-by: Yong He <yhe@nvidia.com>
48 files changed, 716 insertions, 221 deletions
@@ -2090,6 +2090,9 @@ extern "C" // SLANG_PARAMETER_CATEGORY_EXISTENTIAL_OBJECT_PARAM, + // The register space offset for the sub-elements that occupies register spaces. + SLANG_PARAMETER_CATEGORY_SUB_ELEMENT_REGISTER_SPACE, + // SLANG_PARAMETER_CATEGORY_COUNT, @@ -2251,6 +2254,7 @@ extern "C" SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeCount(SlangReflectionTypeLayout* typeLayout); SLANG_API SlangBindingType spReflectionTypeLayout_getBindingRangeType(SlangReflectionTypeLayout* typeLayout, SlangInt index); + SLANG_API SlangInt spReflectionTypeLayout_isBindingRangeSpecializable(SlangReflectionTypeLayout* typeLayout, SlangInt index); SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeBindingCount(SlangReflectionTypeLayout* typeLayout, SlangInt index); SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getBindingRangeLeafTypeLayout(SlangReflectionTypeLayout* typeLayout, SlangInt index); SLANG_API SlangReflectionVariable* spReflectionTypeLayout_getBindingRangeLeafVariable(SlangReflectionTypeLayout* typeLayout, SlangInt index); @@ -2638,6 +2642,8 @@ namespace slang ExistentialTypeParam = SLANG_PARAMETER_CATEGORY_EXISTENTIAL_TYPE_PARAM, ExistentialObjectParam = SLANG_PARAMETER_CATEGORY_EXISTENTIAL_OBJECT_PARAM, + SubElementRegisterSpace = SLANG_PARAMETER_CATEGORY_SUB_ELEMENT_REGISTER_SPACE, + // DEPRECATED: VertexInput = SLANG_PARAMETER_CATEGORY_VERTEX_INPUT, FragmentOutput = SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT, @@ -2849,6 +2855,14 @@ namespace slang index); } + bool isBindingRangeSpecializable(SlangInt index) + { + return (bool)spReflectionTypeLayout_isBindingRangeSpecializable( + (SlangReflectionTypeLayout*)this, + index); + + } + SlangInt getBindingRangeBindingCount(SlangInt index) { return spReflectionTypeLayout_getBindingRangeBindingCount( diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp index 840aa4a67..af4f6d124 100644 --- a/source/slang/slang-ast-type.cpp +++ b/source/slang/slang-ast-type.cpp @@ -19,7 +19,14 @@ Type* Type::_createCanonicalTypeOverride() Val* Type::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) { int diff = 0; - auto canSubst = getCanonicalType()->substituteImpl(astBuilder, subst, &diff); + auto canonicalType = getCanonicalType(); + + // If canonicalType is identical to this, then we shouldn't try to call + // canonicalType->substituteImpl because that would lead to infinite recursion. + if (canonicalType == this) + return this; + + auto canSubst = canonicalType->substituteImpl(astBuilder, subst, &diff); // If nothing changed, then don't drop any sugar that is applied if (!diff) diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 072a4a5fa..7dd46037b 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -17,6 +17,8 @@ namespace Slang bool isGlobalDecl(Decl* decl); + bool isUniformParameterType(Type* type); + Type* checkProperType( Linkage* linkage, TypeExp typeExp, diff --git a/source/slang/slang-check-shader.cpp b/source/slang/slang-check-shader.cpp index d2ac0d12f..00c924982 100644 --- a/source/slang/slang-check-shader.cpp +++ b/source/slang/slang-check-shader.cpp @@ -301,6 +301,56 @@ namespace Slang return entryPointFuncDecl; } + // Is a entry pointer parmaeter of `type` always a uniform parameter? + bool isUniformParameterType(Type* type) + { + if (as<ResourceType>(type)) + return true; + if (as<HLSLStructuredBufferTypeBase>(type)) + return true; + if (as<UntypedBufferResourceType>(type)) + return true; + if (as<UniformParameterGroupType>(type)) + return true; + if (as<SamplerStateType>(type)) + return true; + return false; + } + + bool isBuiltinParameterType(Type* type) + { + return as<BuiltinType>(type) != nullptr; + } + + bool doStructFieldsHaveSemanticImpl(Type* type, HashSet<Type*>& seenTypes) + { + auto declRefType = as<DeclRefType>(type); + if (!declRefType) + return false; + auto structDecl = as<StructDecl>(declRefType->getDeclRef().getDecl()); + if (!structDecl) + return false; + seenTypes.add(type); + for (auto field : structDecl->getFields()) + { + if (!field->findModifier<HLSLSemantic>()) + { + if (!seenTypes.contains(type)) + { + if (!doStructFieldsHaveSemanticImpl(field->getType(), seenTypes)) + return false; + } + } + } + return true; + } + + bool doStructFieldsHaveSemantic(Type* type) + { + HashSet<Type*> seenTypes; + return doStructFieldsHaveSemanticImpl(type, seenTypes); + } + // Validate that an entry point function conforms to any additional // constraints based on the stage (and profile?) it specifies. void validateEntryPoint( @@ -424,6 +474,32 @@ namespace Slang } } } + + for (const auto& param : entryPointFuncDecl->getParameters()) + { + if (isUniformParameterType(param->getType())) + { + // Automatically add `uniform` modifier to entry point parameters. + if (!param->hasModifier<HLSLUniformModifier>()) + addModifier(param, getCurrentASTBuilder()->create<HLSLUniformModifier>()); + } + else if (isBuiltinParameterType(param->getType())) + { + } + else + { + // For all non-uniform parameters of a general type, we require the parameter be associated with + // a system value semantic. + if (!param->hasModifier<HLSLUniformModifier>()) + { + if (!param->findModifier<HLSLSemantic>()) + { + if (!doStructFieldsHaveSemantic(param->getType())) + sink->diagnose(param, Diagnostics::nonUniformEntryPointParameterMustHaveSemantic, param->getName()); + } + } + } + } } // Given an entry point specified via API or command line options, diff --git a/source/slang/slang-check-type.cpp b/source/slang/slang-check-type.cpp index 5967da8b0..b5ee2c4fc 100644 --- a/source/slang/slang-check-type.cpp +++ b/source/slang/slang-check-type.cpp @@ -317,6 +317,8 @@ namespace Slang if (!genericTypeParamDecl) return false; auto defaultType = CheckProperType(genericTypeParamDecl->initType); + if (!defaultType) + return false; auto witness = tryGetSubtypeWitness(defaultType, CheckProperType(constraintParam->sup)); if (!witness) { @@ -326,8 +328,6 @@ namespace Slang Diagnostics::typeArgumentDoesNotConformToInterface, defaultType, constraintParam->sup); - - SLANG_UNEXPECTED("default type argument does not conform to interface"); return false; } witnessArgs.add(witness); diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 79889a39d..da91449f4 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -569,6 +569,8 @@ DIAGNOSTIC(38033, Error, cannotUseNoDiffInNonDifferentiableFunc, "cannot use 'no DIAGNOSTIC(38034, Error, cannotUseConstRefOnDifferentiableParameter, "cannot use '__constref' on a differentiable parameter.") DIAGNOSTIC(38034, Error, cannotUseConstRefOnDifferentiableMemberMethod, "cannot use '[constref]' on a differentiable member method of a differentiable type.") +DIAGNOSTIC(38040, Error, nonUniformEntryPointParameterMustHaveSemantic, "non-uniform parameter '$0' must have a system-value semantic.") + DIAGNOSTIC(38200, Error, recursiveModuleImport, "module `$0` recursively imports itself") DIAGNOSTIC(39999, Error, errorInImportedModule, "import of module '$0' failed because of a compilation error") DIAGNOSTIC(39999, Fatal, complationCeased, "compilation ceased") diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index a2c3abb5e..7eebf1cac 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -642,9 +642,14 @@ UInt CLikeSourceEmitter::getBindingOffsetForKinds(EmitVarChain* chain, LayoutRes return offset; } +Index findRegisterSpaceResourceInfo(IRVarLayout* layout); + UInt CLikeSourceEmitter::getBindingSpaceForKinds(EmitVarChain* chain, LayoutResourceKindFlags kindFlags) { UInt space = 0; + + bool useSubElementSpace = false; + for (auto cc = chain; cc; cc = cc->next) { auto varLayout = cc->varLayout; @@ -657,10 +662,21 @@ UInt CLikeSourceEmitter::getBindingSpaceForKinds(EmitVarChain* chain, LayoutReso space += offsetAttr->getSpace(); } } - - if (auto resInfo = varLayout->findOffsetAttr(LayoutResourceKind::RegisterSpace)) + if (!useSubElementSpace) { - space += resInfo->getOffset(); + auto spaceOffset = findRegisterSpaceResourceInfo(varLayout); + if (spaceOffset != -1) + { + space += spaceOffset; + useSubElementSpace = true; + } + } + else + { + if (auto resInfo = varLayout->findOffsetAttr(LayoutResourceKind::SubElementRegisterSpace)) + { + space += resInfo->getOffset(); + } } } return space; @@ -669,6 +685,7 @@ UInt CLikeSourceEmitter::getBindingSpaceForKinds(EmitVarChain* chain, LayoutReso UInt CLikeSourceEmitter::getBindingOffset(EmitVarChain* chain, LayoutResourceKind kind) { UInt offset = 0; + for(auto cc = chain; cc; cc = cc->next) { if(auto resInfo = cc->varLayout->findOffsetAttr(kind)) @@ -682,6 +699,7 @@ UInt CLikeSourceEmitter::getBindingOffset(EmitVarChain* chain, LayoutResourceKin UInt CLikeSourceEmitter::getBindingSpace(EmitVarChain* chain, LayoutResourceKind kind) { UInt space = 0; + bool useSubElementSpace = false; for(auto cc = chain; cc; cc = cc->next) { auto varLayout = cc->varLayout; @@ -689,9 +707,21 @@ UInt CLikeSourceEmitter::getBindingSpace(EmitVarChain* chain, LayoutResourceKind { space += resInfo->getSpace(); } - if(auto resInfo = varLayout->findOffsetAttr(LayoutResourceKind::RegisterSpace)) + if (!useSubElementSpace) { - space += resInfo->getOffset(); + auto spaceOffset = findRegisterSpaceResourceInfo(varLayout); + if (spaceOffset != -1) + { + space += spaceOffset; + useSubElementSpace = true; + } + } + else + { + if (auto resInfo = varLayout->findOffsetAttr(LayoutResourceKind::SubElementRegisterSpace)) + { + space += resInfo->getOffset(); + } } } return space; diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp index 4b519b065..bd5c45ff4 100644 --- a/source/slang/slang-ir-legalize-types.cpp +++ b/source/slang/slang-ir-legalize-types.cpp @@ -3254,7 +3254,6 @@ static LegalVal declareVars( { // Just declare a variable of the pointed-to type, // since we are removing the indirection. - auto val = declareVars( context, op, diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp index 715b4f6ce..2155ce499 100644 --- a/source/slang/slang-ir-spirv-legalize.cpp +++ b/source/slang/slang-ir-spirv-legalize.cpp @@ -526,7 +526,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase varLayout = as<IRVarLayout>(varLayoutInst->getLayout()); if (varLayout) { - auto registerSpaceOffsetAttr = varLayout->findOffsetAttr(LayoutResourceKind::RegisterSpace); + auto registerSpaceOffsetAttr = varLayout->findOffsetAttr(LayoutResourceKind::SubElementRegisterSpace); if (registerSpaceOffsetAttr) { List<IRInst*> operands; diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp index cea5d0151..7f8338b1b 100644 --- a/source/slang/slang-language-server.cpp +++ b/source/slang/slang-language-server.cpp @@ -1986,76 +1986,91 @@ SlangResult LanguageServer::queueJSONCall(JSONRPCCall call) SlangResult LanguageServer::runCommand(Command& call) { - // Do different things - if (call.method == DidOpenTextDocumentParams::methodName) - { - return didOpenTextDocument(call.openDocArgs.get()); - } - else if (call.method == DidCloseTextDocumentParams::methodName) - { - return didCloseTextDocument(call.closeDocArgs.get()); - } - else if (call.method == DidChangeTextDocumentParams::methodName) - { - return didChangeTextDocument(call.changeDocArgs.get()); - } - else if (call.method == HoverParams::methodName) - { - return hover(call.hoverArgs.get(), call.id); - } - else if (call.method == DefinitionParams::methodName) - { - return gotoDefinition(call.definitionArgs.get(), call.id); - } - else if (call.method == CompletionParams::methodName) - { - return completion(call.completionArgs.get(), call.id); - } - else if (call.method == SemanticTokensParams::methodName) - { - return semanticTokens(call.semanticTokenArgs.get(), call.id); - } - else if (call.method == SignatureHelpParams::methodName) - { - return signatureHelp(call.signatureHelpArgs.get(), call.id); - } - else if (call.method == "completionItem/resolve") - { - return completionResolve(call.completionResolveArgs.get(), call.textEditCompletionResolveArgs.get(), call.id); - } - else if (call.method == DocumentSymbolParams::methodName) - { - return documentSymbol(call.documentSymbolArgs.get(), call.id); - } - else if (call.method == DidChangeConfigurationParams::methodName) - { - return didChangeConfiguration(call.changeConfigArgs.get()); - } - else if (call.method == InlayHintParams::methodName) - { - return inlayHint(call.inlayHintArgs.get(), call.id); - } - else if (call.method == DocumentOnTypeFormattingParams::methodName) - { - return onTypeFormatting(call.onTypeFormattingArgs.get(), call.id); - } - else if (call.method == DocumentRangeFormattingParams::methodName) + try { - return rangeFormatting(call.rangeFormattingArgs.get(), call.id); + // Do different things + if (call.method == DidOpenTextDocumentParams::methodName) + { + return didOpenTextDocument(call.openDocArgs.get()); + } + else if (call.method == DidCloseTextDocumentParams::methodName) + { + return didCloseTextDocument(call.closeDocArgs.get()); + } + else if (call.method == DidChangeTextDocumentParams::methodName) + { + return didChangeTextDocument(call.changeDocArgs.get()); + } + else if (call.method.startsWith("$/")) + { + // Ignore. + return SLANG_OK; + } } - else if (call.method == DocumentFormattingParams::methodName) + catch (...) { - return formatting(call.formattingArgs.get(), call.id); + return SLANG_FAIL; } - else if (call.method.startsWith("$/")) + + try { - // Ignore. - return SLANG_OK; + if (call.method == HoverParams::methodName) + { + return hover(call.hoverArgs.get(), call.id); + } + else if (call.method == DefinitionParams::methodName) + { + return gotoDefinition(call.definitionArgs.get(), call.id); + } + else if (call.method == CompletionParams::methodName) + { + return completion(call.completionArgs.get(), call.id); + } + else if (call.method == SemanticTokensParams::methodName) + { + return semanticTokens(call.semanticTokenArgs.get(), call.id); + } + else if (call.method == SignatureHelpParams::methodName) + { + return signatureHelp(call.signatureHelpArgs.get(), call.id); + } + else if (call.method == "completionItem/resolve") + { + return completionResolve(call.completionResolveArgs.get(), call.textEditCompletionResolveArgs.get(), call.id); + } + else if (call.method == DocumentSymbolParams::methodName) + { + return documentSymbol(call.documentSymbolArgs.get(), call.id); + } + else if (call.method == DidChangeConfigurationParams::methodName) + { + return didChangeConfiguration(call.changeConfigArgs.get()); + } + else if (call.method == InlayHintParams::methodName) + { + return inlayHint(call.inlayHintArgs.get(), call.id); + } + else if (call.method == DocumentOnTypeFormattingParams::methodName) + { + return onTypeFormatting(call.onTypeFormattingArgs.get(), call.id); + } + else if (call.method == DocumentRangeFormattingParams::methodName) + { + return rangeFormatting(call.rangeFormattingArgs.get(), call.id); + } + else if (call.method == DocumentFormattingParams::methodName) + { + return formatting(call.formattingArgs.get(), call.id); + } } - else + catch (...) { - return m_connection->sendError(JSONRPC::ErrorCode::MethodNotFound, call.id); + // If we encountered an internal compiler error, don't crash the language server. + // Instead we just return a null response. + return m_connection->sendResult(NullResponse::get(), call.id); } + + return m_connection->sendError(JSONRPC::ErrorCode::MethodNotFound, call.id); } void LanguageServer::processCommands() diff --git a/source/slang/slang-legalize-types.cpp b/source/slang/slang-legalize-types.cpp index 65e279f52..8ed5a12b7 100644 --- a/source/slang/slang-legalize-types.cpp +++ b/source/slang/slang-legalize-types.cpp @@ -1425,6 +1425,25 @@ IRVarLayout* getFieldLayout( return nullptr; } +Index findRegisterSpaceResourceInfo(IRVarLayout* layout) +{ + if (auto parameterGroupLayout = as<IRParameterGroupTypeLayout>(layout->getTypeLayout())) + { + auto registerInfo = parameterGroupLayout->getContainerVarLayout()->findOffsetAttr(LayoutResourceKind::RegisterSpace); + auto containerRegisterInfo = layout->findOffsetAttr(LayoutResourceKind::SubElementRegisterSpace); + if (registerInfo) + { + if (containerRegisterInfo) + return (Index)(registerInfo->getOffset() + containerRegisterInfo->getOffset()); + else + return (Index)(registerInfo->getOffset()); + } + } + if (auto registerSpaceOffset = layout->findOffsetAttr(LayoutResourceKind::RegisterSpace)) + return (Index)registerSpaceOffset->getOffset(); + return -1; +} + void buildSimpleVarLayout( IRVarLayout::Builder* builder, SimpleLegalVarChain* varChain, @@ -1478,11 +1497,26 @@ void buildSimpleVarLayout( { // Sum up contributions from all parents. UInt space = 0; + bool useSubElementSpace = false; for (auto vv = varChain; vv; vv = vv->next) { - if (auto parentResInfo = vv->varLayout->findOffsetAttr(LayoutResourceKind::RegisterSpace)) + if (!useSubElementSpace) { - space += parentResInfo->getOffset(); + auto spaceOffset = findRegisterSpaceResourceInfo(vv->varLayout); + if (spaceOffset != -1) + { + space += spaceOffset; + useSubElementSpace = true; + } + } + else + { + // Once we found the first RegisterSpace usage, we will sum up offets from parent's SubElementReigsterSpace info. + if (auto parentResInfo = vv->varLayout->findOffsetAttr(LayoutResourceKind::SubElementRegisterSpace)) + { + space += parentResInfo->getOffset(); + useSubElementSpace = true; + } } } diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index 7d7cfeefe..7241fdd6e 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -515,7 +515,7 @@ LayoutResourceKind findRegisterClassFromName(UnownedStringSlice const& registerC case 5: if( registerClassName == toSlice("space") ) { - return LayoutResourceKind::RegisterSpace; + return LayoutResourceKind::SubElementRegisterSpace; } break; @@ -583,7 +583,7 @@ LayoutSemanticInfo extractHLSLLayoutSemanticInfo( UnownedStringSlice spaceDigits; splitNameAndIndex(spaceName, spaceSpelling, spaceDigits); - if( kind == LayoutResourceKind::RegisterSpace ) + if( kind == LayoutResourceKind::SubElementRegisterSpace) { sink->diagnose(spaceLoc, Diagnostics::unexpectedSpecifierAfterSpace, spaceName); } @@ -902,7 +902,7 @@ static void addExplicitParameterBinding( bindingInfo.space = semanticInfo.space; VarLayout* overlappedVarLayout = nullptr; - if( kind == LayoutResourceKind::RegisterSpace ) + if( kind == LayoutResourceKind::RegisterSpace || kind == LayoutResourceKind::SubElementRegisterSpace ) { // Parameter is being bound to an entire space, so we // need to mark the given space as used and report @@ -1071,7 +1071,7 @@ static void addExplicitParameterBindings_GLSL( semanticInfo.space = attr->set; } } - else if( (foundResInfo = typeLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) != nullptr ) + else if( (foundResInfo = typeLayout->FindResourceInfo(LayoutResourceKind::SubElementRegisterSpace)) != nullptr ) { // Try to find `set` if (auto attr = varDecl.getDecl()->findModifier<GLSLBindingAttribute>()) @@ -1243,7 +1243,7 @@ static void completeBindingsForParameterImpl( } break; - case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::SubElementRegisterSpace: // If the parameter consumes any full spaces (e.g., it // is a `struct` type with one or more unbounded arrays // for fields), then we will include those spaces in @@ -1312,7 +1312,7 @@ static void completeBindingsForParameterImpl( // switch( kind ) { - case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::SubElementRegisterSpace: { // The parameter's type needs to consume some number of whole // register spaces, and we have already allocated a contiguous @@ -3547,6 +3547,7 @@ static bool _calcNeedsDefaultSpace(SharedParameterBindingContext& sharedContext) switch (resInfo.kind) { case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::SubElementRegisterSpace: case LayoutResourceKind::PushConstantBuffer: continue; case LayoutResourceKind::Uniform: @@ -3579,7 +3580,7 @@ static bool _calcNeedsDefaultSpace(SharedParameterBindingContext& sharedContext) // for (auto& entryPoint : sharedContext.programLayout->entryPoints) { - auto paramsLayout = entryPoint->parametersLayout; + auto paramsLayout = entryPoint->parametersLayout->getTypeLayout(); for (auto resInfo : paramsLayout->resourceInfos) { switch (resInfo.kind) diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp index 9d687245f..3a521589e 100644 --- a/source/slang/slang-reflection-api.cpp +++ b/source/slang/slang-reflection-api.cpp @@ -1539,56 +1539,50 @@ namespace Slang // Index bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount(); SlangBindingType bindingType = SLANG_BINDING_TYPE_CONSTANT_BUFFER; - Index spaceOffset = -1; bool shouldAllocDescriptorSet = true; LayoutResourceKind kind = LayoutResourceKind::None; - // TODO: It is unclear if this should be looking at the resource - // usage of the parameter group, or of its "container" layout. - // - for(auto& resInfo : parameterGroupTypeLayout->resourceInfos) + // If the parameter group container starts a new space, + // we do not want to allocate a descriptor set from the current parent. + if (parameterGroupTypeLayout->containerVarLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) { - if( spaceOffset == -1 ) - { - spaceOffset = _calcSpaceOffset(path.primary, kind); - } + kind = LayoutResourceKind::RegisterSpace; + bindingType = SLANG_BINDING_TYPE_PARAMETER_BLOCK; + shouldAllocDescriptorSet = false; + } - kind = resInfo.kind; - switch(kind) + if (shouldAllocDescriptorSet) + { + // If this is not a parameter block, derive the binding type + // from resource infos. + for(auto& resInfo : parameterGroupTypeLayout->resourceInfos) { - default: - continue; + kind = resInfo.kind; + switch(kind) + { + default: + continue; - case LayoutResourceKind::ConstantBuffer: - case LayoutResourceKind::PushConstantBuffer: - case LayoutResourceKind::DescriptorTableSlot: - break; + case LayoutResourceKind::ConstantBuffer: + case LayoutResourceKind::PushConstantBuffer: + case LayoutResourceKind::DescriptorTableSlot: + break; - // Certain cases indicate a parameter block that - // actually involves indirection. - // - // Note: the only case where a parameter group should - // reflect as consuming `Uniform` storage is on CPU/CUDA, - // where that will be the only resource it contains. - case LayoutResourceKind::Uniform: - break; - // - // TODO: If we ever support targets that don't have - // constant buffers at all, this logic would be questionable. - // - case LayoutResourceKind::RegisterSpace: - shouldAllocDescriptorSet = false; + // Certain cases indicate a parameter block that + // actually involves indirection. + // + // Note: the only case where a parameter group should + // reflect as consuming `Uniform` storage is on CPU/CUDA, + // where that will be the only resource it contains. + case LayoutResourceKind::Uniform: + break; + } + + bindingType = _calcBindingType(typeLayout, kind); break; } - - bindingType = _calcBindingType(typeLayout, kind); - break; - } - if(spaceOffset == -1) - { - spaceOffset = 0; } - + TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange; bindingRange.leafTypeLayout = typeLayout; bindingRange.leafVariable = path.primary ? path.primary->var->getVariable() : nullptr; @@ -1606,10 +1600,12 @@ namespace Slang subObjectRange.bindingRangeIndex = bindingRangeIndex; subObjectRange.offsetVarLayout = createOffsetVarLayout(typeLayout, path); subObjectRange.spaceOffset = 0; - if (kind == LayoutResourceKind::RegisterSpace && path.primary) + if (kind == LayoutResourceKind::SubElementRegisterSpace && path.primary) { - auto resInfo = path.primary->var->FindResourceInfo(LayoutResourceKind::RegisterSpace); - subObjectRange.spaceOffset = resInfo->index; + if (auto resInfo = path.primary->var->FindResourceInfo(LayoutResourceKind::SubElementRegisterSpace)) + { + subObjectRange.spaceOffset = resInfo->index; + } } // It is possible that the sub-object has descriptor ranges // that will need to be exposed upward, into the parent. @@ -1659,7 +1655,7 @@ namespace Slang // (If the contents of a group consume whole spaces/sets, then // those resources will be accounted for separately). // - Int descriptorSetIndex = _findOrAddDescriptorSet(spaceOffset); + Int descriptorSetIndex = _findOrAddDescriptorSet(0); auto descriptorSet = m_extendedInfo->m_descriptorSets[descriptorSetIndex]; auto firstDescriptorRangeIndex = descriptorSet->descriptorRanges.getCount(); @@ -1672,7 +1668,7 @@ namespace Slang // more whole register spaces/sets, then nothing should // leak through that is measured in descriptor sets. // - case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::SubElementRegisterSpace: case LayoutResourceKind::None: break; @@ -1686,7 +1682,7 @@ namespace Slang { switch( resInfo.kind ) { - case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::SubElementRegisterSpace: continue; default: @@ -1715,7 +1711,7 @@ namespace Slang // be no "leakage" of descriptor ranges from the element type // to the parent. // - case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::SubElementRegisterSpace: case LayoutResourceKind::Uniform: case LayoutResourceKind::None: break; @@ -1797,8 +1793,21 @@ namespace Slang // For structured buffers we expect them to consume a single // resource descriptor slot (not counting the possible counter // buffer) - SLANG_ASSERT(typeLayout->resourceInfos.getCount() == 1); - const auto& resInfo = typeLayout->resourceInfos[0]; + SLANG_ASSERT(typeLayout->resourceInfos.getCount() >= 1); + TypeLayout::ResourceInfo resInfo; + for (auto& info : typeLayout->resourceInfos) + { + switch (info.kind) + { + case LayoutResourceKind::UnorderedAccess: + case LayoutResourceKind::ShaderResource: + case LayoutResourceKind::DescriptorTableSlot: + case LayoutResourceKind::Uniform: + resInfo = info; + break; + } + } + SLANG_ASSERT(resInfo.kind != LayoutResourceKind::None); const auto bindingType = as<HLSLStructuredBufferType>(typeLayout->getType()) ? SLANG_BINDING_TYPE_RAW_BUFFER @@ -1967,7 +1976,7 @@ namespace Slang // TODO: Make some clear decisions about what should and should // not appear here. // - case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::SubElementRegisterSpace: case LayoutResourceKind::VaryingInput: case LayoutResourceKind::VaryingOutput: case LayoutResourceKind::HitAttributes: @@ -2063,6 +2072,26 @@ SLANG_API SlangBindingType spReflectionTypeLayout_getBindingRangeType(SlangRefle return bindingRange.bindingType; } +SLANG_API SlangInt spReflectionTypeLayout_isBindingRangeSpecializable(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if (!typeLayout) return SLANG_BINDING_TYPE_UNKNOWN; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + if (index < 0) return SLANG_BINDING_TYPE_UNKNOWN; + if (index >= extTypeLayout->m_bindingRanges.getCount()) return SLANG_BINDING_TYPE_UNKNOWN; + auto& bindingRange = extTypeLayout->m_bindingRanges[index]; + auto type = bindingRange.leafTypeLayout->getType(); + if (asInterfaceType(type)) + return 1; + if (auto parameterGroupType = as<ParameterGroupType>(type)) + { + if (asInterfaceType(parameterGroupType->getElementType())) + return 1; + } + return 0; +} + SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeBindingCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) { auto typeLayout = convert(inTypeLayout); @@ -2581,6 +2610,9 @@ SLANG_API size_t spReflectionVariableLayout_GetSpace(SlangReflectionVariableLayo space += info->space; } + if (auto regSpaceInfo = varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) + space += regSpaceInfo->index; + // Note: this code used to try and take a variable with // an offset for `LayoutResourceKind::RegisterSpace` and // add it to the space returned, but that isn't going diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index 1534b6cc5..8c1108870 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -1689,7 +1689,7 @@ static SimpleLayoutInfo _getParameterGroupLayoutInfo( // // TODO: wouldn't it be any different to just allocate this // as an empty `SimpleLayoutInfo` of any other kind? - return SimpleLayoutInfo(LayoutResourceKind::RegisterSpace, 0); + return SimpleLayoutInfo(LayoutResourceKind::SubElementRegisterSpace, 0); } // TODO: the vertex-input and fragment-output cases should @@ -1905,6 +1905,23 @@ static bool shouldAllocateRegisterSpaceForParameterBlock( return false; } +bool canTypeDirectlyUseRegisterSpace(TypeLayout* layout) +{ + // A ParameterBlock type will directly use a register space, if it is non empty. + if (as<ParameterBlockType>(layout->getType())) + return true; + // An infinite array type will also consume a register space. + if (auto arrLayout = as<ArrayTypeLayout>(layout)) + { + for (auto info : arrLayout->resourceInfos) + { + if (info.count.isInfinite()) + return true; + } + } + return false; +} + // Given an existing type layout `oldTypeLayout`, apply offsets // to any contained fields based on the resource infos in `offsetVarLayout`. RefPtr<TypeLayout> applyOffsetToTypeLayout( @@ -2191,7 +2208,7 @@ static void _addUnmaskedResourceUsage( } break; - case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::SubElementRegisterSpace: case LayoutResourceKind::ExistentialTypeParam: // A parameter group will always pay for full registers // spaces consumed by its element type. @@ -2394,7 +2411,7 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout( for( auto elementResourceInfo : rawElementTypeLayout->resourceInfos ) { - if(elementResourceInfo.kind != LayoutResourceKind::RegisterSpace) + if(elementResourceInfo.kind != LayoutResourceKind::SubElementRegisterSpace) { wantSpaceOrSet = true; break; @@ -2408,7 +2425,14 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout( // if( wantSpaceOrSet ) { - containerTypeLayout->addResourceUsage(LayoutResourceKind::RegisterSpace, 1); + containerTypeLayout->addResourceUsage(LayoutResourceKind::SubElementRegisterSpace, 1); + + // Add a RegisterSpace entry to containerVarLayout to signal that this ParameterGroupTypeLayout + // initiates a new space for its element. This allows us to distinguish between the ConstantBuffer + // and ParameterBlock cases. The index of this entry is set to 0 since there is already a + // SubElementRegisterSpace entry stored in `typeLayout` that corresponds to the space used by + // this parameter group. + containerVarLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace); } // Now that we've computed basic resource requirements for the container @@ -3152,7 +3176,7 @@ static RefPtr<TypeLayout> maybeAdjustLayoutForArrayElementType( auto originalFieldTypeLayout = originalField->typeLayout; LayoutSize originalFieldSpaceCount = 0; - if(auto resInfo = originalFieldTypeLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) + if(auto resInfo = originalFieldTypeLayout->FindResourceInfo(LayoutResourceKind::SubElementRegisterSpace)) originalFieldSpaceCount = resInfo->count; // Compute the adjusted type for the field @@ -3180,6 +3204,7 @@ static RefPtr<TypeLayout> maybeAdjustLayoutForArrayElementType( // the adjusted field, and try to figure out what // to do with it all. // + bool requireNewSpace = false; for(auto& resInfo : adjustedField->resourceInfos ) { if( doesResourceRequireAdjustmentForArrayOfStructs(resInfo.kind) ) @@ -3198,11 +3223,16 @@ static RefPtr<TypeLayout> maybeAdjustLayoutForArrayElementType( // field with resource type will turn into its own space, // and it will start at register zero in that space. // + requireNewSpace = true; resInfo.index = 0; - resInfo.space = spaceOffsetForField.getFiniteValue(); + resInfo.space = 0; } } } + if (requireNewSpace) + { + adjustedField->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace)->index = spaceOffsetForField.getFiniteValue(); + } adjustedStructTypeLayout->fields.add(adjustedField); @@ -3328,6 +3358,16 @@ RefPtr<VarLayout> StructTypeLayoutBuilder::addField( // fields to be safe... // LayoutSize uniformOffset = m_info.size; + if (fieldInfo.size == 0) + { + // In case the field has a mixed resource usage, + // the simple view will not be able to represent the uniform usage. + // we try to find uniform usage from res info. + if (auto uniformUsage = fieldTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform)) + { + fieldInfo.size = uniformUsage->count; + } + } if(fieldInfo.size != 0) { uniformOffset = m_rules->AddStructField(&m_info, fieldInfo); @@ -3377,14 +3417,17 @@ RefPtr<VarLayout> StructTypeLayoutBuilder::addField( { // We need to add one register space to own the storage for this field. // - auto structTypeSpaceResourceInfo = m_typeLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace); + auto structTypeSpaceResourceInfo = m_typeLayout->findOrAddResourceInfo(LayoutResourceKind::SubElementRegisterSpace); auto spaceOffset = structTypeSpaceResourceInfo->count; structTypeSpaceResourceInfo->count += 1; - + // The field itself will record itself as having a zero offset into - // the chosen space. + // the chosen space. We encode the space offset as a separate RegisterSpace + // entry in the field layout so consuming code can use the existance of RegisterSpace entry + // to tell that the field is introducing a new space for itself. // - fieldResourceInfo->space = spaceOffset.getFiniteValue(); + fieldLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace)->index = spaceOffset.getFiniteValue(); + fieldResourceInfo->space = 0; fieldResourceInfo->index = 0; } else @@ -3397,6 +3440,11 @@ RefPtr<VarLayout> StructTypeLayoutBuilder::addField( auto structTypeResourceInfo = m_typeLayout->findOrAddResourceInfo(fieldTypeResourceInfo.kind); fieldResourceInfo->index = structTypeResourceInfo->count.getFiniteValue(); structTypeResourceInfo->count += fieldTypeResourceInfo.count; + if (fieldTypeResourceInfo.kind == LayoutResourceKind::SubElementRegisterSpace && + canTypeDirectlyUseRegisterSpace(fieldTypeLayout)) + { + fieldLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace)->index = fieldResourceInfo->index; + } } } @@ -3677,7 +3725,7 @@ static TypeLayoutResult createArrayLikeTypeLayout( // if( adjustedElementTypeLayout != elementTypeLayout ) { - typeLayout->addResourceUsage(LayoutResourceKind::RegisterSpace, additionalSpacesNeededForAdjustedElementType); + typeLayout->addResourceUsage(LayoutResourceKind::SubElementRegisterSpace, additionalSpacesNeededForAdjustedElementType); } return TypeLayoutResult(typeLayout, arrayUniformInfo); diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h index 1ebd26098..23b70d59d 100644 --- a/source/slang/slang-type-layout.h +++ b/source/slang/slang-type-layout.h @@ -269,6 +269,7 @@ typedef slang::ParameterCategory LayoutResourceKind; x(ExistentialTypeParam) \ x(ExistentialObjectParam) \ \ + x(SubElementRegisterSpace) \ x(VertexInput) \ x(FragmentOutput) @@ -1360,6 +1361,8 @@ IRVarLayout* applyOffsetToVarLayout( IRVarLayout* baseLayout, IRVarLayout* offsetLayout); +bool canTypeDirectlyUseRegisterSpace(TypeLayout* layout); + } #endif diff --git a/source/slang/slang-workspace-version.cpp b/source/slang/slang-workspace-version.cpp index ed568b470..86cdd000a 100644 --- a/source/slang/slang-workspace-version.cpp +++ b/source/slang/slang-workspace-version.cpp @@ -451,6 +451,9 @@ UnownedStringSlice DocumentVersion::peekIdentifier(Index& offset) { Index start = offset; Index end = offset; + if (start >= text.getLength()) + return UnownedStringSlice(""); + while (start >= 0 && _isIdentifierChar(text[start])) start--; while (end < text.getLength() && _isIdentifierChar(text[end])) diff --git a/tests/bindings/nested-parameter-block-2.slang b/tests/bindings/nested-parameter-block-2.slang new file mode 100644 index 000000000..38ce9232e --- /dev/null +++ b/tests/bindings/nested-parameter-block-2.slang @@ -0,0 +1,42 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -d3d12 -use-dxil -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -vk -shaderobj -output-using-type +// nested-parameter-block-2.slang + +struct CB +{ + uint4 value; +} + +struct MaterialSystem +{ + CB cb; + RWStructuredBuffer<uint4> data; +} + +struct Scene +{ + CB sceneCb; + RWStructuredBuffer<uint4> data; + ParameterBlock<MaterialSystem> material; +} + +//TEST_INPUT: set scene = new Scene { { {1,2,3,4} }, ubuffer(data=[1 2 3 4], stride=4), new MaterialSystem {{ {1,2,3,4} }, ubuffer(data=[1 2 3 4], stride=4)} } +ParameterBlock<Scene> scene; + +struct MyBuffer +{ + RWStructuredBuffer<uint4> resultBuffer; +} +//TEST_INPUT: set pb2 = new MyBuffer { out ubuffer(data=[0 0 0 0], stride=4) } +ParameterBlock<MyBuffer> pb2; + +// Main entry-point. Applies the transformation encoded by `transformer` +// to all elements in `buffer`. +[shader("compute")] +[numthreads(4,1,1)] +void computeMain(uint3 sv_dispatchThreadID : SV_DispatchThreadID) +{ + // CHECK: 4 + pb2.resultBuffer[sv_dispatchThreadID.x] = scene.sceneCb.value.x + scene.data[0].x + scene.material.cb.value.x + scene.material.data[0].x; +} diff --git a/tests/language-feature/generics/generic-shader-object-cbuffer.slang b/tests/language-feature/generics/generic-shader-object-cbuffer.slang new file mode 100644 index 000000000..eaaca7097 --- /dev/null +++ b/tests/language-feature/generics/generic-shader-object-cbuffer.slang @@ -0,0 +1,53 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -d3d11 -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -d3d12 -shaderobj -output-using-type -use-dxil +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -vk -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -cpu -shaderobj -output-using-type + +interface IFoo +{ + float getVal(); +} +interface IElement +{ + float getElementVal(); +} + +struct Elem : IElement +{ + float x; + float getElementVal() + { + return x; + } +} + +struct Impl<T1:IElement, T2:IElement> : IFoo +{ + float v1; + RWStructuredBuffer<T1> buffer0; + RWStructuredBuffer<T2> buffer1; + + float getVal() + { + return buffer0[0].getElementVal() + buffer1[0].getElementVal() + v1; + } +} + +//TEST_INPUT:set cparams = new Params { new Impl<Elem,Elem>{2.0, ubuffer(data=[1.0], stride = 4), ubuffer(data=[2.0], stride = 4)}, 1.0, ubuffer(data=[1.0], stride=4) } +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer + +struct Params +{ + ParameterBlock<Impl<Elem, Elem>> gFoo; + float v; + RWStructuredBuffer<float> buffer; +} + +ConstantBuffer<Params> cparams; +RWStructuredBuffer<float> outputBuffer; +[numthreads(1, 1, 1)] +void computeMain() +{ + // CHECK: 7.0 + outputBuffer[0] = cparams.gFoo.getVal() + cparams.v + cparams.buffer[0]; +} diff --git a/tests/language-feature/generics/generic-shader-object-cbuffer2.slang b/tests/language-feature/generics/generic-shader-object-cbuffer2.slang new file mode 100644 index 000000000..57b175418 --- /dev/null +++ b/tests/language-feature/generics/generic-shader-object-cbuffer2.slang @@ -0,0 +1,46 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -d3d11 -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -d3d12 -shaderobj -output-using-type -use-dxil +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -vk -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -cpu -shaderobj -output-using-type + +interface IFoo +{ + float getVal(); +} +interface IElement +{ + float getElementVal(); +} + +struct Elem : IElement +{ + float x; + float getElementVal() + { + return x; + } +} + +struct Impl<T1:IElement, T2:IElement> : IFoo +{ + float v1; + RWStructuredBuffer<T1> buffer0; + RWStructuredBuffer<T2> buffer1; + + float getVal() + { + return buffer0[0].getElementVal() + buffer1[0].getElementVal() + v1; + } +} +//TEST_INPUT:set gFoo = new Impl<Elem,Elem>{2.0, ubuffer(data=[1.0], stride = 4), ubuffer(data=[2.0], stride = 4)} +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer +//TEST_INPUT:set v = 1.0; + +[numthreads(1, 1, 1)] +void computeMain(uniform ParameterBlock<Impl<Elem, Elem>> gFoo, + uniform float v, + uniform RWStructuredBuffer<float> outputBuffer) +{ + // CHECK: 6.0 + outputBuffer[0] = gFoo.getVal() + v; +} diff --git a/tests/language-feature/generics/generic-shader-object.slang b/tests/language-feature/generics/generic-shader-object.slang new file mode 100644 index 000000000..746a0d0a7 --- /dev/null +++ b/tests/language-feature/generics/generic-shader-object.slang @@ -0,0 +1,48 @@ +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -d3d11 -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -d3d12 -shaderobj -output-using-type -use-dxil +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -vk -shaderobj -output-using-type +//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -cpu -shaderobj -output-using-type + +interface IFoo +{ + float getVal(); +} +interface IElement +{ + float getElementVal(); +} + +struct Elem : IElement +{ + float x; + float getElementVal() + { + return x; + } +} + +struct Impl<T1:IElement, T2:IElement> : IFoo +{ + RWStructuredBuffer<T1> buffer0; + RWStructuredBuffer<T2> buffer1; + + float getVal() + { + return buffer0[0].getElementVal() + buffer1[0].getElementVal(); + } +} + +//TEST_INPUT:set gFoo = new Impl<Elem,Elem>{ubuffer(data=[1.0], stride = 4), ubuffer(data=[2.0], stride = 4)} +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer +//TEST_INPUT:set v = 1.0; + +[numthreads(1, 1, 1)] +void computeMain( + uniform ParameterBlock<Impl<Elem, Elem>> gFoo, + uniform float v, + uniform RWStructuredBuffer<float> outputBuffer +) +{ + // CHECK: 4.0 + outputBuffer[0] = gFoo.getVal() + v; +} diff --git a/tests/reflection/default-space.slang.expected b/tests/reflection/default-space.slang.expected index 5ba17790c..2667ae96e 100644 --- a/tests/reflection/default-space.slang.expected +++ b/tests/reflection/default-space.slang.expected @@ -14,7 +14,7 @@ standard output = { }, { "name": "b", - "binding": {"kind": "registerSpace", "index": 0}, + "binding": {"kind": "subElementRegisterSpace", "index": 0}, "type": { "kind": "parameterBlock", "elementType": { @@ -32,7 +32,7 @@ standard output = { ] }, "containerVarLayout": { - "binding": {"kind": "registerSpace", "index": 0} + "binding": {"kind": "subElementRegisterSpace", "index": 0} }, "elementVarLayout": { "type": { diff --git a/tests/reflection/mix-explicit-and-implicit-spaces.slang.expected b/tests/reflection/mix-explicit-and-implicit-spaces.slang.expected index 63fe23551..36943df02 100644 --- a/tests/reflection/mix-explicit-and-implicit-spaces.slang.expected +++ b/tests/reflection/mix-explicit-and-implicit-spaces.slang.expected @@ -6,7 +6,7 @@ standard output = { "parameters": [ { "name": "a", - "binding": {"kind": "registerSpace", "index": 0}, + "binding": {"kind": "subElementRegisterSpace", "index": 0}, "type": { "kind": "parameterBlock", "elementType": { @@ -26,7 +26,7 @@ standard output = { "containerVarLayout": { "bindings": [ {"kind": "constantBuffer", "index": 0}, - {"kind": "registerSpace", "index": 0} + {"kind": "subElementRegisterSpace", "index": 0} ] }, "elementVarLayout": { @@ -50,7 +50,7 @@ standard output = { }, { "name": "b", - "binding": {"kind": "registerSpace", "index": 1}, + "binding": {"kind": "subElementRegisterSpace", "index": 1}, "type": { "kind": "parameterBlock", "elementType": { @@ -70,7 +70,7 @@ standard output = { "containerVarLayout": { "bindings": [ {"kind": "constantBuffer", "index": 0}, - {"kind": "registerSpace", "index": 0} + {"kind": "subElementRegisterSpace", "index": 0} ] }, "elementVarLayout": { @@ -94,7 +94,7 @@ standard output = { }, { "name": "c", - "binding": {"kind": "registerSpace", "index": 2}, + "binding": {"kind": "subElementRegisterSpace", "index": 2}, "type": { "kind": "parameterBlock", "elementType": { @@ -114,7 +114,7 @@ standard output = { "containerVarLayout": { "bindings": [ {"kind": "constantBuffer", "index": 0}, - {"kind": "registerSpace", "index": 0} + {"kind": "subElementRegisterSpace", "index": 0} ] }, "elementVarLayout": { diff --git a/tests/reflection/parameter-block-explicit-space.slang.expected b/tests/reflection/parameter-block-explicit-space.slang.expected index 1aa41519d..6a0c1467a 100644 --- a/tests/reflection/parameter-block-explicit-space.slang.expected +++ b/tests/reflection/parameter-block-explicit-space.slang.expected @@ -6,7 +6,7 @@ standard output = { "parameters": [ { "name": "a", - "binding": {"kind": "registerSpace", "index": 2}, + "binding": {"kind": "subElementRegisterSpace", "index": 2}, "type": { "kind": "parameterBlock", "elementType": { @@ -53,7 +53,7 @@ standard output = { "containerVarLayout": { "bindings": [ {"kind": "constantBuffer", "index": 0}, - {"kind": "registerSpace", "index": 0} + {"kind": "subElementRegisterSpace", "index": 0} ] }, "elementVarLayout": { @@ -108,7 +108,7 @@ standard output = { }, { "name": "b", - "binding": {"kind": "registerSpace", "index": 3}, + "binding": {"kind": "subElementRegisterSpace", "index": 3}, "type": { "kind": "parameterBlock", "elementType": { @@ -147,7 +147,7 @@ standard output = { "containerVarLayout": { "bindings": [ {"kind": "constantBuffer", "index": 0}, - {"kind": "registerSpace", "index": 0} + {"kind": "subElementRegisterSpace", "index": 0} ] }, "elementVarLayout": { diff --git a/tests/reflection/parameter-block.slang.2.expected b/tests/reflection/parameter-block.slang.2.expected index e4bf9b6cb..fdcc428e9 100644 --- a/tests/reflection/parameter-block.slang.2.expected +++ b/tests/reflection/parameter-block.slang.2.expected @@ -6,7 +6,7 @@ standard output = { "parameters": [ { "name": "a", - "binding": {"kind": "registerSpace", "index": 1}, + "binding": {"kind": "subElementRegisterSpace", "index": 1}, "type": { "kind": "parameterBlock", "elementType": { @@ -31,7 +31,7 @@ standard output = { ] }, "containerVarLayout": { - "binding": {"kind": "registerSpace", "index": 0} + "binding": {"kind": "subElementRegisterSpace", "index": 0} }, "elementVarLayout": { "type": { diff --git a/tests/reflection/parameter-block.slang.expected b/tests/reflection/parameter-block.slang.expected index 0909dc8cf..1d0feaa77 100644 --- a/tests/reflection/parameter-block.slang.expected +++ b/tests/reflection/parameter-block.slang.expected @@ -6,7 +6,7 @@ standard output = { "parameters": [ { "name": "a", - "binding": {"kind": "registerSpace", "index": 1}, + "binding": {"kind": "subElementRegisterSpace", "index": 1}, "type": { "kind": "parameterBlock", "elementType": { @@ -31,7 +31,7 @@ standard output = { ] }, "containerVarLayout": { - "binding": {"kind": "registerSpace", "index": 0} + "binding": {"kind": "subElementRegisterSpace", "index": 0} }, "elementVarLayout": { "type": { diff --git a/tests/reflection/unbounded-arrays.hlsl.1.expected b/tests/reflection/unbounded-arrays.hlsl.1.expected index 60d894ba7..daa1cb789 100644 --- a/tests/reflection/unbounded-arrays.hlsl.1.expected +++ b/tests/reflection/unbounded-arrays.hlsl.1.expected @@ -65,7 +65,7 @@ standard output = { }, { "name": "ee", - "binding": {"kind": "registerSpace", "index": 3, "count": 2}, + "binding": {"kind": "subElementRegisterSpace", "index": 3, "count": 2}, "type": { "kind": "array", "elementCount": 0, diff --git a/tools/gfx-unit-test/nested-parameter-block.cpp b/tools/gfx-unit-test/nested-parameter-block.cpp index 907b4c868..758fc42f5 100644 --- a/tools/gfx-unit-test/nested-parameter-block.cpp +++ b/tools/gfx-unit-test/nested-parameter-block.cpp @@ -145,11 +145,8 @@ namespace gfx_test runTestImpl(nestedParameterBlockTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); } - // TODO: Vulkan's PipelineLayout creation logic is still wrong. -#if 0 SLANG_UNIT_TEST(nestedParameterBlockTestVulkan) { runTestImpl(nestedParameterBlockTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } -#endif } diff --git a/tools/gfx-unit-test/root-shader-parameter.cpp b/tools/gfx-unit-test/root-shader-parameter.cpp index b13935c11..1a7be91c4 100644 --- a/tools/gfx-unit-test/root-shader-parameter.cpp +++ b/tools/gfx-unit-test/root-shader-parameter.cpp @@ -131,4 +131,9 @@ namespace gfx_test { runTestImpl(rootShaderParameterTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); } + + SLANG_UNIT_TEST(rootShaderParameterVulkan) + { + runTestImpl(rootShaderParameterTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + } } diff --git a/tools/gfx/cpu/cpu-shader-object-layout.cpp b/tools/gfx/cpu/cpu-shader-object-layout.cpp index 3b969c9a6..2ff89efff 100644 --- a/tools/gfx/cpu/cpu-shader-object-layout.cpp +++ b/tools/gfx/cpu/cpu-shader-object-layout.cpp @@ -81,6 +81,7 @@ ShaderObjectLayoutImpl::ShaderObjectLayoutImpl(RendererBase* renderer, slang::Ty bindingRangeInfo.baseIndex = baseIndex; bindingRangeInfo.uniformOffset = uniformOffset; bindingRangeInfo.subObjectIndex = subObjectIndex; + bindingRangeInfo.isSpecializable = m_elementTypeLayout->isBindingRangeSpecializable(r); m_bindingRanges.add(bindingRangeInfo); } diff --git a/tools/gfx/cpu/cpu-shader-object-layout.h b/tools/gfx/cpu/cpu-shader-object-layout.h index 44c225f83..e421918f1 100644 --- a/tools/gfx/cpu/cpu-shader-object-layout.h +++ b/tools/gfx/cpu/cpu-shader-object-layout.h @@ -30,6 +30,8 @@ struct BindingRangeInfo // range index and array index. // Index uniformOffset; // Uniform offset for a resource typed field. + + bool isSpecializable; }; struct SubObjectRangeInfo diff --git a/tools/gfx/cuda/cuda-shader-object-layout.cpp b/tools/gfx/cuda/cuda-shader-object-layout.cpp index 0cbe23a63..eacae0fc0 100644 --- a/tools/gfx/cuda/cuda-shader-object-layout.cpp +++ b/tools/gfx/cuda/cuda-shader-object-layout.cpp @@ -78,7 +78,8 @@ ShaderObjectLayoutImpl::ShaderObjectLayoutImpl(RendererBase* renderer, slang::Ty bindingRangeInfo.baseIndex = baseIndex; bindingRangeInfo.uniformOffset = uniformOffset; bindingRangeInfo.subObjectIndex = subObjectIndex; - m_bindingRanges.add(bindingRangeInfo); + bindingRangeInfo.isSpecializable = m_elementTypeLayout->isBindingRangeSpecializable(r); + m_bindingRanges.add(bindingRangeInfo); } SlangInt subObjectRangeCount = m_elementTypeLayout->getSubObjectRangeCount(); diff --git a/tools/gfx/cuda/cuda-shader-object-layout.h b/tools/gfx/cuda/cuda-shader-object-layout.h index 305129109..5d3a2d52a 100644 --- a/tools/gfx/cuda/cuda-shader-object-layout.h +++ b/tools/gfx/cuda/cuda-shader-object-layout.h @@ -31,6 +31,8 @@ struct BindingRangeInfo // range index and array index. // Index uniformOffset; // Uniform offset for a resource typed field. + + bool isSpecializable; }; struct SubObjectRangeInfo diff --git a/tools/gfx/d3d11/d3d11-shader-object-layout.cpp b/tools/gfx/d3d11/d3d11-shader-object-layout.cpp index ff1c5d03c..8032719b0 100644 --- a/tools/gfx/d3d11/d3d11-shader-object-layout.cpp +++ b/tools/gfx/d3d11/d3d11-shader-object-layout.cpp @@ -51,7 +51,7 @@ Result ShaderObjectLayoutImpl::Builder::setElementTypeLayout(slang::TypeLayoutRe BindingRangeInfo bindingRangeInfo; bindingRangeInfo.bindingType = slangBindingType; bindingRangeInfo.count = count; - + bindingRangeInfo.isSpecializable = typeLayout->isBindingRangeSpecializable(r); switch (slangBindingType) { case slang::BindingType::ConstantBuffer: diff --git a/tools/gfx/d3d11/d3d11-shader-object-layout.h b/tools/gfx/d3d11/d3d11-shader-object-layout.h index 717f270bc..e029a7b76 100644 --- a/tools/gfx/d3d11/d3d11-shader-object-layout.h +++ b/tools/gfx/d3d11/d3d11-shader-object-layout.h @@ -52,6 +52,9 @@ public: /// An index into the sub-object array if this binding range is treated /// as a sub-object. Index subObjectIndex; + + /// Is this binding range specializable, e.g. an existential value or ParameterBlock<IFoo>. + bool isSpecializable; }; // Sometimes we just want to iterate over the ranges that represent diff --git a/tools/gfx/d3d11/d3d11-shader-object.cpp b/tools/gfx/d3d11/d3d11-shader-object.cpp index 0354b3fdb..285cc60b6 100644 --- a/tools/gfx/d3d11/d3d11-shader-object.cpp +++ b/tools/gfx/d3d11/d3d11-shader-object.cpp @@ -334,7 +334,7 @@ Result ShaderObjectImpl::bindAsConstantBuffer( // Note that this call will use the `offset` value that might have // been modified during `_bindOrindaryDataBufferIfNeeded`. // - SLANG_RETURN_ON_FAIL(bindAsValue(context, offset, specializedLayout)); + SLANG_RETURN_ON_FAIL(bindAsValue(context, inOffset, specializedLayout)); return SLANG_OK; } diff --git a/tools/gfx/d3d12/d3d12-device.cpp b/tools/gfx/d3d12/d3d12-device.cpp index eb9e597bf..44a9faa45 100644 --- a/tools/gfx/d3d12/d3d12-device.cpp +++ b/tools/gfx/d3d12/d3d12-device.cpp @@ -98,6 +98,7 @@ Result DeviceImpl::createBuffer( D3D12_RESOURCE_STATES initialState = finalState; + switch (memoryType) { case MemoryType::ReadBack: @@ -106,18 +107,17 @@ Result DeviceImpl::createBuffer( heapProps.Type = D3D12_HEAP_TYPE_READBACK; desc.Flags = D3D12_RESOURCE_FLAG_NONE; initialState |= D3D12_RESOURCE_STATE_COPY_DEST; - break; case MemoryType::Upload: heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; desc.Flags = D3D12_RESOURCE_FLAG_NONE; initialState |= D3D12_RESOURCE_STATE_GENERIC_READ; - break; case MemoryType::DeviceLocal: heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - initialState = (srcData ? D3D12_RESOURCE_STATE_COPY_DEST : finalState); + if (initialState != D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE) + initialState = D3D12_RESOURCE_STATE_COMMON; break; default: return SLANG_FAIL; diff --git a/tools/gfx/d3d12/d3d12-shader-object-layout.cpp b/tools/gfx/d3d12/d3d12-shader-object-layout.cpp index d90b638ba..c43d3881e 100644 --- a/tools/gfx/d3d12/d3d12-shader-object-layout.cpp +++ b/tools/gfx/d3d12/d3d12-shader-object-layout.cpp @@ -124,6 +124,7 @@ Result ShaderObjectLayoutImpl::Builder::setElementTypeLayout( static_cast<DeviceImpl*>(m_renderer)->m_extendedDesc.rootParameterShaderAttributeName, typeLayout, r); + bindingRangeInfo.isSpecializable = typeLayout->isBindingRangeSpecializable(r); if (bindingRangeInfo.isRootParameter) { RootParameterInfo rootInfo = {}; @@ -587,7 +588,7 @@ Result RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addDescriptorRange( physicalDescriptorSetIndex, rangeType, (UINT)index + elementOffset[rangeType], - (UINT)space + containerOffset.spaceOffset, + (UINT)space + elementOffset.spaceOffset, (UINT)count, isRootParameter); } @@ -646,7 +647,10 @@ void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addAsValue( slang::VariableLayoutReflection* varLayout, Index physicalDescriptorSetIndex) { BindingRegisterOffsetPair offset(varLayout); - addAsValue(varLayout->getTypeLayout(), physicalDescriptorSetIndex, offset, offset); + auto elementOffset = offset; + elementOffset.primary.spaceOffset = 0; + elementOffset.pending.spaceOffset = 0; + addAsValue(varLayout->getTypeLayout(), physicalDescriptorSetIndex, offset, elementOffset); } /// Add binding ranges and parameter blocks to the root signature. @@ -658,30 +662,34 @@ void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addAsValue( /// the descriptor set that binding ranges not belonging to nested /// parameter blocks should be added to. /// -/// The `offset` encodes information about space and/or register offsets that -/// should be applied to descrptor ranges. +/// The `offsetForChildrenThatNeedNewSpace` and `offsetForOrdinaryChildren` parameters +/// encode information about space and/or register offsets that should be applied to +/// descrptor ranges. `offsetForChildrenThatNeedNewSpace` will contain a space offset +/// for children that requires a new space, such as a ParameterBlock. +/// `offsetForOrdinaryChildren` contains the space for all direct children that should +/// be placed in. /// void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addAsConstantBuffer( slang::TypeLayoutReflection* typeLayout, Index physicalDescriptorSetIndex, - BindingRegisterOffsetPair const& containerOffset, - BindingRegisterOffsetPair const& elementOffset) + BindingRegisterOffsetPair const& offsetForChildrenThatNeedNewSpace, + BindingRegisterOffsetPair const& offsetForOrdinaryChildren) { if (typeLayout->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM) != 0) { auto descriptorRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - auto& offsetForRangeType = containerOffset.primary.offsetForRangeType[descriptorRangeType]; + auto& offsetForRangeType = offsetForOrdinaryChildren.primary.offsetForRangeType[descriptorRangeType]; addDescriptorRange( physicalDescriptorSetIndex, descriptorRangeType, offsetForRangeType, - containerOffset.primary.spaceOffset, + offsetForOrdinaryChildren.primary.spaceOffset, 1, false); } - addAsValue(typeLayout, physicalDescriptorSetIndex, containerOffset, elementOffset); + addAsValue(typeLayout, physicalDescriptorSetIndex, offsetForChildrenThatNeedNewSpace, offsetForOrdinaryChildren); } void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addAsValue( @@ -743,6 +751,8 @@ void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addAsValue( BindingRegisterOffsetPair subObjectRangeElementOffset = elementOffset; subObjectRangeElementOffset += BindingRegisterOffsetPair(typeLayout->getSubObjectRangeOffset(subObjectRangeIndex)); + subObjectRangeElementOffset.primary.spaceOffset = elementOffset.primary.spaceOffset; + subObjectRangeElementOffset.pending.spaceOffset = elementOffset.pending.spaceOffset; switch (bindingType) { @@ -781,23 +791,30 @@ void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addAsValue( BindingRegisterOffsetPair subDescriptorSetOffset; subDescriptorSetOffset.primary.spaceOffset = - subObjectRangeElementOffset.primary.spaceOffset; + subObjectRangeContainerOffset.primary.spaceOffset; subDescriptorSetOffset.pending.spaceOffset = - subObjectRangeElementOffset.pending.spaceOffset; + subObjectRangeContainerOffset.pending.spaceOffset; auto subPhysicalDescriptorSetIndex = addDescriptorSet(); - BindingRegisterOffsetPair containerOffset = subDescriptorSetOffset; - containerOffset += BindingRegisterOffsetPair(containerVarLayout); - - BindingRegisterOffsetPair elementOffset = subDescriptorSetOffset; - elementOffset += BindingRegisterOffsetPair(elementVarLayout); + // We recursively call `addAsConstantBuffer` to actually generate + // the root signature bindings for children in the parameter block. + // We must compute `containerOffset`, which include a space offset + // that any sub ParameterBlocks should start from, and `elementOffset` + // that encodes the space offset of the current parameter block. + // The space offset of the current parameter block can be obtained from the + // `containerVarLayout`, and the space offset of any sub ParameterBlocks + // are obatined from `elementVarLayout`. + BindingRegisterOffsetPair offsetForChildrenThatNeedNewSpace = subDescriptorSetOffset; + offsetForChildrenThatNeedNewSpace += BindingRegisterOffsetPair(elementVarLayout); + BindingRegisterOffsetPair offsetForOrindaryChildren = subDescriptorSetOffset; + offsetForOrindaryChildren += BindingRegisterOffsetPair(containerVarLayout); addAsConstantBuffer( elementTypeLayout, subPhysicalDescriptorSetIndex, - containerOffset, - elementOffset); + offsetForChildrenThatNeedNewSpace, + offsetForOrindaryChildren); } break; diff --git a/tools/gfx/d3d12/d3d12-shader-object-layout.h b/tools/gfx/d3d12/d3d12-shader-object-layout.h index 8b72067f7..accd30aa9 100644 --- a/tools/gfx/d3d12/d3d12-shader-object-layout.h +++ b/tools/gfx/d3d12/d3d12-shader-object-layout.h @@ -67,6 +67,9 @@ public: uint32_t subObjectIndex; bool isRootParameter; + + /// Is this binding range represent a specialization point, such as an existential value, or a `ParameterBlock<IFoo>`. + bool isSpecializable; }; /// Offset information for a sub-object range @@ -320,7 +323,7 @@ public: if (varLayout) { spaceOffset = - (UINT)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_REGISTER_SPACE); + (UINT)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SUB_ELEMENT_REGISTER_SPACE); offsetForRangeType[D3D12_DESCRIPTOR_RANGE_TYPE_CBV] = (UINT)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER); offsetForRangeType[D3D12_DESCRIPTOR_RANGE_TYPE_SRV] = diff --git a/tools/gfx/d3d12/d3d12-shader-object.cpp b/tools/gfx/d3d12/d3d12-shader-object.cpp index 74760eabd..5227579ce 100644 --- a/tools/gfx/d3d12/d3d12-shader-object.cpp +++ b/tools/gfx/d3d12/d3d12-shader-object.cpp @@ -440,7 +440,7 @@ void ShaderObjectImpl::updateSubObjectsRecursive() if (!subObject) continue; subObject->updateSubObjectsRecursive(); - if (m_subObjectVersions[objectIndex] != m_objects[objectIndex]->m_version) + if (m_subObjectVersions.getCount() > objectIndex && m_subObjectVersions[objectIndex] != m_objects[objectIndex]->m_version) { ShaderOffset offset; offset.bindingRangeIndex = (GfxIndex)subObjectRange.bindingRangeIndex; diff --git a/tools/gfx/open-gl/render-gl.cpp b/tools/gfx/open-gl/render-gl.cpp index 16f2b0045..c9eb1d94d 100644 --- a/tools/gfx/open-gl/render-gl.cpp +++ b/tools/gfx/open-gl/render-gl.cpp @@ -670,6 +670,7 @@ public: Index count; Index baseIndex; Index subObjectIndex; + bool isSpecializable; }; struct SubObjectRangeInfo @@ -721,7 +722,7 @@ public: BindingRangeInfo bindingRangeInfo; bindingRangeInfo.bindingType = slangBindingType; bindingRangeInfo.count = count; - + bindingRangeInfo.isSpecializable = typeLayout->isBindingRangeSpecializable(r); switch (slangBindingType) { case slang::BindingType::ConstantBuffer: diff --git a/tools/gfx/renderer-shared.h b/tools/gfx/renderer-shared.h index f94b909f7..9e208c34c 100644 --- a/tools/gfx/renderer-shared.h +++ b/tools/gfx/renderer-shared.h @@ -1524,16 +1524,20 @@ Result ShaderObjectBaseImpl<TShaderObjectImpl, TShaderObjectLayoutImpl, TShaderO case slang::BindingType::ConstantBuffer: case slang::BindingType::RawBuffer: case slang::BindingType::MutableRawBuffer: - // Currently we only handle the case where the field's type is - // `ParameterBlock<SomeStruct>` or `ConstantBuffer<SomeStruct>`, where - // `SomeStruct` is a struct type (not directly an interface type). In this case, - // we just recursively collect the specialization arguments from the bound sub - // object. + // If the field's type is `ParameterBlock<IFoo>`, we want to pull in the type argument + // from the sub object for specialization. + if (bindingRange.isSpecializable) + { + ExtendedShaderObjectType specializedSubObjType; + SLANG_RETURN_ON_FAIL( + subObject->getSpecializedShaderObjectType(&specializedSubObjType)); + typeArgs.add(specializedSubObjType); + } + + // If field's type is `ParameterBlock<SomeStruct>` or `ConstantBuffer<SomeStruct>`, where + // `SomeStruct` is a struct type (not directly an interface type), we need to recursively + // collect the specialization arguments from the bound sub object. SLANG_RETURN_ON_FAIL(subObject->collectSpecializationArgs(typeArgs)); - // TODO: we need to handle the case where the field is of the form - // `ParameterBlock<IFoo>`. We should treat this case the same way as the - // `ExistentialValue` case here, but currently we lack a mechanism to - // distinguish the two scenarios. break; } diff --git a/tools/gfx/vulkan/vk-command-encoder.cpp b/tools/gfx/vulkan/vk-command-encoder.cpp index ddb48833f..78d8a751f 100644 --- a/tools/gfx/vulkan/vk-command-encoder.cpp +++ b/tools/gfx/vulkan/vk-command-encoder.cpp @@ -130,12 +130,8 @@ Result PipelineCommandEncoder::bindRootShaderObjectImpl(VkPipelineBindPoint bind // by the specialized program layout. // List<VkDescriptorSet> descriptorSetsStorage; - auto descriptorSetCount = specializedLayout->getTotalDescriptorSetCount(); - descriptorSetsStorage.setCount(descriptorSetCount); - auto descriptorSets = descriptorSetsStorage.getBuffer(); - - context.descriptorSets = descriptorSets; + context.descriptorSets = &descriptorSetsStorage; // We kick off recursive binding of shader objects to the pipeline (plus // the state in `context`). @@ -151,15 +147,15 @@ Result PipelineCommandEncoder::bindRootShaderObjectImpl(VkPipelineBindPoint bind // Once we've filled in all the descriptor sets, we bind them // to the pipeline at once. // - if (descriptorSetCount > 0) + if (descriptorSetsStorage.getCount() > 0) { m_device->m_api.vkCmdBindDescriptorSets( m_commandBuffer->m_commandBuffer, bindPoint, specializedLayout->m_pipelineLayout, 0, - (uint32_t)descriptorSetCount, - descriptorSets, + (uint32_t)descriptorSetsStorage.getCount(), + descriptorSetsStorage.getBuffer(), 0, nullptr); } diff --git a/tools/gfx/vulkan/vk-helper-functions.h b/tools/gfx/vulkan/vk-helper-functions.h index e2fae801e..8eab863f4 100644 --- a/tools/gfx/vulkan/vk-helper-functions.h +++ b/tools/gfx/vulkan/vk-helper-functions.h @@ -140,12 +140,10 @@ struct RootBindingContext DeviceImpl* device; /// The descriptor sets that are being allocated and bound - VkDescriptorSet* descriptorSets; + List<VkDescriptorSet>* descriptorSets; /// Information about all the push-constant ranges that should be bound ConstArrayView<VkPushConstantRange> pushConstantRanges; - - uint32_t descriptorSetCounter = 0; }; Size calcRowSize(Format format, int width); diff --git a/tools/gfx/vulkan/vk-shader-object-layout.cpp b/tools/gfx/vulkan/vk-shader-object-layout.cpp index 03dc1f11a..d7f0d0fd0 100644 --- a/tools/gfx/vulkan/vk-shader-object-layout.cpp +++ b/tools/gfx/vulkan/vk-shader-object-layout.cpp @@ -394,7 +394,7 @@ void ShaderObjectLayoutImpl::Builder::addBindingRanges(slang::TypeLayoutReflecti bindingRangeInfo.count = count; bindingRangeInfo.baseIndex = baseIndex; bindingRangeInfo.subObjectIndex = subObjectIndex; - + bindingRangeInfo.isSpecializable = typeLayout->isBindingRangeSpecializable(r); // We'd like to extract the information on the GLSL/SPIR-V // `binding` that this range should bind into (or whatever // other specific kind of offset/index is appropriate to it). diff --git a/tools/gfx/vulkan/vk-shader-object-layout.h b/tools/gfx/vulkan/vk-shader-object-layout.h index cf4035f70..e1a01dcf3 100644 --- a/tools/gfx/vulkan/vk-shader-object-layout.h +++ b/tools/gfx/vulkan/vk-shader-object-layout.h @@ -59,6 +59,10 @@ public: // TODO: Ideally we could refactor so that only the root shader object layout // stores a set offset for its binding ranges, and all other objects skip // storing a field that never actually matters. + + // Is this binding range representing a specialization point, such as + // an existential value or a ParameterBlock<IFoo>. + bool isSpecializable; }; // Sometimes we just want to iterate over the ranges that represent diff --git a/tools/gfx/vulkan/vk-shader-object.cpp b/tools/gfx/vulkan/vk-shader-object.cpp index 3c452c59c..31422429b 100644 --- a/tools/gfx/vulkan/vk-shader-object.cpp +++ b/tools/gfx/vulkan/vk-shader-object.cpp @@ -321,7 +321,7 @@ void ShaderObjectImpl::writeBufferDescriptor( Offset bufferOffset, Size bufferSize) { - auto descriptorSet = context.descriptorSets[offset.bindingSet]; + auto descriptorSet = (*context.descriptorSets)[offset.bindingSet]; VkDescriptorBufferInfo bufferInfo = {}; if (buffer) @@ -359,7 +359,7 @@ void ShaderObjectImpl::writePlainBufferDescriptor( VkDescriptorType descriptorType, ArrayView<RefPtr<ResourceViewInternalBase>> resourceViews) { - auto descriptorSet = context.descriptorSets[offset.bindingSet]; + auto descriptorSet = (*context.descriptorSets)[offset.bindingSet]; Index count = resourceViews.getCount(); for (Index i = 0; i < count; ++i) @@ -398,7 +398,7 @@ void ShaderObjectImpl::writeTexelBufferDescriptor( VkDescriptorType descriptorType, ArrayView<RefPtr<ResourceViewInternalBase>> resourceViews) { - auto descriptorSet = context.descriptorSets[offset.bindingSet]; + auto descriptorSet = (*context.descriptorSets)[offset.bindingSet]; Index count = resourceViews.getCount(); for (Index i = 0; i < count; ++i) @@ -432,7 +432,7 @@ void ShaderObjectImpl::writeTextureSamplerDescriptor( VkDescriptorType descriptorType, ArrayView<CombinedTextureSamplerSlot> slots) { - auto descriptorSet = context.descriptorSets[offset.bindingSet]; + auto descriptorSet = (*context.descriptorSets)[offset.bindingSet]; Index count = slots.getCount(); for (Index i = 0; i < count; ++i) @@ -473,7 +473,7 @@ void ShaderObjectImpl::writeAccelerationStructureDescriptor( VkDescriptorType descriptorType, ArrayView<RefPtr<ResourceViewInternalBase>> resourceViews) { - auto descriptorSet = context.descriptorSets[offset.bindingSet]; + auto descriptorSet = (*context.descriptorSets)[offset.bindingSet]; Index count = resourceViews.getCount(); for (Index i = 0; i < count; ++i) @@ -511,7 +511,7 @@ void ShaderObjectImpl::writeTextureDescriptor( VkDescriptorType descriptorType, ArrayView<RefPtr<ResourceViewInternalBase>> resourceViews) { - auto descriptorSet = context.descriptorSets[offset.bindingSet]; + auto descriptorSet = (*context.descriptorSets)[offset.bindingSet]; Index count = resourceViews.getCount(); for (Index i = 0; i < count; ++i) @@ -548,7 +548,7 @@ void ShaderObjectImpl::writeSamplerDescriptor( VkDescriptorType descriptorType, ArrayView<RefPtr<SamplerStateImpl>> samplers) { - auto descriptorSet = context.descriptorSets[offset.bindingSet]; + auto descriptorSet = (*context.descriptorSets)[offset.bindingSet]; Index count = samplers.getCount(); for (Index i = 0; i < count; ++i) @@ -865,8 +865,7 @@ Result ShaderObjectImpl::allocateDescriptorSets( // we can bind all the descriptor sets to the pipeline when the // time comes. // - context.descriptorSets[context.descriptorSetCounter] = descriptorSetHandle; - context.descriptorSetCounter++; + (*context.descriptorSets).add(descriptorSetHandle); } return SLANG_OK; @@ -884,7 +883,7 @@ Result ShaderObjectImpl::bindAsParameterBlock( // not the sets for any parent object(s). // BindingOffset offset = inOffset; - offset.bindingSet = context.descriptorSetCounter; + offset.bindingSet = (uint32_t)context.descriptorSets->getCount(); offset.binding = 0; // TODO: We should also be writing to `offset.pending` here, @@ -901,7 +900,7 @@ Result ShaderObjectImpl::bindAsParameterBlock( // SLANG_RETURN_ON_FAIL(allocateDescriptorSets(encoder, context, offset, specializedLayout)); - assert(offset.bindingSet < context.descriptorSetCounter); + assert(offset.bindingSet < (uint32_t)context.descriptorSets->getCount()); SLANG_RETURN_ON_FAIL(bindAsConstantBuffer(encoder, context, offset, specializedLayout)); return SLANG_OK; diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp index 80ce4e316..6b30315fb 100644 --- a/tools/render-test/shader-input-layout.cpp +++ b/tools/render-test/shader-input-layout.cpp @@ -436,7 +436,13 @@ namespace renderer_test { StringBuilder sb; sb << typeName << "<"; - sb << parseTypeName(parser); + for (;;) + { + sb << parseTypeName(parser); + if (!parser.AdvanceIf(",")) + break; + sb << ","; + } sb << ">"; parser.Read(">"); return sb.produceString(); diff --git a/tools/slang-reflection-test/slang-reflection-test-main.cpp b/tools/slang-reflection-test/slang-reflection-test-main.cpp index cd726eb59..19d8f1a18 100644 --- a/tools/slang-reflection-test/slang-reflection-test-main.cpp +++ b/tools/slang-reflection-test/slang-reflection-test-main.cpp @@ -291,6 +291,7 @@ static void emitReflectionVarBindingInfoJSON( CASE(SPECIALIZATION_CONSTANT, specializationConstant); CASE(MIXED, mixed); CASE(REGISTER_SPACE, registerSpace); + CASE(SUB_ELEMENT_REGISTER_SPACE, subElementRegisterSpace); CASE(GENERIC, generic); #undef CASE |
