summaryrefslogtreecommitdiff
path: root/slang.h
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2019-08-08 11:22:32 -0700
committerGitHub <noreply@github.com>2019-08-08 11:22:32 -0700
commit2552217b76c0bd83e18fceba1d35a367bf569eca (patch)
tree0651175e4601af75bc18687c853068f013e6c1b9 /slang.h
parent81ce78d08a7e3fbe74f2fd41c5a258ea4b078245 (diff)
Revise new COM-lite API (#1007)
* Revise new COM-lite API This change revises the "COM-lite" API that was recently introduced to try to streamline it and introduce some missing central/base concepts. The central new abstraction in the API is the notion of a "component type," which is a unit of shader code composition. A component type can have: * IR code for some number of functions/types/etc. * Zero or more global shader parameters * Zero or more "entry point" functions at which execution can start * Zero or more "specialization" parameters (types or values that must be filled in before kernel code can be generated) * Zero or more "requirements" (dependencies on other component types that must be satisfied before kernel code can be generated) Both individual compiled modules, and validated entry points are then examples of component types, and we additionally define a few services that apply to all component types: * We can take N component types and compose them to create a new component type that combines their code, shader parameters, entry points, and specialization parameters. A composed component type may also include requirements from the sub-component types, but it is also possible that by composing thing we satisfy requirements (if `A` requires `B`, and we compose `A` and `B`, then the requirement is now satisfied, and doesn't appear on the composite). * We can take a component type with N specialization parameters, and specialize it by giving N compatible specialization arguments. The result of specialization is a new component type with zero specialization parameters. Under the right circumstances the specialzed component type will be layout compatible with the unspecialized one. * One more example that isn't exposed in the public API today is that we can take a component with requirements and "complete" it by automatically composing it with component types that satisfy those requirements. This can be seen as a kind of linking step that pulls together the transitive closure of dependencies. * We can query the layout for the shader parameters and entry points of a component type, for a specific target. * We can query compiled kernel code for an entry point in a component type (for a specific target). This only works for component types with zero specialization parameters and zero requirements. The idea is that by giving users a fairly general algebra of operations on component types, they can compose final programs in ways that meet their requirements. For example, it becomes possible to incrementally "grow" a component type to represent the global root signature for ray tracing shaders as new entry points are added, in such a way that it always stays layout-compatible with kernels that have already been compiled. Much of the implementation work here is in implementing the unifying component type abstraction, and in particular re-writing code that used to assume a program consisted of a flat list of modules and entry points to work with a hierarchical representation that reflects the underlying algebra (e.g., with types to represent composite and specialized component types). There's also a hidden "legacy" case of a component type to deal with some legacy compiler behaviors that can't be directly modeled on top of the simple algebra with modules and entry points. This API is by no means feature-complete or fully developed. It is expected that we will flesh it out more when bringing up application code (e.g., Falcor) on top of the revamped API. One notable thing that went away in this change is explicit support for "entry point groups" and notions of local root signatures (especially the Falcor-specific handling of the `shared` keyword, which a previous change turned into an explicitly supported feature). With the new "building blocks" approach, it should be possible for a DXR application to deal with local root signatures as a matter of policy (on top of the API we provide). If/when we need to provide some kind of emulation of local root signatures for Vulkan (and/or if Vulkan is extended with an explicit notion of local root signatures), we might need to revisit this choice. * Fix debug build There was invalid code inside an `assert()`, so the release build didn't catch it. * fixup: warnings * fixup: more warnings-as-errors * fixup: review notes * fixup: use component type visitors in place of dynamic casting
Diffstat (limited to 'slang.h')
-rw-r--r--slang.h298
1 files changed, 181 insertions, 117 deletions
diff --git a/slang.h b/slang.h
index 55c454d0d..583072686 100644
--- a/slang.h
+++ b/slang.h
@@ -1571,10 +1571,7 @@ extern "C"
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;
@@ -1900,6 +1897,12 @@ extern "C"
SLANG_API int spReflectionEntryPoint_usesAnySampleRateInput(
SlangReflectionEntryPoint* entryPoint);
+ SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getVarLayout(
+ SlangReflectionEntryPoint* entryPoint);
+
+ SLANG_API int spReflectionEntryPoint_hasDefaultConstantBuffer(
+ SlangReflectionEntryPoint* entryPoint);
+
// SlangReflectionTypeParameter
SLANG_API char const* spReflectionTypeParameter_GetName(SlangReflectionTypeParameter* typeParam);
SLANG_API unsigned spReflectionTypeParameter_GetIndex(SlangReflectionTypeParameter* typeParam);
@@ -1922,9 +1925,6 @@ 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);
@@ -1935,16 +1935,6 @@ 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
}
@@ -2448,36 +2438,23 @@ 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);
+ return (VariableLayoutReflection*) spReflectionEntryPoint_getVarLayout((SlangReflectionEntryPoint*) this);
}
- SlangInt getParameterCount()
+ TypeLayoutReflection* getTypeLayout()
{
- return spEntryPointGroupLayout_getParameterCount((SlangEntryPointGroupLayout*) this);
+ return getVarLayout()->getTypeLayout();
}
- VariableLayoutReflection* getParameterByIndex(SlangInt index)
+ bool hasDefaultConstantBuffer()
{
- return (VariableLayoutReflection*) spEntryPointGroupLayout_getParameterByIndex((SlangEntryPointGroupLayout*) this, index);
+ return spReflectionEntryPoint_hasDefaultConstantBuffer((SlangReflectionEntryPoint*) this) != 0;
}
};
+ typedef EntryPointReflection EntryPointLayout;
struct TypeParameterReflection
{
@@ -2548,16 +2525,6 @@ 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);
@@ -2609,13 +2576,12 @@ namespace slang
typedef ISlangBlob IBlob;
+ struct IComponentType;
struct IGlobalSession;
struct IModule;
- struct IProgram;
struct ISession;
struct SessionDesc;
- struct ProgramDesc;
struct SpecializationArg;
struct TargetDesc;
@@ -2759,20 +2725,39 @@ namespace slang
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;
+ /** Combine multiple component types to create a composite component type.
+
+ The `componentTypes` array must contain `componentTypeCount` pointers
+ to component types that were loaded or created using the same session.
+
+ The shader parameters and specialization parameters of the composite will
+ be the union of those in `componentTypes`. The relative order of child
+ component types is significant, and will affect the order in which
+ parameters are reflected and laid out.
+
+ The entry-point functions of the composite will be the union of those in
+ `componentTypes`, and will follow the ordering of `componentTypes`.
+
+ The requirements of the composite component type will be a subset of
+ those in `componentTypes`. If an entry in `componentTypes` has a requirement
+ that can be satisfied by another entry, then the composition will
+ satisfy the requirement and it will not appear as a requirement of
+ the composite. If multiple entries in `componentTypes` have a requirement
+ for the same type, then only the first such requirement will be retained
+ on the composite. The relative ordering of requirements on the composite
+ will otherwise match that of `componentTypes`.
+
+ If any diagnostics are generated during creation of the composite, they
+ will be written to `outDiagnostics`. If an error is encountered, the
+ function will return null.
- /** Specialize a program based on type arguments.
+ It is an error to create a composite component type that recursively
+ aggregates the a single module more than once.
*/
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL specializeProgram(
- IProgram* program,
- SlangInt specializationArgCount,
- SpecializationArg const* specializationArgs,
- IProgram** outSpecializedProgram,
- ISlangBlob** outDiagnostics = nullptr) = 0;
+ virtual SLANG_NO_THROW IComponentType* SLANG_MCALL createCompositeComponentType(
+ IComponentType* const* componentTypes,
+ SlangInt componentTypeCount,
+ ISlangBlob** outDiagnostics = nullptr) = 0;
/** Specialize a type based on type arguments.
*/
@@ -2799,76 +2784,95 @@ namespace slang
#define SLANG_UUID_ISession { 0x67618701, 0xd116, 0x468f, { 0xab, 0x3b, 0x47, 0x4b, 0xed, 0xce, 0xe, 0x3d } }
+ /** A component type is a unit of shader code layout, reflection, and linking.
- /** A module is the granularity of shader code compilation and loading.
+ A component type is a unit of shader code that can be included into
+ a linked and compiled shader program. Each component type may have:
- 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.
+ * Zero or more uniform shader parameters, representing textures,
+ buffers, etc. that the code in the component depends on.
- 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 } }
+ * Zero or more *specialization* parameters, which are type or
+ value parameters that can be used to synthesize specialized
+ versions of the component type.
+ * Zero or more entry points, which are the individually invocable
+ kernels that can have final code generated.
- /** Argument used for specialization to types/values.
- */
- struct SpecializationArg
- {
- enum class Kind : int32_t
- {
- Unknown,
- Type,
- };
- Kind kind;
- union
- {
- TypeReflection* type;
- };
- };
+ * Zero or more *requirements*, which are other component
+ types on which the component type depends.
- /** 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;
- };
- };
+ One example of a component type is a module of Slang code:
- Item const* items;
- SlangInt itemCount;
- };
+ * The global-scope shader parameters declared in the module are
+ the parameters when considered as a component type.
+
+ * Any global-scope generic or interface type parameters introduce
+ specialization parameters for the module.
+
+ * A module does not by default include any entry points when
+ considered as a component type (although the code of the
+ module might *declare* some entry points).
+
+ * Any other modules that are `import`ed in the source code
+ become requirements of the module, when considered as a
+ component type.
+
+ An entry point is another example of a component type:
+
+ * The `uniform` parameters of the entry point function are
+ its shader parameters when considered as a component type.
+
+ * Any generic or interface-type parameters of the entry point
+ introduce specialization parameters.
+
+ * An entry point component type exposes a single entry point (itself).
+
+ * An entry point has one requirement for the module in which
+ it was defined.
+
+ Component types can be manipulated in a few ways:
+
+ * Multiple component types can be combined into a composite, which
+ combines all of their code, parameters, etc.
+ * A component type can be specialized, by "plugging in" types and
+ values for its specialization parameters.
+
+ * A component type can be laid out for a particular target, giving
+ offsets/bindings to the shader parameters it contains.
+
+ * Generated kernel code can be requested for entry points.
- /** A program comprises zero or more modules, entry points, etc. that have been linked together.
*/
- struct IProgram : public ISlangUnknown
+ struct IComponentType : public ISlangUnknown
{
- public:
- /** Get the runtime session that this program belongs to.
+ /** Get the runtime session that this component type belongs to.
*/
virtual SLANG_NO_THROW ISession* SLANG_MCALL getSession() = 0;
- /** Get the layout for this program for the chosen `targetIndex`
+ /** Get the layout for this program for the chosen `targetIndex`.
+
+ The resulting layout will establish offsets/bindings for all
+ of the global and entry-point shader parameters in the
+ component type.
+
+ If this component type has specialization parameters (that is,
+ it is not fully specialized), then the resulting layout may
+ be incomplete, and plugging in arguments for generic specialization
+ parameters may result in a component type that doesn't have
+ a compatible layout. If the component type only uses
+ interface-type specialization parameters, then the layout
+ for a specialization should be compatible with an unspecialized
+ layout (all parameters in the unspecialized layout will have
+ the same offset/binding in the specialized layout).
+
+ If this component type is combined into a composite, then
+ the absolute offsets/bindings of parameters may not stay the same.
+ If the shader parameters in a component type don't make
+ use of explicit binding annotations (e.g., `register(...)`),
+ then the *relative* offset of shader parameters will stay
+ the same when it is used in a composition.
*/
virtual SLANG_NO_THROW ProgramLayout* SLANG_MCALL getLayout(
SlangInt targetIndex = 0,
@@ -2876,6 +2880,10 @@ namespace slang
/** Get the compiled code for the entry point at `entryPointIndex` for the chosen `targetIndex`
+ Entry point code can only be computed for a component type that
+ has no specialization parameters (it must be fully specialized)
+ and that has no requirements (it must be fully linked).
+
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.
@@ -2885,9 +2893,65 @@ namespace slang
SlangInt targetIndex,
IBlob** outCode,
IBlob** outDiagnostics = nullptr) = 0;
+
+ /** Specialize the component by binding its specialization parameters to concrete arguments.
+
+ The `specializationArgs` array must have `specializationArgCount` entries, and
+ this must match the number of specialization parameters on this component type.
+
+ If the specialization arguments are not valid, then the function will return null.
+
+ If any diagnostics (error or warnings) are produced, they will be written to `outDiagnostics`.
+ */
+ virtual SLANG_NO_THROW IComponentType* SLANG_MCALL specialize(
+ SpecializationArg const* specializationArgs,
+ SlangInt specializationArgCount,
+ ISlangBlob** outDiagnostics = nullptr) = 0;
+ };
+ #define SLANG_UUID_IComponentType { 0x5bc42be8, 0x5c50, 0x4929, { 0x9e, 0x5e, 0xd1, 0x5e, 0x7c, 0x24, 0x1, 0x5f } };
+
+ /** 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`).
+
+ A module establishes a namespace for looking up types, functions, etc.
+ */
+ struct IModule : public IComponentType
+ {
+ public:
+ /** Note: eventually operations for looking up types or entry
+ points by name should appear here.
+ */
};
- #define SLANG_UUID_IProgram { 0x5bc42be8, 0x5c50, 0x4929, { 0x9e, 0x5e, 0xd1, 0x5e, 0x7c, 0x24, 0x1, 0x5f } };
+ #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, /**< An invalid specialization argument. */
+ Type, /**< Specialize to a type. */
+ };
+
+ /** The kind of specialization argument. */
+ Kind kind;
+ union
+ {
+ /** A type specialization argument, used for `Kind::Type`. */
+ TypeReflection* type;
+ };
+ };
}
#define SLANG_API_VERSION 0
@@ -2909,7 +2973,7 @@ namespace slang
*/
SLANG_API SlangResult spCompileRequest_getProgram(
SlangCompileRequest* request,
- slang::IProgram** outProgram);
+ slang::IComponentType** outProgram);
#endif