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 /source/slang | |
| 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>
Diffstat (limited to 'source/slang')
| -rw-r--r-- | source/slang/slang-ast-type.cpp | 9 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-check-shader.cpp | 76 | ||||
| -rw-r--r-- | source/slang/slang-check-type.cpp | 4 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 40 | ||||
| -rw-r--r-- | source/slang/slang-ir-legalize-types.cpp | 1 | ||||
| -rw-r--r-- | source/slang/slang-ir-spirv-legalize.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-language-server.cpp | 139 | ||||
| -rw-r--r-- | source/slang/slang-legalize-types.cpp | 38 | ||||
| -rw-r--r-- | source/slang/slang-parameter-binding.cpp | 15 | ||||
| -rw-r--r-- | source/slang/slang-reflection-api.cpp | 130 | ||||
| -rw-r--r-- | source/slang/slang-type-layout.cpp | 70 | ||||
| -rw-r--r-- | source/slang/slang-type-layout.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-workspace-version.cpp | 3 |
15 files changed, 393 insertions, 141 deletions
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])) |
