summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--slang.h14
-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
-rw-r--r--tests/bindings/nested-parameter-block-2.slang42
-rw-r--r--tests/language-feature/generics/generic-shader-object-cbuffer.slang53
-rw-r--r--tests/language-feature/generics/generic-shader-object-cbuffer2.slang46
-rw-r--r--tests/language-feature/generics/generic-shader-object.slang48
-rw-r--r--tests/reflection/default-space.slang.expected4
-rw-r--r--tests/reflection/mix-explicit-and-implicit-spaces.slang.expected12
-rw-r--r--tests/reflection/parameter-block-explicit-space.slang.expected8
-rw-r--r--tests/reflection/parameter-block.slang.2.expected4
-rw-r--r--tests/reflection/parameter-block.slang.expected4
-rw-r--r--tests/reflection/unbounded-arrays.hlsl.1.expected2
-rw-r--r--tools/gfx-unit-test/nested-parameter-block.cpp3
-rw-r--r--tools/gfx-unit-test/root-shader-parameter.cpp5
-rw-r--r--tools/gfx/cpu/cpu-shader-object-layout.cpp1
-rw-r--r--tools/gfx/cpu/cpu-shader-object-layout.h2
-rw-r--r--tools/gfx/cuda/cuda-shader-object-layout.cpp3
-rw-r--r--tools/gfx/cuda/cuda-shader-object-layout.h2
-rw-r--r--tools/gfx/d3d11/d3d11-shader-object-layout.cpp2
-rw-r--r--tools/gfx/d3d11/d3d11-shader-object-layout.h3
-rw-r--r--tools/gfx/d3d11/d3d11-shader-object.cpp2
-rw-r--r--tools/gfx/d3d12/d3d12-device.cpp6
-rw-r--r--tools/gfx/d3d12/d3d12-shader-object-layout.cpp53
-rw-r--r--tools/gfx/d3d12/d3d12-shader-object-layout.h5
-rw-r--r--tools/gfx/d3d12/d3d12-shader-object.cpp2
-rw-r--r--tools/gfx/open-gl/render-gl.cpp3
-rw-r--r--tools/gfx/renderer-shared.h22
-rw-r--r--tools/gfx/vulkan/vk-command-encoder.cpp12
-rw-r--r--tools/gfx/vulkan/vk-helper-functions.h4
-rw-r--r--tools/gfx/vulkan/vk-shader-object-layout.cpp2
-rw-r--r--tools/gfx/vulkan/vk-shader-object-layout.h4
-rw-r--r--tools/gfx/vulkan/vk-shader-object.cpp21
-rw-r--r--tools/render-test/shader-input-layout.cpp8
-rw-r--r--tools/slang-reflection-test/slang-reflection-test-main.cpp1
48 files changed, 716 insertions, 221 deletions
diff --git a/slang.h b/slang.h
index fab62cf81..3fc92d01d 100644
--- a/slang.h
+++ b/slang.h
@@ -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