summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2019-12-06 09:29:09 -0800
committerGitHub <noreply@github.com>2019-12-06 09:29:09 -0800
commit54d3c5f6657b1099326e1ce7ec0f0692e7025442 (patch)
treeaa9baed99939fc3b068f3c330e4a59f5147020e4
parent4e2cfc95fb02fb47f02b8702494929e7cca3bec7 (diff)
Remove legacy feature for merging global shader parameters (#1139)
* Remove legacy feature for merging global shader parameters There is a fair amount of special-case code in the Slang compiler today to deal with the scenario where a programmer declares the "same" shader parameter across two different translation units: ```hlsl // a.hlsl Texture2D a; cbuffer C { float4 c; } ``` ```hlsl // b.hlsl cbuffer C { float4 c; } Texture2D b; ``` An important note here is that the declaration of `C` may be in a header file that both `a.hlsl` and `b.hlsl` `#include`, because from the standpoint of the parser and later stages of the compiler, there is no difference between `C` being in an included file vs. it being copy-pasted across both `a.hlsl` and `b.hlsl`. When a user invokes `slangc a.hlsl b.hlsl` (or the equivalent via the API), then they may decide that it is "obvious" that the shader parameter `C` is the "same" in both `a.hlsl` and `b.hlsl`. Knowing that the parameter is the "same" may lead them to make certain assumptions: * They may assume that generated code for entry points in `a.hlsl` and `b.hlsl` will both agree on the exact `register`/`binding` occupied by `C`. * They may assume that reflection information for their program will only reflect `C` once, and it will reflect it in a way that is applicable to entry points in both `a.hlsl` and `b.hlsl` * They may assume that the compiler can and should handle this use case even when `C` contains fields with `struct` types that are declared in both `a.hlsl` and `b.hlsl` that have the "same" definition. * They may assume that in cases where `C` is declared inconsistently between `a.hlsl` and `b.hlsl` the compiler can and will diagnose an error. Making these assumptions work in practice required a lot of special-case code: * When composing/linking programs was `ComponentType`s we had to include a special case `LegacyProgram` type that could provide these "do what I mean" semantics, since they are *not* what one would want in the general case for a `CompositeComponentType`. * During enumeration of global shader parameter in a `LegacyProgram`, we had to detect parameters from distinct modules (translation units) with the same name, and then enforce that they must have the "same" type (via an ad hoc recursive structural type match). No other semantic checking logic needs or uses that kind of structural check. * During parameter binding generation, we need to handle the case where a single global shader parameter might have multiple declarations, and make sure to collect explicit bindings from all of them (checking for inconsistency) and also to apply generated bindings to all of them. * The `mapVarToLayout` member in `StructTypeLayout` is a concession to the fact that we might have multiple `VarDecl`s for each field of the struct that represents the global scope, we might need to look up a field and its layout using any of those declarations (much of the need for this field had gone away now that IR passes are largely using IR-based layout). All of these different special cases added more complex code in many places in the compiler, all to support a scenario that isn't especially common. Most users won't be affected by the original issue, because they will do one of several things that rule it out: * Anybody using `slangc` like a stand-in for `fxc` or `dxc` and compiling one translation unit at a time will not suffer from any problems. If/when such users want consistent bindings across translation units, they already use either explicit binding or rely on consistent ordering and implicit binding. * Anybody who puts all the entry points that get combined into a pass/pipeline in a single file will not have problems. They will automatically get consistent bindings because of Slang's guarantees, and there can't be duplicated declarations when there is only one translation unit. * Anybody using `import` to factor out common declarations while compiling multiple translation units at once will not be affected. Parameters declared in an `import`ed module are the "same" in a much deeper way that it is trivial for Slang to support. Only users of the Falcor framework are likely to be affected by this, and they have two easy migration paths: either put related entry points into the same file, or factor common parameters into an `import`ed module. (It is also worth noting that for command-line `slangc`, it is possible to have a single module with multiple `.slang` files in it, which can all see global declarations like parameters across all the files. Anybody who buys into doing things the Slang Way should have no problem avoiding duplicated declarations) With the rationale out of the way, the actual change mostly just amounts to deleting lots of code that is no longer needed. An astute reviewer might notice several `assert`-fail conditions where complex Slang features were never actually made to work correctly with this legacy behavior. A small number of test cases broke with the code changes, but these were tests that specifically exercised the behavior being removed. In the case of the tests around binding/reflection generating, I rewrote the tests to use one of the idomatic workarounds (putting the shared parameters into an `import`ed module), but doing so required me to add support for `#include` when doing pass-through compilation with `fxc`. That logic added a bit more cruft than I had originally hoped to this commit, but having `#include` support when doing pass-through compilation is probably a net win. * fixup: 64-bit warning
-rw-r--r--source/slang/slang-check-shader.cpp513
-rw-r--r--source/slang/slang-compiler.cpp106
-rw-r--r--source/slang/slang-compiler.h116
-rw-r--r--source/slang/slang-lower-to-ir.cpp11
-rw-r--r--source/slang/slang-parameter-binding.cpp202
-rw-r--r--source/slang/slang.cpp265
-rw-r--r--tests/bindings/multi-file-defines.h44
-rw-r--r--tests/bindings/multi-file-extra.hlsl77
-rw-r--r--tests/bindings/multi-file-shared.slang25
-rw-r--r--tests/bindings/multi-file.hlsl80
-rw-r--r--tests/diagnostics/gh-38-vs.hlsl2
-rw-r--r--tests/diagnostics/gh-38-vs.hlsl.expected4
-rw-r--r--tests/reflection/multi-file-defines.h44
-rw-r--r--tests/reflection/multi-file-extra.hlsl51
-rw-r--r--tests/reflection/multi-file-shared.slang25
-rw-r--r--tests/reflection/multi-file.hlsl68
-rw-r--r--tests/reflection/multi-file.hlsl.expected82
17 files changed, 489 insertions, 1226 deletions
diff --git a/source/slang/slang-check-shader.cpp b/source/slang/slang-check-shader.cpp
index c229e8f96..611f6be58 100644
--- a/source/slang/slang-check-shader.cpp
+++ b/source/slang/slang-check-shader.cpp
@@ -569,408 +569,15 @@ namespace Slang
return entryPoint;
}
- /// Get the name a variable will use for reflection purposes
-Name* getReflectionName(VarDeclBase* varDecl)
-{
- if (auto reflectionNameModifier = varDecl->FindModifier<ParameterGroupReflectionName>())
- return reflectionNameModifier->nameAndLoc.name;
-
- return varDecl->getName();
-}
-
-// Information tracked when doing a structural
-// match of types.
-struct StructuralTypeMatchStack
-{
- DeclRef<VarDeclBase> leftDecl;
- DeclRef<VarDeclBase> rightDecl;
- StructuralTypeMatchStack* parent;
-};
-
-static void diagnoseParameterTypeMismatch(
- DiagnosticSink* sink,
- StructuralTypeMatchStack* inStack)
-{
- SLANG_ASSERT(inStack);
-
- // The bottom-most entry in the stack should represent
- // the shader parameters that kicked things off
- auto stack = inStack;
- while(stack->parent)
- stack = stack->parent;
-
- sink->diagnose(stack->leftDecl, Diagnostics::shaderParameterDeclarationsDontMatch, getReflectionName(stack->leftDecl));
- sink->diagnose(stack->rightDecl, Diagnostics::seeOtherDeclarationOf, getReflectionName(stack->rightDecl));
-}
-
-// Two types that were expected to match did not.
-// Inform the user with a suitable message.
-static void diagnoseTypeMismatch(
- DiagnosticSink* sink,
- StructuralTypeMatchStack* inStack)
-{
- auto stack = inStack;
- SLANG_ASSERT(stack);
- diagnoseParameterTypeMismatch(sink, stack);
-
- auto leftType = GetType(stack->leftDecl);
- auto rightType = GetType(stack->rightDecl);
-
- if( stack->parent )
- {
- sink->diagnose(stack->leftDecl, Diagnostics::fieldTypeMisMatch, getReflectionName(stack->leftDecl), leftType, rightType);
- sink->diagnose(stack->rightDecl, Diagnostics::seeOtherDeclarationOf, getReflectionName(stack->rightDecl));
-
- stack = stack->parent;
- if( stack )
- {
- while( stack->parent )
- {
- sink->diagnose(stack->leftDecl, Diagnostics::usedInDeclarationOf, getReflectionName(stack->leftDecl));
- stack = stack->parent;
- }
- }
- }
- else
- {
- sink->diagnose(stack->leftDecl, Diagnostics::shaderParameterTypeMismatch, leftType, rightType);
- }
-}
-
-// Two types that were expected to match did not.
-// Inform the user with a suitable message.
-static void diagnoseTypeFieldsMismatch(
- DiagnosticSink* sink,
- DeclRef<Decl> const& left,
- DeclRef<Decl> const& right,
- StructuralTypeMatchStack* stack)
-{
- diagnoseParameterTypeMismatch(sink, stack);
-
- sink->diagnose(left, Diagnostics::fieldDeclarationsDontMatch, left.GetName());
- sink->diagnose(right, Diagnostics::seeOtherDeclarationOf, right.GetName());
-
- if( stack )
- {
- while( stack->parent )
- {
- sink->diagnose(stack->leftDecl, Diagnostics::usedInDeclarationOf, getReflectionName(stack->leftDecl));
- stack = stack->parent;
- }
- }
-}
-
-static void collectFields(
- DeclRef<AggTypeDecl> declRef,
- List<DeclRef<VarDecl>>& outFields)
-{
- for( auto fieldDeclRef : getMembersOfType<VarDecl>(declRef) )
- {
- if(fieldDeclRef.getDecl()->HasModifier<HLSLStaticModifier>())
- continue;
-
- outFields.add(fieldDeclRef);
- }
-}
-
-static bool validateTypesMatch(
- DiagnosticSink* sink,
- Type* left,
- Type* right,
- StructuralTypeMatchStack* stack);
-
-static bool validateIntValuesMatch(
- DiagnosticSink* sink,
- IntVal* left,
- IntVal* right,
- StructuralTypeMatchStack* stack)
-{
- if(left->EqualsVal(right))
- return true;
-
- // TODO: are there other cases we need to handle here?
-
- diagnoseTypeMismatch(sink, stack);
- return false;
-}
-
-
-static bool validateValuesMatch(
- DiagnosticSink* sink,
- Val* left,
- Val* right,
- StructuralTypeMatchStack* stack)
-{
- if( auto leftType = dynamicCast<Type>(left) )
- {
- if( auto rightType = dynamicCast<Type>(right) )
- {
- return validateTypesMatch(sink, leftType, rightType, stack);
- }
- }
-
- if( auto leftInt = dynamicCast<IntVal>(left) )
- {
- if( auto rightInt = dynamicCast<IntVal>(right) )
- {
- return validateIntValuesMatch(sink, leftInt, rightInt, stack);
- }
- }
-
- if( auto leftWitness = dynamicCast<SubtypeWitness>(left) )
- {
- if( auto rightWitness = dynamicCast<SubtypeWitness>(right) )
- {
- return true;
- }
- }
-
- diagnoseTypeMismatch(sink, stack);
- return false;
-}
-
-static bool validateGenericSubstitutionsMatch(
- DiagnosticSink* sink,
- GenericSubstitution* left,
- GenericSubstitution* right,
- StructuralTypeMatchStack* stack)
-{
- if( !left )
- {
- if( !right )
- {
- return true;
- }
-
- diagnoseTypeMismatch(sink, stack);
- return false;
- }
-
-
-
- Index argCount = left->args.getCount();
- if( argCount != right->args.getCount() )
- {
- diagnoseTypeMismatch(sink, stack);
- return false;
- }
-
- for( Index aa = 0; aa < argCount; ++aa )
- {
- auto leftArg = left->args[aa];
- auto rightArg = right->args[aa];
-
- if(!validateValuesMatch(sink, leftArg, rightArg, stack))
- return false;
- }
-
- return true;
-}
-
-static bool validateThisTypeSubstitutionsMatch(
- DiagnosticSink* /*sink*/,
- ThisTypeSubstitution* /*left*/,
- ThisTypeSubstitution* /*right*/,
- StructuralTypeMatchStack* /*stack*/)
-{
- // TODO: actual checking.
- return true;
-}
-
-static bool validateSpecializationsMatch(
- DiagnosticSink* sink,
- SubstitutionSet left,
- SubstitutionSet right,
- StructuralTypeMatchStack* stack)
-{
- auto ll = left.substitutions;
- auto rr = right.substitutions;
- for(;;)
- {
- // Skip any global generic substitutions.
- if(auto leftGlobalGeneric = as<GlobalGenericParamSubstitution>(ll))
- {
- ll = leftGlobalGeneric->outer;
- continue;
- }
- if(auto rightGlobalGeneric = as<GlobalGenericParamSubstitution>(rr))
- {
- rr = rightGlobalGeneric->outer;
- continue;
- }
-
- // If either ran out, then we expect both to have run out.
- if(!ll || !rr)
- return !ll && !rr;
-
- auto leftSubst = ll;
- auto rightSubst = rr;
-
- ll = ll->outer;
- rr = rr->outer;
-
- if(auto leftGeneric = as<GenericSubstitution>(leftSubst))
- {
- if(auto rightGeneric = as<GenericSubstitution>(rightSubst))
- {
- if(validateGenericSubstitutionsMatch(sink, leftGeneric, rightGeneric, stack))
- {
- continue;
- }
- }
- }
- else if(auto leftThisType = as<ThisTypeSubstitution>(leftSubst))
- {
- if(auto rightThisType = as<ThisTypeSubstitution>(rightSubst))
- {
- if(validateThisTypeSubstitutionsMatch(sink, leftThisType, rightThisType, stack))
- {
- continue;
- }
- }
- }
-
- return false;
- }
-
- return true;
-}
-
-// Determine if two types "match" for the purposes of `cbuffer` layout rules.
-//
-static bool validateTypesMatch(
- DiagnosticSink* sink,
- Type* left,
- Type* right,
- StructuralTypeMatchStack* stack)
-{
- if(left->Equals(right))
- return true;
-
- // It is possible that the types don't match exactly, but
- // they *do* match structurally.
-
- // Note: the following code will lead to infinite recursion if there
- // are ever recursive types. We'd need a more refined system to
- // cache the matches we've already found.
-
- if( auto leftDeclRefType = as<DeclRefType>(left) )
- {
- if( auto rightDeclRefType = as<DeclRefType>(right) )
- {
- // Are they references to matching decl refs?
- auto leftDeclRef = leftDeclRefType->declRef;
- auto rightDeclRef = rightDeclRefType->declRef;
-
- // Do the reference the same declaration? Or declarations
- // with the same name?
- //
- // TODO: we should only consider the same-name case if the
- // declarations come from translation units being compiled
- // (and not an imported module).
- if( leftDeclRef.getDecl() == rightDeclRef.getDecl()
- || leftDeclRef.GetName() == rightDeclRef.GetName() )
- {
- // Check that any generic arguments match
- if( !validateSpecializationsMatch(
- sink,
- leftDeclRef.substitutions,
- rightDeclRef.substitutions,
- stack) )
- {
- return false;
- }
-
- // Check that any declared fields match too.
- if( auto leftStructDeclRef = leftDeclRef.as<AggTypeDecl>() )
- {
- if( auto rightStructDeclRef = rightDeclRef.as<AggTypeDecl>() )
- {
- List<DeclRef<VarDecl>> leftFields;
- List<DeclRef<VarDecl>> rightFields;
-
- collectFields(leftStructDeclRef, leftFields);
- collectFields(rightStructDeclRef, rightFields);
-
- Index leftFieldCount = leftFields.getCount();
- Index rightFieldCount = rightFields.getCount();
-
- if( leftFieldCount != rightFieldCount )
- {
- diagnoseTypeFieldsMismatch(sink, leftDeclRef, rightDeclRef, stack);
- return false;
- }
-
- for( Index ii = 0; ii < leftFieldCount; ++ii )
- {
- auto leftField = leftFields[ii];
- auto rightField = rightFields[ii];
-
- if( leftField.GetName() != rightField.GetName() )
- {
- diagnoseTypeFieldsMismatch(sink, leftDeclRef, rightDeclRef, stack);
- return false;
- }
-
- auto leftFieldType = GetType(leftField);
- auto rightFieldType = GetType(rightField);
-
- StructuralTypeMatchStack subStack;
- subStack.parent = stack;
- subStack.leftDecl = leftField;
- subStack.rightDecl = rightField;
-
- if(!validateTypesMatch(sink, leftFieldType,rightFieldType, &subStack))
- return false;
- }
- }
- }
-
- // Everything seemed to match recursively.
- return true;
- }
- }
- }
-
- // If we are looking at `T[N]` and `U[M]` we want to check that
- // `T` is structurally equivalent to `U` and `N` is the same as `M`.
- else if( auto leftArrayType = as<ArrayExpressionType>(left) )
+ /// Get the name a variable will use for reflection purposes
+ Name* getReflectionName(VarDeclBase* varDecl)
{
- if( auto rightArrayType = as<ArrayExpressionType>(right) )
- {
- if(!validateTypesMatch(sink, leftArrayType->baseType, rightArrayType->baseType, stack) )
- return false;
-
- if(!validateValuesMatch(sink, leftArrayType->ArrayLength, rightArrayType->ArrayLength, stack))
- return false;
+ if (auto reflectionNameModifier = varDecl->FindModifier<ParameterGroupReflectionName>())
+ return reflectionNameModifier->nameAndLoc.name;
- return true;
- }
+ return varDecl->getName();
}
- diagnoseTypeMismatch(sink, stack);
- return false;
-}
-
-// This function is supposed to determine if two global shader
-// parameter declarations represent the same logical parameter
-// (so that they should get the exact same binding(s) allocated).
-//
-static bool doesParameterMatch(
- DiagnosticSink* sink,
- DeclRef<VarDeclBase> varDeclRef,
- DeclRef<VarDeclBase> existingVarDeclRef)
-{
- StructuralTypeMatchStack stack;
- stack.parent = nullptr;
- stack.leftDecl = varDeclRef;
- stack.rightDecl = existingVarDeclRef;
-
- validateTypesMatch(sink, GetType(varDeclRef), GetType(existingVarDeclRef), &stack);
-
- return true;
-}
-
void Module::_collectShaderParams()
{
auto moduleDecl = m_moduleDecl;
@@ -1003,7 +610,7 @@ static bool doesParameterMatch(
// At this point we know we have a global shader parameter.
- GlobalShaderParamInfo shaderParamInfo;
+ ShaderParamInfo shaderParamInfo;
shaderParamInfo.paramDeclRef = makeDeclRef(globalVar.Ptr());
// We need to consider what specialization parameters
@@ -1072,102 +679,6 @@ static bool doesParameterMatch(
}
- /// Enumerate the parameters of a `LegacyProgram`.
- void LegacyProgram::_collectShaderParams(DiagnosticSink* sink)
- {
- // We need to collect all of the global shader parameters
- // referenced by the compile request, and for each we
- // need to do a few things:
- //
- // * We need to determine if the parameter is a duplicate/redeclaration
- // of the "same" parameter in another translation unit, and collapse
- // those into one logical shader parameter if so.
- //
- // * We need to determine what existential type slots are introduced
- // by the parameter, and associate that information with the parameter.
- //
- // To deal with the first issue, we will maintain a map from a parameter
- // name to the index of an existing parameter with that name.
- //
- // TODO: Eventually we should deprecate support for the
- // deduplication feature of `LegaqcyProgram`, at which point
- // this entire type and all its complications can be eliminated
- // from the code (that includes a lot of support in the "parameter
- // binding" step for shader parameters with multiple declarations).
- // Until that point this type will have a fair amount of duplication
- // with stuff in `Module` and `CompositeComponentType`.
-
- // We use a dictionary to keep track of any shader parameter
- // we've alrady collected with a given name.
- //
- Dictionary<Name*, Int> mapNameToParamIndex;
-
- for( auto translationUnit : m_translationUnits )
- {
- auto module = translationUnit->getModule();
- auto moduleDecl = module->getModuleDecl();
- for( auto globalVar : moduleDecl->getMembersOfType<VarDecl>() )
- {
- // We do not want to consider global variable declarations
- // that don't represents shader parameters. This includes
- // things like `static` globals and `groupshared` variables.
- //
- if(!isGlobalShaderParameter(globalVar))
- continue;
-
- // This declaration may represent the same logical parameter
- // as a declaration that came from a different translation unit.
- // If that is the case, we want to re-use the same `ShaderParamInfo`
- // across both parameters.
- //
- // TODO: This logic currently detects *any* global-scope parameters
- // with matching names, but it should eventually be narrowly
- // scoped so that it only applies to parameters from unnamed modules
- // (that is, modules that represent directly-compiled shader files
- // and not `import`ed code).
- //
- // First we look for an existing entry matching the name
- // of this parameter:
- //
- auto paramName = getReflectionName(globalVar);
- Int existingParamIndex = -1;
- if( mapNameToParamIndex.TryGetValue(paramName, existingParamIndex) )
- {
- // If the parameters have the same name, but don't "match" according to some reasonable rules,
- // then we will treat them as distinct global parameters.
- //
- // Note: all of the mismatch cases currently report errors, so that
- // compilation will fail on a mismatch.
- //
- auto& existingParam = m_shaderParams[existingParamIndex];
- if( doesParameterMatch(sink, makeDeclRef(globalVar.Ptr()), existingParam.paramDeclRef) )
- {
- // If we hit this case, then we had a match, and we should
- // consider the new variable to be a redclaration of
- // the existing one.
-
- existingParam.additionalParamDeclRefs.add(
- makeDeclRef(globalVar.Ptr()));
- continue;
- }
- }
-
- Int newParamIndex = Int(m_shaderParams.getCount());
- mapNameToParamIndex.Add(paramName, newParamIndex);
-
- GlobalShaderParamInfo shaderParamInfo;
- shaderParamInfo.paramDeclRef = makeDeclRef(globalVar.Ptr());
-
- _collectExistentialSpecializationParamsForShaderParam(
- shaderParamInfo,
- m_specializationParams,
- makeDeclRef(globalVar.Ptr()));
-
- m_shaderParams.add(shaderParamInfo);
- }
- }
- }
-
/// Create a new component type based on `inComponentType`, but with all its requiremetns filled.
RefPtr<ComponentType> fillRequirements(
ComponentType* inComponentType)
@@ -1234,7 +745,6 @@ static bool doesParameterMatch(
// compiler behavior (at least for now).
//
auto linkage = compileRequest->getLinkage();
- auto sink = compileRequest->getSink();
RefPtr<ComponentType> globalComponentType;
if(compileRequest->translationUnits.getCount() == 1)
@@ -1248,10 +758,15 @@ static bool doesParameterMatch(
}
else
{
- globalComponentType = new LegacyProgram(
+ List<RefPtr<ComponentType>> translationUnitComponentTypes;
+ for( auto tu : compileRequest->translationUnits )
+ {
+ translationUnitComponentTypes.add(tu->getModule());
+ }
+
+ globalComponentType = CompositeComponentType::create(
linkage,
- compileRequest->translationUnits,
- sink);
+ translationUnitComponentTypes);
}
return fillRequirements(globalComponentType);
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index cc60f18f4..6cb3603b9 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -939,6 +939,93 @@ namespace Slang
return UnownedStringSlice();
}
+ /// Read a file in the context of handling a preprocessor directive
+ static SlangResult readFile(
+ Linkage* linkage,
+ String const& path,
+ ISlangBlob** outBlob)
+ {
+ // The actual file loading will be handled by the file system
+ // associated with the parent linkage.
+ //
+ auto fileSystemExt = linkage->getFileSystemExt();
+ SLANG_RETURN_ON_FAIL(fileSystemExt->loadFile(path.getBuffer(), outBlob));
+
+ return SLANG_OK;
+ }
+
+ struct FxcIncludeHandler : ID3DInclude
+ {
+ Linkage* linkage;
+ DiagnosticSink* sink;
+ IncludeHandler* includeHandler;
+ PathInfo rootPathInfo;
+
+ STDMETHOD(Open)(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) override
+ {
+ SLANG_UNUSED(IncludeType);
+ SLANG_UNUSED(pParentData);
+
+ String path(pFileName);
+
+ SourceLoc loc;
+
+ PathInfo includedFromPathInfo = rootPathInfo;
+
+ if (!includeHandler)
+ {
+ return SLANG_E_NOT_IMPLEMENTED;
+ }
+
+ // Find the path relative to the foundPath
+ PathInfo filePathInfo;
+ if (SLANG_FAILED(includeHandler->findFile(path, includedFromPathInfo.foundPath, filePathInfo)))
+ {
+ return SLANG_E_CANNOT_OPEN;
+ }
+
+ // We must have a uniqueIdentity to be compare
+ if (!filePathInfo.hasUniqueIdentity())
+ {
+ return SLANG_E_ABORT;
+ }
+
+ // Simplify the path
+ filePathInfo.foundPath = includeHandler->simplifyPath(filePathInfo.foundPath);
+
+ // See if this an already loaded source file
+ auto sourceManager = linkage->getSourceManager();
+ SourceFile* sourceFile = sourceManager->findSourceFileRecursively(filePathInfo.uniqueIdentity);
+
+ // If not create a new one, and add to the list of known source files
+ if (!sourceFile)
+ {
+ ComPtr<ISlangBlob> foundSourceBlob;
+ if (SLANG_FAILED(readFile(linkage, filePathInfo.foundPath, foundSourceBlob.writeRef())))
+ {
+ return SLANG_E_CANNOT_OPEN;
+ }
+
+ sourceFile = sourceManager->createSourceFileWithBlob(filePathInfo, foundSourceBlob);
+ sourceManager->addSourceFile(filePathInfo.uniqueIdentity, sourceFile);
+ }
+
+ // This is a new parse (even if it's a pre-existing source file), so create a new SourceUnit
+ SourceView* sourceView = sourceManager->createSourceView(sourceFile, &filePathInfo);
+
+ *ppData = sourceView->getContent().begin();
+ *pBytes = (UINT) sourceView->getContentSize();
+
+ return S_OK;
+ }
+
+ STDMETHOD(Close)(LPCVOID pData) override
+ {
+ SLANG_UNUSED(pData);
+ return S_OK;
+ }
+ };
+
SlangResult emitDXBytecodeForEntryPoint(
BackEndCompileRequest* compileRequest,
EntryPoint* entryPoint,
@@ -963,6 +1050,8 @@ namespace Slang
auto profile = getEffectiveProfile(entryPoint, targetReq);
+ auto linkage = compileRequest->getLinkage();
+
// If we have been invoked in a pass-through mode, then we need to make sure
// that the downstream compiler sees whatever options were passed to Slang
// via the command line or API.
@@ -971,6 +1060,14 @@ namespace Slang
//
List<D3D_SHADER_MACRO> dxMacrosStorage;
D3D_SHADER_MACRO const* dxMacros = nullptr;
+
+ IncludeHandlerImpl includeHandler;
+ includeHandler.linkage = linkage;
+ includeHandler.searchDirectories = &linkage->searchDirectories;
+
+ FxcIncludeHandler fxcIncludeHandlerStorage;
+ FxcIncludeHandler* fxcIncludeHandler = nullptr;
+
if(auto translationUnit = findPassThroughTranslationUnit(endToEndReq, entryPointIndex))
{
for( auto& define : translationUnit->compileRequest->preprocessorDefinitions )
@@ -991,6 +1088,12 @@ namespace Slang
dxMacrosStorage.add(nullTerminator);
dxMacros = dxMacrosStorage.getBuffer();
+
+ fxcIncludeHandler = &fxcIncludeHandlerStorage;
+ fxcIncludeHandler->linkage = linkage;
+ fxcIncludeHandler->sink = compileRequest->getSink();
+ fxcIncludeHandler->includeHandler = &includeHandler;
+ fxcIncludeHandler->rootPathInfo = translationUnit->m_sourceFiles[0]->getPathInfo();
}
DWORD flags = 0;
@@ -1018,7 +1121,6 @@ namespace Slang
flags |= D3DCOMPILE_ENABLE_STRICTNESS;
flags |= D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES;
- auto linkage = compileRequest->getLinkage();
switch( linkage->optimizationLevel )
{
default:
@@ -1049,7 +1151,7 @@ namespace Slang
hlslCode.getLength(),
sourcePath.getBuffer(),
dxMacros,
- nullptr,
+ fxcIncludeHandler,
getText(entryPoint->getName()).begin(),
GetHLSLProfileName(profile).getBuffer(),
flags,
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 17da14c14..9950764e4 100644
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -10,6 +10,7 @@
#include "slang-diagnostics.h"
#include "slang-name.h"
+#include "slang-preprocessor.h"
#include "slang-profile.h"
#include "slang-syntax.h"
@@ -159,20 +160,6 @@ namespace Slang
Int specializationParamCount = 0;
};
- /// Extended information specific to global shader parameters
- struct GlobalShaderParamInfo : ShaderParamInfo
- {
- // TODO: This type should be eliminated if/when we remove
- // support for compilation with multiple translation units
- // that all declare the "same" shader parameter (e.g., a
- // `cbuffer`) and expect those duplicate declarations
- // to get the same parameter binding/layout.
-
- // Additional global-scope declarations that are conceptually
- // declaring the "same" parameter as the `paramDeclRef`.
- List<DeclRef<VarDeclBase>> additionalParamDeclRefs;
- };
-
/// A request for the front-end to find and validate an entry-point function
struct FrontEndEntryPointRequest : RefObject
{
@@ -321,7 +308,7 @@ namespace Slang
virtual Index getShaderParamCount() = 0;
/// Get one of the global shader parametesr linked into this component type.
- virtual GlobalShaderParamInfo getShaderParam(Index index) = 0;
+ virtual ShaderParamInfo getShaderParam(Index index) = 0;
/// Get the number of (unspecialized) specialization parameters for the component type.
virtual Index getSpecializationParamCount() = 0;
@@ -351,8 +338,7 @@ namespace Slang
/// to the provided `sink`.
///
/// TODO: This function shouldn't be on the base class, since
- /// it only really makes sense on `Module` and (as a compatibility
- /// feature) on `LegacyProgram`.
+ /// it only really makes sense on `Module`.
///
Type* getTypeFromString(
String const& typeStr,
@@ -508,7 +494,7 @@ namespace Slang
String getEntryPointMangledName(Index index) SLANG_OVERRIDE;
Index getShaderParamCount() SLANG_OVERRIDE;
- GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE;
+ ShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE;
Index getSpecializationParamCount() SLANG_OVERRIDE;
SpecializationParam const& getSpecializationParam(Index index) SLANG_OVERRIDE;
@@ -555,7 +541,7 @@ namespace Slang
//
List<EntryPoint*> m_entryPoints;
List<String> m_entryPointMangledNames;
- List<GlobalShaderParamInfo> m_shaderParams;
+ List<ShaderParamInfo> m_shaderParams;
List<SpecializationParam> m_specializationParams;
List<ComponentType*> m_requirements;
@@ -595,7 +581,7 @@ namespace Slang
String getEntryPointMangledName(Index index) SLANG_OVERRIDE;
Index getShaderParamCount() SLANG_OVERRIDE { return m_base->getShaderParamCount(); }
- GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { return m_base->getShaderParam(index); }
+ ShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { return m_base->getShaderParam(index); }
Index getSpecializationParamCount() SLANG_OVERRIDE { return 0; }
SpecializationParam const& getSpecializationParam(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); static SpecializationParam dummy; return dummy; }
@@ -726,7 +712,7 @@ namespace Slang
String getEntryPointMangledName(Index index) SLANG_OVERRIDE;
Index getShaderParamCount() SLANG_OVERRIDE { return 0; }
- GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return GlobalShaderParamInfo(); }
+ ShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return ShaderParamInfo(); }
class EntryPointSpecializationInfo : public SpecializationInfo
{
@@ -890,7 +876,7 @@ namespace Slang
String getEntryPointMangledName(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return String(); }
Index getShaderParamCount() SLANG_OVERRIDE { return m_shaderParams.getCount(); }
- GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { return m_shaderParams[index]; }
+ ShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { return m_shaderParams[index]; }
Index getSpecializationParamCount() SLANG_OVERRIDE { return m_specializationParams.getCount(); }
SpecializationParam const& getSpecializationParam(Index index) SLANG_OVERRIDE { return m_specializationParams[index]; }
@@ -940,7 +926,7 @@ namespace Slang
// The IR for the module
RefPtr<IRModule> m_irModule = nullptr;
- List<GlobalShaderParamInfo> m_shaderParams;
+ List<ShaderParamInfo> m_shaderParams;
SpecializationParams m_specializationParams;
List<Module*> m_requirements;
@@ -1479,64 +1465,6 @@ namespace Slang
List<RefPtr<ComponentType>> m_unspecializedEntryPoints;
};
- /// A "legacy" program composes multiple translation units from a single compile request,
- /// and takes care to treat global declarations of the same name from different translation
- /// units as representing the "same" parameter.
- ///
- /// TODO: This type only exists to support a single requirement: that multiple translation
- /// units can be compiled in one pass and be guaranteed that the "same" parameter declared
- /// in different translation units (hence different modules) will get the same layout.
- /// This feature should be deprecated and removed as soon as possible, since the complexity
- /// it creates in the codebase is not justified by its limited utility.
- ///
- class LegacyProgram : public ComponentType
- {
- public:
- LegacyProgram(
- Linkage* linkage,
- List<RefPtr<TranslationUnitRequest>> const& translationUnits,
- DiagnosticSink* sink);
-
- Index getTranslationUnitCount() { return m_translationUnits.getCount(); }
- RefPtr<TranslationUnitRequest> getTranslationUnit(Index index) { return m_translationUnits[index]; }
-
- Index getEntryPointCount() SLANG_OVERRIDE { return 0; }
- RefPtr<EntryPoint> getEntryPoint(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return nullptr; }
- String getEntryPointMangledName(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return String(); }
-
- Index getShaderParamCount() SLANG_OVERRIDE { return m_shaderParams.getCount(); }
- GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { return m_shaderParams[index]; }
-
- Index getSpecializationParamCount() SLANG_OVERRIDE { return m_specializationParams.getCount(); }
- SpecializationParam const& getSpecializationParam(Index index) SLANG_OVERRIDE { return m_specializationParams[index]; }
-
- Index getRequirementCount() SLANG_OVERRIDE;
- RefPtr<ComponentType> getRequirement(Index index) SLANG_OVERRIDE;
-
- List<Module*> const& getModuleDependencies() SLANG_OVERRIDE { return m_moduleDependencies.getModuleList(); }
- List<String> const& getFilePathDependencies() SLANG_OVERRIDE { return m_fileDependencies.getFilePathList(); }
-
- protected:
- void acceptVisitor(ComponentTypeVisitor* visitor, SpecializationInfo* specializationInfo) SLANG_OVERRIDE;
-
- RefPtr<SpecializationInfo> _validateSpecializationArgsImpl(
- SpecializationArg const* args,
- Index argCount,
- DiagnosticSink* sink) SLANG_OVERRIDE;
-
- private:
- void _collectShaderParams(DiagnosticSink* sink);
-
- List<RefPtr<TranslationUnitRequest>> m_translationUnits;
-
- List<EntryPoint*> m_entryPoints;
- List<GlobalShaderParamInfo> m_shaderParams;
- List<ComponentType*> m_requirements;
- SpecializationParams m_specializationParams;
- ModuleDependencyList m_moduleDependencies;
- FilePathDependencyList m_fileDependencies;
- };
-
/// A visitor for use with `ComponentType`s, allowing dispatch over the concrete subclasses.
class ComponentTypeVisitor
{
@@ -1552,23 +1480,14 @@ namespace Slang
virtual void visitModule(Module* module, Module::ModuleSpecializationInfo* specializationInfo) = 0;
virtual void visitComposite(CompositeComponentType* composite, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) = 0;
virtual void visitSpecialized(SpecializedComponentType* specialized) = 0;
- virtual void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) = 0;
protected:
// These helpers can be used to recurse into the logical children of a
// component type, and are useful for the common case where a visitor
// only cares about a few leaf cases.
//
- // Note that for a `LegacyProgram` the "children" in this case are the
- // `Module`s of the translation units that make up the legacy program.
- // In some cases this is what is desired, but in others it is incorrect
- // to treat a legacy program as a composition of modules, and instead
- // it should be treated directly as a leaf case. Clients should make
- // an informed decision based on an understanding of what `LegacyProgram` is used for.
- //
void visitChildren(CompositeComponentType* composite, CompositeComponentType::CompositeSpecializationInfo* specializationInfo);
void visitChildren(SpecializedComponentType* specialized);
- void visitChildren(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo);
};
/// A `TargetProgram` represents a `ComponentType` specialized for a particular `TargetRequest`
@@ -2079,6 +1998,23 @@ namespace Slang
PassThroughMode m_defaultDownstreamCompilers[int(SourceLanguage::CountOf)];
};
+struct IncludeHandlerImpl : IncludeHandler
+{
+ Linkage* linkage;
+ SearchDirectoryList* searchDirectories;
+
+ ISlangFileSystemExt* _getFileSystemExt();
+
+ SlangResult _findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& pathInfoOut);
+
+ virtual SlangResult findFile(
+ String const& pathToInclude,
+ String const& pathIncludedFrom,
+ PathInfo& pathInfoOut) override;
+
+ virtual String simplifyPath(const String& path) override;
+};
+
//
// The following functions are utilties to convert between
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 2ea4f3d32..b3c45b704 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -6941,17 +6941,6 @@ struct SpecializedComponentTypeIRGenContext : ComponentTypeVisitor
{
visitChildren(specialized);
}
-
- void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- // TODO: This case should be akin to the `Module` case,
- // and deal with global-scope specialization parameters
- // directly.
- //
- SLANG_UNUSED(legacy);
- SLANG_UNUSED(specializationInfo);
- SLANG_UNIMPLEMENTED_X("legacy program case");
- }
};
RefPtr<IRModule> generateIRForSpecializedComponentType(
diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp
index 9e11152c4..5cd4156c3 100644
--- a/source/slang/slang-parameter-binding.cpp
+++ b/source/slang/slang-parameter-binding.cpp
@@ -306,13 +306,13 @@ struct UsedRangeSet : RefObject
// Information on a single parameter
struct ParameterInfo : RefObject
{
- // Layout info for the concrete variables that will make up this parameter
- List<RefPtr<VarLayout>> varLayouts;
+ // Layout info for the variable that represents this parameter
+ RefPtr<VarLayout> varLayout;
ParameterBindingInfo bindingInfo[kLayoutResourceKindCount];
// The translation unit this parameter is specific to, if any
- TranslationUnitRequest* translationUnit = nullptr;
+// TranslationUnitRequest* translationUnit = nullptr;
ParameterInfo()
{
@@ -696,9 +696,9 @@ static RefPtr<VarLayout> _createVarLayout(
// Collect a single declaration into our set of parameters
static void collectGlobalScopeParameter(
- ParameterBindingContext* context,
- GlobalShaderParamInfo const& shaderParamInfo,
- SubstitutionSet globalGenericSubst)
+ ParameterBindingContext* context,
+ ShaderParamInfo const& shaderParamInfo,
+ SubstitutionSet globalGenericSubst)
{
auto varDeclRef = shaderParamInfo.paramDeclRef;
@@ -722,7 +722,7 @@ static void collectGlobalScopeParameter(
// Now create a variable layout that we can use
RefPtr<VarLayout> varLayout = _createVarLayout(typeLayout, varDeclRef);
- // The logic in `check.cpp` that created the `GlobalShaderParamInfo`
+ // The logic in `check.cpp` that created the `ShaderParamInfo`
// will have identified any cases where there might be multiple
// global variables that logically represent the same shader parameter.
//
@@ -734,30 +734,10 @@ static void collectGlobalScopeParameter(
ParameterInfo* parameterInfo = new ParameterInfo();
context->shared->parameters.add(parameterInfo);
- // Add the first variable declaration to the list of declarations for the parameter
- parameterInfo->varLayouts.add(varLayout);
-
- // Add any additional variables to the list of declarations
- for( auto additionalVarDeclRef : shaderParamInfo.additionalParamDeclRefs )
- {
- // TODO: We should either eliminate the design choice where different
- // declarations of the "same" shade parameter get merged across
- // translation units (it is effectively just a compatiblity feature),
- // or we should clean things up earlier in the chain so that we can
- // re-use a single `VarLayout` across all of the different declarations.
- //
- // TODO: It would also make sense in these cases to ensure that
- // such global shader parameters get the same mangled name across
- // all translation units, so that they can automatically be collapsed
- // during linking.
-
- RefPtr<VarLayout> additionalVarLayout = new VarLayout();
- additionalVarLayout->typeLayout = typeLayout;
- additionalVarLayout->varDecl = additionalVarDeclRef;
- additionalVarLayout->pendingVarLayout = varLayout->pendingVarLayout;
-
- parameterInfo->varLayouts.add(additionalVarLayout);
- }
+ // Add the created var layout to the parameter information structure,
+ // so that we can update it as we proceed with parameter binding.
+ //
+ parameterInfo->varLayout = varLayout;
}
static RefPtr<UsedRangeSet> findUsedRangeSetForSpace(
@@ -831,12 +811,6 @@ static void addExplicitParameterBinding(
|| bindingInfo.space != semanticInfo.space )
{
getSink(context)->diagnose(varDecl, Diagnostics::conflictingExplicitBindingsForParameter, getReflectionName(varDecl));
-
- auto firstVarDecl = parameterInfo->varLayouts[0]->varDecl.getDecl();
- if( firstVarDecl != varDecl )
- {
- getSink(context)->diagnose(firstVarDecl, Diagnostics::seeOtherDeclarationOf, getReflectionName(firstVarDecl));
- }
}
// TODO(tfoley): `register` semantics can technically be
@@ -859,13 +833,13 @@ static void addExplicitParameterBinding(
markSpaceUsed(context, semanticInfo.space);
}
auto overlappedVarLayout = usedRangeSet->usedResourceRanges[(int)semanticInfo.kind].Add(
- parameterInfo->varLayouts[0],
+ parameterInfo->varLayout,
semanticInfo.index,
semanticInfo.index + count);
if (overlappedVarLayout)
{
- auto paramA = parameterInfo->varLayouts[0]->varDecl.getDecl();
+ auto paramA = parameterInfo->varLayout->varDecl.getDecl();
auto paramB = overlappedVarLayout->varDecl.getDecl();
auto& diagnosticInfo = Diagnostics::parameterBindingsOverlap;
@@ -1052,19 +1026,24 @@ void generateParameterBindings(
ParameterBindingContext* context,
RefPtr<ParameterInfo> parameterInfo)
{
- // There must be at least one declaration for the parameter.
- SLANG_RELEASE_ASSERT(parameterInfo->varLayouts.getCount() != 0);
+ // There must have been a declaration for the parameter.
+ SLANG_RELEASE_ASSERT(parameterInfo->varLayout);
- // Iterate over all declarations looking for explicit binding information.
- for( auto& varLayout : parameterInfo->varLayouts )
- {
- // Handle HLSL `register` and `packoffset` modifiers
- addExplicitParameterBindings_HLSL(context, parameterInfo, varLayout);
+ // We will look for explicit binding information on the declaration.
+ auto varLayout = parameterInfo->varLayout;
+ // Handle HLSL `register` and `packoffset` modifiers
+ addExplicitParameterBindings_HLSL(context, parameterInfo, varLayout);
- // Handle GLSL `layout` modifiers
- addExplicitParameterBindings_GLSL(context, parameterInfo, varLayout);
- }
+
+ // Handle GLSL `layout` modifiers and `[vk::...]` attributes.
+ //
+ // TODO: We should deprecate the support for `layout` and then rename
+ // these `_HLSL` and `_GLSL` functions to be more explicit and clear
+ // about the fact that they are specific to the *target* and not to
+ // the *source language* (as they were at one point).
+ //
+ addExplicitParameterBindings_GLSL(context, parameterInfo, varLayout);
}
// Generate the binding information for a shader parameter.
@@ -1292,17 +1271,12 @@ static void completeBindingsForParameter(
ParameterBindingContext* context,
RefPtr<ParameterInfo> parameterInfo)
{
- // We will use the first declaration of the parameter as
- // a stand-in for all the declarations, so it is important
- // that earlier code has validated that the declarations
- // "match".
-
- SLANG_RELEASE_ASSERT(parameterInfo->varLayouts.getCount() != 0);
- auto firstVarLayout = parameterInfo->varLayouts.getFirst();
+ auto varLayout = parameterInfo->varLayout;
+ SLANG_RELEASE_ASSERT(varLayout);
completeBindingsForParameterImpl(
context,
- firstVarLayout,
+ varLayout,
parameterInfo->bindingInfo,
parameterInfo);
@@ -1310,10 +1284,7 @@ static void completeBindingsForParameter(
// all the relevant resource kinds, so we can apply these to the
// declarations:
- for(auto& varLayout : parameterInfo->varLayouts)
- {
- applyBindingInfoToParameter(varLayout, parameterInfo->bindingInfo);
- }
+ applyBindingInfoToParameter(varLayout, parameterInfo->bindingInfo);
}
static void completeBindingsForParameter(
@@ -1925,11 +1896,10 @@ struct ScopeLayoutBuilder
}
void _addParameter(
- RefPtr<VarLayout> firstVarLayout,
- ParameterInfo* parameterInfo)
+ RefPtr<VarLayout> varLayout)
{
// Does the parameter have any uniform data?
- auto layoutInfo = firstVarLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform);
+ auto layoutInfo = varLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform);
LayoutSize uniformSize = layoutInfo ? layoutInfo->count : 0;
if( uniformSize != 0 )
{
@@ -1937,44 +1907,24 @@ struct ScopeLayoutBuilder
UniformLayoutInfo fieldInfo(
uniformSize,
- firstVarLayout->typeLayout->uniformAlignment);
+ varLayout->typeLayout->uniformAlignment);
LayoutSize uniformOffset = m_rules->AddStructField(
&m_structLayoutInfo,
fieldInfo);
- if( parameterInfo )
- {
- for( auto& varLayout : parameterInfo->varLayouts )
- {
- varLayout->findOrAddResourceInfo(LayoutResourceKind::Uniform)->index = uniformOffset.getFiniteValue();
- }
- }
- else
- {
- firstVarLayout->findOrAddResourceInfo(LayoutResourceKind::Uniform)->index = uniformOffset.getFiniteValue();
- }
+ varLayout->findOrAddResourceInfo(LayoutResourceKind::Uniform)->index = uniformOffset.getFiniteValue();
}
- m_structLayout->fields.add(firstVarLayout);
+ m_structLayout->fields.add(varLayout);
- if( parameterInfo )
- {
- for( auto& varLayout : parameterInfo->varLayouts )
- {
- m_structLayout->mapVarToLayout.Add(varLayout->varDecl.getDecl(), varLayout);
- }
- }
- else
- {
- m_structLayout->mapVarToLayout.Add(firstVarLayout->varDecl.getDecl(), firstVarLayout);
- }
+ m_structLayout->mapVarToLayout.Add(varLayout->varDecl.getDecl(), varLayout);
}
void addParameter(
RefPtr<VarLayout> varLayout)
{
- _addParameter(varLayout, nullptr);
+ _addParameter(varLayout);
// Any "pending" items on a field type become "pending" items
// on the overall `struct` type layout.
@@ -1997,17 +1947,17 @@ struct ScopeLayoutBuilder
void addParameter(
ParameterInfo* parameterInfo)
{
- SLANG_RELEASE_ASSERT(parameterInfo->varLayouts.getCount() != 0);
- auto firstVarLayout = parameterInfo->varLayouts.getFirst();
+ auto varLayout = parameterInfo->varLayout;
+ SLANG_RELEASE_ASSERT(varLayout);
- _addParameter(firstVarLayout, parameterInfo);
+ _addParameter(varLayout);
// Global parameters will have their non-orindary/uniform
// pending data handled by the main parameter binding
// logic, but we still need to construct a layout
// that includes any pending data.
//
- if(auto fieldPendingVarLayout = firstVarLayout->pendingVarLayout)
+ if(auto fieldPendingVarLayout = varLayout->pendingVarLayout)
{
auto fieldPendingTypeLayout = fieldPendingVarLayout->typeLayout;
@@ -2404,13 +2354,6 @@ struct CollectGlobalGenericArgumentsVisitor : ComponentTypeVisitor
{
specialized->getBaseComponentType()->acceptVisitor(this, specialized->getSpecializationInfo());
}
-
- void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- // TODO: Need to do something in this case...
- SLANG_UNUSED(legacy);
- SLANG_UNUSED(specializationInfo);
- }
};
/// Collect an ordered list of all the specialization arguments given for global generic specialization parameters in `program`.
@@ -2563,34 +2506,6 @@ struct CollectParametersVisitor : ComponentTypeVisitor
}
}
-
- void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- // A legacy program is also a leaf case, and we
- // can enumerate its parameters directly.
- //
- // Note: there is a mismatch here where we really
- // ought to be tracking specialization arguments
- // for a `LegacyProgram` akin to how they are
- // tracked for a `Module`, but right now we try
- // to do it like a `CompositeComponentType`.
- // As a result we are just ignoring specialization
- // information here, which will lead to incorrect
- // results if somebody every uses specialization
- // together with the "legacy" program case.
- //
- // TODO: eliminate this problem by getting rid of
- // `LegacyProgram`, rather than spend time trying
- // to make this corner case actually work.
- //
- SLANG_UNUSED(specializationInfo);
-
- auto paramCount = legacy->getShaderParamCount();
- for(Index pp = 0; pp < paramCount; ++pp)
- {
- collectGlobalScopeParameter(m_context, legacy->getShaderParam(pp), SubstitutionSet());
- }
- }
};
/// Recursively collect the global shader parameters and entry points in `program`.
@@ -2751,13 +2666,6 @@ struct CompleteBindingsVisitor : ComponentTypeVisitor
visitLeafParams(module);
}
- void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- SLANG_UNUSED(specializationInfo);
- // A legacy program is a leaf case: we just want to visit each parameter.
- visitLeafParams(legacy);
- }
-
void visitLeafParams(ComponentType* componentType)
{
auto paramCount = componentType->getShaderParamCount();
@@ -2881,12 +2789,6 @@ struct FlushPendingDataVisitor : ComponentTypeVisitor
visitLeafParams(module);
}
- void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- SLANG_UNUSED(specializationInfo);
- visitLeafParams(legacy);
- }
-
void visitLeafParams(ComponentType* componentType)
{
// In the "leaf" case we just allocate space for any
@@ -2897,9 +2799,9 @@ struct FlushPendingDataVisitor : ComponentTypeVisitor
{
auto globalParamIndex = m_counters->globalParamCounter++;
auto globalParamInfo = m_context->shared->parameters[globalParamIndex];
- auto firstVarLayout = globalParamInfo->varLayouts[0];
+ auto varLayout = globalParamInfo->varLayout;
- _allocateBindingsForPendingData(m_context, firstVarLayout->pendingVarLayout);
+ _allocateBindingsForPendingData(m_context, varLayout->pendingVarLayout);
}
}
@@ -3072,14 +2974,14 @@ RefPtr<ProgramLayout> generateParameterBindings(
{
for( auto& parameterInfo : sharedContext.parameters )
{
- SLANG_RELEASE_ASSERT(parameterInfo->varLayouts.getCount() != 0);
- auto firstVarLayout = parameterInfo->varLayouts.getFirst();
+ auto varLayout = parameterInfo->varLayout;
+ SLANG_RELEASE_ASSERT(varLayout);
// Does the field have any uniform data?
- if( firstVarLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform) )
+ if( varLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform) )
{
needDefaultConstantBuffer = true;
- diagnoseGlobalUniform(&sharedContext, firstVarLayout->varDecl);
+ diagnoseGlobalUniform(&sharedContext, varLayout->varDecl);
}
}
}
@@ -3102,12 +3004,12 @@ RefPtr<ProgramLayout> generateParameterBindings(
//
for (auto& parameterInfo : sharedContext.parameters)
{
- SLANG_RELEASE_ASSERT(parameterInfo->varLayouts.getCount() != 0);
- auto firstVarLayout = parameterInfo->varLayouts.getFirst();
+ auto varLayout = parameterInfo->varLayout;
+ SLANG_RELEASE_ASSERT(varLayout);
// For each parameter, we will look at each resource it consumes.
//
- for (auto resInfo : firstVarLayout->typeLayout->resourceInfos)
+ for (auto resInfo : varLayout->typeLayout->resourceInfos)
{
// We don't care about whole register spaces/sets, since
// we don't need to allocate a default space/set for a parameter
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 28e0a358d..339ace54f 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -297,112 +297,92 @@ CPPCompiler* Session::getDefaultCPPCompiler(SourceLanguage sourceLanguage)
return getCPPCompiler(m_defaultDownstreamCompilers[int(sourceLanguage)]);
}
-struct IncludeHandlerImpl : IncludeHandler
+ISlangFileSystemExt* IncludeHandlerImpl::_getFileSystemExt()
{
- Linkage* linkage;
- SearchDirectoryList* searchDirectories;
+ return linkage->getFileSystemExt();
+}
+
+SlangResult IncludeHandlerImpl::_findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& pathInfoOut)
+{
+ ISlangFileSystemExt* fileSystemExt = _getFileSystemExt();
- ISlangFileSystemExt* _getFileSystemExt()
+ // Get relative path
+ ComPtr<ISlangBlob> combinedPathBlob;
+ SLANG_RETURN_ON_FAIL(fileSystemExt->calcCombinedPath(fromPathType, fromPath.begin(), path.begin(), combinedPathBlob.writeRef()));
+ String combinedPath(StringUtil::getString(combinedPathBlob));
+ if (combinedPath.getLength() <= 0)
{
- return linkage->getFileSystemExt();
+ return SLANG_FAIL;
}
-
- SlangResult _findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& pathInfoOut)
+
+ SlangPathType pathType;
+ SLANG_RETURN_ON_FAIL(fileSystemExt->getPathType(combinedPath.begin(), &pathType));
+ if (pathType != SLANG_PATH_TYPE_FILE)
{
- ISlangFileSystemExt* fileSystemExt = _getFileSystemExt();
+ return SLANG_E_NOT_FOUND;
+ }
- // Get relative path
- ComPtr<ISlangBlob> combinedPathBlob;
- SLANG_RETURN_ON_FAIL(fileSystemExt->calcCombinedPath(fromPathType, fromPath.begin(), path.begin(), combinedPathBlob.writeRef()));
- String combinedPath(StringUtil::getString(combinedPathBlob));
- if (combinedPath.getLength() <= 0)
- {
- return SLANG_FAIL;
- }
-
- SlangPathType pathType;
- SLANG_RETURN_ON_FAIL(fileSystemExt->getPathType(combinedPath.begin(), &pathType));
- if (pathType != SLANG_PATH_TYPE_FILE)
- {
- return SLANG_E_NOT_FOUND;
- }
+ // Get the uniqueIdentity
+ ComPtr<ISlangBlob> uniqueIdentityBlob;
+ SLANG_RETURN_ON_FAIL(fileSystemExt->getFileUniqueIdentity(combinedPath.begin(), uniqueIdentityBlob.writeRef()));
+
+ // If the rel path exists -> a uniqueIdentity MUST exists too
+ String uniqueIdentity(StringUtil::getString(uniqueIdentityBlob));
+ if (uniqueIdentity.getLength() <= 0)
+ {
+ // Unique identity can't be empty
+ return SLANG_FAIL;
+ }
+
+ pathInfoOut.type = PathInfo::Type::Normal;
+ pathInfoOut.foundPath = combinedPath;
+ pathInfoOut.uniqueIdentity = uniqueIdentity;
+ return SLANG_OK;
+}
- // Get the uniqueIdentity
- ComPtr<ISlangBlob> uniqueIdentityBlob;
- SLANG_RETURN_ON_FAIL(fileSystemExt->getFileUniqueIdentity(combinedPath.begin(), uniqueIdentityBlob.writeRef()));
+SlangResult IncludeHandlerImpl::findFile(
+ String const& pathToInclude,
+ String const& pathIncludedFrom,
+ PathInfo& pathInfoOut)
+{
+ pathInfoOut.type = PathInfo::Type::Unknown;
- // If the rel path exists -> a uniqueIdentity MUST exists too
- String uniqueIdentity(StringUtil::getString(uniqueIdentityBlob));
- if (uniqueIdentity.getLength() <= 0)
- {
- // Unique identity can't be empty
- return SLANG_FAIL;
+ // Try just relative to current path
+ {
+ SlangResult res = _findFile(SLANG_PATH_TYPE_FILE, pathIncludedFrom, pathToInclude, pathInfoOut);
+ // It either succeeded or wasn't found, anything else is a failure passed back
+ if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND)
+ {
+ return res;
}
-
- pathInfoOut.type = PathInfo::Type::Normal;
- pathInfoOut.foundPath = combinedPath;
- pathInfoOut.uniqueIdentity = uniqueIdentity;
- return SLANG_OK;
}
- virtual SlangResult findFile(
- String const& pathToInclude,
- String const& pathIncludedFrom,
- PathInfo& pathInfoOut) override
+ // Search all the searchDirectories
+ for(auto sd = searchDirectories; sd; sd = sd->parent)
{
- pathInfoOut.type = PathInfo::Type::Unknown;
-
- // Try just relative to current path
+ for(auto& dir : sd->searchDirectories)
{
- SlangResult res = _findFile(SLANG_PATH_TYPE_FILE, pathIncludedFrom, pathToInclude, pathInfoOut);
- // It either succeeded or wasn't found, anything else is a failure passed back
+ SlangResult res = _findFile(SLANG_PATH_TYPE_DIRECTORY, dir.path, pathToInclude, pathInfoOut);
if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND)
{
return res;
}
}
-
- // Search all the searchDirectories
- for(auto sd = searchDirectories; sd; sd = sd->parent)
- {
- for(auto& dir : sd->searchDirectories)
- {
- SlangResult res = _findFile(SLANG_PATH_TYPE_DIRECTORY, dir.path, pathToInclude, pathInfoOut);
- if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND)
- {
- return res;
- }
- }
- }
-
- return SLANG_E_NOT_FOUND;
}
-#if 0
- virtual SlangResult readFile(const String& path,
- ISlangBlob** blobOut) override
- {
- ISlangFileSystem* fileSystemExt = _getFileSystemExt();
- SLANG_RETURN_ON_FAIL(fileSystemExt->loadFile(path.begin(), blobOut));
-
- request->mDependencyFilePaths.Add(path);
-
- return SLANG_OK;
- }
-#endif
+ return SLANG_E_NOT_FOUND;
+}
- virtual String simplifyPath(const String& path) override
+String IncludeHandlerImpl::simplifyPath(const String& path)
+{
+ ISlangFileSystemExt* fileSystemExt = _getFileSystemExt();
+ ComPtr<ISlangBlob> simplifiedPath;
+ if (SLANG_FAILED(fileSystemExt->getSimplifiedPath(path.getBuffer(), simplifiedPath.writeRef())))
{
- ISlangFileSystemExt* fileSystemExt = _getFileSystemExt();
- ComPtr<ISlangBlob> simplifiedPath;
- if (SLANG_FAILED(fileSystemExt->getSimplifiedPath(path.getBuffer(), simplifiedPath.writeRef())))
- {
- return path;
- }
- return StringUtil::getString(simplifiedPath);
+ return path;
}
-
-};
+ return StringUtil::getString(simplifiedPath);
+}
//
@@ -2039,11 +2019,6 @@ struct EnumerateModulesVisitor : ComponentTypeVisitor
{
visitChildren(specialized);
}
-
- void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- visitChildren(legacy, specializationInfo);
- }
};
@@ -2082,11 +2057,6 @@ struct EnumerateIRModulesVisitor : ComponentTypeVisitor
m_callback(specialized->getIRModule(), m_userData);
}
-
- void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- visitChildren(legacy, specializationInfo);
- }
};
void ComponentType::enumerateIRModules(EnumerateIRModulesCallback callback, void* userData)
@@ -2211,7 +2181,7 @@ Index CompositeComponentType::getShaderParamCount()
return m_shaderParams.getCount();
}
-GlobalShaderParamInfo CompositeComponentType::getShaderParam(Index index)
+ShaderParamInfo CompositeComponentType::getShaderParam(Index index)
{
return m_shaderParams[index];
}
@@ -2357,8 +2327,6 @@ SpecializedComponentType::SpecializedComponentType(
{ visitChildren(composite, specializationInfo); }
void visitSpecialized(SpecializedComponentType* specialized) SLANG_OVERRIDE
{ visitChildren(specialized); }
- void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- { visitChildren(legacy, specializationInfo); }
};
// With the visitor defined, we apply it to ourself to compute
@@ -2395,96 +2363,6 @@ String SpecializedComponentType::getEntryPointMangledName(Index index)
return m_entryPointMangledNames[index];
}
-//
-// LegacyProgram
-//
-
-LegacyProgram::LegacyProgram(
- Linkage* linkage,
- List<RefPtr<TranslationUnitRequest>> const& translationUnits,
- DiagnosticSink* sink)
- : ComponentType(linkage)
- , m_translationUnits(translationUnits)
-{
- HashSet<ComponentType*> requirementsSet;
-
- for(auto translationUnit : translationUnits )
- {
- ComponentType* child = translationUnit->getModule();
-
- auto childEntryPointCount = child->getEntryPointCount();
- for(Index cc = 0; cc < childEntryPointCount; ++cc)
- {
- m_entryPoints.add(child->getEntryPoint(cc));
- }
-
- for(auto module : child->getModuleDependencies())
- {
- m_moduleDependencies.addDependency(module);
- }
- for(auto filePath : child->getFilePathDependencies())
- {
- m_fileDependencies.addDependency(filePath);
- }
-
- auto childRequirementCount = child->getRequirementCount();
- for(Index rr = 0; rr < childRequirementCount; ++rr)
- {
- auto childRequirement = child->getRequirement(rr);
- if(!requirementsSet.Contains(childRequirement))
- {
- requirementsSet.Add(childRequirement);
- m_requirements.add(childRequirement);
- }
- }
- }
-
- _collectShaderParams(sink);
-}
-
-void LegacyProgram::acceptVisitor(ComponentTypeVisitor* visitor, SpecializationInfo* specializationInfo)
-{
- visitor->visitLegacy(this, as<CompositeComponentType::CompositeSpecializationInfo>(specializationInfo));
-}
-
-RefPtr<ComponentType::SpecializationInfo> LegacyProgram::_validateSpecializationArgsImpl(
- SpecializationArg const* args,
- Index argCount,
- DiagnosticSink* sink)
-{
- SLANG_UNUSED(argCount);
-
- RefPtr<CompositeComponentType::CompositeSpecializationInfo> info = new CompositeComponentType::CompositeSpecializationInfo();
-
- Index offset = 0;
- for(auto translationUnit : m_translationUnits)
- {
- ComponentType* child = translationUnit->getModule();
- auto childParamCount = child->getSpecializationParamCount();
- SLANG_ASSERT(offset + childParamCount <= argCount);
-
- auto childInfo = child->_validateSpecializationArgs(
- args + offset,
- childParamCount,
- sink);
-
- info->childInfos.add(childInfo);
-
- offset += childParamCount;
- }
- return info;
-}
-
-Index LegacyProgram::getRequirementCount()
-{
- return m_requirements.getCount();
-}
-
-RefPtr<ComponentType> LegacyProgram::getRequirement(Index index)
-{
- return m_requirements[index];
-}
-
void ComponentTypeVisitor::visitChildren(CompositeComponentType* composite, CompositeComponentType::CompositeSpecializationInfo* specializationInfo)
{
auto childCount = composite->getChildComponentCount();
@@ -2504,21 +2382,6 @@ void ComponentTypeVisitor::visitChildren(SpecializedComponentType* specialized)
specialized->getBaseComponentType()->acceptVisitor(this, specialized->getSpecializationInfo());
}
-void ComponentTypeVisitor::visitChildren(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo)
-{
- auto childCount = legacy->getTranslationUnitCount();
- for(Index ii = 0; ii < childCount; ++ii)
- {
- auto translationUnit = legacy->getTranslationUnit(ii);
- ComponentType* child = translationUnit->getModule();
- auto childSpecializationInfo = specializationInfo
- ? specializationInfo->childInfos[ii]
- : nullptr;
-
- child->acceptVisitor(this, childSpecializationInfo);
- }
-}
-
TargetProgram* ComponentType::getTargetProgram(TargetRequest* target)
{
RefPtr<TargetProgram> targetProgram;
diff --git a/tests/bindings/multi-file-defines.h b/tests/bindings/multi-file-defines.h
new file mode 100644
index 000000000..52a5826b6
--- /dev/null
+++ b/tests/bindings/multi-file-defines.h
@@ -0,0 +1,44 @@
+// multi-file-defines.h
+
+#ifdef __SLANG__
+#define R(X) /**/
+#define BEGIN_CBUFFER(NAME) cbuffer NAME
+#define END_CBUFFER(NAME, REG) /**/
+#define CBUFFER_REF(NAME, FIELD) FIELD
+#else
+#define R(X) X
+#define BEGIN_CBUFFER(NAME) struct SLANG_ParameterGroup_##NAME
+#define END_CBUFFER(NAME, REG) ; cbuffer NAME : REG { SLANG_ParameterGroup_##NAME NAME; }
+#define CBUFFER_REF(NAME, FIELD) NAME.FIELD
+
+#define sharedC sharedC_0
+#define sharedCA sharedCA_0
+#define sharedCB sharedCB_0
+#define sharedCC sharedCC_0
+#define sharedCD sharedCD_0
+
+#define vertexC vertexC_0
+#define vertexCA vertexCA_0
+#define vertexCB vertexCB_0
+#define vertexCC vertexCC_0
+#define vertexCD vertexCD_0
+
+#define fragmentC fragmentC_0
+#define fragmentCA fragmentCA_0
+#define fragmentCB fragmentCB_0
+#define fragmentCC fragmentCC_0
+#define fragmentCD fragmentCD_0
+
+#define sharedS sharedS_0
+#define sharedT sharedT_0
+#define sharedTV sharedTV_0
+#define sharedTF sharedTF_0
+
+#define vertexS vertexS_0
+#define vertexT vertexT_0
+
+#define fragmentS fragmentS_0
+#define fragmentT fragmentT_0
+
+#endif
+
diff --git a/tests/bindings/multi-file-extra.hlsl b/tests/bindings/multi-file-extra.hlsl
index fe8766dcd..9be7a34a0 100644
--- a/tests/bindings/multi-file-extra.hlsl
+++ b/tests/bindings/multi-file-extra.hlsl
@@ -5,74 +5,16 @@
// This file provides the fragment shader, and is only meant to be tested in combination with `multi-file.hlsl`
+#include "multi-file-defines.h"
+
#ifdef __SLANG__
-#define R(X) /**/
-#define BEGIN_CBUFFER(NAME) cbuffer NAME
-#define END_CBUFFER(NAME, REG) /**/
-#define CBUFFER_REF(NAME, FIELD) FIELD
+import multi_file_shared;
#else
-#define R(X) X
-#define BEGIN_CBUFFER(NAME) struct SLANG_ParameterGroup_##NAME
-#define END_CBUFFER(NAME, REG) ; cbuffer NAME : REG { SLANG_ParameterGroup_##NAME NAME; }
-#define CBUFFER_REF(NAME, FIELD) NAME.FIELD
-
-#define sharedC sharedC_0
-#define sharedCA sharedCA_0
-#define sharedCB sharedCB_0
-#define sharedCC sharedCC_0
-#define sharedCD sharedCD_0
-
-#define vertexC vertexC_0
-#define vertexCA vertexCA_0
-#define vertexCB vertexCB_0
-#define vertexCC vertexCC_0
-#define vertexCD vertexCD_0
-
-#define fragmentC fragmentC_0
-#define fragmentCA fragmentCA_0
-#define fragmentCB fragmentCB_0
-#define fragmentCC fragmentCC_0
-#define fragmentCD fragmentCD_0
-
-#define sharedS sharedS_0
-#define sharedT sharedT_0
-#define sharedTV sharedTV_0
-#define sharedTF sharedTF_0
-
-#define vertexS vertexS_0
-#define vertexT vertexT_0
-
-#define fragmentS fragmentS_0
-#define fragmentT fragmentT_0
-
+#include "multi-file-shared.slang"
#endif
-float4 use(float val) { return val; };
-float4 use(float2 val) { return float4(val,0.0,0.0); };
-float4 use(float3 val) { return float4(val,0.0); };
-float4 use(float4 val) { return val; };
-float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); }
-
-// Start with some parameters that will appear in both shaders
-Texture2D sharedT R(: register(t0));
-SamplerState sharedS R(: register(s0));
-
-BEGIN_CBUFFER(sharedC)
-{
- float3 sharedCA;
- float sharedCB;
- float3 sharedCC;
- float2 sharedCD;
-}
-END_CBUFFER(sharedC, register(b0))
-
-// Then some parameters specific to this shader.
-// These will be placed *after* the ones from the main file,
-// and even after the parameters further down in this file
-// that end up being shared between the two files.
-
-Texture2D fragmentT R(: register(t4));
-SamplerState fragmentS R(: register(s2));
+Texture2D fragmentT R(: register(t1));
+SamplerState fragmentS R(: register(s1));
BEGIN_CBUFFER(fragmentC)
{
@@ -81,12 +23,7 @@ BEGIN_CBUFFER(fragmentC)
float3 fragmentCC;
float2 fragmentCD;
}
-END_CBUFFER(fragmentC, register(b2))
-
-// And end with some shared parameters again
-Texture2D sharedTV R(: register(t2));
-Texture2D sharedTF R(: register(t3));
-
+END_CBUFFER(fragmentC, register(b1))
float4 main() : SV_TARGET
{
diff --git a/tests/bindings/multi-file-shared.slang b/tests/bindings/multi-file-shared.slang
new file mode 100644
index 000000000..af91d5251
--- /dev/null
+++ b/tests/bindings/multi-file-shared.slang
@@ -0,0 +1,25 @@
+// multi-file-shared.slang
+//TEST_IGNORE_FILE:
+
+#include "multi-file-defines.h"
+
+float4 use(float val) { return val; };
+float4 use(float2 val) { return float4(val,0.0,0.0); };
+float4 use(float3 val) { return float4(val,0.0); };
+float4 use(float4 val) { return val; };
+float4 use(Texture2D t, SamplerState s) { return t.SampleLevel(s, 0.0, 0.0); }
+
+Texture2D sharedT R(: register(t2));
+SamplerState sharedS R(: register(s2));
+
+BEGIN_CBUFFER(sharedC)
+{
+ float3 sharedCA;
+ float sharedCB;
+ float3 sharedCC;
+ float2 sharedCD;
+}
+END_CBUFFER(sharedC, register(b2))
+
+Texture2D sharedTV R(: register(t3));
+Texture2D sharedTF R(: register(t4));
diff --git a/tests/bindings/multi-file.hlsl b/tests/bindings/multi-file.hlsl
index 8c719bbcf..73ce181b0 100644
--- a/tests/bindings/multi-file.hlsl
+++ b/tests/bindings/multi-file.hlsl
@@ -6,77 +6,16 @@
// This file provides the vertex shader, while the fragment shader resides in
// the file `multi-file-extra.hlsl`
+#include "multi-file-defines.h"
+
#ifdef __SLANG__
-#define R(X) /**/
-#define BEGIN_CBUFFER(NAME) cbuffer NAME
-#define END_CBUFFER(NAME, REG) /**/
-#define CBUFFER_REF(NAME, FIELD) FIELD
+import multi_file_shared;
#else
-#define R(X) X
-#define BEGIN_CBUFFER(NAME) struct SLANG_ParameterGroup_##NAME
-#define END_CBUFFER(NAME, REG) ; cbuffer NAME : REG { SLANG_ParameterGroup_##NAME NAME; }
-#define CBUFFER_REF(NAME, FIELD) NAME.FIELD
-
-#define sharedC sharedC_0
-#define sharedCA sharedCA_0
-#define sharedCB sharedCB_0
-#define sharedCC sharedCC_0
-#define sharedCD sharedCD_0
-
-#define vertexC vertexC_0
-#define vertexCA vertexCA_0
-#define vertexCB vertexCB_0
-#define vertexCC vertexCC_0
-#define vertexCD vertexCD_0
-
-#define fragmentC fragmentC_0
-#define fragmentCA fragmentCA_0
-#define fragmentCB fragmentCB_0
-#define fragmentCC fragmentCC_0
-#define fragmentCD fragmentCD_0
-
-#define sharedS sharedS_0
-#define sharedT sharedT_0
-#define sharedTV sharedTV_0
-#define sharedTF sharedTF_0
-
-#define vertexS vertexS_0
-#define vertexT vertexT_0
-
-#define fragmentS fragmentS_0
-#define fragmentT fragmentT_0
-
+#include "multi-file-shared.slang"
#endif
-float4 use(float val) { return val; };
-float4 use(float2 val) { return float4(val,0.0,0.0); };
-float4 use(float3 val) { return float4(val,0.0); };
-float4 use(float4 val) { return val; };
-float4 use(Texture2D t, SamplerState s)
-{
- // This is the vertex shader, so we can't do implicit-gradient sampling
- return t.SampleGrad(s, 0.0, 0.0, 0.0);
-}
-
-// Start with some parameters that will appear in both shaders
-Texture2D sharedT R(: register(t0));
-SamplerState sharedS R(: register(s0));
-
-BEGIN_CBUFFER(sharedC)
-{
- float3 sharedCA;
- float sharedCB;
- float3 sharedCC;
- float2 sharedCD;
-}
-END_CBUFFER(sharedC, register(b0))
-
-// Then some parameters specific to this shader
-// (these will get placed before the ones in the `extra` file,
-// based on how they get named on the command-line)
-
-Texture2D vertexT R(: register(t1));
-SamplerState vertexS R(: register(s1));
+Texture2D vertexT R(: register(t0));
+SamplerState vertexS R(: register(s0));
BEGIN_CBUFFER(vertexC)
{
@@ -85,12 +24,7 @@ BEGIN_CBUFFER(vertexC)
float3 vertexCC;
float2 vertexCD;
}
-END_CBUFFER(vertexC, register(b1))
-
-// And end with some shared parameters again
-Texture2D sharedTV R(: register(t2));
-Texture2D sharedTF R(: register(t3));
-
+END_CBUFFER(vertexC, register(b0))
float4 main() : SV_POSITION
{
diff --git a/tests/diagnostics/gh-38-vs.hlsl b/tests/diagnostics/gh-38-vs.hlsl
index bb97482c4..3e61d7f2e 100644
--- a/tests/diagnostics/gh-38-vs.hlsl
+++ b/tests/diagnostics/gh-38-vs.hlsl
@@ -1,4 +1,4 @@
-//DIAGNOSTIC_TEST:SIMPLE: -profile sm_5_0 -entry main -stage vertex tests/diagnostics/gh-38-fs.hlsl -entry main -stage fragment
+//DIAGNOSTIC_TEST:SIMPLE: -profile sm_5_0 -entry main -stage vertex tests/diagnostics/gh-38-fs.hlsl -entry main -stage fragment -no-codegen
// Ensure that we catch errors with overlapping or conflicting parameter bindings.
diff --git a/tests/diagnostics/gh-38-vs.hlsl.expected b/tests/diagnostics/gh-38-vs.hlsl.expected
index 76987ae44..1c784e283 100644
--- a/tests/diagnostics/gh-38-vs.hlsl.expected
+++ b/tests/diagnostics/gh-38-vs.hlsl.expected
@@ -1,7 +1,5 @@
-result code = -1
+result code = 0
standard error = {
-tests/diagnostics/gh-38-fs.hlsl(7): error 39000: conflicting explicit bindings for parameter 'conflicting'
-tests/diagnostics/gh-38-vs.hlsl(7): note: see other declaration of 'conflicting'
tests/diagnostics/gh-38-fs.hlsl(5): warning 39001: explicit binding for parameter 'overlappingB' overlaps with parameter 'overlappingA'
tests/diagnostics/gh-38-vs.hlsl(5): note: see declaration of 'overlappingA'
}
diff --git a/tests/reflection/multi-file-defines.h b/tests/reflection/multi-file-defines.h
new file mode 100644
index 000000000..aed4c510a
--- /dev/null
+++ b/tests/reflection/multi-file-defines.h
@@ -0,0 +1,44 @@
+// multi-file-defines.h
+
+#ifdef __SLANG__
+#define R(X) /**/
+#define BEGIN_CBUFFER(NAME) cbuffer NAME
+#define END_CBUFFER(NAME, REG) /**/
+#define CBUFFER_REF(NAME, FIELD) FIELD
+#else
+#define R(X) /*X*/
+#define BEGIN_CBUFFER(NAME) struct SLANG_ParameterGroup_##NAME
+#define END_CBUFFER(NAME, REG) ; cbuffer NAME /*REG*/ { SLANG_ParameterGroup_##NAME NAME; }
+#define CBUFFER_REF(NAME, FIELD) NAME.FIELD
+
+#define sharedC sharedC_0
+#define sharedCA sharedCA_0
+#define sharedCB sharedCB_0
+#define sharedCC sharedCC_0
+#define sharedCD sharedCD_0
+
+#define vertexC vertexC_0
+#define vertexCA vertexCA_0
+#define vertexCB vertexCB_0
+#define vertexCC vertexCC_0
+#define vertexCD vertexCD_0
+
+#define fragmentC fragmentC_0
+#define fragmentCA fragmentCA_0
+#define fragmentCB fragmentCB_0
+#define fragmentCC fragmentCC_0
+#define fragmentCD fragmentCD_0
+
+#define sharedS sharedS_0
+#define sharedT sharedT_0
+#define sharedTV sharedTV_0
+#define sharedTF sharedTF_0
+
+#define vertexS vertexS_0
+#define vertexT vertexT_0
+
+#define fragmentS fragmentS_0
+#define fragmentT fragmentT_0
+
+#endif
+
diff --git a/tests/reflection/multi-file-extra.hlsl b/tests/reflection/multi-file-extra.hlsl
index be5757d14..701118d01 100644
--- a/tests/reflection/multi-file-extra.hlsl
+++ b/tests/reflection/multi-file-extra.hlsl
@@ -1,63 +1,32 @@
//TEST_IGNORE_FILE:
-// Here we are going to test that we can correctly generating bindings when we
-// are presented with a program spanning multiple input files (and multiple entry points)
-
-// This file provides the fragment shader, and is only meant to be tested in combination with `multi-file.hlsl`
-
-// Let's make sure we generate correct output in cases
-// where there are non-trivial `packoffset`s needed
+#include "multi-file-defines.h"
#ifdef __SLANG__
-#define R(X) /**/
+import multi_file_shared;
#else
-#define R(X) X
+#include "multi-file-shared.slang"
#endif
-float4 use(float val) { return val; };
-float4 use(float2 val) { return float4(val,0.0,0.0); };
-float4 use(float3 val) { return float4(val,0.0); };
-float4 use(float4 val) { return val; };
-float4 use(Texture2D t, SamplerState s) { return t.SampleLevel(s, 0.0, 0.0); }
-
-// Start with some parameters that will appear in both shaders
-Texture2D sharedT;
-SamplerState sharedS;
-cbuffer sharedC
-{
- float3 sharedCA;
- float sharedCB;
- float3 sharedCC;
- float2 sharedCD;
-}
-
-// Then some parameters specific to this shader.
-// These will be placed *after* the ones from the main file,
-// and even after the parameters further down in this file
-// that end up being shared between the two files.
+Texture2D fragmentT R(: register(t1));
+SamplerState fragmentS R(: register(s1));
-Texture2D fragmentT;
-SamplerState fragmentS;
-cbuffer fragmentC
+BEGIN_CBUFFER(fragmentC)
{
float3 fragmentCA;
float fragmentCB;
float3 fragmentCC;
float2 fragmentCD;
}
+END_CBUFFER(fragmentC, register(b1))
-// And end with some shared parameters again
-Texture2D sharedTV;
-Texture2D sharedTF;
-
-
-float4 mainVS() : SV_Position
+float4 mainFS() : SV_TARGET
{
// Go ahead and use everything here, just to make sure things got placed correctly
return use(sharedT, sharedS)
- + use(sharedCD)
+ + use(CBUFFER_REF(sharedC,sharedCD))
+ use(fragmentT, fragmentS)
- + use(fragmentCD)
+ + use(CBUFFER_REF(fragmentC, fragmentCD))
+ use(sharedTF, sharedS)
;
} \ No newline at end of file
diff --git a/tests/reflection/multi-file-shared.slang b/tests/reflection/multi-file-shared.slang
new file mode 100644
index 000000000..af91d5251
--- /dev/null
+++ b/tests/reflection/multi-file-shared.slang
@@ -0,0 +1,25 @@
+// multi-file-shared.slang
+//TEST_IGNORE_FILE:
+
+#include "multi-file-defines.h"
+
+float4 use(float val) { return val; };
+float4 use(float2 val) { return float4(val,0.0,0.0); };
+float4 use(float3 val) { return float4(val,0.0); };
+float4 use(float4 val) { return val; };
+float4 use(Texture2D t, SamplerState s) { return t.SampleLevel(s, 0.0, 0.0); }
+
+Texture2D sharedT R(: register(t2));
+SamplerState sharedS R(: register(s2));
+
+BEGIN_CBUFFER(sharedC)
+{
+ float3 sharedCA;
+ float sharedCB;
+ float3 sharedCC;
+ float2 sharedCD;
+}
+END_CBUFFER(sharedC, register(b2))
+
+Texture2D sharedTV R(: register(t3));
+Texture2D sharedTF R(: register(t4));
diff --git a/tests/reflection/multi-file.hlsl b/tests/reflection/multi-file.hlsl
index 4a9cf9a86..fd9235ab5 100644
--- a/tests/reflection/multi-file.hlsl
+++ b/tests/reflection/multi-file.hlsl
@@ -1,56 +1,36 @@
-//TEST:REFLECTION:-entry mainFS -profile ps_4_0 -target hlsl tests/reflection/multi-file-extra.hlsl -entry mainVS -profile vs_4_0
+//TEST:REFLECTION:-D__SLANG__ -entry mainVS -profile vs_4_0 -target hlsl tests/reflection/multi-file-extra.hlsl -entry mainFS -profile ps_4_0
// Here we are testing the case where multiple translation units are provided
// at once, so that we want combined reflection information for the resulting
// program. The other part of this program is in `multi-file-extra.hlsl`.
-float4 use(float val) { return val; };
-float4 use(float2 val) { return float4(val,0.0,0.0); };
-float4 use(float3 val) { return float4(val,0.0); };
-float4 use(float4 val) { return val; };
-float4 use(Texture2D t, SamplerState s)
-{
- // This is the vertex shader, so we can't do implicit-gradient sampling
- return t.SampleGrad(s, 0.0, 0.0, 0.0);
-}
+#include "multi-file-defines.h"
-// Start with some parameters that will appear in both shaders
-Texture2D sharedT;
-SamplerState sharedS;
-cbuffer sharedC
-{
- float3 sharedCA;
- float sharedCB;
- float3 sharedCC;
- float2 sharedCD;
-}
+#ifdef __SLANG__
+import multi_file_shared;
+#else
+#include "multi-file-shared.slang"
+#endif
-// Then some parameters specific to this shader
-// (these will get placed before the ones in the `extra` file,
-// based on how they get named on the command-line)
+Texture2D vertexT R(: register(t0));
+SamplerState vertexS R(: register(s0));
-Texture2D vertexT;
-SamplerState vertexS;
-cbuffer vertexC
+BEGIN_CBUFFER(vertexC)
{
- float3 vertexCA;
- float vertexCB;
- float3 vertexCC;
- float2 vertexCD;
+ float3 vertexCA;
+ float vertexCB;
+ float3 vertexCC;
+ float2 vertexCD;
}
+END_CBUFFER(vertexC, register(b0))
-// And end with some shared parameters again
-Texture2D sharedTV;
-Texture2D sharedTF;
-
-
-float4 mainFS() : SV_Target
+float4 mainVS() : SV_POSITION
{
- // Go ahead and use everything here, just to make sure things got placed correctly
- return use(sharedT, sharedS)
- + use(sharedCD)
- + use(vertexT, vertexS)
- + use(vertexCD)
- + use(sharedTV, vertexS)
- ;
-} \ No newline at end of file
+ // Go ahead and use everything here, just to make sure things got placed correctly
+ return use(sharedT, sharedS)
+ + use(CBUFFER_REF(sharedC, sharedCD))
+ + use(vertexT, vertexS)
+ + use(CBUFFER_REF(vertexC, vertexCD))
+ + use(sharedTV, vertexS)
+ ;
+}
diff --git a/tests/reflection/multi-file.hlsl.expected b/tests/reflection/multi-file.hlsl.expected
index 4ad95fb35..814c648e0 100644
--- a/tests/reflection/multi-file.hlsl.expected
+++ b/tests/reflection/multi-file.hlsl.expected
@@ -5,7 +5,7 @@ standard output = {
{
"parameters": [
{
- "name": "sharedT",
+ "name": "vertexT",
"binding": {"kind": "shaderResource", "index": 0},
"type": {
"kind": "resource",
@@ -13,14 +13,14 @@ standard output = {
}
},
{
- "name": "sharedS",
+ "name": "vertexS",
"binding": {"kind": "samplerState", "index": 0},
"type": {
"kind": "samplerState"
}
},
{
- "name": "sharedC",
+ "name": "vertexC",
"binding": {"kind": "constantBuffer", "index": 0},
"type": {
"kind": "constantBuffer",
@@ -28,7 +28,7 @@ standard output = {
"kind": "struct",
"fields": [
{
- "name": "sharedCA",
+ "name": "vertexCA",
"type": {
"kind": "vector",
"elementCount": 3,
@@ -40,7 +40,7 @@ standard output = {
"binding": {"kind": "uniform", "offset": 0, "size": 12}
},
{
- "name": "sharedCB",
+ "name": "vertexCB",
"type": {
"kind": "scalar",
"scalarType": "float32"
@@ -48,7 +48,7 @@ standard output = {
"binding": {"kind": "uniform", "offset": 12, "size": 4}
},
{
- "name": "sharedCC",
+ "name": "vertexCC",
"type": {
"kind": "vector",
"elementCount": 3,
@@ -60,7 +60,7 @@ standard output = {
"binding": {"kind": "uniform", "offset": 16, "size": 12}
},
{
- "name": "sharedCD",
+ "name": "vertexCD",
"type": {
"kind": "vector",
"elementCount": 2,
@@ -76,7 +76,7 @@ standard output = {
}
},
{
- "name": "vertexT",
+ "name": "fragmentT",
"binding": {"kind": "shaderResource", "index": 1},
"type": {
"kind": "resource",
@@ -84,14 +84,14 @@ standard output = {
}
},
{
- "name": "vertexS",
+ "name": "fragmentS",
"binding": {"kind": "samplerState", "index": 1},
"type": {
"kind": "samplerState"
}
},
{
- "name": "vertexC",
+ "name": "fragmentC",
"binding": {"kind": "constantBuffer", "index": 1},
"type": {
"kind": "constantBuffer",
@@ -99,7 +99,7 @@ standard output = {
"kind": "struct",
"fields": [
{
- "name": "vertexCA",
+ "name": "fragmentCA",
"type": {
"kind": "vector",
"elementCount": 3,
@@ -111,7 +111,7 @@ standard output = {
"binding": {"kind": "uniform", "offset": 0, "size": 12}
},
{
- "name": "vertexCB",
+ "name": "fragmentCB",
"type": {
"kind": "scalar",
"scalarType": "float32"
@@ -119,7 +119,7 @@ standard output = {
"binding": {"kind": "uniform", "offset": 12, "size": 4}
},
{
- "name": "vertexCC",
+ "name": "fragmentCC",
"type": {
"kind": "vector",
"elementCount": 3,
@@ -131,7 +131,7 @@ standard output = {
"binding": {"kind": "uniform", "offset": 16, "size": 12}
},
{
- "name": "vertexCD",
+ "name": "fragmentCD",
"type": {
"kind": "vector",
"elementCount": 2,
@@ -147,7 +147,7 @@ standard output = {
}
},
{
- "name": "sharedTV",
+ "name": "sharedT",
"binding": {"kind": "shaderResource", "index": 2},
"type": {
"kind": "resource",
@@ -155,30 +155,14 @@ standard output = {
}
},
{
- "name": "sharedTF",
- "binding": {"kind": "shaderResource", "index": 3},
- "type": {
- "kind": "resource",
- "baseShape": "texture2D"
- }
- },
- {
- "name": "fragmentT",
- "binding": {"kind": "shaderResource", "index": 4},
- "type": {
- "kind": "resource",
- "baseShape": "texture2D"
- }
- },
- {
- "name": "fragmentS",
+ "name": "sharedS",
"binding": {"kind": "samplerState", "index": 2},
"type": {
"kind": "samplerState"
}
},
{
- "name": "fragmentC",
+ "name": "sharedC",
"binding": {"kind": "constantBuffer", "index": 2},
"type": {
"kind": "constantBuffer",
@@ -186,7 +170,7 @@ standard output = {
"kind": "struct",
"fields": [
{
- "name": "fragmentCA",
+ "name": "sharedCA",
"type": {
"kind": "vector",
"elementCount": 3,
@@ -198,7 +182,7 @@ standard output = {
"binding": {"kind": "uniform", "offset": 0, "size": 12}
},
{
- "name": "fragmentCB",
+ "name": "sharedCB",
"type": {
"kind": "scalar",
"scalarType": "float32"
@@ -206,7 +190,7 @@ standard output = {
"binding": {"kind": "uniform", "offset": 12, "size": 4}
},
{
- "name": "fragmentCC",
+ "name": "sharedCC",
"type": {
"kind": "vector",
"elementCount": 3,
@@ -218,7 +202,7 @@ standard output = {
"binding": {"kind": "uniform", "offset": 16, "size": 12}
},
{
- "name": "fragmentCD",
+ "name": "sharedCD",
"type": {
"kind": "vector",
"elementCount": 2,
@@ -232,16 +216,32 @@ standard output = {
]
}
}
+ },
+ {
+ "name": "sharedTV",
+ "binding": {"kind": "shaderResource", "index": 3},
+ "type": {
+ "kind": "resource",
+ "baseShape": "texture2D"
+ }
+ },
+ {
+ "name": "sharedTF",
+ "binding": {"kind": "shaderResource", "index": 4},
+ "type": {
+ "kind": "resource",
+ "baseShape": "texture2D"
+ }
}
],
"entryPoints": [
{
- "name": "mainFS",
- "stage:": "fragment"
- },
- {
"name": "mainVS",
"stage:": "vertex"
+ },
+ {
+ "name": "mainFS",
+ "stage:": "fragment"
}
]
}