diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2019-05-31 17:20:37 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-05-31 17:20:37 -0400 |
| commit | 6cbc3929a54d37bd23cb5efa8e3320ba02f78b2f (patch) | |
| tree | 5a23cb47782e9e2a77762c90dd35da1005eba8d0 /source/slang/slang-type-layout.h | |
| parent | b81ff3ef968d1cc4e954b31a1812b3c391d17b02 (diff) | |
Use slang- prefix on slang compiler and core source (#973)
* Prefixing source files in source/slang with slang-
* Prefix source in source/slang with slang- prefix.
* Rename core source files with slang- prefix.
* Update project files.
* Fix problems from automatic merge.
Diffstat (limited to 'source/slang/slang-type-layout.h')
| -rw-r--r-- | source/slang/slang-type-layout.h | 1118 |
1 files changed, 1118 insertions, 0 deletions
diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h new file mode 100644 index 000000000..97113c77f --- /dev/null +++ b/source/slang/slang-type-layout.h @@ -0,0 +1,1118 @@ +#ifndef SLANG_TYPE_LAYOUT_H +#define SLANG_TYPE_LAYOUT_H + +#include "../core/slang-basic.h" +#include "slang-compiler.h" +#include "slang-profile.h" +#include "slang-syntax.h" + +#include "../../slang.h" + +namespace Slang { + +// Forward declarations + +enum class BaseType; +class Type; + +// + +enum class LayoutRule +{ + Std140, + Std430, + HLSLConstantBuffer, + HLSLStructuredBuffer, +}; + +#if 0 +enum class LayoutRulesFamily +{ + HLSL, + GLSL, +}; +#endif + +// A "size" that can either be a simple finite size or +// the special case of an infinite/unbounded size. +// +struct LayoutSize +{ + typedef size_t RawValue; + + LayoutSize() + : raw(0) + {} + + LayoutSize(RawValue size) + : raw(size) + { + SLANG_ASSERT(size != RawValue(-1)); + } + + static LayoutSize infinite() + { + LayoutSize result; + result.raw = RawValue(-1); + return result; + } + + bool isInfinite() const { return raw == RawValue(-1); } + + bool isFinite() const { return raw != RawValue(-1); } + RawValue getFiniteValue() const { SLANG_ASSERT(isFinite()); return raw; } + + bool operator==(LayoutSize that) const + { + return raw == that.raw; + } + + bool operator!=(LayoutSize that) const + { + return raw != that.raw; + } + + void operator+=(LayoutSize right) + { + if( isInfinite() ) {} + else if( right.isInfinite() ) + { + *this = LayoutSize::infinite(); + } + else + { + *this = LayoutSize(raw + right.raw); + } + } + + void operator*=(LayoutSize right) + { + // Deal with zero first, so that anything (even the "infinite" value) times zero is zero. + if( raw == 0 ) + { + return; + } + + if( right.raw == 0 ) + { + raw = 0; + return; + } + + // Next we deal with infinite cases, so that infinite times anything non-zero is infinite + if( isInfinite() ) + { + return; + } + + if( right.isInfinite() ) + { + *this = LayoutSize::infinite(); + return; + } + + // Finally deal with the case where both sides are finite + *this = LayoutSize(raw * right.raw); + } + + void operator-=(RawValue right) + { + if( isInfinite() ) {} + else + { + *this = LayoutSize(raw - right); + } + } + + void operator/=(RawValue right) + { + if( isInfinite() ) {} + else + { + *this = LayoutSize(raw / right); + } + } + RawValue raw; +}; + +inline LayoutSize operator+(LayoutSize left, LayoutSize right) +{ + LayoutSize result(left); + result += right; + return result; +} + +inline LayoutSize operator*(LayoutSize left, LayoutSize right) +{ + LayoutSize result(left); + result *= right; + return result; +} + +inline LayoutSize operator-(LayoutSize left, LayoutSize::RawValue right) +{ + LayoutSize result(left); + result -= right; + return result; +} + +inline LayoutSize operator/(LayoutSize left, LayoutSize::RawValue right) +{ + LayoutSize result(left); + result /= right; + return result; +} + +inline LayoutSize maximum(LayoutSize left, LayoutSize right) +{ + if(left.isInfinite() || right.isInfinite()) + return LayoutSize::infinite(); + + return LayoutSize(Math::Max( + left.getFiniteValue(), + right.getFiniteValue())); +} + +inline bool operator>(LayoutSize left, LayoutSize::RawValue right) +{ + return left.isInfinite() || (left.getFiniteValue() > right); +} + +inline bool operator<=(LayoutSize left, LayoutSize::RawValue right) +{ + return left.isFinite() && (left.getFiniteValue() <= right); +} + +// Layout appropriate to "just memory" scenarios, +// such as laying out the members of a constant buffer. +struct UniformLayoutInfo +{ + LayoutSize size; + size_t alignment; + + UniformLayoutInfo() + : size(0) + , alignment(1) + {} + + UniformLayoutInfo( + LayoutSize 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( + LayoutSize 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 resource kind. +struct SimpleLayoutInfo +{ + // What kind of resource should we consume? + LayoutResourceKind kind; + + // How many resources of that kind? + LayoutSize 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, LayoutSize 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; + +// Base class for things that store layout info +class Layout : public RefObject +{ +}; + +// A reified representation of a particular laid-out type +class TypeLayout : public Layout +{ +public: + // The type that was laid out + RefPtr<Type> type; + Type* 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? + LayoutSize 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; + + + /// The layout for data that is conceptually owned by this type, but which is pending layout. + /// + /// When a type contains interface/existential fields (recursively), the + /// actual data referenced by these fields needs to get allocated somewhere, + /// but it cannot go inline at the point where the interface/existential + /// type appears, or else the layout of a composite object would change + /// when the concrete type(s) we plug in change. + /// + /// We solve this problem by tracking this data that is "pending" layout, + /// and then "flushing" the pending data at appropriate places during + /// the layout process. + /// + RefPtr<TypeLayout> pendingDataTypeLayout; + + 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.getLast(); + } + + void addResourceUsage(ResourceInfo info) + { + if(info.count == 0) return; + + findOrAddResourceInfo(info.kind)->count += info.count; + } + + void addResourceUsage(LayoutResourceKind kind, LayoutSize count) + { + ResourceInfo info; + info.kind = kind; + info.count = count; + addResourceUsage(info); + } + + void addResourceUsageFrom(TypeLayout* otherTypeLayout); + + /// "Unwrap" any layers of array-ness from this type layout. + /// + /// If this is an `ArrayTypeLayout`, returns the result of unwrapping the element type layout. + /// Otherwise, returns this type layout. + /// + RefPtr<TypeLayout> unwrapArray(); +}; + +typedef unsigned int VarLayoutFlags; +enum VarLayoutFlag : VarLayoutFlags +{ + HasSemantic = 1 << 1 +}; + +// A reified layout for a particular variable, field, etc. +class VarLayout : public Layout +{ +public: + // The variable we are laying out + DeclRef<VarDeclBase> varDecl; + VarDeclBase* getVariable() { return varDecl.getDecl(); } + + Name* 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; + + // System-value semantic (and index) if this is a system value + String systemValueSemantic; + int systemValueSemanticIndex; + + // General case semantic name and index + // TODO: this and the system-value field are redundant + // TODO: the `VarLayout` type is getting bloated; we need to not store this + // information unless actually required. + String semanticName; + int semanticIndex; + + // The stage this variable belongs to, in case it is + // stage-specific. + // TODO: This is wasteful to be storing on every single + // variable layout. + Stage stage = Stage::Unknown; + + // 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.getLast(); + } + + ResourceInfo* findOrAddResourceInfo(LayoutResourceKind kind) + { + auto existing = FindResourceInfo(kind); + if(existing) return existing; + + return AddResourceInfo(kind); + } + + RefPtr<VarLayout> pendingVarLayout; +}; + +// type layout for a variable that has a constant-buffer type +class ParameterGroupTypeLayout : public TypeLayout +{ +public: + // The layout of the "container" part itself. + // E.g., for a constant buffer, this would reflect + // the resource usage of the container, without + // the element type factored in. All of the offsets + // for this variable should be zero, but it is included + // for completeness. + RefPtr<VarLayout> containerVarLayout; + + // A variable layout for the element of the container. + // The offsets of the variable layout will reflect + // the offsets that need to applied to get past the + // container types resource usage, while the actual + // type layout won't have offsets applied (unlike + // `offsetElementTypeLayout` below). + RefPtr<VarLayout> elementVarLayout; + + // The layout of the element type, with offsets applied + // so that any fields (if the element type is a `struct`) + // will be offset by the resource usage of the container. + RefPtr<TypeLayout> offsetElementTypeLayout; + + // If the element type layout had any "pending" data, then + // as much of that data as possible will be flushed to + // fit into the overall layout of the parameter group. + // + // This field stores the offset information for where + // the pending data got stored relative to the start of + // the group. + // +// RefPtr<VarLayout> flushedDataVarLayout; +}; + +// type layout for a variable that has a constant-buffer type +class StructuredBufferTypeLayout : public TypeLayout +{ +public: + RefPtr<TypeLayout> elementTypeLayout; +}; + + /// Type layout for a logical sequence type +class SequenceTypeLayout : public TypeLayout +{ +public: + /// The layout of the element type. + /// + /// This layout may include adjustments to make lookups in elements + /// of the array Just Work, and may not be the same as the layout + /// of the element type when used in a non-array context. + /// + RefPtr<TypeLayout> elementTypeLayout; + + /// The stride in bytes between elements. + size_t uniformStride = 0; +}; + + /// Type layout for an array type +class ArrayTypeLayout : public SequenceTypeLayout +{ +public: + /// The original layout of the element type. + /// + /// This layout does not include any adjustments that + /// were made to the element type in order to make + /// lookup into array elements Just Work. + /// + RefPtr<TypeLayout> originalElementTypeLayout; +}; + +// type layout for a variable with stream-output type +class StreamOutputTypeLayout : public TypeLayout +{ +public: + RefPtr<TypeLayout> elementTypeLayout; +}; + +class VectorTypeLayout : public SequenceTypeLayout +{ +public: +}; + + +class MatrixTypeLayout : public SequenceTypeLayout +{ +public: + /// Is this matrix laid out as row-major or column-major? + /// + /// Note that this does *not* affect the interpretation + /// of the `elementTypeLayout` field, which always represents + /// the logical elements of the matrix type, which are its + /// rows. + /// + MatrixLayoutMode mode; +}; + +// 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`. + // + // TODO: This should map from a declaration to the *index* + // in the array above, rather than to the actual pointer, + // so that we + Dictionary<Decl*, RefPtr<VarLayout>> mapVarToLayout; + + // As an accellerator for type layouts created at the + // IR layer, we include a second map that use IR "key" + // instructions to map to fields. + // + Dictionary<IRInst*, RefPtr<VarLayout>> mapKeyToLayout; +}; + +class GenericParamTypeLayout : public TypeLayout +{ +public: + RefPtr<GlobalGenericParamDecl> getGlobalGenericParamDecl(); + int paramIndex = 0; +}; + + /// Layout information for a tagged union type. +class TaggedUnionTypeLayout : public TypeLayout +{ +public: + /// The layouts of each of the case types. + /// + /// The order of entries in this array matches + /// the order of case types on the original + /// `TaggedUnionType`, and the index of a case + /// type is also the tag value for that case. + /// + List<RefPtr<TypeLayout>> caseTypeLayouts; + + /// The byte offset for the tag field. + /// + /// The tag field will always be allocated as + /// a `uint`, so we don't store a separate layout + /// for it. + /// + LayoutSize tagOffset; +}; + + /// Layout information for a type with existential (sub-)field types specialized. +class ExistentialSpecializedTypeLayout : public TypeLayout +{ +public: + RefPtr<TypeLayout> baseTypeLayout; + RefPtr<VarLayout> pendingDataVarLayout; +}; + + /// Layout for a scoped entity like a program, module, or entry point +class ScopeLayout : public Layout +{ +public: + // The layout for the parameters of this entity. + // + RefPtr<VarLayout> parametersLayout; +}; + +StructTypeLayout* getScopeStructLayout( + ScopeLayout* programLayout); + +// Layout information for a single shader entry point +// within a program +// +// Treated as a subclass of `StructTypeLayout` because +// it needs to include computed layout information +// for the parameters of the entry point. +// +// TODO: where to store layout info for the return +// type of the function? +class EntryPointLayout : public ScopeLayout +{ +public: + // The corresponding function declaration + RefPtr<FuncDecl> entryPoint; + + // The shader profile that was used to compile the entry point + Profile profile; + + // Layout for any results of the entry point + RefPtr<VarLayout> resultLayout; + + enum Flag : unsigned + { + usesAnySampleRateInput = 0x1, + }; + unsigned flags = 0; + + /// Layouts for all tagged union types required by this entry point. + /// + /// These are any tagged union types used by the generic + /// arguments that this entry point is being compiled with. + List<RefPtr<TypeLayout>> taggedUnionTypeLayouts; +}; + +class GenericParamLayout : public Layout +{ +public: + RefPtr<GlobalGenericParamDecl> decl; + int index; +}; + +// Layout information for the global scope of a program +class ProgramLayout : public ScopeLayout +{ +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 `ParameterGroupTypeLayout`, + // 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<VarLayout> globalScopeLayout; + */ + + /// The target and program for which layout was computed + TargetProgram* targetProgram; + + TargetProgram* getTargetProgram() { return targetProgram; } + TargetRequest* getTargetReq() { return targetProgram->getTargetReq(); } + Program* getProgram() { return targetProgram->getProgram(); } + + + // We catalog the requested entry points here, + // and any entry-point-specific parameter data + // will (eventually) belong there... + List<RefPtr<EntryPointLayout>> entryPoints; + + List<RefPtr<GenericParamLayout>> globalGenericParams; + Dictionary<String, GenericParamLayout*> globalGenericParamsMap; +}; + +StructTypeLayout* getGlobalStructLayout( + ProgramLayout* programLayout); + +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, + + RawBuffer, + MutableRawBuffer, + + Buffer, + MutableBuffer, + + Texture, + MutableTexture, + + TextureSampler, + MutableTextureSampler, + + InputRenderTarget, + + SamplerState, + + Image, + MutableImage, + + RegisterSpace, +}; + +struct SimpleLayoutRulesImpl +{ + // Get size and alignment for a single value of base type. + virtual SimpleLayoutInfo GetScalarLayout(BaseType baseType) = 0; + + // Get size and alignment for an array of elements + virtual SimpleArrayLayoutInfo GetArrayLayout(SimpleLayoutInfo elementInfo, LayoutSize elementCount) = 0; + + // Get layout for a vector or matrix type + virtual SimpleLayoutInfo GetVectorLayout(SimpleLayoutInfo elementInfo, size_t elementCount) = 0; + virtual SimpleArrayLayoutInfo 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 LayoutSize 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); + } + + SimpleArrayLayoutInfo GetArrayLayout(SimpleLayoutInfo elementInfo, LayoutSize elementCount) + { + return simpleRules->GetArrayLayout(elementInfo, elementCount); + } + + SimpleLayoutInfo GetVectorLayout(SimpleLayoutInfo elementInfo, size_t elementCount) + { + return simpleRules->GetVectorLayout(elementInfo, elementCount); + } + + SimpleArrayLayoutInfo GetMatrixLayout(SimpleLayoutInfo elementInfo, size_t rowCount, size_t columnCount) + { + return simpleRules->GetMatrixLayout(elementInfo, rowCount, columnCount); + } + + UniformLayoutInfo BeginStructLayout() + { + return simpleRules->BeginStructLayout(); + } + + LayoutSize 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* getPushConstantBufferRules() = 0; + virtual LayoutRulesImpl* getTextureBufferRules() = 0; + virtual LayoutRulesImpl* getVaryingInputRules() = 0; + virtual LayoutRulesImpl* getVaryingOutputRules() = 0; + virtual LayoutRulesImpl* getSpecializationConstantRules()= 0; + virtual LayoutRulesImpl* getShaderStorageBufferRules() = 0; + virtual LayoutRulesImpl* getParameterBlockRules() = 0; + + virtual LayoutRulesImpl* getRayPayloadParameterRules() = 0; + virtual LayoutRulesImpl* getCallablePayloadParameterRules() = 0; + virtual LayoutRulesImpl* getHitAttributesParameterRules()= 0; + + virtual LayoutRulesImpl* getShaderRecordConstantBufferRules() = 0; +}; + +typedef List<RefPtr<GenericParamLayout>> GenericParamLayouts; + +struct TypeLayoutContext +{ + // The layout rules to use (e.g., we compute + // layout differently in a `cbuffer` vs. the + // parameter list of a fragment shader). + LayoutRulesImpl* rules; + + // The target request that is triggering layout + TargetRequest* targetReq; + + // A parent program layout that will establish the ordering + // of all global generic type parameters. + // + ProgramLayout* programLayout; + + // Whether to lay out matrices column-major + // or row-major. + MatrixLayoutMode matrixLayoutMode; + + // The concrete types (if any) to plug into the currently in-scope + // existential type slots. + // + Int existentialTypeArgCount = 0; + ExistentialTypeSlots::Arg const* existentialTypeArgs = nullptr; + + LayoutRulesImpl* getRules() { return rules; } + LayoutRulesFamilyImpl* getRulesFamily() const { return rules->getLayoutRulesFamily(); } + + TypeLayoutContext with(LayoutRulesImpl* inRules) const + { + TypeLayoutContext result = *this; + result.rules = inRules; + return result; + } + + TypeLayoutContext with(MatrixLayoutMode inMatrixLayoutMode) const + { + TypeLayoutContext result = *this; + result.matrixLayoutMode = inMatrixLayoutMode; + return result; + } + + TypeLayoutContext withExistentialTypeArgs( + Int argCount, + ExistentialTypeSlots::Arg const* args) const + { + TypeLayoutContext result = *this; + result.existentialTypeArgCount = argCount; + result.existentialTypeArgs = args; + return result; + } + + TypeLayoutContext withExistentialTypeSlotsOffsetBy( + Int offset) const + { + TypeLayoutContext result = *this; + if( existentialTypeArgCount > offset ) + { + result.existentialTypeArgCount = existentialTypeArgCount - offset; + result.existentialTypeArgs = existentialTypeArgs + offset; + } + else + { + result.existentialTypeArgCount = 0; + result.existentialTypeArgs = nullptr; + } + return result; + + } +}; + +// + + /// A custom tuple to capture the outputs of type layout +struct TypeLayoutResult +{ + /// The actual heap-allocated layout object with all the details + RefPtr<TypeLayout> layout; + + /// A simplified representation of layout information. + /// + /// This information is suitable for the case where a type only + /// consumes a single resource. + /// + SimpleLayoutInfo info; + + /// Default constructor. + TypeLayoutResult() + {} + + /// Construct a result from the given layout object and simple layout info. + TypeLayoutResult(RefPtr<TypeLayout> inLayout, SimpleLayoutInfo const& inInfo) + : layout(inLayout) + , info(inInfo) + {} +}; + + /// Helper type for building `struct` type layouts +struct StructTypeLayoutBuilder +{ +public: + /// Begin the layout process for `type`, using `rules` + void beginLayout( + Type* type, + LayoutRulesImpl* rules); + + /// Begin the layout process for `type`, using `rules`, if it hasn't already been begun. + /// + /// This functions allows for a `StructTypeLayoutBuilder` to be use lazily, + /// only allocating a type layout object if it is actaully needed. + /// + void beginLayoutIfNeeded( + Type* type, + LayoutRulesImpl* rules); + + /// Add a field to the struct type layout. + /// + /// One of the `beginLayout*()` functions must have been called previously. + /// + RefPtr<VarLayout> addField( + DeclRef<VarDeclBase> field, + TypeLayoutResult fieldResult); + + /// Add a field to the struct type layout. + /// + /// One of the `beginLayout*()` functions must have been called previously. + /// + RefPtr<VarLayout> addField( + DeclRef<VarDeclBase> field, + RefPtr<TypeLayout> fieldTypeLayout); + + /// Complete layout. + /// + /// If layout was begun, ensures that the result of `getTypeLayout()` is usable. + /// If layout was never begin, does nothing. + /// + void endLayout(); + + /// Get the type layout. + /// + /// This can be called any time after `beginLayout*()`. + /// In particular, it can be called before `endLayout`. + /// + RefPtr<StructTypeLayout> getTypeLayout(); + + /// The the type layout result. + /// + /// This is primarily useful for implementation code in `_createTypeLayout`. + /// + TypeLayoutResult getTypeLayoutResult(); + +private: + /// The layout rules being used, if layout has begun. + LayoutRulesImpl* m_rules = nullptr; + + /// The type layout being computed, if layout has begun. + RefPtr<StructTypeLayout> m_typeLayout; + + /// Uniform offset/alignment statte used when computing offset for uniform fields. + UniformLayoutInfo m_info; +}; + +// + +// Get an appropriate set of layout rules (packaged up +// as a `TypeLayoutContext`) to perform type layout +// for the given target. +// +// The provided `programLayout` is used to establish +// the ordering of all global generic type paramters. +// +TypeLayoutContext getInitialLayoutContextForTarget( + TargetRequest* targetReq, + ProgramLayout* programLayout); + + /// Direction(s) of a varying shader parameter +typedef unsigned int EntryPointParameterDirectionMask; +enum +{ + kEntryPointParameterDirection_Input = 0x1, + kEntryPointParameterDirection_Output = 0x2, +}; + + + /// Get layout information for a simple varying parameter type. + /// + /// A simple varying parameter is a scalar, vector, or matrix. + /// +RefPtr<TypeLayout> getSimpleVaryingParameterTypeLayout( + TypeLayoutContext const& context, + Type* type, + EntryPointParameterDirectionMask directionMask); + +// Create a full type-layout object for a type, +// according to the layout rules in `context`. +RefPtr<TypeLayout> createTypeLayout( + TypeLayoutContext const& context, + Type* type); + +// + + /// Create a layout for a parameter-group type (a `ConstantBuffer` or `ParameterBlock`). +RefPtr<TypeLayout> createParameterGroupTypeLayout( + TypeLayoutContext const& context, + RefPtr<ParameterGroupType> parameterGroupType); + + /// Create a wrapper constant buffer type layout, if needed. + /// + /// When dealing with entry-point `uniform` and global-scope parameters, + /// we want to create a wrapper constant buffer for all the parameters + /// if and only if there exist some parameters that use "ordinary" data + /// (`LayoutResourceKind::Uniform`). + /// + /// This function determines whether such a wrapper is needed, based + /// on the `elementTypeLayout` given, and either creates and returns + /// the layout for the wrapper, or the unmodified `elementTypeLayout`. + /// +RefPtr<TypeLayout> createConstantBufferTypeLayoutIfNeeded( + TypeLayoutContext const& context, + RefPtr<TypeLayout> elementTypeLayout); + +// Create a type layout for a structured buffer type. +RefPtr<StructuredBufferTypeLayout> +createStructuredBufferTypeLayout( + TypeLayoutContext const& context, + ShaderParameterKind kind, + RefPtr<Type> structuredBufferType, + RefPtr<Type> elementType); + +int findGenericParam(List<RefPtr<GenericParamLayout>> & genericParameters, GlobalGenericParamDecl * decl); +// + +// Given an existing type layout `oldTypeLayout`, apply offsets +// to any contained fields based on the resource infos in `offsetVarLayout`. +RefPtr<TypeLayout> applyOffsetToTypeLayout( + RefPtr<TypeLayout> oldTypeLayout, + RefPtr<VarLayout> offsetVarLayout); + +} + +#endif |
