summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2023-11-01 21:42:12 -0700
committerGitHub <noreply@github.com>2023-11-01 21:42:12 -0700
commit6aca3813c4ccc496c0f9b2db293acb546aa11d2d (patch)
tree5281f0ac62946787db90409c1ab3da5ed3f0fc5c /source/slang
parent532c4322c9d9ab2c95a5bb573c89062456b59236 (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.cpp9
-rw-r--r--source/slang/slang-check-impl.h2
-rw-r--r--source/slang/slang-check-shader.cpp76
-rw-r--r--source/slang/slang-check-type.cpp4
-rw-r--r--source/slang/slang-diagnostic-defs.h2
-rw-r--r--source/slang/slang-emit-c-like.cpp40
-rw-r--r--source/slang/slang-ir-legalize-types.cpp1
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp2
-rw-r--r--source/slang/slang-language-server.cpp139
-rw-r--r--source/slang/slang-legalize-types.cpp38
-rw-r--r--source/slang/slang-parameter-binding.cpp15
-rw-r--r--source/slang/slang-reflection-api.cpp130
-rw-r--r--source/slang/slang-type-layout.cpp70
-rw-r--r--source/slang/slang-type-layout.h3
-rw-r--r--source/slang/slang-workspace-version.cpp3
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]))