diff options
Diffstat (limited to 'source/slang/type-layout.cpp')
| -rw-r--r-- | source/slang/type-layout.cpp | 913 |
1 files changed, 538 insertions, 375 deletions
diff --git a/source/slang/type-layout.cpp b/source/slang/type-layout.cpp index 6040df155..eefcfe1fd 100644 --- a/source/slang/type-layout.cpp +++ b/source/slang/type-layout.cpp @@ -120,12 +120,10 @@ struct DefaultLayoutRulesImpl : SimpleLayoutRulesImpl return vectorInfo; } - SimpleLayoutInfo GetMatrixLayout(SimpleLayoutInfo elementInfo, size_t rowCount, size_t columnCount) override + SimpleArrayLayoutInfo GetMatrixLayout(SimpleLayoutInfo elementInfo, size_t rowCount, size_t columnCount) override { // The default behavior here is to lay out a matrix - // as an array of column vectors (that is column-major). - // That is because this is the default convention - // used by HLSL. + // as an array of row vectors (that is row-major). // // In practice, the code that calls `GetMatrixLayout` will // potentially transpose the row/column counts in order @@ -880,26 +878,50 @@ bool IsResourceKind(LayoutResourceKind kind) } -SimpleLayoutInfo GetSimpleLayoutImpl( + /// 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) + {} +}; + + /// Create a type layout for a type that has simple layout needs. + /// + /// This handles any type that can express its layout in `SimpleLayoutInfo`, + /// and that only needs a `TypeLayout` and not a refined subclass. + /// +static TypeLayoutResult createSimpleTypeLayout( SimpleLayoutInfo info, RefPtr<Type> type, - LayoutRulesImpl* rules, - RefPtr<TypeLayout>* outTypeLayout) + LayoutRulesImpl* rules) { - if (outTypeLayout) - { - RefPtr<TypeLayout> typeLayout = new TypeLayout(); - *outTypeLayout = typeLayout; + RefPtr<TypeLayout> typeLayout = new TypeLayout(); - typeLayout->type = type; - typeLayout->rules = rules; + typeLayout->type = type; + typeLayout->rules = rules; - typeLayout->uniformAlignment = info.alignment; + typeLayout->uniformAlignment = info.alignment; - typeLayout->addResourceUsage(info.kind, info.size); - } + typeLayout->addResourceUsage(info.kind, info.size); - return info; + return TypeLayoutResult(typeLayout, info); } static SimpleLayoutInfo getParameterGroupLayoutInfo( @@ -1162,8 +1184,7 @@ RefPtr<TypeLayout> applyOffsetToTypeLayout( return newTypeLayout; } -RefPtr<ParameterGroupTypeLayout> -createParameterGroupTypeLayout( +static RefPtr<ParameterGroupTypeLayout> _createParameterGroupTypeLayout( TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, SimpleLayoutInfo parameterGroupInfo, @@ -1357,23 +1378,21 @@ createParameterGroupTypeLayout( return typeLayout; } -RefPtr<ParameterGroupTypeLayout> -createParameterGroupTypeLayout( +RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, LayoutRulesImpl* parameterGroupRules, SimpleLayoutInfo parameterGroupInfo, RefPtr<TypeLayout> elementTypeLayout) { - return createParameterGroupTypeLayout( + return _createParameterGroupTypeLayout( context.with(parameterGroupRules).with(context.targetReq->getDefaultMatrixLayoutMode()), parameterGroupType, parameterGroupInfo, elementTypeLayout); } -RefPtr<ParameterGroupTypeLayout> -createParameterGroupTypeLayout( +static RefPtr<ParameterGroupTypeLayout> _createParameterGroupTypeLayout( TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, RefPtr<Type> elementType, @@ -1408,7 +1427,7 @@ createParameterGroupTypeLayout( context.with(elementTypeRules), elementType); - return createParameterGroupTypeLayout( + return _createParameterGroupTypeLayout( context, parameterGroupType, info, @@ -1450,8 +1469,7 @@ LayoutRulesImpl* getParameterBufferElementTypeLayoutRules( } } -RefPtr<ParameterGroupTypeLayout> -createParameterGroupTypeLayout( +RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType) { @@ -1464,7 +1482,7 @@ createParameterGroupTypeLayout( auto elementType = parameterGroupType->elementType; - return createParameterGroupTypeLayout( + return _createParameterGroupTypeLayout( context, parameterGroupType, elementType, @@ -1519,7 +1537,7 @@ createStructuredBufferTypeLayout( LayoutRule::HLSLStructuredBuffer); // Create and save type layout for the buffer contents. - auto elementTypeLayout = CreateTypeLayout( + auto elementTypeLayout = createTypeLayout( context.with(structuredBufferLayoutRules), elementType.Ptr()); @@ -1531,21 +1549,41 @@ createStructuredBufferTypeLayout( } -SimpleLayoutInfo GetLayoutImpl( + /// Create layout information for the given `type`. + /// + /// This internal routine returns both the constructed type + /// layout object and the simple layout info, encapsulated + /// together as a `TypeLayoutResult`. + /// +static TypeLayoutResult _createTypeLayout( TypeLayoutContext const& context, - Type* type, - RefPtr<TypeLayout>* outTypeLayout); + Type* type); -SimpleLayoutInfo GetLayoutImpl( + /// Create layout information for the given `type`, obeying any layout modifiers on the given declaration. + /// + /// If `declForModifiers` has any matrix layout modifiers associated with it, then + /// the resulting type layout will respect those modifiers. + /// +static TypeLayoutResult _createTypeLayout( TypeLayoutContext const& context, Type* type, - RefPtr<TypeLayout>* outTypeLayout, Decl* declForModifiers) { TypeLayoutContext subContext = context; if (declForModifiers) { + // TODO: The approach implemented here has a row/column-major + // layout model recursively affect any sub-fields (so that + // the layout of a nested struct depends on the context where + // it is nested). This is consistent with the GLSL behavior + // for these modifiers, but it is *not* how HLSL is supposed + // to work. + // + // In the trivial case where `row_major` and `column_major` + // are only applied to leaf fields/variables of matrix type + // the difference should be immaterial. + if (declForModifiers->HasModifier<RowMajorLayoutModifier>()) subContext.matrixLayoutMode = kMatrixLayoutMode_RowMajor; @@ -1556,7 +1594,7 @@ SimpleLayoutInfo GetLayoutImpl( // layout, such as GLSL `std140`. } - return GetLayoutImpl(subContext, type, outTypeLayout); + return _createTypeLayout(subContext, type); } int findGenericParam(List<RefPtr<GenericParamLayout>> & genericParameters, GlobalGenericParamDecl * decl) @@ -1824,10 +1862,9 @@ static RefPtr<TypeLayout> maybeAdjustLayoutForArrayElementType( } } -SimpleLayoutInfo GetLayoutImpl( +static TypeLayoutResult _createTypeLayout( TypeLayoutContext const& context, - Type* type, - RefPtr<TypeLayout>* outTypeLayout) + Type* type) { auto rules = context.rules; @@ -1851,22 +1888,18 @@ SimpleLayoutInfo GetLayoutImpl( // the constant buffer, which need to be surfaces out // to the top level. // - if (outTypeLayout) - { - *outTypeLayout = createParameterGroupTypeLayout( - context, - parameterGroupType); - } + auto typeLayout = createParameterGroupTypeLayout( + context, + parameterGroupType); - return info; + return TypeLayoutResult(typeLayout, info); } else if (auto samplerStateType = as<SamplerStateType>(type)) { - return GetSimpleLayoutImpl( + return createSimpleTypeLayout( rules->GetObjectLayout(ShaderParameterKind::SamplerState), type, - rules, - outTypeLayout); + rules); } else if (auto textureType = as<TextureType>(type)) { @@ -1884,11 +1917,10 @@ SimpleLayoutInfo GetLayoutImpl( break; } - return GetSimpleLayoutImpl( + return createSimpleTypeLayout( rules->GetObjectLayout(kind), type, - rules, - outTypeLayout); + rules); } else if (auto imageType = as<GLSLImageType>(type)) { @@ -1906,11 +1938,10 @@ SimpleLayoutInfo GetLayoutImpl( break; } - return GetSimpleLayoutImpl( + return createSimpleTypeLayout( rules->GetObjectLayout(kind), type, - rules, - outTypeLayout); + rules); } else if (auto textureSamplerType = as<TextureSamplerType>(type)) { @@ -1928,26 +1959,22 @@ SimpleLayoutInfo GetLayoutImpl( break; } - return GetSimpleLayoutImpl( + return createSimpleTypeLayout( rules->GetObjectLayout(kind), type, - rules, - outTypeLayout); + rules); } // TODO: need a better way to handle this stuff... #define CASE(TYPE, KIND) \ - else if(auto type_##TYPE = as<TYPE>(type)) do { \ + else if(auto type_##TYPE = as<TYPE>(type)) do { \ auto info = rules->GetObjectLayout(ShaderParameterKind::KIND); \ - if (outTypeLayout) \ - { \ - *outTypeLayout = createStructuredBufferTypeLayout( \ + auto typeLayout = createStructuredBufferTypeLayout( \ context, \ ShaderParameterKind::KIND, \ type_##TYPE, \ type_##TYPE->elementType.Ptr()); \ - } \ - return info; \ + return TypeLayoutResult(typeLayout, info); \ } while(0) CASE(HLSLStructuredBufferType, StructuredBuffer); @@ -1962,9 +1989,9 @@ SimpleLayoutInfo GetLayoutImpl( // TODO: need a better way to handle this stuff... #define CASE(TYPE, KIND) \ else if(as<TYPE>(type)) do { \ - return GetSimpleLayoutImpl( \ + return createSimpleTypeLayout( \ rules->GetObjectLayout(ShaderParameterKind::KIND), \ - type, rules, outTypeLayout); \ + type, rules); \ } while(0) CASE(HLSLByteAddressBufferType, RawBuffer); @@ -1978,75 +2005,118 @@ SimpleLayoutInfo GetLayoutImpl( #undef CASE - // - // TODO(tfoley): Need to recognize any UAV types here - // else if(auto basicType = as<BasicExpressionType>(type)) { - return GetSimpleLayoutImpl( + return createSimpleTypeLayout( rules->GetScalarLayout(basicType->baseType), type, - rules, - outTypeLayout); + rules); } else if(auto vecType = as<VectorExpressionType>(type)) { - return GetSimpleLayoutImpl( - rules->GetVectorLayout( - GetLayout(context, vecType->elementType.Ptr()), - (size_t) GetIntVal(vecType->elementCount)), - type, - rules, - outTypeLayout); + auto elementType = vecType->elementType; + size_t elementCount = (size_t) GetIntVal(vecType->elementCount); + + auto element = _createTypeLayout( + context, + elementType); + + auto info = rules->GetVectorLayout(element.info, elementCount); + + RefPtr<VectorTypeLayout> typeLayout = new VectorTypeLayout(); + typeLayout->type = type; + typeLayout->rules = rules; + typeLayout->uniformAlignment = info.alignment; + + typeLayout->elementTypeLayout = element.layout; + typeLayout->uniformStride = element.info.getUniformLayout().size.getFiniteValue(); + + typeLayout->addResourceUsage(info.kind, info.size); + + return TypeLayoutResult(typeLayout, info); } else if(auto matType = as<MatrixExpressionType>(type)) { - // The `GetMatrixLayout` implementation in the layout rules - // currently defaults to assuming column-major layout, - // so if we want row-major layout we achieve it here by - // transposing the row/column counts. - // - // TODO: If it is really a universal convention that matrices - // are laid out just like arrays of vectors, when we can - // probably eliminate the `virtual` `GetLayout` method entirely, - // and have the code here be responsible for the layout choice. - // size_t rowCount = (size_t) GetIntVal(matType->getRowCount()); size_t colCount = (size_t) GetIntVal(matType->getColumnCount()); + + auto elementType = matType->getElementType(); + auto elementResult = _createTypeLayout( + context, + elementType); + auto elementTypeLayout = elementResult.layout; + auto elementInfo = elementResult.info; + + // The `GetMatrixLayout` implementation in the layout rules + // currently defaults to assuming row-major layout, + // so if we want column-major layout we achieve it here by + // transposing the major/minor axes counts. + // + size_t layoutMajorCount = rowCount; + size_t layoutMinorCount = colCount; if (context.matrixLayoutMode == kMatrixLayoutMode_ColumnMajor) { - size_t tmp = rowCount; - rowCount = colCount; - colCount = tmp; + size_t tmp = layoutMajorCount; + layoutMajorCount = layoutMinorCount; + layoutMinorCount = tmp; } - auto info = rules->GetMatrixLayout( - GetLayout(context, matType->getElementType()), - rowCount, + elementInfo, + layoutMajorCount, + layoutMinorCount); + + auto rowType = matType->getRowType(); + RefPtr<VectorTypeLayout> rowTypeLayout = new VectorTypeLayout(); + + auto rowInfo = rules->GetVectorLayout( + elementInfo, colCount); - if (outTypeLayout) + size_t majorStride = info.elementStride; + size_t minorStride = elementInfo.getUniformLayout().size.getFiniteValue(); + + size_t rowStride = 0; + size_t colStride = 0; + if(context.matrixLayoutMode == kMatrixLayoutMode_ColumnMajor) { - RefPtr<MatrixTypeLayout> typeLayout = new MatrixTypeLayout(); - *outTypeLayout = typeLayout; + colStride = majorStride; + rowStride = minorStride; + } + else + { + rowStride = majorStride; + colStride = minorStride; + } - typeLayout->type = type; - typeLayout->rules = rules; - typeLayout->uniformAlignment = info.alignment; - typeLayout->mode = context.matrixLayoutMode; + rowTypeLayout->type = type; + rowTypeLayout->rules = rules; + rowTypeLayout->uniformAlignment = elementInfo.getUniformLayout().alignment; - typeLayout->addResourceUsage(info.kind, info.size); - } + rowTypeLayout->uniformStride = colStride; + rowTypeLayout->elementTypeLayout = elementTypeLayout; + rowTypeLayout->addResourceUsage(rowInfo.kind, rowInfo.size); - return info; + RefPtr<MatrixTypeLayout> typeLayout = new MatrixTypeLayout(); + + typeLayout->type = type; + typeLayout->rules = rules; + typeLayout->uniformAlignment = info.alignment; + + typeLayout->elementTypeLayout = rowTypeLayout; + typeLayout->uniformStride = rowStride; + typeLayout->mode = context.matrixLayoutMode; + + typeLayout->addResourceUsage(info.kind, info.size); + + return TypeLayoutResult(typeLayout, info); } else if (auto arrayType = as<ArrayExpressionType>(type)) { - RefPtr<TypeLayout> elementTypeLayout; - auto elementInfo = GetLayoutImpl( + auto elementResult = _createTypeLayout( context, - arrayType->baseType.Ptr(), - outTypeLayout ? &elementTypeLayout : nullptr); + arrayType->baseType.Ptr()); + auto elementInfo = elementResult.info; + auto elementTypeLayout = elementResult.layout; // To a first approximation, an array will usually be laid out // by taking the element's type layout and laying out `elementCount` @@ -2073,124 +2143,121 @@ SimpleLayoutInfo GetLayoutImpl( elementInfo, elementCount).getUniformLayout(); - if (outTypeLayout) - { - RefPtr<ArrayTypeLayout> typeLayout = new ArrayTypeLayout(); - *outTypeLayout = typeLayout; + RefPtr<ArrayTypeLayout> typeLayout = new ArrayTypeLayout(); - // Some parts of the array type layout object are easy to fill in: - typeLayout->type = type; - typeLayout->rules = rules; - typeLayout->originalElementTypeLayout = elementTypeLayout; - typeLayout->uniformAlignment = arrayUniformInfo.alignment; - typeLayout->uniformStride = arrayUniformInfo.elementStride; + // Some parts of the array type layout object are easy to fill in: + typeLayout->type = type; + typeLayout->rules = rules; + typeLayout->originalElementTypeLayout = elementTypeLayout; + typeLayout->uniformAlignment = arrayUniformInfo.alignment; + typeLayout->uniformStride = arrayUniformInfo.elementStride; - typeLayout->addResourceUsage(LayoutResourceKind::Uniform, arrayUniformInfo.size); + typeLayout->addResourceUsage(LayoutResourceKind::Uniform, arrayUniformInfo.size); + // + // The tricky part in constructing an array type layout comes when + // the element type is (or nests) a structure with resource-type + // fields, because in that case we need to perform AoS-to-SoA + // conversion as part of computing the final type layout, and + // we also need to pre-compute an "adjusted" element type + // layout that accounts for the striding that happens with + // resource-type contents. + // + // This complication is only made worse when we have to deal with + // unbounded-size arrays over such element types, since those + // resource-type fields will each end up consuming a full space + // in the resulting layout. + // + // The `maybeAdjustLayoutForArrayElementType` computes an "adjusted" + // type layout for the element type which takes the array stride into + // account. If it returns the same type layout that was passed in, + // then that means no adjustement took place. + // + // The `additionalSpacesNeededForAdjustedElementType` variable counts + // the number of additional register spaces that were consumed, + // in the case of an unbounded array. + // + UInt additionalSpacesNeededForAdjustedElementType = 0; + RefPtr<TypeLayout> adjustedElementTypeLayout = maybeAdjustLayoutForArrayElementType( + elementTypeLayout, + elementCount, + additionalSpacesNeededForAdjustedElementType); + + typeLayout->elementTypeLayout = adjustedElementTypeLayout; + + // We will now iterate over the resources consumed by the element + // type to compute how they contribute to the resource usage + // of the overall array type. + // + for( auto elementResourceInfo : elementTypeLayout->resourceInfos ) + { + // The uniform case was already handled above + if( elementResourceInfo.kind == LayoutResourceKind::Uniform ) + continue; + + LayoutSize arrayResourceCount = 0; + + // In almost all cases, the resources consumed by an array + // will be its element count times the resources consumed + // by its element type. // - // The tricky part in constructing an array type layout comes when - // the element type is (or nests) a structure with resource-type - // fields, because in that case we need to perform AoS-to-SoA - // conversion as part of computing the final type layout, and - // we also need to pre-compute an "adjusted" element type - // layout that accounts for the striding that happens with - // resource-type contents. - // - // This complication is only made worse when we have to deal with - // unbounded-size arrays over such element types, since those - // resource-type fields will each end up consuming a full space - // in the resulting layout. + // The first exception to this is arrays of resources when + // compiling to GLSL for Vulkan, where an entire array + // only consumes a single descriptor-table slot. // - // The `maybeAdjustLayoutForArrayElementType` computes an "adjusted" - // type layout for the element type which takes the array stride into - // account. If it returns the same type layout that was passed in, - // then that means no adjustement took place. + if (elementResourceInfo.kind == LayoutResourceKind::DescriptorTableSlot) + { + arrayResourceCount = elementResourceInfo.count; + } // - // The `additionalSpacesNeededForAdjustedElementType` variable counts - // the number of additional register spaces that were consumed, - // in the case of an unbounded array. + // The next big exception is when we are forming an unbounded-size + // array and the element type got "adjusted," because that means + // the array type will need to allocate full spaces for any resource-type + // fields in the element type. // - UInt additionalSpacesNeededForAdjustedElementType = 0; - RefPtr<TypeLayout> adjustedElementTypeLayout = maybeAdjustLayoutForArrayElementType( - elementTypeLayout, - elementCount, - additionalSpacesNeededForAdjustedElementType); - - typeLayout->elementTypeLayout = adjustedElementTypeLayout; - - // We will now iterate over the resources consumed by the element - // type to compute how they contribute to the resource usage - // of the overall array type. + // Note: we carefully carve things out so that the case of a simple + // array of resources does *not* lead to the element type being adjusted, + // so that this logic doesn't trigger and we instead handle it with + // the default logic below. // - for( auto elementResourceInfo : elementTypeLayout->resourceInfos ) + else if( + elementCount.isInfinite() + && adjustedElementTypeLayout != elementTypeLayout + && doesResourceRequireAdjustmentForArrayOfStructs(elementResourceInfo.kind) ) { - // The uniform case was already handled above - if( elementResourceInfo.kind == LayoutResourceKind::Uniform ) - continue; - - LayoutSize arrayResourceCount = 0; - - // In almost all cases, the resources consumed by an array - // will be its element count times the resources consumed - // by its element type. - // - // The first exception to this is arrays of resources when - // compiling to GLSL for Vulkan, where an entire array - // only consumes a single descriptor-table slot. - // - if (elementResourceInfo.kind == LayoutResourceKind::DescriptorTableSlot) - { - arrayResourceCount = elementResourceInfo.count; - } - // - // The next big exception is when we are forming an unbounded-size - // array and the element type got "adjusted," because that means - // the array type will need to allocate full spaces for any resource-type - // fields in the element type. - // - // Note: we carefully carve things out so that the case of a simple - // array of resources does *not* lead to the element type being adjusted, - // so that this logic doesn't trigger and we instead handle it with - // the default logic below. - // - else if( - elementCount.isInfinite() - && adjustedElementTypeLayout != elementTypeLayout - && doesResourceRequireAdjustmentForArrayOfStructs(elementResourceInfo.kind) ) - { - // We want to ignore resource types consumed by the element type - // that need adjustement if the array size is infinite, since - // we will be allocating whole spaces for that part of the - // element's resource usage. - } - else - { - arrayResourceCount = elementResourceInfo.count * elementCount; - } - - // Now that we've computed how the resource usage of the element type - // should contribute to the resource usage of the array, we can - // add in that resource usage. - // - typeLayout->addResourceUsage( - elementResourceInfo.kind, - arrayResourceCount); + // We want to ignore resource types consumed by the element type + // that need adjustement if the array size is infinite, since + // we will be allocating whole spaces for that part of the + // element's resource usage. } - - // The loop above to compute the resource usage of the array from its - // element type ignored any resource-type fields in an unbounded-size - // array if they would have been allocated as full register spaces. - // Those same fields were counted in `additionalSpacesNeededForAdjustedElementType`, - // and need to be added into the total resource usage for the array - // if we skipped them as part of the loop (which happens when - // we detect that the element type layout had been "adjusted"). - // - if( adjustedElementTypeLayout != elementTypeLayout ) + else { - typeLayout->addResourceUsage(LayoutResourceKind::RegisterSpace, additionalSpacesNeededForAdjustedElementType); + arrayResourceCount = elementResourceInfo.count * elementCount; } + + // Now that we've computed how the resource usage of the element type + // should contribute to the resource usage of the array, we can + // add in that resource usage. + // + typeLayout->addResourceUsage( + elementResourceInfo.kind, + arrayResourceCount); } - return arrayUniformInfo; + + // The loop above to compute the resource usage of the array from its + // element type ignored any resource-type fields in an unbounded-size + // array if they would have been allocated as full register spaces. + // Those same fields were counted in `additionalSpacesNeededForAdjustedElementType`, + // and need to be added into the total resource usage for the array + // if we skipped them as part of the loop (which happens when + // we detect that the element type layout had been "adjusted"). + // + if( adjustedElementTypeLayout != elementTypeLayout ) + { + typeLayout->addResourceUsage(LayoutResourceKind::RegisterSpace, additionalSpacesNeededForAdjustedElementType); + } + + return TypeLayoutResult(typeLayout, arrayUniformInfo); } else if (auto declRefType = as<DeclRefType>(type)) { @@ -2198,14 +2265,9 @@ SimpleLayoutInfo GetLayoutImpl( if (auto structDeclRef = declRef.as<StructDecl>()) { - RefPtr<StructTypeLayout> typeLayout; - if (outTypeLayout) - { - typeLayout = new StructTypeLayout(); - typeLayout->type = type; - typeLayout->rules = rules; - *outTypeLayout = typeLayout; - } + RefPtr<StructTypeLayout> typeLayout = new StructTypeLayout(); + typeLayout->type = type; + typeLayout->rules = rules; // The layout of a `struct` type is computed in the somewhat // obvious fashion by keeping a running counter of the resource @@ -2219,12 +2281,12 @@ SimpleLayoutInfo GetLayoutImpl( for (auto field : GetFields(structDeclRef)) { - RefPtr<TypeLayout> fieldTypeLayout; - UniformLayoutInfo fieldInfo = GetLayoutImpl( + TypeLayoutResult fieldResult = _createTypeLayout( context, GetType(field).Ptr(), - outTypeLayout ? &fieldTypeLayout : nullptr, - field.getDecl()).getUniformLayout(); + field.getDecl()); + RefPtr<TypeLayout> fieldTypeLayout = fieldResult.layout; + UniformLayoutInfo fieldInfo = fieldResult.info.getUniformLayout(); // Note: we don't add any zero-size fields // when computing structure layout, just @@ -2240,81 +2302,75 @@ SimpleLayoutInfo GetLayoutImpl( uniformOffset = rules->AddStructField(&info, fieldInfo); } - if (outTypeLayout) + // We need to create variable layouts + // for each field of the structure. + RefPtr<VarLayout> fieldLayout = new VarLayout(); + fieldLayout->varDecl = field; + fieldLayout->typeLayout = fieldTypeLayout; + typeLayout->fields.Add(fieldLayout); + typeLayout->mapVarToLayout.Add(field.getDecl(), fieldLayout); + + // Set up uniform offset information, if there is any uniform data in the field + if( fieldTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform) ) { - // If we are computing a complete layout, - // then we need to create variable layouts - // for each field of the structure. - RefPtr<VarLayout> fieldLayout = new VarLayout(); - fieldLayout->varDecl = field; - fieldLayout->typeLayout = fieldTypeLayout; - typeLayout->fields.Add(fieldLayout); - typeLayout->mapVarToLayout.Add(field.getDecl(), fieldLayout); - - // Set up uniform offset information, if there is any uniform data in the field - if( fieldTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform) ) - { - fieldLayout->AddResourceInfo(LayoutResourceKind::Uniform)->index = uniformOffset.getFiniteValue(); - } + fieldLayout->AddResourceInfo(LayoutResourceKind::Uniform)->index = uniformOffset.getFiniteValue(); + } - // Add offset information for any other resource kinds - for( auto fieldTypeResourceInfo : fieldTypeLayout->resourceInfos ) + // Add offset information for any other resource kinds + for( auto fieldTypeResourceInfo : fieldTypeLayout->resourceInfos ) + { + // Uniforms were dealt with above + if(fieldTypeResourceInfo.kind == LayoutResourceKind::Uniform) + continue; + + // We should not have already processed this resource type + SLANG_RELEASE_ASSERT(!fieldLayout->FindResourceInfo(fieldTypeResourceInfo.kind)); + + // The field will need offset information for this kind + auto fieldResourceInfo = fieldLayout->AddResourceInfo(fieldTypeResourceInfo.kind); + + // It is possible for a `struct` field to use an unbounded array + // type, and in the D3D case that would consume an unbounded number + // of registers. What is more, a single `struct` could have multiple + // such fields, or ordinary resource fields after an unbounded field. + // + // We handle this case by allocating a distinct register space for + // any field that consumes an unbounded amount of registers. + // + if( fieldTypeResourceInfo.count.isInfinite() ) { - // Uniforms were dealt with above - if(fieldTypeResourceInfo.kind == LayoutResourceKind::Uniform) - continue; - - // We should not have already processed this resource type - SLANG_RELEASE_ASSERT(!fieldLayout->FindResourceInfo(fieldTypeResourceInfo.kind)); - - // The field will need offset information for this kind - auto fieldResourceInfo = fieldLayout->AddResourceInfo(fieldTypeResourceInfo.kind); + // We need to add one register space to own the storage for this field. + // + auto structTypeSpaceResourceInfo = typeLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace); + auto spaceOffset = structTypeSpaceResourceInfo->count; + structTypeSpaceResourceInfo->count += 1; - // It is possible for a `struct` field to use an unbounded array - // type, and in the D3D case that would consume an unbounded number - // of registers. What is more, a single `struct` could have multiple - // such fields, or ordinary resource fields after an unbounded field. + // The field itself will record itself as having a zero offset into + // the chosen space. // - // We handle this case by allocating a distinct register space for - // any field that consumes an unbounded amount of registers. + fieldResourceInfo->space = spaceOffset.getFiniteValue(); + fieldResourceInfo->index = 0; + } + else + { + // In the case where the field consumes a finite number of slots, we + // can simply set its offset/index to the number of such slots consumed + // so far, and then increment the number of slots consumed by the + // `struct` type itself. // - if( fieldTypeResourceInfo.count.isInfinite() ) - { - // We need to add one register space to own the storage for this field. - // - auto structTypeSpaceResourceInfo = typeLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace); - auto spaceOffset = structTypeSpaceResourceInfo->count; - structTypeSpaceResourceInfo->count += 1; - - // The field itself will record itself as having a zero offset into - // the chosen space. - // - fieldResourceInfo->space = spaceOffset.getFiniteValue(); - fieldResourceInfo->index = 0; - } - else - { - // In the case where the field consumes a finite number of slots, we - // can simply set its offset/index to the number of such slots consumed - // so far, and then increment the number of slots consumed by the - // `struct` type itself. - // - auto structTypeResourceInfo = typeLayout->findOrAddResourceInfo(fieldTypeResourceInfo.kind); - fieldResourceInfo->index = structTypeResourceInfo->count.getFiniteValue(); - structTypeResourceInfo->count += fieldTypeResourceInfo.count; - } + auto structTypeResourceInfo = typeLayout->findOrAddResourceInfo(fieldTypeResourceInfo.kind); + fieldResourceInfo->index = structTypeResourceInfo->count.getFiniteValue(); + structTypeResourceInfo->count += fieldTypeResourceInfo.count; } } } rules->EndStructLayout(&info); - if (outTypeLayout) - { - typeLayout->uniformAlignment = info.alignment; - typeLayout->addResourceUsage(LayoutResourceKind::Uniform, info.size); - } - return info; + typeLayout->uniformAlignment = info.alignment; + typeLayout->addResourceUsage(LayoutResourceKind::Uniform, info.size); + + return TypeLayoutResult(typeLayout, info); } else if (auto globalGenParam = declRef.as<GlobalGenericParamDecl>()) { @@ -2322,18 +2378,16 @@ SimpleLayoutInfo GetLayoutImpl( info.alignment = 0; info.size = 0; info.kind = LayoutResourceKind::GenericResource; - if (outTypeLayout) - { - auto genParamTypeLayout = new GenericParamTypeLayout(); - // we should have already populated ProgramLayout::genericEntryPointParams list at this point, - // so we can find the index of this generic param decl in the list - genParamTypeLayout->type = type; - genParamTypeLayout->paramIndex = findGenericParam(context.programLayout->globalGenericParams, genParamTypeLayout->getGlobalGenericParamDecl()); - genParamTypeLayout->rules = rules; - genParamTypeLayout->findOrAddResourceInfo(LayoutResourceKind::GenericResource)->count += 1; - *outTypeLayout = genParamTypeLayout; - } - return info; + + auto genParamTypeLayout = new GenericParamTypeLayout(); + // we should have already populated ProgramLayout::genericEntryPointParams list at this point, + // so we can find the index of this generic param decl in the list + genParamTypeLayout->type = type; + genParamTypeLayout->paramIndex = findGenericParam(context.programLayout->globalGenericParams, genParamTypeLayout->getGlobalGenericParamDecl()); + genParamTypeLayout->rules = rules; + genParamTypeLayout->findOrAddResourceInfo(LayoutResourceKind::GenericResource)->count += 1; + + return TypeLayoutResult(genParamTypeLayout, info); } else if( auto simpleGenericParam = declRef.as<GenericTypeParamDecl>() ) { @@ -2350,12 +2404,10 @@ SimpleLayoutInfo GetLayoutImpl( // any parameters, even those that don't depend on // generics. // - SimpleLayoutInfo info; - return GetSimpleLayoutImpl( - info, + return createSimpleTypeLayout( + SimpleLayoutInfo(), type, - rules, - outTypeLayout); + rules); } else if( auto interfaceDeclRef = declRef.as<InterfaceDecl>() ) { @@ -2373,25 +2425,22 @@ SimpleLayoutInfo GetLayoutImpl( // represents the indirections needed to reference the // data to be referenced by this field. // - return GetSimpleLayoutImpl( + return createSimpleTypeLayout( SimpleLayoutInfo(LayoutResourceKind::ExistentialSlot, 1), type, - rules, - outTypeLayout); + rules); } } else if (auto errorType = as<ErrorType>(type)) { // An error type means that we encountered something we don't understand. // - // We should probalby inform the user with an error message here. + // We should probably inform the user with an error message here. - SimpleLayoutInfo info; - return GetSimpleLayoutImpl( - info, + return createSimpleTypeLayout( + SimpleLayoutInfo(), type, - rules, - outTypeLayout); + rules); } else if( auto taggedUnionType = as<TaggedUnionType>(type) ) { @@ -2408,47 +2457,34 @@ SimpleLayoutInfo GetLayoutImpl( // UniformLayoutInfo info(0, 1); - // If we are being asked to construct a full `TypeLayout` - // object, then we'll allocate it up front. - // - RefPtr<TaggedUnionTypeLayout> taggedUnionLayout; - if( outTypeLayout ) - { - taggedUnionLayout = new TaggedUnionTypeLayout(); - taggedUnionLayout->type = type; - taggedUnionLayout->rules = rules; - *outTypeLayout = taggedUnionLayout; - } + RefPtr<TaggedUnionTypeLayout> taggedUnionLayout = new TaggedUnionTypeLayout(); + taggedUnionLayout->type = type; + taggedUnionLayout->rules = rules; // Now we iterate over the case types and see if they // change our computed maximum size/alignement. // for( auto caseType : taggedUnionType->caseTypes ) { - RefPtr<TypeLayout> caseTypeLayout; - UniformLayoutInfo caseTypeInfo = GetLayoutImpl(context, caseType, outTypeLayout ? &caseTypeLayout : nullptr).getUniformLayout(); + auto caseTypeResult = _createTypeLayout(context, caseType); + RefPtr<TypeLayout> caseTypeLayout = caseTypeResult.layout; + UniformLayoutInfo caseTypeInfo = caseTypeResult.info.getUniformLayout(); info.size = maximum(info.size, caseTypeInfo.size); info.alignment = std::max(info.alignment, caseTypeInfo.alignment); - // If we are building a full `TypeLayout` we need to - // do a few more steps for each case type. + // We need to remember the layout of the case type + // on the final `TaggedUnionTypeLayout`. // - if( outTypeLayout ) - { - // We need to remember the layout of the case type - // on the final `TaggedUnionTypeLayout`. - // - taggedUnionLayout->caseTypeLayouts.Add(caseTypeLayout); + taggedUnionLayout->caseTypeLayouts.Add(caseTypeLayout); - // We also need to consider contributions for other - // resource kinds beyond uniform data. - // - for( auto caseResInfo : caseTypeLayout->resourceInfos ) - { - auto unionResInfo = taggedUnionLayout->findOrAddResourceInfo(caseResInfo.kind); - unionResInfo->count = maximum(unionResInfo->count, caseResInfo.count); - } + // We also need to consider contributions for other + // resource kinds beyond uniform data. + // + for( auto caseResInfo : caseTypeLayout->resourceInfos ) + { + auto unionResInfo = taggedUnionLayout->findOrAddResourceInfo(caseResInfo.kind); + unionResInfo->count = maximum(unionResInfo->count, caseResInfo.count); } } @@ -2467,10 +2503,7 @@ SimpleLayoutInfo GetLayoutImpl( auto tagInfo = context.rules->GetScalarLayout(BaseType::UInt); info.size = RoundToAlignment(info.size, tagInfo.alignment); - if( outTypeLayout ) - { - taggedUnionLayout->tagOffset = info.size; - } + taggedUnionLayout->tagOffset = info.size; info.size += tagInfo.size; info.alignment = std::max(info.alignment, tagInfo.alignment); @@ -2480,48 +2513,178 @@ SimpleLayoutInfo GetLayoutImpl( // we will make sure that its information on uniform layout // matches what we've computed in the `UniformLayoutInfo` we return. // - if( outTypeLayout ) - { - taggedUnionLayout->findOrAddResourceInfo(LayoutResourceKind::Uniform)->count = info.size; - taggedUnionLayout->uniformAlignment = info.alignment; - } + taggedUnionLayout->findOrAddResourceInfo(LayoutResourceKind::Uniform)->count = info.size; + taggedUnionLayout->uniformAlignment = info.alignment; - return info; + return TypeLayoutResult(taggedUnionLayout, info); } // catch-all case in case nothing matched - SLANG_ASSERT(!"unimplemented"); - SimpleLayoutInfo info; - return GetSimpleLayoutImpl( - info, + SLANG_ASSERT(!"unimplemented case in type layout"); + return createSimpleTypeLayout( + SimpleLayoutInfo(), type, - rules, - outTypeLayout); + rules); } -SimpleLayoutInfo GetLayout( - TypeLayoutContext const& context, - Type* inType) +RefPtr<TypeLayout> getSimpleVaryingParameterTypeLayout( + TypeLayoutContext const& context, + Type* type, + EntryPointParameterDirectionMask directionMask) { - return GetLayoutImpl(context, inType, nullptr); -} + auto rules = context.rules; -RefPtr<TypeLayout> createTypeLayout( - TypeLayoutContext const& context, - Type* type) -{ - RefPtr<TypeLayout> typeLayout; - GetLayoutImpl(context, type, &typeLayout); - return typeLayout; + // TODO: This logic should ideally share as much + // as possible with the `_createTypeLayout` function, + // to avoid duplication, but we also have to deal + // with the many ways in which varying parameter + // layout differs from non-varying layout. + + // We will compute resource consumption for the type + // as a varying input, output, or both/neither. + // To avoid duplication, we'll build an array that + // includes all the layout rules we need to apply. + // + int varyingRulesCount = 0; + LayoutRulesImpl* varyingRules[2]; + + if( directionMask & kEntryPointParameterDirection_Input ) + { + varyingRules[varyingRulesCount++] = context.getRulesFamily()->getVaryingInputRules(); + } + if( directionMask & kEntryPointParameterDirection_Output ) + { + varyingRules[varyingRulesCount++] = context.getRulesFamily()->getVaryingOutputRules(); + } + + if(auto basicType = as<BasicExpressionType>(type)) + { + auto baseType = basicType->baseType; + + RefPtr<TypeLayout> typeLayout = new TypeLayout(); + typeLayout->type = type; + typeLayout->rules = rules; + + for( int rr = 0; rr < varyingRulesCount; ++rr ) + { + auto info = varyingRules[rr]->GetScalarLayout(baseType); + typeLayout->addResourceUsage(info.kind, info.size); + } + + return typeLayout; + } + else if(auto vecType = as<VectorExpressionType>(type)) + { + auto elementType = vecType->elementType; + size_t elementCount = (size_t) GetIntVal(vecType->elementCount); + + BaseType elementBaseType = BaseType::Void; + if( auto elementBasicType = as<BasicExpressionType>(elementType) ) + { + elementBaseType = elementBasicType->baseType; + } + + // Note that we do *not* add any resource usage to the type + // layout for the element type, because we currently cannot count + // varying parameter usage at a granularity finer than + // individual "locations." + // + RefPtr<TypeLayout> elementTypeLayout = new TypeLayout(); + elementTypeLayout->type = elementType; + elementTypeLayout->rules = rules; + + RefPtr<VectorTypeLayout> typeLayout = new VectorTypeLayout(); + typeLayout->type = vecType; + typeLayout->rules = rules; + typeLayout->elementTypeLayout = elementTypeLayout; + + for( int rr = 0; rr < varyingRulesCount; ++rr ) + { + auto varyingRuleSet = varyingRules[rr]; + auto elementInfo = varyingRuleSet->GetScalarLayout(elementBaseType); + auto info = varyingRuleSet->GetVectorLayout(elementInfo, elementCount); + typeLayout->addResourceUsage(info.kind, info.size); + } + + return typeLayout; + } + else if(auto matType = as<MatrixExpressionType>(type)) + { + size_t rowCount = (size_t) GetIntVal(matType->getRowCount()); + size_t colCount = (size_t) GetIntVal(matType->getColumnCount()); + auto elementType = matType->getElementType(); + + BaseType elementBaseType = BaseType::Void; + if( auto elementBasicType = as<BasicExpressionType>(elementType) ) + { + elementBaseType = elementBasicType->baseType; + } + + // Just as for `_createTypeLayout`, we need to handle row- and + // column-major matrices differently, to ensure we get + // the expected layout. + // + // A varying parameter with row-major layout is effectively + // just an array of row vectors, while a column-major one + // is just an array of column vectors. + // + size_t layoutMajorCount = rowCount; + size_t layoutMinorCount = colCount; + if (context.matrixLayoutMode == kMatrixLayoutMode_ColumnMajor) + { + size_t tmp = layoutMajorCount; + layoutMajorCount = layoutMinorCount; + layoutMinorCount = tmp; + } + + RefPtr<TypeLayout> elementTypeLayout = new TypeLayout(); + elementTypeLayout->type = elementType; + elementTypeLayout->rules = rules; + + RefPtr<VectorTypeLayout> rowTypeLayout = new VectorTypeLayout(); + rowTypeLayout->type = matType->getRowType(); + rowTypeLayout->rules = rules; + rowTypeLayout->elementTypeLayout = elementTypeLayout; + + RefPtr<MatrixTypeLayout> typeLayout = new MatrixTypeLayout(); + typeLayout->type = type; + typeLayout->rules = rules; + typeLayout->elementTypeLayout = rowTypeLayout; + typeLayout->mode = context.matrixLayoutMode; + + for( int rr = 0; rr < varyingRulesCount; ++rr ) + { + auto varyingRuleSet = varyingRules[rr]; + auto elementInfo = varyingRuleSet->GetScalarLayout(elementBaseType); + + auto info = varyingRuleSet->GetMatrixLayout(elementInfo, layoutMajorCount, layoutMinorCount); + typeLayout->addResourceUsage(info.kind, info.size); + + if(context.matrixLayoutMode == kMatrixLayoutMode_RowMajor) + { + // For row-major matrices only, we can compute an effective + // resource usage for the row type. + auto rowInfo = varyingRuleSet->GetVectorLayout(elementInfo, colCount); + rowTypeLayout->addResourceUsage(rowInfo.kind, rowInfo.size); + } + } + + return typeLayout; + } + + // catch-all case in case nothing matched + SLANG_ASSERT(!"unimplemented case for varying parameter layout"); + return createSimpleTypeLayout( + SimpleLayoutInfo(), + type, + rules).layout; } -RefPtr<TypeLayout> CreateTypeLayout( +RefPtr<TypeLayout> createTypeLayout( TypeLayoutContext const& context, Type* type) { - RefPtr<TypeLayout> typeLayout; - GetLayoutImpl(context, type, &typeLayout); - return typeLayout; + return _createTypeLayout(context, type).layout; } RefPtr<TypeLayout> TypeLayout::unwrapArray() |
