diff options
Diffstat (limited to 'source/slang/type-layout.h')
| -rw-r--r-- | source/slang/type-layout.h | 550 |
1 files changed, 550 insertions, 0 deletions
diff --git a/source/slang/type-layout.h b/source/slang/type-layout.h new file mode 100644 index 000000000..be54bbf53 --- /dev/null +++ b/source/slang/type-layout.h @@ -0,0 +1,550 @@ +#ifndef SLANG_TYPE_LAYOUT_H +#define SLANG_TYPE_LAYOUT_H + +#include "../core/basic.h" +#include "profile.h" +#include "syntax.h" + +#include "../../slang.h" + +namespace Slang { + +typedef intptr_t Int; +typedef uintptr_t UInt; + +namespace Compiler { + +// Forward declarations + +enum class BaseType; +class ExpressionType; + +// + +enum class LayoutRule +{ + Std140, + Std430, + HLSLConstantBuffer, + HLSLStructuredBuffer, +}; + +enum class LayoutRulesFamily +{ + HLSL, + GLSL, +}; + +// Layout appropriate to "just memory" scenarios, +// such as laying out the members of a constant buffer. +struct UniformLayoutInfo +{ + size_t size; + size_t alignment; + + UniformLayoutInfo() + : size(0) + , alignment(1) + {} + + UniformLayoutInfo( + size_t size, + size_t alignment) + : size(size) + , alignment(alignment) + {} +}; + +// Extended information required for an array of uniform data, +// including the "stride" of the array (the space between +// consecutive elements). +struct UniformArrayLayoutInfo : UniformLayoutInfo +{ + size_t elementStride; + + UniformArrayLayoutInfo() + : elementStride(0) + {} + + UniformArrayLayoutInfo( + size_t size, + size_t alignment, + size_t elementStride) + : UniformLayoutInfo(size, alignment) + , elementStride(elementStride) + {} +}; + +typedef slang::ParameterCategory LayoutResourceKind; + +// Layout information for a value that only consumes +// a single reosurce kind. +struct SimpleLayoutInfo +{ + // What kind of resource should we consume? + LayoutResourceKind kind; + + // How many resources of that kind? + size_t size; + + // only useful in the uniform case + size_t alignment; + + SimpleLayoutInfo() + : kind(LayoutResourceKind::None) + , size(0) + , alignment(1) + {} + + SimpleLayoutInfo( + UniformLayoutInfo uniformInfo) + : kind(LayoutResourceKind::Uniform) + , size(uniformInfo.size) + , alignment(uniformInfo.alignment) + {} + + SimpleLayoutInfo(LayoutResourceKind kind, size_t size, size_t alignment=1) + : kind(kind) + , size(size) + , alignment(alignment) + {} + + // Convert to layout for uniform data + UniformLayoutInfo getUniformLayout() + { + if(kind == LayoutResourceKind::Uniform) + { + return UniformLayoutInfo(size, alignment); + } + else + { + return UniformLayoutInfo(0, 1); + } + } +}; + +// Only useful in the case of a homogeneous array +struct SimpleArrayLayoutInfo : SimpleLayoutInfo +{ + // This field is only useful in the uniform case + size_t elementStride; + + // Convert to layout for uniform data + UniformArrayLayoutInfo getUniformLayout() + { + if(kind == LayoutResourceKind::Uniform) + { + return UniformArrayLayoutInfo(size, alignment, elementStride); + } + else + { + return UniformArrayLayoutInfo(0, 1, 0); + } + } +}; + +struct LayoutRulesImpl; + +// A reified reprsentation of a particular laid-out type +class TypeLayout : public RefObject +{ +public: + // The type that was laid out + RefPtr<ExpressionType> type; + ExpressionType* getType() { return type.Ptr(); } + + // The layout rules that were used to produce this type + LayoutRulesImpl* rules; + + struct ResourceInfo + { + // What kind of register was it? + LayoutResourceKind kind = LayoutResourceKind::None; + + // How many registers of the above kind did we use? + UInt count; + }; + + List<ResourceInfo> resourceInfos; + + // For uniform data, alignment matters, but not for + // any other resource category, so we don't waste + // the space storing it in the above array + UInt uniformAlignment = 1; + + ResourceInfo* FindResourceInfo(LayoutResourceKind kind) + { + for(auto& rr : resourceInfos) + { + if(rr.kind == kind) + return &rr; + } + return nullptr; + } + + ResourceInfo* findOrAddResourceInfo(LayoutResourceKind kind) + { + auto existing = FindResourceInfo(kind); + if(existing) return existing; + + ResourceInfo info; + info.kind = kind; + info.count = 0; + resourceInfos.Add(info); + return &resourceInfos.Last(); + } + + void addResourceUsage(ResourceInfo info) + { + if(info.count == 0) return; + + findOrAddResourceInfo(info.kind)->count += info.count; + } + + void addResourceUsage(LayoutResourceKind kind, UInt count) + { + ResourceInfo info; + info.kind = kind; + info.count = count; + addResourceUsage(info); + } +}; + +typedef unsigned int VarLayoutFlags; +enum VarLayoutFlag : VarLayoutFlags +{ + IsRedeclaration = 1 << 0, ///< This is a redeclaration of some shader parameter +}; + +// A reified layout for a particular variable, field, etc. +class VarLayout : public RefObject +{ +public: + // The variable we are laying out + VarDeclBaseRef varDecl; + VarDeclBase* getVariable() { return varDecl.GetDecl(); } + + String const& getName() { return getVariable()->getName(); } + + // The result of laying out the variable's type + RefPtr<TypeLayout> typeLayout; + TypeLayout* getTypeLayout() { return typeLayout.Ptr(); } + + // Additional flags + VarLayoutFlags flags = 0; + + // The start register(s) for any resources + struct ResourceInfo + { + // What kind of register was it? + LayoutResourceKind kind = LayoutResourceKind::None; + + // What binding space (HLSL) or set (Vulkan) are we placed in? + UInt space; + + // What is our starting register in that space? + // + // (In the case of uniform data, this is a byte offset) + UInt index; + }; + List<ResourceInfo> resourceInfos; + + ResourceInfo* FindResourceInfo(LayoutResourceKind kind) + { + for(auto& rr : resourceInfos) + { + if(rr.kind == kind) + return &rr; + } + return nullptr; + } + + ResourceInfo* AddResourceInfo(LayoutResourceKind kind) + { + ResourceInfo info; + info.kind = kind; + info.space = 0; + info.index = 0; + + resourceInfos.Add(info); + return &resourceInfos.Last(); + } + + ResourceInfo* findOrAddResourceInfo(LayoutResourceKind kind) + { + auto existing = FindResourceInfo(kind); + if(existing) return existing; + + return AddResourceInfo(kind); + } +}; + +// Type layout for a variable that has a constant-buffer type +class ParameterBlockTypeLayout : public TypeLayout +{ +public: + RefPtr<TypeLayout> elementTypeLayout; +}; + +// Type layout for a variable that has a constant-buffer type +class StructuredBufferTypeLayout : public TypeLayout +{ +public: + RefPtr<TypeLayout> elementTypeLayout; +}; + +// Specific case of type layout for an array +class ArrayTypeLayout : public TypeLayout +{ +public: + // The layout used for the element type + RefPtr<TypeLayout> elementTypeLayout; + + // the stride between elements when used in + // a uniform buffer + size_t uniformStride; +}; + +// Specific case of type layout for a struct +class StructTypeLayout : public TypeLayout +{ +public: + // An ordered list of layouts for the known fields + List<RefPtr<VarLayout>> fields; + + // Map a variable to its layout directly. + // + // Note that in the general case, there may be entries + // in the `fields` array that came from multiple + // translation units, and in cases where there are + // multiple declarations of the same parameter, only + // one will appear in `fields`, while all of + // them will be reflected in `mapVarToLayout`. + // + Dictionary<Decl*, RefPtr<VarLayout>> mapVarToLayout; +}; + +// Layout information for a single shader entry point +// within a program +class EntryPointLayout : public RefObject +{ +public: + // The corresponding function declaration + RefPtr<FunctionSyntaxNode> entryPoint; + + // The shader profile that was used to compile the entry point + Profile profile; +}; + +// Layout information for the global scope of a program +class ProgramLayout : public RefObject +{ +public: + // We store a layout for the declarations at the global + // scope. Note that this will *either* be a single + // `StructTypeLayout` with the fields stored directly, + // or it will be a single `ParameterBlockTypeLayout`, + // where the global-scope fields are the members of + // that constant buffer. + // + // The `struct` case will be used if there are no + // "naked" global-scope uniform variables, and the + // constant-buffer case will be used if there are + // (since a constant buffer will have to be allocated + // to store them). + // + RefPtr<TypeLayout> globalScopeLayout; + + // We catalog the requested entry points here, + // and any entry-point-specific parameter data + // will (eventually) belong there... + List<RefPtr<EntryPointLayout>> entryPoints; +}; + +// A modifier to be attached to syntax after we've computed layout +class ComputedLayoutModifier : public Modifier +{ +public: + RefPtr<TypeLayout> typeLayout; +}; + + +struct LayoutRulesFamilyImpl; + +// A delineation of shader parameter types into fine-grained +// categories that can then be mapped down to actual resources +// by a given set of rules. +// +// TODO(tfoley): `SlangParameterCategory` and `slang::ParameterCategory` +// are badly named, and need to be revised so they can't be confused +// with this concept. +enum class ShaderParameterKind +{ + ConstantBuffer, + TextureUniformBuffer, + ShaderStorageBuffer, + + StructuredBuffer, + MutableStructuredBuffer, + + SampledBuffer, + MutableSampledBuffer, + + RawBuffer, + MutableRawBuffer, + + Buffer, + MutableBuffer, + + Texture, + MutableTexture, + + TextureSampler, + MutableTextureSampler, + + InputRenderTarget, + + SamplerState, +}; + +struct SimpleLayoutRulesImpl +{ + // Get size and alignment for a single value of base type. + virtual SimpleLayoutInfo GetScalarLayout(BaseType baseType) = 0; + virtual SimpleLayoutInfo GetScalarLayout(slang::TypeReflection::ScalarType scalarType) = 0; + + // Get size and alignment for an array of elements + virtual SimpleArrayLayoutInfo GetArrayLayout(SimpleLayoutInfo elementInfo, size_t elementCount) = 0; + + // Get layout for a vector or matrix type + virtual SimpleLayoutInfo GetVectorLayout(SimpleLayoutInfo elementInfo, size_t elementCount) = 0; + virtual SimpleLayoutInfo GetMatrixLayout(SimpleLayoutInfo elementInfo, size_t rowCount, size_t columnCount) = 0; + + // Begin doing layout on a `struct` type + virtual UniformLayoutInfo BeginStructLayout() = 0; + + // Add a field to a `struct` type, and return the offset for the field + virtual size_t AddStructField(UniformLayoutInfo* ioStructInfo, UniformLayoutInfo fieldInfo) = 0; + + // End layout for a struct, and finalize its size/alignment. + virtual void EndStructLayout(UniformLayoutInfo* ioStructInfo) = 0; +}; + +struct ObjectLayoutRulesImpl +{ + // Compute layout info for an object type + virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind) = 0; +}; + +struct LayoutRulesImpl +{ + LayoutRulesFamilyImpl* family; + SimpleLayoutRulesImpl* simpleRules; + ObjectLayoutRulesImpl* objectRules; + + // Forward `SimpleLayoutRulesImpl` interface + + SimpleLayoutInfo GetScalarLayout(BaseType baseType) + { + return simpleRules->GetScalarLayout(baseType); + } + + SimpleLayoutInfo GetScalarLayout(slang::TypeReflection::ScalarType scalarType) + { + return simpleRules->GetScalarLayout(scalarType); + } + + SimpleArrayLayoutInfo GetArrayLayout(SimpleLayoutInfo elementInfo, size_t elementCount) + { + return simpleRules->GetArrayLayout(elementInfo, elementCount); + } + + SimpleLayoutInfo GetVectorLayout(SimpleLayoutInfo elementInfo, size_t elementCount) + { + return simpleRules->GetVectorLayout(elementInfo, elementCount); + } + + SimpleLayoutInfo GetMatrixLayout(SimpleLayoutInfo elementInfo, size_t rowCount, size_t columnCount) + { + return simpleRules->GetMatrixLayout(elementInfo, rowCount, columnCount); + } + + UniformLayoutInfo BeginStructLayout() + { + return simpleRules->BeginStructLayout(); + } + + size_t AddStructField(UniformLayoutInfo* ioStructInfo, UniformLayoutInfo fieldInfo) + { + return simpleRules->AddStructField(ioStructInfo, fieldInfo); + } + + void EndStructLayout(UniformLayoutInfo* ioStructInfo) + { + return simpleRules->EndStructLayout(ioStructInfo); + } + + // Forward `ObjectLayoutRulesImpl` interface + + SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind) + { + return objectRules->GetObjectLayout(kind); + } + + // + + LayoutRulesFamilyImpl* getLayoutRulesFamily() { return family; } +}; + +struct LayoutRulesFamilyImpl +{ + virtual LayoutRulesImpl* getConstantBufferRules() = 0; + virtual LayoutRulesImpl* getTextureBufferRules() = 0; + virtual LayoutRulesImpl* getVaryingInputRules() = 0; + virtual LayoutRulesImpl* getVaryingOutputRules() = 0; + virtual LayoutRulesImpl* getSpecializationConstantRules() = 0; + virtual LayoutRulesImpl* getShaderStorageBufferRules() = 0; +}; + +LayoutRulesImpl* GetLayoutRulesImpl(LayoutRule rule); +LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(LayoutRulesFamily rule); +LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(SourceLanguage language); + +SimpleLayoutInfo GetLayout(ExpressionType* type, LayoutRulesImpl* rules); + +SimpleLayoutInfo GetLayout(ExpressionType* type, LayoutRule rule = LayoutRule::Std430); + +RefPtr<TypeLayout> CreateTypeLayout(ExpressionType* type, LayoutRulesImpl* rules); + +// + +// Create a type layout for a parameter block type. +RefPtr<ParameterBlockTypeLayout> +createParameterBlockTypeLayout( + RefPtr<ParameterBlockType> parameterBlockType, + LayoutRulesImpl* rules); + +// Create a type layout for a constant buffer type, +// in the case where we already know the layout +// for the element type. +RefPtr<ParameterBlockTypeLayout> +createParameterBlockTypeLayout( + RefPtr<ParameterBlockType> parameterBlockType, + RefPtr<TypeLayout> elementTypeLayout, + LayoutRulesImpl* rules); + + +// Create a type layout for a structured buffer type. +RefPtr<StructuredBufferTypeLayout> +createStructuredBufferTypeLayout( + ShaderParameterKind kind, + RefPtr<ExpressionType> structuredBufferType, + RefPtr<ExpressionType> elementType, + LayoutRulesImpl* rules); + + +// + +}} + +#endif
\ No newline at end of file |
