summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--slang-com-helper.h8
-rw-r--r--slang.h407
-rw-r--r--source/core/core.vcxproj4
-rw-r--r--source/core/slang-writer.h2
-rw-r--r--source/slang/slang-check.cpp300
-rw-r--r--source/slang/slang-compiler.cpp87
-rw-r--r--source/slang/slang-compiler.h261
-rw-r--r--source/slang/slang-diagnostic-defs.h2
-rw-r--r--source/slang/slang-diagnostics.h6
-rw-r--r--source/slang/slang-emit.cpp50
-rw-r--r--source/slang/slang-file-system.h6
-rw-r--r--source/slang/slang-ir-link.cpp40
-rw-r--r--source/slang/slang-parameter-binding.cpp276
-rw-r--r--source/slang/slang-parser.cpp3
-rw-r--r--source/slang/slang-reflection.cpp131
-rw-r--r--source/slang/slang-type-layout.cpp91
-rw-r--r--source/slang/slang-type-layout.h40
-rw-r--r--source/slang/slang.cpp464
-rw-r--r--source/slang/slang.natvis12
-rw-r--r--source/slang/slang.vcxproj5
-rw-r--r--source/slang/slang.vcxproj.filters7
-rw-r--r--tests/compute/interface-shader-param-in-struct.slang19
-rw-r--r--tests/compute/interface-shader-param3.slang34
-rw-r--r--tests/compute/interface-shader-param4.slang28
-rw-r--r--tests/reflection/parameter-block-explicit-space.slang.expected4
26 files changed, 1957 insertions, 332 deletions
diff --git a/.gitignore b/.gitignore
index 206dfca5e..09133cdf1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,8 @@
*.VC.db
*.vcxproj.user
*.sdf
+*.ilk
+*.obj
bin/
intermediate/
build.*/
diff --git a/slang-com-helper.h b/slang-com-helper.h
index 245c800b6..e674ff27f 100644
--- a/slang-com-helper.h
+++ b/slang-com-helper.h
@@ -70,7 +70,7 @@ For SLANG_IUNKNOWN_QUERY_INTERFACE to work - must have a method 'getInterface' t
if not found. */
#define SLANG_IUNKNOWN_QUERY_INTERFACE \
-SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) \
+SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE \
{ \
ISlangUnknown* intf = getInterface(uuid); \
if (intf) \
@@ -108,7 +108,7 @@ SLANG_NO_THROW uint32_t SLANG_MCALL release() \
// ------------------------ RefObject IUnknown -----------------------------
#define SLANG_REF_OBJECT_IUNKNOWN_QUERY_INTERFACE \
-SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) \
+SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE \
{ \
ISlangUnknown* intf = getInterface(uuid); \
if (intf) \
@@ -120,8 +120,8 @@ SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, voi
return SLANG_E_NO_INTERFACE;\
}
-#define SLANG_REF_OBJECT_IUNKNOWN_ADD_REF SLANG_NO_THROW uint32_t SLANG_MCALL addRef() { return (uint32_t)addReference(); }
-#define SLANG_REF_OBJECT_IUNKNOWN_RELEASE SLANG_NO_THROW uint32_t SLANG_MCALL release() { return (uint32_t)releaseReference(); }
+#define SLANG_REF_OBJECT_IUNKNOWN_ADD_REF SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return (uint32_t)addReference(); }
+#define SLANG_REF_OBJECT_IUNKNOWN_RELEASE SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return (uint32_t)releaseReference(); }
#define SLANG_REF_OBJECT_IUNKNOWN_ALL \
SLANG_REF_OBJECT_IUNKNOWN_QUERY_INTERFACE \
diff --git a/slang.h b/slang.h
index 23d8c5f12..1fd92f440 100644
--- a/slang.h
+++ b/slang.h
@@ -298,8 +298,15 @@ convention for interface methods.
#ifdef __cplusplus
// C++ specific macros
+// Clang
+#if SLANG_CLANG
+# if (__clang_major__*10 + __clang_minor__) >= 33
+# define SLANG_HAS_MOVE_SEMANTICS 1
+# define SLANG_HAS_ENUM_CLASS 1
+# define SLANG_OVERRIDE override
+# endif
// Gcc
-# if SLANG_GCC_FAMILY
+#elif SLANG_GCC_FAMILY
// Check for C++11
# if (__cplusplus >= 201103L)
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
@@ -1044,8 +1051,7 @@ extern "C"
*/
typedef struct SlangSession SlangSession;
- typedef struct SlangLinkage SlangLinkage;
- typedef struct SlangModule SlangModule;
+ typedef struct SlangProgramLayout SlangProgramLayout;
/*!
@brief A request for one or more compilation actions to be performed.
@@ -1113,20 +1119,6 @@ extern "C"
char const* sourcePath,
char const* sourceString);
-
-
- SLANG_API SlangLinkage* spCreateLinkage(
- SlangSession* session);
-
- SLANG_API void spDestroyLinkage(
- SlangLinkage* linkage);
-
- SLANG_API SlangModule* spLoadModule(
- SlangLinkage* linkage,
- char const* moduleName);
-
-
-
/*!
@brief Create a compile request.
*/
@@ -1563,11 +1555,17 @@ extern "C"
SlangCompileRequest* request,
size_t* outSize);
- /* Note(tfoley): working on new reflection interface...
+ /*
+ Forward declarations of types used in the reflection interface;
*/
- typedef struct SlangReflection SlangReflection;
- typedef struct SlangReflectionEntryPoint SlangReflectionEntryPoint;
+ typedef struct SlangProgramLayout SlangProgramLayout;
+ typedef struct SlangEntryPoint SlangEntryPoint;
+ typedef struct SlangEntryPointLayout SlangEntryPointLayout;
+ typedef struct SlangEntryPointGroupLayout SlangEntryPointGroupLayout;
+
+// typedef struct SlangReflection SlangReflection;
+// typedef struct SlangReflectionEntryPoint SlangReflectionEntryPoint;
typedef struct SlangReflectionModifier SlangReflectionModifier;
typedef struct SlangReflectionType SlangReflectionType;
typedef struct SlangReflectionTypeLayout SlangReflectionTypeLayout;
@@ -1576,6 +1574,12 @@ extern "C"
typedef struct SlangReflectionTypeParameter SlangReflectionTypeParameter;
typedef struct SlangReflectionUserAttribute SlangReflectionUserAttribute;
+ /*
+ Type aliases to maintain backward compatibility.
+ */
+ typedef SlangProgramLayout SlangReflection;
+ typedef SlangEntryPointLayout SlangReflectionEntryPoint;
+
// get reflection data from a compilation request
SLANG_API SlangReflection* spGetReflection(
SlangCompileRequest* request);
@@ -1909,6 +1913,9 @@ extern "C"
SLANG_API SlangReflectionEntryPoint* spReflection_getEntryPointByIndex(SlangReflection* reflection, SlangUInt index);
SLANG_API SlangReflectionEntryPoint* spReflection_findEntryPointByName(SlangReflection* reflection, char const* name);
+ SLANG_API SlangInt spReflection_getEntryPointGroupCount(SlangReflection* reflection);
+ SLANG_API SlangEntryPointGroupLayout* spReflection_getEntryPointGroupByIndex(SlangReflection* reflection, SlangInt index);
+
SLANG_API SlangUInt spReflection_getGlobalConstantBufferBinding(SlangReflection* reflection);
SLANG_API size_t spReflection_getGlobalConstantBufferSize(SlangReflection* reflection);
@@ -1919,6 +1926,15 @@ extern "C"
SlangReflectionType* const* specializationArgs,
ISlangBlob** outDiagnostics);
+ // Entry point group reflection
+
+ SLANG_API SlangInt spEntryPointGroupLayout_getEntryPointCount(SlangEntryPointGroupLayout* group);
+ SLANG_API SlangReflectionEntryPoint* spEntryPointGroupLayout_getEntryPointByIndex(SlangEntryPointGroupLayout* group, SlangInt index);
+ SLANG_API SlangReflectionVariableLayout* spEntryPointGroupLayout_getVarLayout(SlangEntryPointGroupLayout* group);
+
+ SLANG_API SlangInt spEntryPointGroupLayout_getParameterCount(SlangEntryPointGroupLayout* group);
+ SLANG_API SlangReflectionVariableLayout* spEntryPointGroupLayout_getParameterByIndex(SlangEntryPointGroupLayout* group, SlangInt index);
+
#ifdef __cplusplus
}
@@ -1926,9 +1942,6 @@ extern "C"
/* Helper interfaces for C++ users */
namespace slang
{
-#define SLANG_SAFE_BOOL(expr) \
- operator bool() const { return expr; }
-
struct BufferReflection;
struct TypeLayoutReflection;
struct TypeReflection;
@@ -2427,6 +2440,35 @@ namespace slang
return 0 != spReflectionEntryPoint_usesAnySampleRateInput((SlangReflectionEntryPoint*) this);
}
};
+ typedef EntryPointReflection EntryPointLayout;
+
+ struct EntryPointGroupLayout
+ {
+ SlangInt getEntryPointCount()
+ {
+ return spEntryPointGroupLayout_getEntryPointCount((SlangEntryPointGroupLayout*) this);
+ }
+
+ EntryPointReflection* getEntryPointByIndex(SlangInt index)
+ {
+ return (EntryPointReflection*) spEntryPointGroupLayout_getEntryPointByIndex((SlangEntryPointGroupLayout*) this, index);
+ }
+
+ VariableLayoutReflection* getVarLayout()
+ {
+ return (VariableLayoutReflection*) spEntryPointGroupLayout_getVarLayout((SlangEntryPointGroupLayout*) this);
+ }
+
+ SlangInt getParameterCount()
+ {
+ return spEntryPointGroupLayout_getParameterCount((SlangEntryPointGroupLayout*) this);
+ }
+
+ VariableLayoutReflection* getParameterByIndex(SlangInt index)
+ {
+ return (VariableLayoutReflection*) spEntryPointGroupLayout_getParameterByIndex((SlangEntryPointGroupLayout*) this, index);
+ }
+ };
struct TypeParameterReflection
{
@@ -2453,6 +2495,8 @@ namespace slang
Default = SLANG_LAYOUT_RULES_DEFAULT,
};
+ typedef struct ShaderReflection ProgramLayout;
+
struct ShaderReflection
{
unsigned getParameterCount()
@@ -2480,9 +2524,9 @@ namespace slang
return (VariableLayoutReflection*) spReflection_GetParameterByIndex((SlangReflection*) this, index);
}
- static ShaderReflection* get(SlangCompileRequest* request)
+ static ProgramLayout* get(SlangCompileRequest* request)
{
- return (ShaderReflection*) spGetReflection(request);
+ return (ProgramLayout*) spGetReflection(request);
}
SlangUInt getEntryPointCount()
@@ -2495,6 +2539,16 @@ namespace slang
return (EntryPointReflection*) spReflection_getEntryPointByIndex((SlangReflection*) this, index);
}
+ SlangInt getEntryPointGroupCount()
+ {
+ return spReflection_getEntryPointGroupCount((SlangReflection*) this);
+ }
+
+ EntryPointGroupLayout* getEntryPointGroupByIndex(SlangInt index)
+ {
+ return (EntryPointGroupLayout*) spReflection_getEntryPointGroupByIndex((SlangReflection*) this, index);
+ }
+
SlangUInt getGlobalConstantBufferBinding()
{
return spReflection_getGlobalConstantBufferBinding((SlangReflection*)this);
@@ -2543,8 +2597,311 @@ namespace slang
outDiagnostics);
}
};
+
+ typedef ISlangBlob IBlob;
+
+ struct IGlobalSession;
+ struct IModule;
+ struct IProgram;
+ struct ISession;
+
+ struct SessionDesc;
+ struct ProgramDesc;
+ struct SpecializationArg;
+ struct TargetDesc;
+
+ /** A global session for interaction with the Slang library.
+
+ An application may create and re-use a single global session across
+ multiple sessions, in order to amortize startups costs (in current
+ Slang this is mostly the cost of loading the Slang standard library).
+
+ The global session is currently *not* thread-safe and objects created from
+ a single global session should only be used from a single thread at
+ a time.
+ */
+ struct IGlobalSession : public ISlangUnknown
+ {
+ public:
+ /** Create a new session for loading and compiling code.
+ */
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL createSession(
+ SessionDesc const& desc,
+ ISession** outSession) = 0;
+
+ /** Look up the internal ID of a profile by its `name`.
+
+ Profile IDs are *not* guaranteed to be stable across versions
+ of the Slang library, so clients are expected to look up
+ profiles by name at runtime.
+ */
+ virtual SLANG_NO_THROW SlangProfileID SLANG_MCALL findProfile(
+ char const* name) = 0;
+ };
+
+ #define SLANG_UUID_IGlobalSession { 0xc140b5fd, 0xc78, 0x452e, { 0xba, 0x7c, 0x1a, 0x1e, 0x70, 0xc7, 0xf7, 0x1c } };
+
+ /** Description of a code generation target.
+ */
+ struct TargetDesc
+ {
+ /** The target format to generate code for (e.g., SPIR-V, DXIL, etc.)
+ */
+ SlangCompileTarget format = SLANG_TARGET_UNKNOWN;
+
+ /** The compilation profile supported by the target (e.g., "Shader Model 5.1")
+ */
+ SlangProfileID profile = SLANG_PROFILE_UNKNOWN;
+
+ /** Flags for the code generation target. Currently unused. */
+ SlangTargetFlags flags = 0;
+
+ /** Default mode to use for floating-point operations on the target.
+ */
+ SlangFloatingPointMode floatingPointMode = SLANG_FLOATING_POINT_MODE_DEFAULT;
+
+ /** Optimization level to use for the target.
+ */
+ SlangOptimizationLevel optimizationLevel = SLANG_OPTIMIZATION_LEVEL_DEFAULT;
+ };
+
+ typedef uint32_t SessionFlags;
+ enum
+ {
+ kSessionFlags_None = 0,
+
+ /** Use application-specific policy for semantics of the `shared` keyword.
+
+ This is a legacy/compatibility flag to help an existing Slang client
+ migrate to new language features, and should *not* be used by other
+ clients. This feature may be removed in a future release without a
+ deprecation warning, and this bit may be re-used for another feature.
+ You have been warned.
+ */
+ kSessionFlag_FalcorCustomSharedKeywordSemantics = 1 << 0,
+ };
+
+ struct PreprocessorMacroDesc
+ {
+ const char* name;
+ const char* value;
+ };
+
+ struct SessionDesc
+ {
+ /** Code generation targets to include in the session.
+ */
+ TargetDesc const* targets = nullptr;
+ SlangInt targetCount = 0;
+
+ /** Flags to configure the session.
+ */
+ SessionFlags flags = kSessionFlags_None;
+
+ /** Default layout to assume for variables with matrix types.
+ */
+ SlangMatrixLayoutMode defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_ROW_MAJOR;
+
+ /** Paths to use when searching for `#include`d or `import`ed files.
+ */
+ char const* const* searchPaths = nullptr;
+ SlangInt searchPathCount = 0;
+
+ PreprocessorMacroDesc const* preprocessorMacros = nullptr;
+ SlangInt preprocessorMacroCount = 0;
+
+ };
+
+ /** A session provides a scope for code that is loaded.
+
+ A session can be used to load modules of Slang source code,
+ and to request target-specific compiled binaries and layout
+ information.
+
+ In order to be able to load code, the session owns a set
+ of active "search paths" for resolving `#include` directives
+ and `import` declrations, as well as a set of global
+ preprocessor definitions that will be used for all code
+ that gets `import`ed in the session.
+
+ If multiple user shaders are loaded in the same session,
+ and import the same module (e.g., two source files do `import X`)
+ then there will only be one copy of `X` loaded within the session.
+
+ In order to be able to generate target code, the session
+ owns a list of available compilation targets, which specify
+ code generation options.
+
+ Code loaded and compiled within a session is owned by the session
+ and will remain resident in memory until the session is released.
+ Applications wishing to control the memory usage for compiled
+ and loaded code should use multiple sessions.
+ */
+ struct ISession : public ISlangUnknown
+ {
+ public:
+ /** Get the global session thas was used to create this session.
+ */
+ virtual SLANG_NO_THROW IGlobalSession* SLANG_MCALL getGlobalSession() = 0;
+
+ /** Load a module as it would be by code using `import`.
+ */
+ virtual SLANG_NO_THROW IModule* SLANG_MCALL loadModule(
+ const char* moduleName,
+ IBlob** outDiagnostics = nullptr) = 0;
+
+ /** Create a program out of existing compiled items.
+ */
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL createProgram(
+ ProgramDesc const& desc,
+ IProgram** outProgram) = 0;
+
+ /** Specialize a program based on type arguments.
+ */
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL specializeProgram(
+ IProgram* program,
+ SlangInt specializationArgCount,
+ SpecializationArg const* specializationArgs,
+ IProgram** outSpecializedProgram,
+ ISlangBlob** outDiagnostics = nullptr) = 0;
+
+ /** Specialize a type based on type arguments.
+ */
+ virtual SLANG_NO_THROW TypeReflection* SLANG_MCALL specializeType(
+ TypeReflection* type,
+ SpecializationArg const* specializationArgs,
+ SlangInt specializationArgCount,
+ ISlangBlob** outDiagnostics = nullptr) = 0;
+
+
+ /** Get the layout `type` on the chosen `target`.
+ */
+ virtual SLANG_NO_THROW TypeLayoutReflection* SLANG_MCALL getTypeLayout(
+ TypeReflection* type,
+ SlangInt targetIndex = 0,
+ LayoutRules rules = LayoutRules::Default,
+ ISlangBlob** outDiagnostics = nullptr) = 0;
+
+ /** Create a request to load/compile front-end code.
+ */
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL createCompileRequest(
+ SlangCompileRequest** outCompileRequest) = 0;
+ };
+
+ #define SLANG_UUID_ISession { 0x67618701, 0xd116, 0x468f, { 0xab, 0x3b, 0x47, 0x4b, 0xed, 0xce, 0xe, 0x3d } }
+
+
+ /** A module is the granularity of shader code compilation and loading.
+
+ In most cases a module corresponds to a single compile "translation unit."
+ This will often be a single `.slang` or `.hlsl` file and everything it
+ `#include`s.
+
+ Notably, a module `M` does *not* include the things it `import`s, as these
+ as distinct modules that `M` depends on. There is a directed graph of
+ module dependencies, and all modules in the graph must belong to the
+ same session (`ISession`).
+ */
+ struct IModule : public ISlangUnknown
+ {
+ public:
+ };
+
+ #define SLANG_UUID_IModule { 0xc720e64, 0x8722, 0x4d31, { 0x89, 0x90, 0x63, 0x8a, 0x98, 0xb1, 0xc2, 0x79 } }
+
+
+ /** Argument used for specialization to types/values.
+ */
+ struct SpecializationArg
+ {
+ enum class Kind : int32_t
+ {
+ Unknown,
+ Type,
+ };
+ Kind kind;
+ union
+ {
+ TypeReflection* type;
+ };
+ };
+
+ /** Description of a program to be created.
+ */
+ struct ProgramDesc
+ {
+ struct Item
+ {
+ enum class Kind : int32_t
+ {
+ Program,
+ Module,
+ };
+ Kind kind;
+ union
+ {
+ IProgram* program;
+ IModule* module;
+ };
+ };
+
+ Item const* items;
+ SlangInt itemCount;
+ };
+
+
+ /** A program comprises zero or more modules, entry points, etc. that have been linked together.
+ */
+ struct IProgram : public ISlangUnknown
+ {
+ public:
+ /** Get the runtime session that this program belongs to.
+ */
+ virtual SLANG_NO_THROW ISession* SLANG_MCALL getSession() = 0;
+
+ /** Get the layout for this program for the chosen `targetIndex`
+ */
+ virtual SLANG_NO_THROW ProgramLayout* SLANG_MCALL getLayout(
+ SlangInt targetIndex = 0,
+ IBlob** outDiagnostics = nullptr) = 0;
+
+ /** Get the compiled code for the entry point at `entryPointIndex` for the chosen `targetIndex`
+
+ If code has not already been generated for the given entry point and target,
+ then a compilation error may be detected, in which case `outDiagnostics`
+ (if non-null) will be filled in with a blob of messages diagnosing the error.
+ */
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointCode(
+ SlangInt entryPointIndex,
+ SlangInt targetIndex,
+ IBlob** outCode,
+ IBlob** outDiagnostics = nullptr) = 0;
+ };
+
+ #define SLANG_UUID_IProgram { 0x5bc42be8, 0x5c50, 0x4929, { 0x9e, 0x5e, 0xd1, 0x5e, 0x7c, 0x24, 0x1, 0x5f } };
+}
+
+#define SLANG_API_VERSION 0
+
+SLANG_API SlangResult slang_createGlobalSession(
+ SlangInt apiVersion,
+ slang::IGlobalSession** outGlobalSession);
+
+namespace slang
+{
+ inline SlangResult createGlobalSession(
+ slang::IGlobalSession** outGlobalSession)
+ {
+ return slang_createGlobalSession(SLANG_API_VERSION, outGlobalSession);
+ }
}
+/**
+*/
+SLANG_API SlangResult spCompileRequest_getProgram(
+ SlangCompileRequest* request,
+ slang::IProgram** outProgram);
+
#endif
/* DEPRECATED DEFINITIONS
diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj
index 177cd2011..dd2f3c144 100644
--- a/source/core/core.vcxproj
+++ b/source/core/core.vcxproj
@@ -231,7 +231,9 @@
<ClCompile Include="windows\slang-win-visual-studio-util.cpp" />
</ItemGroup>
<ItemGroup>
- <None Include="core.natvis" />
+ <Natvis Include="core.natvis">
+ <FileType>Document</FileType>
+ </Natvis>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
diff --git a/source/core/slang-writer.h b/source/core/slang-writer.h
index 6e26d6750..cd5737b3d 100644
--- a/source/core/slang-writer.h
+++ b/source/core/slang-writer.h
@@ -45,7 +45,7 @@ public:
// ISlangUnknown
SLANG_REF_OBJECT_IUNKNOWN_QUERY_INTERFACE
SLANG_REF_OBJECT_IUNKNOWN_ADD_REF
- SLANG_NO_THROW uint32_t SLANG_MCALL release() { return (m_flags & WriterFlag::IsStatic) ? (uint32_t)decreaseReference() : (uint32_t)releaseReference(); }
+ SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return (m_flags & WriterFlag::IsStatic) ? (uint32_t)decreaseReference() : (uint32_t)releaseReference(); }
// ISlangWriter - default impl
SLANG_NO_THROW virtual void SLANG_MCALL flush() SLANG_OVERRIDE {}
diff --git a/source/slang/slang-check.cpp b/source/slang/slang-check.cpp
index 90947cf54..83b75b964 100644
--- a/source/slang/slang-check.cpp
+++ b/source/slang/slang-check.cpp
@@ -433,7 +433,7 @@ namespace Slang
Session* getSession()
{
- return m_linkage->getSession();
+ return m_linkage->getSessionImpl();
}
public:
@@ -9656,6 +9656,111 @@ namespace Slang
}
}
+static bool shouldUseFalcorCustomSharedKeywordSemantics(
+ EntryPointGroup* entryPointGroup)
+{
+ if( !entryPointGroup->getLinkageImpl()->m_useFalcorCustomSharedKeywordSemantics )
+ return false;
+
+ // As a sanity check, if we are being asked to lay out an
+ // empty entry-point group, then don't apply the convention.
+ //
+ if(entryPointGroup->getEntryPointCount() == 0)
+ return false;
+
+ // Otherwise we will look at the first entry point in the group,
+ // and use that to determine whether it looks like we are compiling
+ // ray-tracing shaders or not.
+ //
+ switch( entryPointGroup->getEntryPoint(0)->getStage() )
+ {
+ case Stage::AnyHit:
+ case Stage::Callable:
+ case Stage::ClosestHit:
+ case Stage::Intersection:
+ case Stage::Miss:
+ case Stage::RayGeneration:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+
+static bool shouldUseFalcorCustomSharedKeywordSemantics(
+ Program* program)
+{
+ if( !program->getLinkageImpl()->m_useFalcorCustomSharedKeywordSemantics )
+ return false;
+
+ // As a sanity check, if we are being asked to lay out a program
+ // with *no* entry points, then we don't apply the convention.
+ //
+ if(program->getEntryPointGroupCount() == 0)
+ return false;
+
+ // Otherwise we let the first entry-point group determine if we should
+ // apply the policy for the entire program.
+ //
+ // Note: this could lead to confusing results if a `Program` mixes
+ // entry point groups for RT and non-RT pipelines, but that isn't
+ // a scenario we expect to come up and this whole routine is handling
+ // "do what I mean" semantics for legacy behavior.
+ //
+ return shouldUseFalcorCustomSharedKeywordSemantics(program->getEntryPointGroup(0));
+}
+
+
+void EntryPointGroup::_collectShaderParams(DiagnosticSink* sink)
+{
+ // If and only if we are in the special mode for Falcor support
+ // where non-`shared` global shader parameters are actually
+ // supposed to go into the "local root signature," then we
+ // will consider such parameters as if they were entry-point
+ // parameters, attached to the group.
+ //
+ if( shouldUseFalcorCustomSharedKeywordSemantics(this) )
+ {
+ for( auto module : getModuleDependencies() )
+ {
+ auto moduleDecl = module->getModuleDecl();
+ for( auto globalVar : moduleDecl->getMembersOfType<VarDecl>() )
+ {
+ // Don't consider globals that aren't shader parameters.
+ //
+ if(!isGlobalShaderParameter(globalVar))
+ continue;
+
+ // Don't consider global shader paramters that were marked
+ // `shared`, since that is how global-root-signature parameters
+ // are being specified.
+ //
+ if( globalVar->HasModifier<HLSLEffectSharedModifier>() )
+ continue;
+
+ auto paramDeclRef = makeDeclRef(globalVar.Ptr());
+
+ ShaderParamInfo shaderParamInfo;
+ shaderParamInfo.paramDeclRef = paramDeclRef;
+
+ ExistentialTypeSlots slots;
+ _collectExistentialSlotsForShaderParam(
+ shaderParamInfo,
+ slots,
+ paramDeclRef);
+
+ if( slots.paramTypes.getCount() != 0 )
+ {
+ sink->diagnose(globalVar, Diagnostics::typeParametersNotAllowedOnEntryPointGlobal, globalVar);
+ }
+
+ m_shaderParams.add(shaderParamInfo);
+ }
+ }
+ }
+}
+
// Validate that an entry point function conforms to any additional
// constraints based on the stage (and profile?) it specifies.
void validateEntryPoint(
@@ -10334,9 +10439,6 @@ static bool doesParameterMatch(
return true;
}
-
-
-
/// Enumerate the existential-type parameters of a `Program`.
///
/// Any parameters found will be added to the list of existential slots on `this`.
@@ -10364,9 +10466,34 @@ static bool doesParameterMatch(
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;
+ // HACK: In order to support existing policy in the Falcor
+ // application, we support a custom mode where only
+ // global variables marked as `shared` should be considered
+ // as global shader parameters (that go in the "global
+ // root signature" for DXR).
+ //
+ // TODO: Eliminate this special case once all of the client
+ // application code has been ported to use more general-purpose
+ // Slang mechanisms (e.g., entry-point `uniform` parameters).
+ //
+ if( shouldUseFalcorCustomSharedKeywordSemantics(this) )
+ {
+ if( !globalVar->HasModifier<HLSLEffectSharedModifier>() )
+ {
+ // Skip a non-`shared` global for purposes of enumerating
+ // shader parameters.
+ //
+ 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`
@@ -10474,7 +10601,13 @@ static bool doesParameterMatch(
entryPointReq);
if( entryPoint )
{
- program->addEntryPoint(entryPoint);
+ // TODO: We need to implement an explicit policy
+ // for what should happen if the user specified
+ // entry points via the command-line (or API),
+ // but didn't specify any groups (since the current
+ // compilation API doesn't allow for grouping).
+ //
+ program->addEntryPoint(entryPoint, sink);
entryPointReq->getTranslationUnit()->entryPoints.add(entryPoint);
}
}
@@ -10540,7 +10673,17 @@ static bool doesParameterMatch(
validateEntryPoint(entryPoint, sink);
- program->addEntryPoint(entryPoint);
+ // Note: in the case that the user didn't explicitly
+ // specify entry points and we are instead compiling
+ // a shader "library," then we do not want to automatically
+ // combine the entry points into groups in the generated
+ // `Program`, since that would be slightly too magical.
+ //
+ // Instead, each entry point will end up in a singleton
+ // group, so that its entry-point parameters lay out
+ // independent of the others.
+ //
+ program->addEntryPoint(entryPoint, sink);
translationUnit->entryPoints.add(entryPoint);
}
}
@@ -10636,7 +10779,7 @@ static bool doesParameterMatch(
// generic application like `F<A,B,C>` if it were
// encountered in the source code.
- auto session = linkage->getSession();
+ auto session = linkage->getSessionImpl();
auto genericDeclRef = makeDeclRef(genericDecl);
// The first pieces is a `VarExpr` that refers to `genericDecl`.
@@ -10760,7 +10903,7 @@ static bool doesParameterMatch(
List<RefPtr<Expr>> const& args,
DiagnosticSink* sink)
{
- Slang::_specializeExistentialTypeParams(getLinkage(), m_globalExistentialSlots, args, sink);
+ Slang::_specializeExistentialTypeParams(getLinkageImpl(), m_globalExistentialSlots, args, sink);
}
Type* Linkage::specializeType(
@@ -10799,14 +10942,34 @@ static bool doesParameterMatch(
return specializedType;
}
- /// Specialize a program to global generic arguments
- RefPtr<Program> createSpecializedProgram(
+ // Shared implementation logic for the `_createSpecializedProgram*` entry points.
+ static RefPtr<Program> _createSpecializedProgramImpl(
Linkage* linkage,
Program* unspecializedProgram,
List<RefPtr<Expr>> const& globalGenericArgs,
List<RefPtr<Expr>> const& globalExistentialArgs,
DiagnosticSink* sink)
{
+ // TODO: If there are no specialization arguments,
+ // then the the result of specialization should
+ // be the same as the input... *but* we are promising
+ // to return a program without any entry points,
+ // and that screws things up here.
+ //
+ // For now we just carefully avod this early-exit
+ // if we have any entry points.
+ //
+ // Eventually we should try to revise the model so
+ // that specialization of a program that includes
+ // entry points can make some kind of sense.
+ //
+ if( globalGenericArgs.getCount() == 0
+ && globalExistentialArgs.getCount() == 0
+ && unspecializedProgram->getEntryPointCount() == 0)
+ {
+ return unspecializedProgram;
+ }
+
// The given `unspecializedProgram` should be one that
// was checked through the front-end, so that now we
// only need to check if the given arguments can satisfy
@@ -10967,6 +11130,37 @@ static bool doesParameterMatch(
specializedProgram->setGlobalGenericSubsitution(globalGenericSubsts);
+ return specializedProgram;
+ }
+
+ /// Create a specialized copy of `unspecializedProgram`.
+ ///
+ /// The specialized program will include the entry points
+ /// from the original program (whether thsoe entry points
+ /// are specialized or not).
+ ///
+ static RefPtr<Program> _createSpecializedProgram(
+ Linkage* linkage,
+ Program* unspecializedProgram,
+ List<RefPtr<Expr>> const& globalGenericArgs,
+ List<RefPtr<Expr>> const& globalExistentialArgs,
+ DiagnosticSink* sink)
+ {
+ auto specializedProgram = _createSpecializedProgramImpl(
+ linkage,
+ unspecializedProgram,
+ globalGenericArgs,
+ globalExistentialArgs,
+ sink);
+
+ // We need to ensure that the specialized program has whatever
+ // entry points (and groups) the unspecialized one had.
+ //
+ for( auto entryPointGroup : unspecializedProgram->getEntryPointGroups() )
+ {
+ specializedProgram->addEntryPointGroup(entryPointGroup);
+ }
+
// Now deal with the shader parameters and existential arguments
//
// Note: We should in theory be able to just copy over the shader
@@ -10981,6 +11175,61 @@ static bool doesParameterMatch(
return specializedProgram;
}
+ SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::specializeProgram(
+ slang::IProgram* inUnspecializedProgram,
+ SlangInt specializationArgCount,
+ slang::SpecializationArg const* specializationArgs,
+ slang::IProgram** outSpecializedProgram,
+ ISlangBlob** outDiagnostics)
+ {
+ auto unspecializedProgram = asInternal(inUnspecializedProgram);
+
+ if( specializationArgCount == 0 )
+ {
+ *outSpecializedProgram = ComPtr<slang::IProgram>(asExternal(unspecializedProgram)).detach();
+ return SLANG_OK;
+ }
+
+ List<RefPtr<Expr>> globalGenericArgs;
+
+ List<RefPtr<Expr>> globalExistentialArgs;
+ for( Int ii = 0; ii < specializationArgCount; ++ii )
+ {
+ auto& specializationArg = specializationArgs[ii];
+ switch( specializationArg.kind )
+ {
+ case slang::SpecializationArg::Kind::Type:
+ {
+ auto typeArg = asInternal(specializationArg.type);
+ RefPtr<SharedTypeExpr> argExpr = new SharedTypeExpr();
+ argExpr->base = TypeExp(typeArg);
+ argExpr->type = QualType(getTypeType(typeArg));
+
+ globalExistentialArgs.add(argExpr);
+ }
+ break;
+
+ default:
+ return SLANG_E_INVALID_ARG;
+ }
+ }
+
+ DiagnosticSink sink(getSourceManager());
+ auto specializedProgram = _createSpecializedProgram(
+ this,
+ unspecializedProgram,
+ globalGenericArgs,
+ globalExistentialArgs,
+ &sink);
+ sink.getBlobIfNeeded(outDiagnostics);
+
+ if(!specializedProgram)
+ return SLANG_FAIL;
+
+ *outSpecializedProgram = ComPtr<slang::IProgram>(asExternal(specializedProgram)).detach();
+ return SLANG_OK;
+ }
+
/// Specialize an entry point that was checked by the front-end, based on generic arguments.
///
/// If the end-to-end compile request included generic argument strings
@@ -11036,6 +11285,7 @@ static bool doesParameterMatch(
// global or entry-point generic parameters.
//
auto unspecializedProgram = endToEndReq->getUnspecializedProgram();
+ auto linkage = endToEndReq->getLinkage();
// First, let's parse the generic argument strings that were
// provided via the API, so taht we can match them
@@ -11058,12 +11308,13 @@ static bool doesParameterMatch(
// applying the global generic arguments (if any) to the
// unspecialized program.
//
- auto specializedProgram = createSpecializedProgram(
+ auto sink = endToEndReq->getSink();
+ auto specializedProgram = _createSpecializedProgramImpl(
endToEndReq->getLinkage(),
unspecializedProgram,
globalGenericArgs,
globalExistentialArgs,
- endToEndReq->getSink());
+ sink);
// If anything went wrong with the global generic
// arguments, then bail out now.
@@ -11090,15 +11341,30 @@ static bool doesParameterMatch(
endToEndReq->entryPoints.setCount(entryPointCount);
}
- for( Index ii = 0; ii < entryPointCount; ++ii )
+ Index entryPointCounter = 0;
+
+ for( auto unspecializedEntryPointGroup : unspecializedProgram->getEntryPointGroups() )
{
- auto unspecializedEntryPoint = unspecializedProgram->getEntryPoint(ii);
- auto& entryPointInfo = endToEndReq->entryPoints[ii];
+ List<RefPtr<EntryPoint>> specializedEntryPoints;
+ for( auto unspecializedEntryPoint : unspecializedEntryPointGroup->getEntryPoints() )
+ {
+ Index entryPointIndex = entryPointCounter++;
+ auto& entryPointInfo = endToEndReq->entryPoints[entryPointIndex];
+
+ auto specializedEntryPoint = createSpecializedEntryPoint(endToEndReq, unspecializedEntryPoint, entryPointInfo);
+ specializedEntryPoints.add(specializedEntryPoint);
+ }
- auto specializedEntryPoint = createSpecializedEntryPoint(endToEndReq, unspecializedEntryPoint, entryPointInfo);
- specializedProgram->addEntryPoint(specializedEntryPoint);
+ RefPtr<EntryPointGroup> specializedEntryPointGroup = EntryPointGroup::create(linkage, specializedEntryPoints, endToEndReq->getSink());
+ specializedProgram->addEntryPointGroup(specializedEntryPointGroup);
}
+ // Finalize the information for the specialized program,
+ // now that we have computed its entry point list, etc.
+ //
+ specializedProgram->_collectShaderParams(sink);
+ specializedProgram->_specializeExistentialTypeParams(globalExistentialArgs, sink);
+
return specializedProgram;
}
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 99caed8f0..ff2facc26 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -293,6 +293,31 @@ namespace Slang
}
//
+ // EntryPointGroup
+ //
+
+ RefPtr<EntryPointGroup> EntryPointGroup::create(
+ Linkage* linkage,
+ List<RefPtr<EntryPoint>> const& entryPoints,
+ DiagnosticSink* sink)
+ {
+ RefPtr<EntryPointGroup> group = new EntryPointGroup(linkage);
+
+ for( auto entryPoint : entryPoints )
+ {
+ for( auto module : entryPoint->getModuleDependencies() )
+ {
+ group->m_dependencyList.addDependency(module);
+ }
+ group->m_entryPoints.add(entryPoint);
+ }
+
+ group->_collectShaderParams(sink);
+
+ return group;
+ }
+
+ //
Profile Profile::LookUp(char const* name)
{
@@ -1481,6 +1506,58 @@ SlangResult dissassembleDXILUsingDXC(
writeEntryPointResultToStandardOutput(compileRequest, entryPoint, targetReq, result);
}
+ CompileResult& TargetProgram::_createEntryPointResult(
+ Int entryPointIndex,
+ BackEndCompileRequest* backEndRequest,
+ EndToEndCompileRequest* endToEndRequest)
+ {
+ // It is possible that entry points goot added to the `Program`
+ // *after* we created this `TargetProgram`, so there might be
+ // a request for an entry point that we didn't allocate space for.
+ //
+ // TODO: Change the construction logic so that a `Program` is
+ // constructed all at once rather than incrementally, to avoid
+ // this problem.
+ //
+ if(entryPointIndex >= m_entryPointResults.getCount())
+ m_entryPointResults.setCount(entryPointIndex+1);
+
+ auto entryPoint = m_program->getEntryPoint(entryPointIndex);
+
+ auto& result = m_entryPointResults[entryPointIndex];
+ result = emitEntryPoint(
+ backEndRequest,
+ entryPoint,
+ entryPointIndex,
+ m_targetReq,
+ endToEndRequest);
+
+ return result;
+
+ }
+
+ CompileResult& TargetProgram::getOrCreateEntryPointResult(
+ Int entryPointIndex,
+ DiagnosticSink* sink)
+ {
+ if(entryPointIndex >= m_entryPointResults.getCount())
+ m_entryPointResults.setCount(entryPointIndex+1);
+
+ auto& result = m_entryPointResults[entryPointIndex];
+ if( result.format != ResultFormat::None )
+ return result;
+
+ RefPtr<BackEndCompileRequest> backEndRequest = new BackEndCompileRequest(
+ m_program->getLinkageImpl(),
+ sink,
+ m_program);
+
+ return _createEntryPointResult(
+ entryPointIndex,
+ backEndRequest,
+ nullptr);
+ }
+
void generateOutputForTarget(
BackEndCompileRequest* compileReq,
TargetRequest* targetReq,
@@ -1494,17 +1571,15 @@ SlangResult dissassembleDXILUsingDXC(
auto entryPointCount = program->getEntryPointCount();
for(Index ii = 0; ii < entryPointCount; ++ii)
{
- auto entryPoint = program->getEntryPoint(ii);
- CompileResult entryPointResult = emitEntryPoint(
- compileReq,
- entryPoint,
+ targetProgram->_createEntryPointResult(
ii,
- targetReq,
+ compileReq,
endToEndReq);
- targetProgram->setEntryPointResult(ii, entryPointResult);
}
}
+
+
static void _generateOutput(
BackEndCompileRequest* compileRequest,
EndToEndCompileRequest* endToEndReq)
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 86c6272a9..2b2c35845 100644
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -366,6 +366,55 @@ namespace Slang
ModuleDependencyList m_dependencyList;
};
+ class EntryPointGroup : public RefObject
+ {
+ public:
+ static RefPtr<EntryPointGroup> create(
+ Linkage* linkage,
+ List<RefPtr<EntryPoint>> const& entryPoints,
+ DiagnosticSink* sink);
+
+ Linkage* getLinkageImpl() { return m_linkage; }
+
+ /// Get the number of entry points in the group
+ Index getEntryPointCount() { return m_entryPoints.getCount(); }
+
+ /// Get the entry point at the given `index`.
+ RefPtr<EntryPoint> getEntryPoint(Index index) { return m_entryPoints[index]; }
+
+ /// Get the full ist of entry points in the group.
+ List<RefPtr<EntryPoint>> const& getEntryPoints() { return m_entryPoints; }
+
+ /// Get a list of modules that this entry point group depends on.
+ ///
+ /// This will include the dependencies of all of the entry points in the group.
+ ///
+ List<RefPtr<Module>> getModuleDependencies() { return m_dependencyList.getModuleList(); }
+
+ /// Get an array of all entry-point-group shader parameters.
+ List<ShaderParamInfo> const& getShaderParams() { return m_shaderParams; }
+
+ private:
+ EntryPointGroup(Linkage* linkage)
+ : m_linkage(linkage)
+ {}
+
+ void _collectShaderParams(DiagnosticSink* sink);
+
+ Linkage* m_linkage;
+ List<RefPtr<EntryPoint>> m_entryPoints;
+
+ /// Information about shader parameters to be associated with the entry-point group itself.
+ ///
+ /// This list captures parameters that logically belong to the group itself, rather than
+ /// to any specific entry point in the group.
+ ///
+ List<ShaderParamInfo> m_shaderParams;
+
+ /// Modules the entry point group depends on.
+ ModuleDependencyList m_dependencyList;
+ };
+
enum class PassThroughMode : SlangPassThrough
{
None = SLANG_PASS_THROUGH_NONE, // don't pass through: use Slang compiler
@@ -382,9 +431,13 @@ namespace Slang
/// may span multiple Slang source files), and provides access
/// to both the AST and IR representations of that code.
///
- class Module : public RefObject
+ class Module : public RefObject, public slang::IModule
{
public:
+ SLANG_REF_OBJECT_IUNKNOWN_ALL
+
+ ISlangUnknown* getInterface(const Guid& guid);
+
/// Create a module (initially empty).
Module(Linkage* linkage);
@@ -525,6 +578,8 @@ namespace Slang
Dictionary<Type*, RefPtr<TypeLayout>> typeLayouts;
Dictionary<Type*, RefPtr<TypeLayout>>& getTypeLayouts() { return typeLayouts; }
+
+ TypeLayout* getTypeLayout(Type* type);
};
/// Are we generating code for a D3D API?
@@ -576,14 +631,54 @@ namespace Slang
ComPtr<ISlangBlob> createRawBlob(void const* data, size_t size);
/// A context for loading and re-using code modules.
- class Linkage : public RefObject
+ class Linkage : public RefObject, public slang::ISession
{
public:
+ SLANG_REF_OBJECT_IUNKNOWN_ALL
+
+ ISlangUnknown* getInterface(const Guid& guid);
+
+ SLANG_NO_THROW slang::IGlobalSession* SLANG_MCALL getGlobalSession() override;
+ SLANG_NO_THROW slang::IModule* SLANG_MCALL loadModule(
+ const char* moduleName,
+ slang::IBlob** outDiagnostics = nullptr) override;
+ SLANG_NO_THROW SlangResult SLANG_MCALL createProgram(
+ slang::ProgramDesc const& desc,
+ slang::IProgram** outProgram) override;
+ SLANG_NO_THROW SlangResult SLANG_MCALL specializeProgram(
+ slang::IProgram* program,
+ SlangInt specializationArgCount,
+ slang::SpecializationArg const* specializationArgs,
+ slang::IProgram** outSpecializedProgram,
+ ISlangBlob** outDiagnostics = nullptr) override;
+ SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL specializeType(
+ slang::TypeReflection* type,
+ slang::SpecializationArg const* specializationArgs,
+ SlangInt specializationArgCount,
+ ISlangBlob** outDiagnostics = nullptr) override;
+ SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL getTypeLayout(
+ slang::TypeReflection* type,
+ SlangInt targetIndex = 0,
+ slang::LayoutRules rules = slang::LayoutRules::Default,
+ ISlangBlob** outDiagnostics = nullptr) override;
+ SLANG_NO_THROW SlangResult SLANG_MCALL createCompileRequest(
+ SlangCompileRequest** outCompileRequest) override;
+
+ void addTarget(
+ slang::TargetDesc const& desc);
+ SlangResult addSearchPath(
+ char const* path);
+ SlangResult addPreprocessorDefine(
+ char const* name,
+ char const* value);
+ SlangResult setMatrixLayoutMode(
+ SlangMatrixLayoutMode mode);
+
/// Create an initially-empty linkage
Linkage(Session* session);
/// Get the parent session for this linkage
- Session* getSession() { return m_session; }
+ Session* getSessionImpl() { return m_session; }
// Information on the targets we are being asked to
// generate code for.
@@ -703,6 +798,8 @@ namespace Slang
OptimizationLevel optimizationLevel = OptimizationLevel::Default;
+ bool m_useFalcorCustomSharedKeywordSemantics = false;
+
private:
Session* m_session = nullptr;
@@ -887,9 +984,25 @@ namespace Slang
/// to be used togehter so that, e.g., layout can make sure to allocate
/// space for the global shader parameters in all referenced modules.
///
- class Program : public RefObject
+ class Program : public RefObject, public slang::IProgram
{
public:
+ SLANG_REF_OBJECT_IUNKNOWN_ALL;
+ ISlangUnknown* getInterface(Guid const& guid);
+
+ SLANG_NO_THROW slang::ISession* SLANG_MCALL getSession() override;
+
+ SLANG_NO_THROW slang::ProgramLayout* SLANG_MCALL getLayout(
+ SlangInt targetIndex,
+ slang::IBlob** outDiagnostics) override;
+
+ SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointCode(
+ SlangInt entryPointIndex,
+ SlangInt targetIndex,
+ slang::IBlob** outCode,
+ slang::IBlob** outDiagnostics) override;
+
+
/// Create a new program, initially empty.
///
/// All code loaded into the program must come
@@ -898,7 +1011,7 @@ namespace Slang
Linkage* linkage);
/// Get the linkage that this program uses.
- Linkage* getLinkage() { return m_linkage; }
+ Linkage* getLinkageImpl() { return m_linkage; }
/// Get the number of entry points added to the program
Index getEntryPointCount() { return m_entryPoints.getCount(); }
@@ -909,6 +1022,12 @@ namespace Slang
/// Get the full ist of entry points on the program.
List<RefPtr<EntryPoint>> const& getEntryPoints() { return m_entryPoints; }
+
+ Index getEntryPointGroupCount() { return m_entryPointGroups.getCount(); }
+ RefPtr<EntryPointGroup> getEntryPointGroup(Index index) { return m_entryPointGroups[index]; }
+ List<RefPtr<EntryPointGroup>> const& getEntryPointGroups() { return m_entryPointGroups; }
+
+
/// Get the substitution (if any) that represents how global generics are specialized.
RefPtr<Substitutions> getGlobalGenericSubstitution() { return m_globalGenericSubst; }
@@ -936,7 +1055,13 @@ namespace Slang
///
/// This also adds everything the entry point depends on to the list of references.
///
- void addEntryPoint(EntryPoint* entryPoint);
+ void addEntryPoint(EntryPoint* entryPoint, DiagnosticSink* sink);
+
+ /// Add an entry point group to the program
+ ///
+ /// This also adds everything the entry point group depends on to the list of references.
+ ///
+ void addEntryPointGroup(EntryPointGroup* entryPointGroup);
/// Set the global generic argument substitution to use.
void setGlobalGenericSubsitution(RefPtr<Substitutions> subst)
@@ -1011,6 +1136,9 @@ namespace Slang
// Entry points that are part of the program.
List<RefPtr<EntryPoint> > m_entryPoints;
+ // Entry points that are part of the program.
+ List<RefPtr<EntryPointGroup> > m_entryPointGroups;
+
// Specializations for global generic parameters (if any)
RefPtr<Substitutions> m_globalGenericSubst;
@@ -1065,23 +1193,34 @@ namespace Slang
/// Get the compiled code for an entry point on the target.
///
- /// This routine assumes code generation has already been
- /// performed and called `setEntryPointResult`.
+ /// If this is the first time that code generation has
+ /// been requested, report any errors that arise during
+ /// code generation to the given `sink`.
+ ///
+ CompileResult& getOrCreateEntryPointResult(Int entryPointIndex, DiagnosticSink* sink);
+
+ /// Get the compiled code for an entry point on the target.
+ ///
+ /// This routine assumes that `getOrCreateEntryPointResult`
+ /// has already been called previously.
///
CompileResult& getExistingEntryPointResult(Int entryPointIndex)
{
return m_entryPointResults[entryPointIndex];
}
- // TODO: Need a lazy `getOrCreateEntryPointResult`
- /// Set the compiled code for an entry point.
+ /// Internal helper for `getOrCreateEntryPointResult`.
///
- /// Should only be called by code generation.
- void setEntryPointResult(Int entryPointIndex, CompileResult const& result)
- {
- m_entryPointResults[entryPointIndex] = result;
- }
+ /// This is used so that command-line and API-based
+ /// requests for code can bottleneck through the same place.
+ ///
+ /// Shouldn't be called directly by most code.
+ ///
+ CompileResult& _createEntryPointResult(
+ Int entryPointIndex,
+ BackEndCompileRequest* backEndRequest,
+ EndToEndCompileRequest* endToEndRequest);
private:
// The program being compiled or laid out
@@ -1143,6 +1282,9 @@ namespace Slang
EndToEndCompileRequest(
Session* session);
+ EndToEndCompileRequest(
+ Linkage* linkage);
+
// What container format are we being asked to generate?
//
// Note: This field is unused except by the options-parsing
@@ -1224,6 +1366,8 @@ namespace Slang
Program* getSpecializedProgram() { return m_specializedProgram; }
private:
+ void init();
+
Session* m_session = nullptr;
RefPtr<Linkage> m_linkage;
DiagnosticSink m_sink;
@@ -1277,9 +1421,24 @@ namespace Slang
struct TypeCheckingCache;
//
- class Session
+ class Session : public RefObject, public slang::IGlobalSession
{
public:
+ SLANG_REF_OBJECT_IUNKNOWN_ALL
+
+ ISlangUnknown* getInterface(const Guid& guid);
+
+ /** Create a new linkage.
+ */
+ SLANG_NO_THROW SlangResult SLANG_MCALL createSession(
+ slang::SessionDesc const& desc,
+ slang::ISession** outSession) override;
+
+ SLANG_NO_THROW SlangProfileID SLANG_MCALL findProfile(
+ char const* name) override;
+
+
+
enum class SharedLibraryFuncType
{
Glslang_Compile,
@@ -1421,6 +1580,76 @@ namespace Slang
RefPtr<Linkage> m_builtinLinkage;
};
+
+//
+// The following functions are utilties to convert between
+// matching "external" (public API) and "internal" (implementation)
+// types. They are favored over explicit casts because they
+// help avoid making incorrect conversions (e.g., when using
+// `reinterpret_cast` or C-style casts), and because they
+// abstract over the conversion required for each pair of types.
+//
+
+inline slang::IGlobalSession* asExternal(Session* session)
+{
+ return static_cast<slang::IGlobalSession*>(session);
+}
+
+inline slang::ISession* asExternal(Linkage* linkage)
+{
+ return static_cast<slang::ISession*>(linkage);
+}
+
+inline Module* asInternal(slang::IModule* module)
+{
+ return static_cast<Module*>(module);
+}
+
+inline slang::IModule* asExternal(Module* module)
+{
+ return static_cast<slang::IModule*>(module);
+}
+
+inline Program* asInternal(slang::IProgram* module)
+{
+ return static_cast<Program*>(module);
+}
+
+inline slang::IProgram* asExternal(Program* module)
+{
+ return static_cast<slang::IProgram*>(module);
+}
+
+static inline slang::ProgramLayout* asExternal(ProgramLayout* programLayout)
+{
+ return (slang::ProgramLayout*) programLayout;
+}
+
+inline Type* asInternal(slang::TypeReflection* type)
+{
+ return reinterpret_cast<Type*>(type);
+}
+
+inline slang::TypeReflection* asExternal(Type* type)
+{
+ return reinterpret_cast<slang::TypeReflection*>(type);
+}
+
+inline TypeLayout* asInternal(slang::TypeLayoutReflection* type)
+{
+ return reinterpret_cast<TypeLayout*>(type);
+}
+
+inline slang::TypeLayoutReflection* asExternal(TypeLayout* type)
+{
+ return reinterpret_cast<slang::TypeLayoutReflection*>(type);
+}
+
+inline SlangCompileRequest* asExternal(EndToEndCompileRequest* request)
+{
+ return reinterpret_cast<SlangCompileRequest*>(request);
+}
+
}
#endif
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index ce4131173..fc9cac3f3 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -409,6 +409,8 @@ DIAGNOSTIC(39016, Error, globalUniformsNotSupported, "'$0' is implicitly a globa
DIAGNOSTIC(39017, Error, tooManyShaderRecordConstantBuffers, "can have at most one 'shader record' attributed constant buffer; found $0.")
+DIAGNOSTIC(39018, Error, typeParametersNotAllowedOnEntryPointGlobal, "local-root-signature shader parameter '$0' at global scope must not include existential/interface types");
+
//
// 4xxxx - IL code generation.
//
diff --git a/source/slang/slang-diagnostics.h b/source/slang/slang-diagnostics.h
index e1b9846d7..3d75c577d 100644
--- a/source/slang/slang-diagnostics.h
+++ b/source/slang/slang-diagnostics.h
@@ -143,7 +143,11 @@ namespace Slang
class DiagnosticSink
{
- public:
+ public:
+ DiagnosticSink(SourceManager* sourceManager)
+ : sourceManager(sourceManager)
+ {}
+
struct Flag
{
enum Enum: uint32_t
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index 623c57f2b..aa56bc0b2 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -48,29 +48,37 @@ enum class BuiltInCOp
//
EntryPointLayout* findEntryPointLayout(
- ProgramLayout* programLayout,
- EntryPoint* entryPoint)
+ ProgramLayout* programLayout,
+ EntryPoint* entryPoint,
+ EntryPointGroupLayout** outEntryPointGroupLayout = nullptr)
{
- for( auto entryPointLayout : programLayout->entryPoints )
+ for( auto entryPointGroupLayout : programLayout->entryPointGroups )
{
- if(entryPointLayout->entryPoint->getName() != entryPoint->getName())
- continue;
-
- // TODO: We need to be careful about this check, since it relies on
- // the profile information in the layout matching that in the request.
- //
- // What we really seem to want here is some dictionary mapping the
- // `EntryPoint` directly to the `EntryPointLayout`, and maybe
- // that is precisely what we should build...
- //
- if(entryPointLayout->profile != entryPoint->getProfile())
- continue;
-
- // TODO: can't easily filter on translation unit here...
- // Ideally the `EntryPoint` should get filled in with a pointer
- // the specific function declaration that represents the entry point.
-
- return entryPointLayout.Ptr();
+ for( auto entryPointLayout : entryPointGroupLayout->entryPoints )
+ {
+ if(entryPointLayout->entryPoint->getName() != entryPoint->getName())
+ continue;
+
+ // TODO: We need to be careful about this check, since it relies on
+ // the profile information in the layout matching that in the request.
+ //
+ // What we really seem to want here is some dictionary mapping the
+ // `EntryPoint` directly to the `EntryPointLayout`, and maybe
+ // that is precisely what we should build...
+ //
+ if(entryPointLayout->profile != entryPoint->getProfile())
+ continue;
+
+ // TODO: can't easily filter on translation unit here...
+ // Ideally the `EntryPoint` should get filled in with a pointer
+ // the specific function declaration that represents the entry point.
+
+ if( outEntryPointGroupLayout )
+ {
+ *outEntryPointGroupLayout = entryPointGroupLayout;
+ }
+ return entryPointLayout;
+ }
}
return nullptr;
diff --git a/source/slang/slang-file-system.h b/source/slang/slang-file-system.h
index e89bf45db..1d747d73f 100644
--- a/source/slang/slang-file-system.h
+++ b/source/slang/slang-file-system.h
@@ -48,7 +48,7 @@ public:
const char* path,
ISlangBlob** outCanonicalPath) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW void SLANG_MCALL clearCache() {}
+ virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE {}
/// Get a default instance
static ISlangFileSystemExt* getSingleton() { return &s_singleton; }
@@ -132,9 +132,9 @@ class CacheFileSystem: public ISlangFileSystemExt, public RefObject
virtual SLANG_NO_THROW SlangResult SLANG_MCALL getCanonicalPath(
const char* path,
- ISlangBlob** outCanonicalPath);
+ ISlangBlob** outCanonicalPath) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW void SLANG_MCALL clearCache();
+ virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE;
/// Ctor
CacheFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode = UniqueIdentityMode::Default, PathStyle pathStyle = PathStyle::Default);
diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp
index 4c1f72adb..07135c148 100644
--- a/source/slang/slang-ir-link.cpp
+++ b/source/slang/slang-ir-link.cpp
@@ -13,8 +13,9 @@ namespace Slang
// TODO: maybe arrange so that codegen is driven from the layout layer
// instead of the input/request layer.
EntryPointLayout* findEntryPointLayout(
- ProgramLayout* programLayout,
- EntryPoint* EntryPoint);
+ ProgramLayout* programLayout,
+ EntryPoint* entryPoint,
+ EntryPointGroupLayout** outEntryPointGroupLayout);
struct IRSpecSymbol : RefObject
{
@@ -783,9 +784,12 @@ IRFunc* specializeIRForEntryPoint(
if( paramIndex < paramLayoutCount )
{
auto paramLayout = paramsStructLayout->fields[paramIndex];
+
+ auto offsetParamLayout = applyOffsetToVarLayout(paramLayout, entryPointLayout->parametersLayout);
+
context->builder->addLayoutDecoration(
pp,
- paramLayout);
+ offsetParamLayout);
}
else
{
@@ -1276,6 +1280,33 @@ LinkedIR linkIR(
context->globalVarLayouts.AddIfNotExists(mangledName, globalVarLayout);
}
+ EntryPointGroupLayout* entryPointGroupLayout = nullptr;
+ auto entryPointLayout = findEntryPointLayout(programLayout, entryPoint, &entryPointGroupLayout);
+
+ auto offsetEntryPointLayout = entryPointLayout->getAbsoluteLayout(entryPointGroupLayout);
+
+ // Note: when we are doing the compatibility approach for Falcor, we
+ // can have global-scope symbols that are actually part of the
+ // local root signature (entry point group), so we need to make
+ // sure to apply those layouts appropriately.
+ auto entryPointGroupStructLayout = getScopeStructLayout(entryPointGroupLayout);
+ for(auto entry : entryPointGroupStructLayout->mapVarToLayout)
+ {
+ if(!entry.Key)
+ continue;
+
+ auto mangledName = getMangledName(entry.Key);
+ auto groupVarLayout = entry.Value;
+
+ // We need to "adjust" the layout that was computed for the parameter
+ // because it will be relative to the start of the entry-point group,
+ // rather than absolute.
+ //
+ auto absoluteVarLayout = groupVarLayout->getAbsoluteLayout(entryPointGroupLayout->parametersLayout);
+
+ context->globalVarLayouts.AddIfNotExists(mangledName, absoluteVarLayout);
+ }
+
context->builder->setInsertInto(context->getModule()->getModuleInst());
// for now, clone all unreferenced witness tables
@@ -1289,13 +1320,12 @@ LinkedIR linkIR(
cloneGlobalValue(context, (IRWitnessTable*)sym.Value->irGlobalValue);
}
- auto entryPointLayout = findEntryPointLayout(programLayout, entryPoint);
// Next, we make sure to clone the global value for
// the entry point function itself, and rely on
// this step to recursively copy over anything else
// it might reference.
- auto irEntryPoint = specializeIRForEntryPoint(context, entryPoint, entryPointLayout);
+ auto irEntryPoint = specializeIRForEntryPoint(context, entryPoint, offsetEntryPointLayout);
// HACK: right now the bindings for global generic parameters are coming in
// as part of the original IR module, and we need to make sure these get
diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp
index 5c4fd24b5..d5efc3515 100644
--- a/source/slang/slang-parameter-binding.cpp
+++ b/source/slang/slang-parameter-binding.cpp
@@ -377,6 +377,7 @@ struct SharedParameterBindingContext
TargetRequest* getTargetRequest() { return targetRequest; }
DiagnosticSink* getSink() { return m_sink; }
+ Linkage* getLinkage() { return targetRequest->getLinkage(); }
};
static DiagnosticSink* getSink(SharedParameterBindingContext* shared)
@@ -403,6 +404,8 @@ struct ParameterBindingContext
TargetRequest* getTargetRequest() { return shared->getTargetRequest(); }
LayoutRulesFamilyImpl* getRulesFamily() { return layoutContext.getRulesFamily(); }
+
+ Linkage* getLinkage() { return shared->getLinkage(); }
};
static DiagnosticSink* getSink(ParameterBindingContext* context)
@@ -610,7 +613,7 @@ RefPtr<TypeLayout> getTypeLayoutForGlobalShaderParameter(
auto layoutContext = context->layoutContext;
auto rules = layoutContext.getRulesFamily();
- if( varDecl->HasModifier<ShaderRecordAttribute>() && as<ConstantBufferType>(type) )
+ if(varDecl->HasModifier<ShaderRecordAttribute>() && as<ConstantBufferType>(type))
{
return createTypeLayout(
layoutContext.with(rules->getShaderRecordConstantBufferRules()),
@@ -620,13 +623,20 @@ RefPtr<TypeLayout> getTypeLayoutForGlobalShaderParameter(
// We want to check for a constant-buffer type with a `push_constant` layout
// qualifier before we move on to anything else.
- if (varDecl->HasModifier<PushConstantAttribute>() && as<ConstantBufferType>(type))
+ if( varDecl->HasModifier<PushConstantAttribute>() && as<ConstantBufferType>(type) )
{
return createTypeLayout(
layoutContext.with(rules->getPushConstantBufferRules()),
type);
}
+ // TODO: The cases below for detecting globals that aren't actually
+ // shader parameters should be redundant now that the semantic
+ // checking logic is responsible for populating the list of
+ // parameters on a `Program`. We should be able to clean up
+ // the code by removing these two cases, and the related null
+ // pointer checks in the code that calls this.
+
// HLSL `static` modifier indicates "thread local"
if(varDecl->HasModifier<HLSLStaticModifier>())
return nullptr;
@@ -1940,6 +1950,45 @@ struct ScopeLayoutBuilder
_addParameter(firstVarLayout, parameterInfo);
}
+
+ // Add a "simple" parameter that cannot have any user-defined
+ // register or binding modifiers, so that its layout computation
+ // can be simplified greatly.
+ //
+ void addSimpleParameter(
+ RefPtr<VarLayout> varLayout)
+ {
+ // The main `addParameter` logic will deal with any ordinary/uniform data,
+ // and with the "pending" part of the layout.
+ //
+ addParameter(varLayout);
+
+ // That leaves us to deal with the resource usage that isn't
+ // handled by `addParameter`.
+ //
+ auto paramTypeLayout = varLayout->getTypeLayout();
+ for (auto paramTypeResInfo : paramTypeLayout->resourceInfos)
+ {
+ // We need to skip ordinary/uniform data because it was
+ // handled by `addParameter`.
+ //
+ if(paramTypeResInfo.kind == LayoutResourceKind::Uniform)
+ continue;
+
+ // Whatever resources the parameter uses, we need to
+ // assign the parameter's location/register/binding offset to
+ // be the sum of everything added so far.
+ //
+ auto scopeResInfo = m_structLayout->findOrAddResourceInfo(paramTypeResInfo.kind);
+ varLayout->findOrAddResourceInfo(paramTypeResInfo.kind)->index = scopeResInfo->count.getFiniteValue();
+
+ // We then need to add the resources consumed by the parameter
+ // to those consumed by the scope.
+ //
+ scopeResInfo->count += paramTypeResInfo.count;
+ }
+ }
+
RefPtr<VarLayout> endLayout()
{
// Finish computing the layout for the ordindary data (if any).
@@ -2007,7 +2056,7 @@ static ParameterBindingAndKindInfo maybeAllocateConstantBufferBinding(
/// Iterate over the parameters of an entry point to compute its requirements.
///
-static void collectEntryPointParameters(
+static RefPtr<EntryPointLayout> collectEntryPointParameters(
ParameterBindingContext* context,
EntryPoint* entryPoint,
SubstitutionSet typeSubst)
@@ -2119,35 +2168,7 @@ static void collectEntryPointParameters(
// we need to add its resource usage to that of the entry
// point as a whole.
//
- // Any "ordinary" data (e.g., a `float4x4`) needs to be accounted
- // for using the `ScopeLayoutBuilder`, since it will handle
- // the details of target-specific `struct` type layout.
- //
- scopeBuilder.addParameter(paramVarLayout);
-
- // All of the other resources types will be handled in a
- // simpler loop that just increments the relevant counters.
- //
- for (auto paramTypeResInfo : paramTypeLayout->resourceInfos)
- {
- // We need to skip ordinary data because it is being
- // handled by the `scopeBuilder`.
- //
- if(paramTypeResInfo.kind == LayoutResourceKind::Uniform)
- continue;
-
- // Whatever resources the parameter uses, we need to
- // assign the parameter's location/register/binding offset to
- // be the sum of everything added so far.
- //
- auto entryPointResInfo = paramsStructLayout->findOrAddResourceInfo(paramTypeResInfo.kind);
- paramVarLayout->findOrAddResourceInfo(paramTypeResInfo.kind)->index = entryPointResInfo->count.getFiniteValue();
-
- // We then need to add the resources consumed by the parameter
- // to those consumed by the entry point.
- //
- entryPointResInfo->count += paramTypeResInfo.count;
- }
+ scopeBuilder.addSimpleParameter(paramVarLayout);
}
entryPointLayout->parametersLayout = scopeBuilder.endLayout();
@@ -2189,6 +2210,25 @@ static void collectEntryPointParameters(
entryPointLayout->resultLayout = resultLayout;
}
+
+ return entryPointLayout;
+}
+
+ /// Remove resource usage from `typeLayout` that should only be stored per-entry-point.
+ ///
+ /// This is used when constructing the layout for an entry point group, to make sure
+ /// that certain kinds of resource usage from the entry point don't "leak" into
+ /// the resource usage of the group.
+ ///
+static void removePerEntryPointParameterKinds(
+ TypeLayout* typeLayout)
+{
+ typeLayout->removeResourceUsage(LayoutResourceKind::VaryingInput);
+ typeLayout->removeResourceUsage(LayoutResourceKind::VaryingOutput);
+ typeLayout->removeResourceUsage(LayoutResourceKind::ShaderRecord);
+ typeLayout->removeResourceUsage(LayoutResourceKind::HitAttributes);
+ typeLayout->removeResourceUsage(LayoutResourceKind::ExistentialObjectParam);
+ typeLayout->removeResourceUsage(LayoutResourceKind::ExistentialTypeParam);
}
static void collectParameters(
@@ -2242,10 +2282,66 @@ static void collectParameters(
}
// Next consider parameters for entry points
- for(auto entryPoint : program->getEntryPoints())
+ for( auto entryPointGroup : program->getEntryPointGroups() )
{
- context->stage = entryPoint->getStage();
- collectEntryPointParameters(context, entryPoint, globalGenericSubst);
+ RefPtr<EntryPointGroupLayout> entryPointGroupLayout = new EntryPointGroupLayout();
+ entryPointGroupLayout->group = entryPointGroup;
+
+ context->shared->programLayout->entryPointGroups.add(entryPointGroupLayout);
+
+
+ ScopeLayoutBuilder scopeBuilder;
+ scopeBuilder.beginLayout(context);
+ auto entryPointGroupParamsStructLayout = scopeBuilder.m_structLayout;
+
+ // First lay out any shader parameters that belong to the group
+ // itself, rather than to its nested entry points.
+ //
+ // This ensures that looking up one of the parameters of the
+ // group by index in its parameters truct will Just Work.
+ //
+ for( auto groupParam : entryPointGroup->getShaderParams() )
+ {
+ auto paramDeclRef = groupParam.paramDeclRef;
+ auto paramType = GetType(paramDeclRef);
+
+ RefPtr<VarLayout> paramVarLayout = new VarLayout();
+ paramVarLayout->varDecl = paramDeclRef;
+
+ auto paramTypeLayout = createTypeLayout(
+ context->layoutContext.with(context->getRulesFamily()->getConstantBufferRules()),
+ paramType);
+ paramVarLayout->typeLayout = paramTypeLayout;
+
+ scopeBuilder.addSimpleParameter(paramVarLayout);
+ }
+
+ for(auto entryPoint : entryPointGroup->getEntryPoints())
+ {
+ // Note: we do not want the entry point group to accumulate
+ // locations for varying input/output parameters: those
+ // should be specific to each entry point.
+ //
+ // We address this issue by manually removing any
+ // layout information for the relevant resource kinds
+ // from the group's layout before adding the parameters
+ // of any entry point for layout.
+ //
+ removePerEntryPointParameterKinds(scopeBuilder.m_structLayout);
+
+ context->stage = entryPoint->getStage();
+ auto entryPointLayout = collectEntryPointParameters(context, entryPoint, globalGenericSubst);
+
+ auto entryPointParamsLayout = entryPointLayout->parametersLayout;
+ auto entryPointParamsTypeLayout = entryPointParamsLayout->typeLayout;
+
+ scopeBuilder.addSimpleParameter(entryPointParamsLayout);
+
+ entryPointGroupLayout->entryPoints.add(entryPointLayout);
+ }
+ removePerEntryPointParameterKinds(scopeBuilder.m_structLayout);
+
+ entryPointGroupLayout->parametersLayout = scopeBuilder.endLayout();
}
context->entryPointLayout = nullptr;
}
@@ -2452,44 +2548,6 @@ RefPtr<ProgramLayout> generateParameterBindings(
completeBindingsForParameter(&context, parameter);
}
- // After we have allocated registers/bindings to everything
- // in the global scope we will process the parameters
- // of each entry point in order.
- //
- // Note: the effect of the current implementation is to
- // allocate non-overlapping registers/bindings between all
- // the entry points in the compile request (e.g., if you
- // have a vertex and fragment shader being compiled together,
- // we will allocate distinct constant buffer registers for
- // their uniform parameters).
- //
- // TODO: We probably need to provide some more nuanced control
- // over whether entry points get overlapping or non-overlapping
- // bindings. It seems clear that if we were compiling multiple
- // compute kernels in one invocation we'd want them to get
- // overlapping bindings, because we cannot ever have them bound
- // together in a single pipeline state.
- //
- // Similarly, entry point parameters of DirectX Raytracing (DXR)
- // shaders should probably be allowed to overlap by default,
- // since those parameters should really go into the "local root signature."
- // (Note: there is a bit more subtlety around ray tracing
- // shaders that will be assembled into a "hit group")
- //
- // For now we are just doing the simplest thing, which will be
- // appropriate for:
- //
- // * Compiling a single compute shader in a compile request.
- // * Compiling some number of rasterization shader entry points
- // in a single request, to be used together.
- // * Compiling a single ray-tracing shader in a compile request.
- //
- for( auto entryPoint : sharedContext.programLayout->entryPoints )
- {
- auto entryPointParamsLayout = entryPoint->parametersLayout;
- completeBindingsForParameter(&context, entryPointParamsLayout);
- }
-
// Next we need to create a type layout to reflect the information
// we have collected, and we will use the `ScopeLayoutBuilder`
// to encapsulate the logic that can be shared with the entry-point
@@ -2510,17 +2568,75 @@ RefPtr<ProgramLayout> generateParameterBindings(
cbInfo->index = globalConstantBufferBinding.index;
}
- // After we have laid out all the ordinary parameters,
- // we need to go through the global scope plus each entry point,
- // and "flush" out any pending data that was associated with
- // those scopes as part of dealing with interface-type parameters.
+ // After we have laid out all the ordinary global parameters,
+ // we need to "flush" out any pending data that was associated with
+ // the global scope as part of dealing with interface-type parameters.
//
_allocateBindingsForPendingData(&context, globalScopeVarLayout->pendingVarLayout);
- for( auto entryPoint : sharedContext.programLayout->entryPoints )
+
+ // After we have allocated registers/bindings to everything
+ // in the global scope we will process the parameters
+ // of the entry points.
+ //
+ // Note: at the moment we are laying out *all* information related to global-scope
+ // parameters (including pending data from interface-type parameters) before
+ // anything pertaining to entry points. This is a crucial design choice to
+ // get right, and we might want to revisit it based on experience.
+
+ // In some cases, a user will want to ensure that all the
+ // entry points they compile get non-overlapping
+ // registers/bindings. E.g., if you have a vertex and fragment
+ // shader being compiled together for Vulkan, you probably want distinct
+ // bindings for their entry-point `uniform` parametres, so
+ // that they can be used together.
+ //
+ // In other cases, however, a user probably doesn't want us
+ // to conservatively allocate non-overlapping bindings.
+ // E.g., if they have a bunch of compute shaders in a single
+ // file, then they probably want each compute shader to
+ // compute its parameter layout "from scratch" as if the
+ // others don't exist.
+ //
+ // The way we handle this is by putting the entry points of a
+ // `Program` into groups, and ensuring that within each group
+ // we allocate parameters that don't overlap, but we don't
+ // worry about overlap across groups.
+ //
+ for( auto entryPointGroup : sharedContext.programLayout->entryPointGroups )
{
- _allocateBindingsForPendingData(&context, entryPoint->parametersLayout->pendingVarLayout);
- }
+ // We save off the allocation state as it was before the entry-point
+ // group, so that we can restore it to this state after each group.
+ //
+ // TODO: We probably ought to wrap all the state relevant to allocation
+ // of registers/bindings into a single struct/field so that we only
+ // have one thing to save/restore here even if new state gets added.
+ //
+ auto savedGlobalSpaceUsedRangeSets = sharedContext.globalSpaceUsedRangeSets;
+ auto savedUsedSpaces = sharedContext.usedSpaces;
+
+ // The group will have been allocated a layout that combines the
+ // usage of all of the contained entry-points, so we just need to
+ // allocate the entry-point group to be placed after all the global-scope
+ // parameters.
+ //
+ auto entryPointGroupParamsLayout = entryPointGroup->parametersLayout;
+ completeBindingsForParameter(&context, entryPointGroupParamsLayout);
+
+ _allocateBindingsForPendingData(&context, entryPointGroupParamsLayout->pendingVarLayout);
+
+ // TODO: Should we add the offset information from the group to
+ // the layout information for each entry point (and thence to its parameters)?
+ //
+ // This seems important if we want to allow clients to conveniently
+ // ignore groups when doing their reflection queries.
+ // Once we've allocated bindigns for the parameters of entry points
+ // in the group, we restore the state for tracking what register/bindings
+ // are used to where it was before.
+ //
+ sharedContext.globalSpaceUsedRangeSets = savedGlobalSpaceUsedRangeSets;
+ sharedContext.usedSpaces = savedUsedSpaces;
+ }
// HACK: we want global parameters to not have to deal with offsetting
// by the `VarLayout` stored in `globalScopeVarLayout`, so we will scan
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index aff1d832d..fffbf2c62 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -1709,8 +1709,7 @@ namespace Slang
TokenSpan tokenSpan;
tokenSpan.mBegin = parser->tokenReader.mCursor;
tokenSpan.mEnd = parser->tokenReader.mEnd;
- DiagnosticSink newSink;
- newSink.sourceManager = parser->sink->sourceManager;
+ DiagnosticSink newSink(parser->sink->sourceManager);
Parser newParser(*parser);
newParser.sink = &newSink;
auto speculateParseRs = parseGenericApp(&newParser, base);
diff --git a/source/slang/slang-reflection.cpp b/source/slang/slang-reflection.cpp
index c5428cdeb..3871e2ccc 100644
--- a/source/slang/slang-reflection.cpp
+++ b/source/slang/slang-reflection.cpp
@@ -86,6 +86,15 @@ static inline SlangReflectionEntryPoint* convert(EntryPointLayout* entryPoint)
return (SlangReflectionEntryPoint*) entryPoint;
}
+static inline EntryPointGroupLayout* convert(SlangEntryPointGroupLayout* entryPointGroup)
+{
+ return (EntryPointGroupLayout*) entryPointGroup;
+}
+
+static inline SlangEntryPointGroupLayout* convert(EntryPointGroupLayout* entryPointGroup)
+{
+ return (SlangEntryPointGroupLayout*) entryPointGroup;
+}
static inline ProgramLayout* convert(SlangReflection* program)
{
@@ -596,9 +605,9 @@ SLANG_API SlangReflectionType * spReflection_FindTypeByName(SlangReflection * re
// TODO: We should extend this API to support getting error messages
// when type lookup fails.
//
- Slang::DiagnosticSink sink;
-
- sink.sourceManager = programLayout->getTargetReq()->getLinkage()->getSourceManager();;
+ Slang::DiagnosticSink sink(
+ programLayout->getTargetReq()->getLinkage()->getSourceManager());
+
RefPtr<Type> result = program->getTypeFromString(name, &sink);
return (SlangReflectionType*)result.Ptr();
}
@@ -611,13 +620,9 @@ SLANG_API SlangReflectionTypeLayout* spReflection_GetTypeLayout(
auto context = convert(reflection);
auto type = convert(inType);
auto targetReq = context->getTargetReq();
- auto layoutContext = getInitialLayoutContextForTarget(targetReq, context);
- RefPtr<TypeLayout> result;
- if (targetReq->getTypeLayouts().TryGetValue(type, result))
- return (SlangReflectionTypeLayout*)result.Ptr();
- result = createTypeLayout(layoutContext, type);
- targetReq->getTypeLayouts()[type] = result;
- return (SlangReflectionTypeLayout*)result.Ptr();
+
+ auto typeLayout = targetReq->getTypeLayout(type);
+ return convert(typeLayout);
}
SLANG_API SlangReflectionType* spReflectionType_GetResourceResultType(SlangReflectionType* inType)
@@ -1071,11 +1076,32 @@ SLANG_API size_t spReflectionVariableLayout_GetSpace(SlangReflectionVariableLayo
space += info->space;
}
- // Next, deal with any dedicated register-space offset applied to, e.g., a parameter block
- if (auto spaceInfo = varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace))
- {
- space += spaceInfo->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
+ // to be right in some cases.
+ //
+ // Imageine if we have:
+ //
+ // struct X { Texture2D y; }
+ // struct S { Texture2D t; ParmaeterBlock<X> x; }
+ //
+ // Texture2D gA;
+ // S gS;
+ //
+ // We expect `gS` to have an offset for `LayoutResourceKind::ShaderResourceView`
+ // of one (since its texture must come after `gA`), and an offset for
+ // `LayoutResourceKind::RegisterSpace` of one (since the default space will be
+ // space zero). It would be incorrect for us to imply that `gS.t` should
+ // be `t1, space1`, though, because the space offset of `gS` doesn't actually
+ // apply to `t`.
+ //
+ // For now we are punting on this issue and leaving it in the hands of the
+ // application to determine when a space offset from an "outer" variable should
+ // apply to the locations of things in an "inner" variable.
+ //
+ // There is no policy we can apply locally in this function that
+ // will Just Work, so the best we can do is try to not lie.
return space;
}
@@ -1392,7 +1418,7 @@ SLANG_API SlangReflectionEntryPoint* spReflection_findEntryPointByName(SlangRefl
auto program = convert(inProgram);
if(!program) return 0;
- // TODO: improve on dumb linear search
+ // TODO: improve on naive linear search
for(auto ep : program->entryPoints)
{
if(ep->entryPoint->getName()->text == name)
@@ -1405,6 +1431,74 @@ SLANG_API SlangReflectionEntryPoint* spReflection_findEntryPointByName(SlangRefl
}
+SLANG_API SlangInt spReflection_getEntryPointGroupCount(SlangReflection* inProgram)
+{
+ auto program = convert(inProgram);
+ if(!program) return 0;
+
+ return program->entryPointGroups.getCount();
+}
+
+SLANG_API SlangEntryPointGroupLayout* spReflection_getEntryPointGroupByIndex(SlangReflection* inProgram, SlangInt index)
+{
+ auto program = convert(inProgram);
+ if(!program) return 0;
+
+ if(index < 0) return nullptr;
+ if(index >= program->entryPointGroups.getCount()) return nullptr;
+
+ return convert(program->entryPointGroups[(int) index].Ptr());
+}
+
+SLANG_API SlangInt spEntryPointGroupLayout_getEntryPointCount(SlangEntryPointGroupLayout* inGroup)
+{
+ auto group = convert(inGroup);
+ if(!group) return 0;
+
+ return group->entryPoints.getCount();
+}
+
+SLANG_API SlangReflectionEntryPoint* spEntryPointGroupLayout_getEntryPointByIndex(SlangEntryPointGroupLayout* inGroup, SlangInt index)
+{
+ auto group = convert(inGroup);
+ if(!group) return 0;
+
+ if(index < 0) return nullptr;
+ if(index >= group->entryPoints.getCount()) return nullptr;
+
+ return convert(group->entryPoints[(int) index].Ptr());
+}
+
+SLANG_API SlangReflectionVariableLayout* spEntryPointGroupLayout_getVarLayout(SlangEntryPointGroupLayout* inGroup)
+{
+ auto group = convert(inGroup);
+ if(!group) return 0;
+
+ return convert(group->parametersLayout);
+}
+
+SLANG_API SlangInt spEntryPointGroupLayout_getParameterCount(SlangEntryPointGroupLayout* inGroup)
+{
+ auto groupLayout = convert(inGroup);
+ if(!groupLayout) return 0;
+
+ auto& params = groupLayout->group->getShaderParams();
+ return params.getCount();
+}
+
+SLANG_API SlangReflectionVariableLayout* spEntryPointGroupLayout_getParameterByIndex(SlangEntryPointGroupLayout* inGroup, SlangInt index)
+{
+ auto groupLayout = convert(inGroup);
+ if(!groupLayout) return nullptr;
+
+ auto& params = groupLayout->group->getShaderParams();
+ if(index < 0) return nullptr;
+ if(index >= params.getCount()) return nullptr;
+
+ return convert(getScopeStructLayout(groupLayout)->fields[index]);
+}
+
+
SLANG_API SlangUInt spReflection_getGlobalConstantBufferBinding(SlangReflection* inProgram)
{
auto program = convert(inProgram);
@@ -1437,10 +1531,9 @@ SLANG_API SlangReflectionType* spReflection_specializeType(
auto unspecializedType = convert(inType);
if(!unspecializedType) return nullptr;
- auto linkage = programLayout->getProgram()->getLinkage();
+ auto linkage = programLayout->getProgram()->getLinkageImpl();
- DiagnosticSink sink;
- sink.sourceManager = linkage->getSourceManager();
+ DiagnosticSink sink(linkage->getSourceManager());
auto specializedType = linkage->specializeType(unspecializedType, specializationArgCount, (Type* const*) specializationArgs, &sink);
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index 30ab53ca6..c3dbb4966 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -1165,6 +1165,83 @@ RefPtr<TypeLayout> applyOffsetToTypeLayout(
return newTypeLayout;
}
+RefPtr<VarLayout> applyOffsetToVarLayout(
+ VarLayout* baseLayout,
+ VarLayout* offsetLayout)
+{
+ RefPtr<VarLayout> adjustedLayout = new VarLayout();
+ adjustedLayout->typeLayout = baseLayout->typeLayout;
+ adjustedLayout->varDecl = baseLayout->varDecl;
+ adjustedLayout->flags = baseLayout->flags;
+ adjustedLayout->semanticName = baseLayout->semanticName;
+ adjustedLayout->semanticIndex = baseLayout->semanticIndex;
+ adjustedLayout->systemValueSemantic = baseLayout->systemValueSemantic;
+ adjustedLayout->systemValueSemanticIndex = baseLayout->systemValueSemanticIndex;
+ adjustedLayout->stage = baseLayout->stage;
+
+ if( auto basePendingLayout = baseLayout->pendingVarLayout )
+ {
+ if( auto offsetPendingLayout = offsetLayout->pendingVarLayout )
+ {
+ adjustedLayout->pendingVarLayout = applyOffsetToVarLayout(
+ basePendingLayout,
+ offsetPendingLayout);
+ }
+ }
+
+ for( auto baseResInfo : baseLayout->resourceInfos )
+ {
+ auto adjustedResInfo = baseResInfo;
+ if( auto offsetResInfo = offsetLayout->FindResourceInfo(baseResInfo.kind) )
+ {
+ adjustedResInfo.index += offsetResInfo->index;
+ adjustedResInfo.space += offsetResInfo->space;
+ }
+ adjustedLayout->resourceInfos.add(adjustedResInfo);
+ }
+
+ return adjustedLayout;
+}
+
+EntryPointLayout* EntryPointLayout::getAbsoluteLayout(
+ VarLayout* parentLayout)
+{
+ SLANG_ASSERT(parentLayout);
+
+ if(m_absoluteLayout)
+ return m_absoluteLayout;
+
+ RefPtr<EntryPointLayout> adjustedLayout = new EntryPointLayout();
+ adjustedLayout->entryPoint = this->entryPoint;
+ adjustedLayout->flags = this->flags;
+ adjustedLayout->parametersLayout = this->parametersLayout->getAbsoluteLayout(parentLayout);
+ adjustedLayout->profile = this->profile;
+ if( auto baseResultLayout = this->resultLayout )
+ {
+ adjustedLayout->resultLayout = baseResultLayout->getAbsoluteLayout(parentLayout);
+ }
+ adjustedLayout->taggedUnionTypeLayouts = this->taggedUnionTypeLayouts;
+
+ m_absoluteLayout = adjustedLayout;
+ return adjustedLayout;
+}
+
+EntryPointLayout* EntryPointLayout::getAbsoluteLayout(EntryPointGroupLayout* parentGroup)
+{
+ SLANG_ASSERT(parentGroup);
+ return getAbsoluteLayout(parentGroup->parametersLayout);
+}
+
+
+VarLayout* VarLayout::getAbsoluteLayout(VarLayout* parentAbsoluteLayout)
+{
+ if( !m_absoluteLayout )
+ {
+ m_absoluteLayout = applyOffsetToVarLayout(this, parentAbsoluteLayout);
+ }
+ return m_absoluteLayout;
+}
+
static bool _usesResourceKind(RefPtr<TypeLayout> typeLayout, LayoutResourceKind kind)
{
auto resInfo = typeLayout->FindResourceInfo(kind);
@@ -3180,6 +3257,20 @@ RefPtr<TypeLayout> createTypeLayout(
return _createTypeLayout(context, type).layout;
}
+void TypeLayout::removeResourceUsage(LayoutResourceKind kind)
+{
+ Int infoCount = resourceInfos.getCount();
+ for( Int ii = 0; ii < infoCount; ++ii )
+ {
+ if( resourceInfos[ii].kind == kind )
+ {
+ resourceInfos.removeAt(ii);
+ return;
+ }
+ }
+}
+
+
void TypeLayout::addResourceUsageFrom(TypeLayout* otherTypeLayout)
{
for(auto resInfo : otherTypeLayout->resourceInfos)
diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h
index 97113c77f..e066c2700 100644
--- a/source/slang/slang-type-layout.h
+++ b/source/slang/slang-type-layout.h
@@ -377,6 +377,8 @@ public:
addResourceUsage(info);
}
+ void removeResourceUsage(LayoutResourceKind kind);
+
void addResourceUsageFrom(TypeLayout* otherTypeLayout);
/// "Unwrap" any layers of array-ness from this type layout.
@@ -473,6 +475,21 @@ public:
}
RefPtr<VarLayout> pendingVarLayout;
+
+
+ /// Get the "absolute" layout of this variable, if applicable.
+ ///
+ /// The `parentAbsoluteLayout` must be the absolute layout
+ /// of the parent of this variable.
+ ///
+ /// The absolute layout will be created once and cached on
+ /// future accesses; if `parentAbsoluteLayout` is not
+ /// consistent at different call sites an unexpected
+ /// layout could be returned.
+ ///
+ VarLayout* getAbsoluteLayout(VarLayout* parentAbsoluteLayout);
+
+ RefPtr<VarLayout> m_absoluteLayout;
};
// type layout for a variable that has a constant-buffer type
@@ -650,6 +667,8 @@ public:
StructTypeLayout* getScopeStructLayout(
ScopeLayout* programLayout);
+class EntryPointGroupLayout;
+
// Layout information for a single shader entry point
// within a program
//
@@ -682,6 +701,18 @@ public:
/// These are any tagged union types used by the generic
/// arguments that this entry point is being compiled with.
List<RefPtr<TypeLayout>> taggedUnionTypeLayouts;
+
+ EntryPointLayout* getAbsoluteLayout(VarLayout* parentLayout);
+ EntryPointLayout* getAbsoluteLayout(EntryPointGroupLayout* parentGroup);
+
+ RefPtr<EntryPointLayout> m_absoluteLayout;
+};
+
+class EntryPointGroupLayout : public ScopeLayout
+{
+public:
+ RefPtr<EntryPointGroup> group;
+ List<RefPtr<EntryPointLayout>> entryPoints;
};
class GenericParamLayout : public Layout
@@ -725,6 +756,10 @@ public:
// will (eventually) belong there...
List<RefPtr<EntryPointLayout>> entryPoints;
+ // Entry points can also be grouped for layout purposes (e.g., to form
+ // ray-tracing hit groups), so this array represents those groups
+ List<RefPtr<EntryPointGroupLayout>> entryPointGroups;
+
List<RefPtr<GenericParamLayout>> globalGenericParams;
Dictionary<String, GenericParamLayout*> globalGenericParamsMap;
};
@@ -1113,6 +1148,11 @@ RefPtr<TypeLayout> applyOffsetToTypeLayout(
RefPtr<TypeLayout> oldTypeLayout,
RefPtr<VarLayout> offsetVarLayout);
+ /// Create a layout like `baseLayout`, but offset by `offsetLayout`
+RefPtr<VarLayout> applyOffsetToVarLayout(
+ VarLayout* baseLayout,
+ VarLayout* offsetLayout);
+
}
#endif
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index a3875ef62..b18e4d4d9 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -33,6 +33,12 @@
namespace Slang {
+// Allocate static const storage for the various interface IDs that the Slang API needs to expose
+static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown;
+static const Guid IID_ISlangBlob = SLANG_UUID_ISlangBlob;
+static const Guid IID_ISession = SLANG_UUID_ISession;
+static const Guid IID_IGlobalSession = SLANG_UUID_IGlobalSession;
+static const Guid IID_IModule = SLANG_UUID_IModule;
Session::Session()
{
@@ -91,6 +97,55 @@ Session::Session()
addBuiltinSource(hlslLanguageScope, "hlsl", getHLSLLibraryCode());
}
+ISlangUnknown* Session::getInterface(const Guid& guid)
+{
+ if(guid == IID_ISlangUnknown || guid == IID_IGlobalSession)
+ return asExternal(this);
+ return nullptr;
+}
+
+SLANG_NO_THROW SlangResult SLANG_MCALL Session::createSession(
+ slang::SessionDesc const& desc,
+ slang::ISession** outSession)
+{
+ RefPtr<Linkage> linkage = new Linkage(this);
+
+ Int targetCount = desc.targetCount;
+ for(Int ii = 0; ii < targetCount; ++ii)
+ {
+ linkage->addTarget(desc.targets[ii]);
+ }
+
+ if(desc.flags & slang::kSessionFlag_FalcorCustomSharedKeywordSemantics)
+ {
+ linkage->m_useFalcorCustomSharedKeywordSemantics = true;
+ }
+
+ linkage->setMatrixLayoutMode(desc.defaultMatrixLayoutMode);
+
+ Int searchPathCount = desc.searchPathCount;
+ for(Int ii = 0; ii < searchPathCount; ++ii)
+ {
+ linkage->addSearchPath(desc.searchPaths[ii]);
+ }
+
+ Int macroCount = desc.preprocessorMacroCount;
+ for(Int ii = 0; ii < macroCount; ++ii)
+ {
+ auto& macro = desc.preprocessorMacros[ii];
+ linkage->addPreprocessorDefine(macro.name, macro.value);
+ }
+
+ *outSession = asExternal(linkage.detach());
+ return SLANG_OK;
+}
+
+SLANG_NO_THROW SlangProfileID SLANG_MCALL Session::findProfile(
+ char const* name)
+{
+ return Slang::Profile::LookUp(name).raw;
+}
+
struct IncludeHandlerImpl : IncludeHandler
{
Linkage* linkage;
@@ -330,9 +385,183 @@ Linkage::Linkage(Session* session)
setFileSystem(nullptr);
}
-// Allocate static const storage for the various interface IDs that the Slang API needs to expose
-static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown;
-static const Guid IID_ISlangBlob = SLANG_UUID_ISlangBlob;
+ISlangUnknown* Linkage::getInterface(const Guid& guid)
+{
+ if(guid == IID_ISlangUnknown || guid == IID_ISession)
+ return asExternal(this);
+
+ return nullptr;
+}
+
+SLANG_NO_THROW slang::IGlobalSession* SLANG_MCALL Linkage::getGlobalSession()
+{
+ return asExternal(getSessionImpl());
+}
+
+void Linkage::addTarget(
+ slang::TargetDesc const& desc)
+{
+ auto targetIndex = addTarget(CodeGenTarget(desc.format));
+ auto target = targets[targetIndex];
+
+ target->floatingPointMode = FloatingPointMode(desc.floatingPointMode);
+ target->targetFlags = desc.flags;
+ target->targetProfile = Profile(desc.profile);
+}
+
+#if 0
+SLANG_NO_THROW SlangInt SLANG_MCALL Linkage::getTargetCount()
+{
+ return targets.getCount();
+}
+
+SLANG_NO_THROW slang::ITarget* SLANG_MCALL Linkage::getTargetByIndex(SlangInt index)
+{
+ if(index < 0) return nullptr;
+ if(index >= targets.getCount()) return nullptr;
+ return asExternal(targets[index]);
+}
+#endif
+
+SLANG_NO_THROW slang::IModule* SLANG_MCALL Linkage::loadModule(
+ const char* moduleName,
+ slang::IBlob** outDiagnostics)
+{
+ auto name = getNamePool()->getName(moduleName);
+
+ DiagnosticSink sink(getSourceManager());
+ auto module = findOrImportModule(name, SourceLoc(), &sink);
+ sink.getBlobIfNeeded(outDiagnostics);
+
+ return asExternal(module);
+}
+
+SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::createProgram(
+ slang::ProgramDesc const& desc,
+ slang::IProgram** outProgram)
+{
+ RefPtr<Program> program = new Program(this);
+
+ auto itemCount = desc.itemCount;
+ for(SlangInt ii = 0; ii < itemCount; ++ii)
+ {
+ auto& item = desc.items[ii];
+ switch(item.kind)
+ {
+ case slang::ProgramDesc::Item::Kind::Program:
+ {
+ Program* existingProgram = asInternal(item.program);
+ for(auto referencedModule : existingProgram->getModuleDependencies())
+ {
+ program->addReferencedLeafModule(referencedModule);
+ }
+
+ // TODO: Need to decide whether to include the entry points as well...
+ }
+ break;
+
+ case slang::ProgramDesc::Item::Kind::Module:
+ {
+ Module* module = asInternal(item.module);
+ program->addReferencedModule(module);
+ }
+ break;
+
+ default:
+ return SLANG_E_INVALID_ARG;
+ }
+ }
+
+ *outProgram = asExternal(program.detach());
+ return SLANG_OK;
+}
+
+SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::specializeType(
+ slang::TypeReflection* inUnspecializedType,
+ slang::SpecializationArg const* specializationArgs,
+ SlangInt specializationArgCount,
+ ISlangBlob** outDiagnostics)
+{
+ auto unspecializedType = asInternal(inUnspecializedType);
+
+ List<Type*> typeArgs;
+
+ for(Int ii = 0; ii < specializationArgCount; ++ii)
+ {
+ auto& arg = specializationArgs[ii];
+ if(arg.kind != slang::SpecializationArg::Kind::Type)
+ return nullptr;
+
+ typeArgs.add(asInternal(arg.type));
+ }
+
+ DiagnosticSink sink(getSourceManager());
+ auto specializedType = specializeType(unspecializedType, typeArgs.getCount(), typeArgs.getBuffer(), &sink);
+ sink.getBlobIfNeeded(outDiagnostics);
+
+ return asExternal(specializedType);
+}
+
+SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL Linkage::getTypeLayout(
+ slang::TypeReflection* inType,
+ SlangInt targetIndex,
+ slang::LayoutRules rules,
+ ISlangBlob** outDiagnostics)
+{
+ auto type = asInternal(inType);
+
+ if(targetIndex < 0 || targetIndex >= targets.getCount())
+ return nullptr;
+
+ auto target = targets[targetIndex];
+
+ // TODO: We need a way to pass through the layout rules
+ // that the user requested (e.g., constant buffers vs.
+ // structured buffer rules). Right now the API only
+ // exposes a single case, so this isn't a big deal.
+ //
+ SLANG_UNUSED(rules);
+
+ auto typeLayout = target->getTypeLayout(type);
+
+ // TODO: We currently don't have a path for capturing
+ // errors that occur during layout (e.g., types that
+ // are invalid because of target-specific layout constraints).
+ //
+ SLANG_UNUSED(outDiagnostics);
+
+ return asExternal(typeLayout);
+}
+
+SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::createCompileRequest(
+ SlangCompileRequest** outCompileRequest)
+{
+ auto compileRequest = new EndToEndCompileRequest(this);
+ *outCompileRequest = asExternal(compileRequest);
+ return SLANG_OK;
+}
+
+SlangResult Linkage::addSearchPath(
+ char const* path)
+{
+ searchDirectories.searchDirectories.add(Slang::SearchDirectory(path));
+ return SLANG_OK;
+}
+
+SlangResult Linkage::addPreprocessorDefine(
+ char const* name,
+ char const* value)
+{
+ preprocessorDefinitions[name] = value;
+ return SLANG_OK;
+}
+
+SlangResult Linkage::setMatrixLayoutMode(
+ SlangMatrixLayoutMode mode)
+{
+ defaultMatrixLayoutMode = MatrixLayoutMode(mode);
+ return SLANG_OK;
+}
/** Base class for simple blobs.
*/
@@ -386,7 +615,7 @@ ComPtr<ISlangBlob> createRawBlob(void const* inData, size_t size)
Session* TargetRequest::getSession()
{
- return linkage->getSession();
+ return linkage->getSessionImpl();
}
MatrixLayoutMode TargetRequest::getDefaultMatrixLayoutMode()
@@ -394,6 +623,29 @@ MatrixLayoutMode TargetRequest::getDefaultMatrixLayoutMode()
return linkage->getDefaultMatrixLayoutMode();
}
+TypeLayout* TargetRequest::getTypeLayout(Type* type)
+{
+ // TODO: We are not passing in a `ProgramLayout` here, although one
+ // is nominally required to establish the global ordering of
+ // generic type parameters, which might be referenced from field types.
+ //
+ // The solution here is to make sure that the reflection data for
+ // uses of global generic/existential types does *not* include any
+ // kind of index in that global ordering, and just refers to the
+ // parameter instead (leaving the user to figure out how that
+ // maps to the ordering via some API on the program layout).
+ //
+ auto layoutContext = getInitialLayoutContextForTarget(this, nullptr);
+
+ RefPtr<TypeLayout> result;
+ if (getTypeLayouts().TryGetValue(type, result))
+ return result.Ptr();
+ result = createTypeLayout(layoutContext, type);
+ getTypeLayouts()[type] = result;
+ return result.Ptr();
+}
+
+
//
// TranslationUnitRequest
//
@@ -485,8 +737,7 @@ RefPtr<Expr> Linkage::parseTypeString(String typeStr, RefPtr<Scope> scope)
Slang::SourceFile* srcFile = localSourceManager.createSourceFileWithString(PathInfo::makeTypeParse(), typeStr);
// We'll use a temporary diagnostic sink
- DiagnosticSink sink;
- sink.sourceManager = &localSourceManager;
+ DiagnosticSink sink(&localSourceManager);
// RAII type to make make sure current SourceManager is restored after parse.
// Use RAII - to make sure everything is reset even if an exception is thrown.
@@ -521,7 +772,7 @@ RefPtr<Expr> Linkage::parseTypeString(String typeStr, RefPtr<Scope> scope)
nullptr);
return parseTypeFromSourceFile(
- getSession(),
+ getSessionImpl(),
tokens, &sink, scope, getNamePool(), SourceLanguage::Slang);
}
@@ -552,7 +803,7 @@ Type* Program::getTypeFromString(String typeStr, DiagnosticSink* sink)
for(auto module : getModuleDependencies())
scopesToTry.add(module->getModuleDecl()->scope);
- auto linkage = getLinkage();
+ auto linkage = getLinkageImpl();
for(auto& s : scopesToTry)
{
RefPtr<Expr> typeExpr = linkage->parseTypeString(
@@ -785,13 +1036,15 @@ SlangResult FrontEndCompileRequest::executeActionsInner()
if (getSink()->GetErrorCount() != 0)
return SLANG_FAIL;
- if ((compileFlags & SLANG_COMPILE_FLAG_NO_CODEGEN) == 0)
- {
- // Generate initial IR for all the translation
- // units, if we are in a mode where IR is called for.
- generateIR();
- }
-
+ // We always generate IR for all the translation units.
+ //
+ // TODO: We may eventually have a mode where we skip
+ // IR codegen and only produce an AST (e.g., for use when
+ // debugging problems in the parser or semantic checking),
+ // but for now there are no cases where not having IR
+ // makes sense.
+ //
+ generateIR();
if (getSink()->GetErrorCount() != 0)
return SLANG_FAIL;
@@ -819,9 +1072,23 @@ BackEndCompileRequest::BackEndCompileRequest(
EndToEndCompileRequest::EndToEndCompileRequest(
Session* session)
: m_session(session)
+ , m_sink(nullptr)
{
m_linkage = new Linkage(session);
+ init();
+}
+EndToEndCompileRequest::EndToEndCompileRequest(
+ Linkage* linkage)
+ : m_session(linkage->getSessionImpl())
+ , m_linkage(linkage)
+ , m_sink(nullptr)
+{
+ init();
+}
+
+void EndToEndCompileRequest::init()
+{
m_sink.sourceManager = m_linkage->getSourceManager();
// Set all the default writers
@@ -919,7 +1186,7 @@ SlangResult EndToEndCompileRequest::executeActionsInner()
entryPointReq->getName(),
entryPointReq->getProfile());
- specializedProgram->addEntryPoint(entryPoint);
+ specializedProgram->addEntryPoint(entryPoint, getSink());
}
}
@@ -1353,6 +1620,12 @@ Module::Module(Linkage* linkage)
: m_linkage(linkage)
{}
+ISlangUnknown* Module::getInterface(const Guid& guid)
+{
+ if(guid == IID_ISlangUnknown || guid == IID_IModule)
+ return asExternal(this);
+ return nullptr;
+}
void Module::addModuleDependency(Module* module)
{
@@ -1367,10 +1640,69 @@ void Module::addFilePathDependency(String const& path)
// Program
+static const Guid IID_IProgram = SLANG_UUID_IProgram;
+
Program::Program(Linkage* linkage)
: m_linkage(linkage)
{}
+ISlangUnknown* Program::getInterface(Guid const& guid)
+{
+ if(guid == IID_ISlangUnknown
+ || guid == IID_IProgram)
+ {
+ return static_cast<slang::IProgram*>(this);
+ }
+
+ return nullptr;
+}
+
+SLANG_NO_THROW slang::ISession* SLANG_MCALL Program::getSession()
+{
+ return m_linkage;
+}
+
+SLANG_NO_THROW slang::ProgramLayout* SLANG_MCALL Program::getLayout(
+ Int targetIndex,
+ slang::IBlob** outDiagnostics)
+{
+ auto linkage = getLinkageImpl();
+ if(targetIndex < 0 || targetIndex >= linkage->targets.getCount())
+ return nullptr;
+ auto target = linkage->targets[targetIndex];
+
+ DiagnosticSink sink(linkage->getSourceManager());
+ auto programLayout = getTargetProgram(target)->getOrCreateLayout(&sink);
+ sink.getBlobIfNeeded(outDiagnostics);
+
+ return asExternal(programLayout);
+}
+
+SLANG_NO_THROW SlangResult SLANG_MCALL Program::getEntryPointCode(
+ SlangInt entryPointIndex,
+ Int targetIndex,
+ slang::IBlob** outCode,
+ slang::IBlob** outDiagnostics)
+{
+ auto linkage = getLinkageImpl();
+ if(targetIndex < 0 || targetIndex >= linkage->targets.getCount())
+ return SLANG_E_INVALID_ARG;
+ auto target = linkage->targets[targetIndex];
+
+ auto targetProgram = getTargetProgram(target);
+
+ DiagnosticSink sink(linkage->getSourceManager());
+ auto& entryPointResult = targetProgram->getOrCreateEntryPointResult(entryPointIndex, &sink);
+ sink.getBlobIfNeeded(outDiagnostics);
+
+ if(entryPointResult.format == ResultFormat::None )
+ return SLANG_FAIL;
+
+ *outCode = entryPointResult.getBlob().detach();
+ return SLANG_OK;
+}
+
+
void Program::addReferencedModule(Module* module)
{
m_moduleDependencyList.addDependency(module);
@@ -1383,13 +1715,27 @@ void Program::addReferencedLeafModule(Module* module)
m_filePathDependencyList.addDependency(module);
}
-void Program::addEntryPoint(EntryPoint* entryPoint)
+void Program::addEntryPoint(EntryPoint* entryPoint, DiagnosticSink* sink)
+{
+ List<RefPtr<EntryPoint>> entryPoints;
+ entryPoints.add(entryPoint);
+
+ RefPtr<EntryPointGroup> entryPointGroup = EntryPointGroup::create(getLinkageImpl(), entryPoints, sink);
+
+ addEntryPointGroup(entryPointGroup);
+}
+
+void Program::addEntryPointGroup(EntryPointGroup* entryPointGroup)
{
- m_entryPoints.add(entryPoint);
+ m_entryPointGroups.add(entryPointGroup);
- for(auto module : entryPoint->getModuleDependencies())
+ for(auto entryPoint : entryPointGroup->getEntryPoints())
{
- addReferencedModule(module);
+ m_entryPoints.add(entryPoint);
+ for(auto module : entryPoint->getModuleDependencies())
+ {
+ addReferencedModule(module);
+ }
}
}
@@ -1398,7 +1744,7 @@ RefPtr<IRModule> Program::getOrCreateIRModule(DiagnosticSink* sink)
if(!m_irModule)
{
m_irModule = generateIRForProgram(
- m_linkage->getSession(),
+ m_linkage->getSessionImpl(),
this,
sink);
}
@@ -1466,7 +1812,7 @@ SlangResult DiagnosticSink::getBlobIfNeeded(ISlangBlob** outBlob)
Session* CompileRequestBase::getSession()
{
- return getLinkage()->getSession();
+ return getLinkage()->getSessionImpl();
}
static const Slang::Guid IID_ISlangFileSystemExt = SLANG_UUID_ISlangFileSystemExt;
@@ -1512,12 +1858,13 @@ void Session::addBuiltinSource(
String const& path,
String const& source)
{
- DiagnosticSink sink;
+ SourceManager* sourceManager = getBuiltinSourceManager();
+
+ DiagnosticSink sink(sourceManager);
RefPtr<FrontEndCompileRequest> compileRequest = new FrontEndCompileRequest(
m_builtinLinkage,
&sink);
- SourceManager* sourceManager = getBuiltinSourceManager();
// Set the source manager on the sink
sink.sourceManager = sourceManager;
@@ -1611,20 +1958,24 @@ static SlangCompileRequest* convert(Slang::EndToEndCompileRequest* request)
static Slang::EndToEndCompileRequest* convert(SlangCompileRequest* request)
{ return reinterpret_cast<Slang::EndToEndCompileRequest*>(request); }
-static SlangLinkage* convert(Slang::Linkage* linkage)
-{ return reinterpret_cast<SlangLinkage*>(linkage); }
-
-static Slang::Linkage* convert(SlangLinkage* linkage)
-{ return reinterpret_cast<Slang::Linkage*>(linkage); }
-
-static SlangModule* convert(Slang::Module* module)
-{ return reinterpret_cast<SlangModule*>(module); }
-
SLANG_API SlangSession* spCreateSession(const char*)
{
return convert(new Slang::Session());
}
+SLANG_API SlangResult slang_createGlobalSession(
+ SlangInt apiVersion,
+ slang::IGlobalSession** outGlobalSession)
+{
+ if(apiVersion != 0)
+ return SLANG_E_NOT_IMPLEMENTED;
+
+ Slang::Session* globalSession = new Slang::Session();
+ Slang::ComPtr<slang::IGlobalSession> result(Slang::asExternal(globalSession));
+ *outGlobalSession = result.detach();
+ return SLANG_OK;
+}
+
SLANG_API void spDestroySession(
SlangSession* session)
{
@@ -1698,35 +2049,6 @@ SLANG_API SlangResult spSessionCheckPassThroughSupport(
return Slang::checkExternalCompilerSupport(s, Slang::PassThroughMode(passThrough));
}
-
-SLANG_API SlangLinkage* spCreateLinkage(
- SlangSession* session)
-{
- auto s = convert(session);
- auto linkage = new Slang::Linkage(s);
- return convert(linkage);
-}
-
-SLANG_API void spDestroyLinkage(
- SlangLinkage* linkage)
-{
- if(!linkage) return;
- auto lnk = convert(linkage);
- delete lnk;
-}
-
-SLANG_API SlangModule* spLoadModule(
- SlangLinkage* linkage,
- char const* moduleName)
-{
- if(!linkage) return nullptr;
- auto lnk = convert(linkage);
-
- auto mod = lnk->loadModule(moduleName);
- return convert(mod);
-}
-
-
SLANG_API SlangCompileRequest* spCreateCompileRequest(
SlangSession* session)
{
@@ -1839,7 +2161,7 @@ SLANG_API void spSetMatrixLayoutMode(
{
auto req = convert(request);
auto linkage = req->getLinkage();
- linkage->defaultMatrixLayoutMode = Slang::MatrixLayoutMode(mode);
+ linkage->setMatrixLayoutMode(mode);
}
SLANG_API void spSetTargetMatrixLayoutMode(
@@ -1932,7 +2254,7 @@ SLANG_API void spAddSearchPath(
{
auto req = convert(request);
auto linkage = req->getLinkage();
- linkage->searchDirectories.searchDirectories.add(Slang::SearchDirectory(path));
+ linkage->addSearchPath(path);
}
SLANG_API void spAddPreprocessorDefine(
@@ -1942,7 +2264,7 @@ SLANG_API void spAddPreprocessorDefine(
{
auto req = convert(request);
auto linkage = req->getLinkage();
- linkage->preprocessorDefinitions[key] = value;
+ linkage->addPreprocessorDefine(key, value);
}
SLANG_API char const* spGetDiagnosticOutput(
@@ -2391,6 +2713,18 @@ SLANG_API void const* spGetCompileRequestCode(
// Reflection API
+SLANG_API SlangResult spCompileRequest_getProgram(
+ SlangCompileRequest* request,
+ slang::IProgram** outProgram)
+{
+ if( !request ) return SLANG_ERROR_INVALID_PARAMETER;
+ auto req = convert(request);
+ auto program = req->getSpecializedProgram();
+
+ *outProgram = Slang::ComPtr<slang::IProgram>(program).detach();
+ return SLANG_OK;
+}
+
SLANG_API SlangReflection* spGetReflection(
SlangCompileRequest* request)
{
diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis
index f19ed925b..0bf32c5e7 100644
--- a/source/slang/slang.natvis
+++ b/source/slang/slang.natvis
@@ -17,16 +17,10 @@
<ExpandedItem>decl ? ($T1*)(decl) : ($T1*)0</ExpandedItem>
<Item Name="[Substitutions]:">"========================="</Item>
<LinkedListItems>
- <HeadPointer>substitutions.genericSubstitutions.pointer</HeadPointer>
+ <HeadPointer>substitutions.substitutions.pointer</HeadPointer>
<NextPointer>outer.pointer</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
- <LinkedListItems>
- <HeadPointer>substitutions.globalGenParamSubstitutions.pointer</HeadPointer>
- <NextPointer>outer.pointer</NextPointer>
- <ValueNode>this</ValueNode>
- </LinkedListItems>
- <Item Name ="thisSubst">substitutions.thisTypeSubstitution</Item>
</Expand>
</Type>
<Type Name="Slang::DeclRefBase">
@@ -66,10 +60,10 @@
<DisplayString>FuncDecl {nameAndLoc}</DisplayString>
</Type>
<Type Name="Slang::Name">
- <DisplayString>{{name={(char*)(text.buffer.pointer+1), s}}}</DisplayString>
+ <DisplayString>{{name={(char*)(text.m_buffer.pointer+1), s}}}</DisplayString>
</Type>
<Type Name="Slang::NameLoc">
- <DisplayString>{{name={(char*)((*name).text.buffer.pointer+1), s} loc={loc.raw}}}</DisplayString>
+ <DisplayString>{{name={(char*)((*name).text.m_buffer.pointer+1), s} loc={loc.raw}}}</DisplayString>
</Type>
<Type Name="Slang::IRWitnessTableEntry">
<Expand>
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index 7c6967f70..251b46b3e 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -297,7 +297,10 @@
<ClCompile Include="slang.cpp" />
</ItemGroup>
<ItemGroup>
- <None Include="slang.natvis" />
+ <Natvis Include="..\core\core.natvis" />
+ <Natvis Include="slang.natvis">
+ <FileType>Document</FileType>
+ </Natvis>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="core.meta.slang">
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index bd9c2f297..3dd2c4a49 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
@@ -394,4 +394,9 @@
<Filter>Source Files</Filter>
</CustomBuild>
</ItemGroup>
+ <ItemGroup>
+ <Natvis Include="..\core\core.natvis">
+ <Filter>Source Files</Filter>
+ </Natvis>
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/tests/compute/interface-shader-param-in-struct.slang b/tests/compute/interface-shader-param-in-struct.slang
index 2ffc70c36..b033bd31c 100644
--- a/tests/compute/interface-shader-param-in-struct.slang
+++ b/tests/compute/interface-shader-param-in-struct.slang
@@ -49,6 +49,9 @@ cbuffer C
IRandomNumberGenerationStrategy gStrategy;
}
+//TEST_INPUT: globalExistentialType MyStrategy
+//TEST_INPUT:ubuffer(data=[1 2 4 8], stride=4):dxbinding(1),glbinding(1)
+
struct Stuff
{
IModifier modifier;
@@ -107,21 +110,5 @@ struct MyModifier : IModifier
}
}
-//TEST_INPUT: globalExistentialType MyStrategy
//TEST_INPUT: entryPointExistentialType MyModifier
-
-// The concrete types we plug in for `gStrategy` and `modifier`
-// have buffer resources in them, so we need to assign them
-// data. The registers/bindings for these parameters will
-// always come after all other shader parameters, and their
-// relative order will match the relative order of their
-// declarations in the global order that Slang uses for
-// assigning bindings (all globals before all entry point parameters).
-//
-// Here's the data for `gStrategy`:
-//
-//TEST_INPUT:ubuffer(data=[1 2 4 8], stride=4):dxbinding(1),glbinding(1)
-//
-// Here's the data for `stuff.modifier`:
-//
//TEST_INPUT:ubuffer(data=[16 32 64 128], stride=4):dxbinding(2),glbinding(3)
diff --git a/tests/compute/interface-shader-param3.slang b/tests/compute/interface-shader-param3.slang
index 3c8b24be1..f4f45689c 100644
--- a/tests/compute/interface-shader-param3.slang
+++ b/tests/compute/interface-shader-param3.slang
@@ -45,17 +45,19 @@ int test(
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
RWStructuredBuffer<int> gOutputBuffer;
-// Note: while we declare `gStrategy` here, there is no matching
-// line providing input data at this point. That is partly to
-// work around an apparent bug in the test runner, but it is also
-// to reflect the fact that this declaration does not cause a
-// constant buffer binding to be allocated, because just from
-// the declaration of `gStrategy` we cannot tell whether a
-// constant buffer binding is even needed (there might be no
-// uniform/ordinary data).
-//
ConstantBuffer<IRandomNumberGenerationStrategy> gStrategy;
+// Note: The current strategy we use for laying out shader
+// parameters in the presence of existential/interface types
+// is to always put global-scope parameters before any
+// entry-point parameters. As a result we need to provide
+// the buffer for the specialized version of `gStrategy`
+// here, and we will go ahead and provide the concrete
+// type argument at the same time.
+//
+//TEST_INPUT: globalExistentialType MyStrategy
+//TEST_INPUT:cbuffer(data=[1 0 0 0], stride=4):dxbinding(0),glbinding(1)
+
[numthreads(4, 1, 1)]
void computeMain(
@@ -81,7 +83,7 @@ void computeMain(
//
// Here's the incantation to make the test runner fill in the constant buffer:
//
-//TEST_INPUT:cbuffer(data=[256 0 0 0 16 0 0 0], stride=4):dxbinding(0),glbinding(1)
+//TEST_INPUT:cbuffer(data=[256 0 0 0 16 0 0 0], stride=4):dxbinding(1),glbinding(2)
//
// So, the value `256` will be used for `extra` and the value `16`
// will be written to the first four bytes of the concrete value
@@ -134,16 +136,4 @@ struct MyModifier : IModifier
}
}
-//TEST_INPUT: globalExistentialType MyStrategy
//TEST_INPUT: entryPointExistentialType MyModifier
-
-// Once the concrete types are plugged in, the compiler can
-// see that `gStrategy` needs a constant buffer register/binding.
-// It will alocate the location for `gStrategy` after all other
-// shader parameters, to ensure that different specializations
-// of the same shader will agree on the locations for all the
-// non-interface-type parameters.
-//
-//TEST_INPUT:cbuffer(data=[1 0 0 0], stride=4):dxbinding(1),glbinding(2)
-
-
diff --git a/tests/compute/interface-shader-param4.slang b/tests/compute/interface-shader-param4.slang
index 07c6951e0..51b6686ef 100644
--- a/tests/compute/interface-shader-param4.slang
+++ b/tests/compute/interface-shader-param4.slang
@@ -48,6 +48,18 @@ RWStructuredBuffer<int> gOutputBuffer;
ConstantBuffer<IRandomNumberGenerationStrategy> gStrategy;
+// The concrete types we plug in for `gStrategy` and `modifier`
+// have buffer resources in them, so we need to assign them
+// data. The registers/bindings for these parameters will
+// always come after all other shader parameters in the same
+// scope (global or entry-point).
+//
+// Here's the data for `gStrategy`:
+//
+//TEST_INPUT: globalExistentialType MyStrategy
+//TEST_INPUT:ubuffer(data=[1 2 4 8], stride=4):dxbinding(1),glbinding(1)
+
+
[numthreads(4, 1, 1)]
void computeMain(
@@ -112,21 +124,7 @@ struct MyModifier : IModifier
}
}
-//TEST_INPUT: globalExistentialType MyStrategy
-//TEST_INPUT: entryPointExistentialType MyModifier
-
-// The concrete types we plug in for `gStrategy` and `modifier`
-// have buffer resources in them, so we need to assign them
-// data. The registers/bindings for these parameters will
-// always come after all other shader parameters, and their
-// relative order will match the relative order of their
-// declarations in the global order that Slang uses for
-// assigning bindings (all globals before all entry point parameters).
-//
-// Here's the data for `gStrategy`:
-//
-//TEST_INPUT:ubuffer(data=[1 2 4 8], stride=4):dxbinding(1),glbinding(1)
-//
// Here's the data for `modifier`:
//
+//TEST_INPUT: entryPointExistentialType MyModifier
//TEST_INPUT:ubuffer(data=[16 32 64 128], stride=4):dxbinding(2),glbinding(3)
diff --git a/tests/reflection/parameter-block-explicit-space.slang.expected b/tests/reflection/parameter-block-explicit-space.slang.expected
index 04093f4ca..f7944c644 100644
--- a/tests/reflection/parameter-block-explicit-space.slang.expected
+++ b/tests/reflection/parameter-block-explicit-space.slang.expected
@@ -7,7 +7,7 @@ standard output = {
{
"name": "a",
"bindings": [
- {"kind": "constantBuffer", "space": 2, "index": 0, "count": 0},
+ {"kind": "constantBuffer", "index": 0, "count": 0},
{"kind": "registerSpace", "index": 2}
],
"type": {
@@ -58,7 +58,7 @@ standard output = {
{
"name": "b",
"bindings": [
- {"kind": "constantBuffer", "space": 3, "index": 0, "count": 0},
+ {"kind": "constantBuffer", "index": 0, "count": 0},
{"kind": "registerSpace", "index": 3}
],
"type": {