|
@@ -34,7 +34,7 @@ inline void roundToPow2(uint32_t *val, uint32_t pow2) {
|
|
}
|
|
}
|
|
} // anonymous namespace
|
|
} // anonymous namespace
|
|
|
|
|
|
-uint32_t TypeTranslator::translateType(QualType type, bool decorateLayout,
|
|
|
|
|
|
+uint32_t TypeTranslator::translateType(QualType type, LayoutRule rule,
|
|
bool isRowMajor) {
|
|
bool isRowMajor) {
|
|
// We can only apply row_major to matrices or arrays of matrices.
|
|
// We can only apply row_major to matrices or arrays of matrices.
|
|
if (isRowMajor)
|
|
if (isRowMajor)
|
|
@@ -43,7 +43,7 @@ uint32_t TypeTranslator::translateType(QualType type, bool decorateLayout,
|
|
// Try to translate the canonical type first
|
|
// Try to translate the canonical type first
|
|
const auto canonicalType = type.getCanonicalType();
|
|
const auto canonicalType = type.getCanonicalType();
|
|
if (canonicalType != type)
|
|
if (canonicalType != type)
|
|
- return translateType(canonicalType, decorateLayout, isRowMajor);
|
|
|
|
|
|
+ return translateType(canonicalType, rule, isRowMajor);
|
|
|
|
|
|
// Primitive types
|
|
// Primitive types
|
|
{
|
|
{
|
|
@@ -70,7 +70,7 @@ uint32_t TypeTranslator::translateType(QualType type, bool decorateLayout,
|
|
|
|
|
|
// Typedefs
|
|
// Typedefs
|
|
if (const auto *typedefType = type->getAs<TypedefType>())
|
|
if (const auto *typedefType = type->getAs<TypedefType>())
|
|
- return translateType(typedefType->desugar(), decorateLayout, isRowMajor);
|
|
|
|
|
|
+ return translateType(typedefType->desugar(), rule, isRowMajor);
|
|
|
|
|
|
// Reference types
|
|
// Reference types
|
|
if (const auto *refType = type->getAs<ReferenceType>()) {
|
|
if (const auto *refType = type->getAs<ReferenceType>()) {
|
|
@@ -80,7 +80,7 @@ uint32_t TypeTranslator::translateType(QualType type, bool decorateLayout,
|
|
// We already pass function arguments via pointers to tempoary local
|
|
// We already pass function arguments via pointers to tempoary local
|
|
// variables. So it should be fine to drop the pointer type and treat it
|
|
// variables. So it should be fine to drop the pointer type and treat it
|
|
// as the underlying pointee type here.
|
|
// as the underlying pointee type here.
|
|
- return translateType(refType->getPointeeType(), decorateLayout, isRowMajor);
|
|
|
|
|
|
+ return translateType(refType->getPointeeType(), rule, isRowMajor);
|
|
}
|
|
}
|
|
|
|
|
|
// In AST, vector/matrix types are TypedefType of TemplateSpecializationType.
|
|
// In AST, vector/matrix types are TypedefType of TemplateSpecializationType.
|
|
@@ -126,21 +126,21 @@ uint32_t TypeTranslator::translateType(QualType type, bool decorateLayout,
|
|
// (ClassTemplateSpecializationDecl is a subclass of CXXRecordDecl, which is
|
|
// (ClassTemplateSpecializationDecl is a subclass of CXXRecordDecl, which is
|
|
// then a subclass of RecordDecl.) So we need to check them before checking
|
|
// then a subclass of RecordDecl.) So we need to check them before checking
|
|
// the general struct type.
|
|
// the general struct type.
|
|
- if (const auto id = translateResourceType(type))
|
|
|
|
|
|
+ if (const auto id = translateResourceType(type, rule))
|
|
return id;
|
|
return id;
|
|
|
|
|
|
// Collect all fields' types and names.
|
|
// Collect all fields' types and names.
|
|
llvm::SmallVector<uint32_t, 4> fieldTypes;
|
|
llvm::SmallVector<uint32_t, 4> fieldTypes;
|
|
llvm::SmallVector<llvm::StringRef, 4> fieldNames;
|
|
llvm::SmallVector<llvm::StringRef, 4> fieldNames;
|
|
for (const auto *field : decl->fields()) {
|
|
for (const auto *field : decl->fields()) {
|
|
- fieldTypes.push_back(translateType(field->getType(), decorateLayout,
|
|
|
|
|
|
+ fieldTypes.push_back(translateType(field->getType(), rule,
|
|
field->hasAttr<HLSLRowMajorAttr>()));
|
|
field->hasAttr<HLSLRowMajorAttr>()));
|
|
fieldNames.push_back(field->getName());
|
|
fieldNames.push_back(field->getName());
|
|
}
|
|
}
|
|
|
|
|
|
llvm::SmallVector<const Decoration *, 4> decorations;
|
|
llvm::SmallVector<const Decoration *, 4> decorations;
|
|
- if (decorateLayout) {
|
|
|
|
- decorations = getLayoutDecorations(decl);
|
|
|
|
|
|
+ if (rule != LayoutRule::Void) {
|
|
|
|
+ decorations = getLayoutDecorations(decl, rule);
|
|
}
|
|
}
|
|
|
|
|
|
return theBuilder.getStructType(fieldTypes, decl->getName(), fieldNames,
|
|
return theBuilder.getStructType(fieldTypes, decl->getName(), fieldNames,
|
|
@@ -149,15 +149,15 @@ uint32_t TypeTranslator::translateType(QualType type, bool decorateLayout,
|
|
|
|
|
|
if (const auto *arrayType = astContext.getAsConstantArrayType(type)) {
|
|
if (const auto *arrayType = astContext.getAsConstantArrayType(type)) {
|
|
const uint32_t elemType =
|
|
const uint32_t elemType =
|
|
- translateType(arrayType->getElementType(), decorateLayout, isRowMajor);
|
|
|
|
|
|
+ translateType(arrayType->getElementType(), rule, isRowMajor);
|
|
// TODO: handle extra large array size?
|
|
// TODO: handle extra large array size?
|
|
const auto size =
|
|
const auto size =
|
|
static_cast<uint32_t>(arrayType->getSize().getZExtValue());
|
|
static_cast<uint32_t>(arrayType->getSize().getZExtValue());
|
|
|
|
|
|
llvm::SmallVector<const Decoration *, 4> decorations;
|
|
llvm::SmallVector<const Decoration *, 4> decorations;
|
|
- if (decorateLayout) {
|
|
|
|
|
|
+ if (rule != LayoutRule::Void) {
|
|
uint32_t stride = 0;
|
|
uint32_t stride = 0;
|
|
- (void)getAlignmentAndSize(type, &stride, isRowMajor);
|
|
|
|
|
|
+ (void)getAlignmentAndSize(type, rule, isRowMajor, &stride);
|
|
decorations.push_back(
|
|
decorations.push_back(
|
|
Decoration::getArrayStride(*theBuilder.getSPIRVContext(), stride));
|
|
Decoration::getArrayStride(*theBuilder.getSPIRVContext(), stride));
|
|
}
|
|
}
|
|
@@ -362,7 +362,7 @@ uint32_t TypeTranslator::getComponentVectorType(QualType matrixType) {
|
|
}
|
|
}
|
|
|
|
|
|
llvm::SmallVector<const Decoration *, 4>
|
|
llvm::SmallVector<const Decoration *, 4>
|
|
-TypeTranslator::getLayoutDecorations(const DeclContext *decl) {
|
|
|
|
|
|
+TypeTranslator::getLayoutDecorations(const DeclContext *decl, LayoutRule rule) {
|
|
const auto spirvContext = theBuilder.getSPIRVContext();
|
|
const auto spirvContext = theBuilder.getSPIRVContext();
|
|
llvm::SmallVector<const Decoration *, 4> decorations;
|
|
llvm::SmallVector<const Decoration *, 4> decorations;
|
|
uint32_t offset = 0, index = 0;
|
|
uint32_t offset = 0, index = 0;
|
|
@@ -379,7 +379,7 @@ TypeTranslator::getLayoutDecorations(const DeclContext *decl) {
|
|
|
|
|
|
uint32_t memberAlignment = 0, memberSize = 0, stride = 0;
|
|
uint32_t memberAlignment = 0, memberSize = 0, stride = 0;
|
|
std::tie(memberAlignment, memberSize) =
|
|
std::tie(memberAlignment, memberSize) =
|
|
- getAlignmentAndSize(fieldType, &stride, isRowMajor);
|
|
|
|
|
|
+ getAlignmentAndSize(fieldType, rule, isRowMajor, &stride);
|
|
|
|
|
|
// Each structure-type member must have an Offset Decoration.
|
|
// Each structure-type member must have an Offset Decoration.
|
|
roundToPow2(&offset, memberAlignment);
|
|
roundToPow2(&offset, memberAlignment);
|
|
@@ -398,7 +398,7 @@ TypeTranslator::getLayoutDecorations(const DeclContext *decl) {
|
|
if (isMxNMatrix(fieldType)) {
|
|
if (isMxNMatrix(fieldType)) {
|
|
memberAlignment = memberSize = stride = 0;
|
|
memberAlignment = memberSize = stride = 0;
|
|
std::tie(memberAlignment, memberSize) =
|
|
std::tie(memberAlignment, memberSize) =
|
|
- getAlignmentAndSize(fieldType, &stride, isRowMajor);
|
|
|
|
|
|
+ getAlignmentAndSize(fieldType, rule, isRowMajor, &stride);
|
|
|
|
|
|
decorations.push_back(
|
|
decorations.push_back(
|
|
Decoration::getMatrixStride(*spirvContext, stride, index));
|
|
Decoration::getMatrixStride(*spirvContext, stride, index));
|
|
@@ -421,7 +421,7 @@ TypeTranslator::getLayoutDecorations(const DeclContext *decl) {
|
|
return decorations;
|
|
return decorations;
|
|
}
|
|
}
|
|
|
|
|
|
-uint32_t TypeTranslator::translateResourceType(QualType type) {
|
|
|
|
|
|
+uint32_t TypeTranslator::translateResourceType(QualType type, LayoutRule rule) {
|
|
const auto *recordType = type->getAs<RecordType>();
|
|
const auto *recordType = type->getAs<RecordType>();
|
|
assert(recordType);
|
|
assert(recordType);
|
|
const llvm::StringRef name = recordType->getDecl()->getName();
|
|
const llvm::StringRef name = recordType->getDecl()->getName();
|
|
@@ -453,6 +453,33 @@ uint32_t TypeTranslator::translateResourceType(QualType type) {
|
|
return theBuilder.getSamplerType();
|
|
return theBuilder.getSamplerType();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (name == "StructuredBuffer" || name == "RWStructuredBuffer") {
|
|
|
|
+ auto &context = *theBuilder.getSPIRVContext();
|
|
|
|
+ // StructureBuffer<S> will be translated into an OpTypeStruct with one
|
|
|
|
+ // field, which is an OpTypeRuntimeArray of OpTypeStruct (S).
|
|
|
|
+
|
|
|
|
+ const auto s = hlsl::GetHLSLResourceResultType(type);
|
|
|
|
+ const uint32_t structType = translateType(s, rule);
|
|
|
|
+ const auto structName = s->getAs<RecordType>()->getDecl()->getName();
|
|
|
|
+
|
|
|
|
+ llvm::SmallVector<const Decoration *, 4> decorations;
|
|
|
|
+ // The stride for the runtime array is the size of S.
|
|
|
|
+ uint32_t size = 0, stride = 0;
|
|
|
|
+ std::tie(std::ignore, size) =
|
|
|
|
+ getAlignmentAndSize(s, rule, /*isRowMajor*/ false, &stride);
|
|
|
|
+ decorations.push_back(Decoration::getArrayStride(context, size));
|
|
|
|
+ const uint32_t raType =
|
|
|
|
+ theBuilder.getRuntimeArrayType(structType, decorations);
|
|
|
|
+
|
|
|
|
+ decorations.clear();
|
|
|
|
+ decorations.push_back(Decoration::getOffset(context, 0, 0));
|
|
|
|
+ if (!name.startswith("RW"))
|
|
|
|
+ decorations.push_back(Decoration::getNonWritable(context, 0));
|
|
|
|
+ decorations.push_back(Decoration::getBufferBlock(context));
|
|
|
|
+ const std::string typeName = "type." + name.str() + "." + structName.str();
|
|
|
|
+ return theBuilder.getStructType(raType, typeName, {}, decorations);
|
|
|
|
+ }
|
|
|
|
+
|
|
// ByteAddressBuffer types.
|
|
// ByteAddressBuffer types.
|
|
if (name == "ByteAddressBuffer") {
|
|
if (name == "ByteAddressBuffer") {
|
|
return theBuilder.getByteAddressBufferType(/*isRW*/ false);
|
|
return theBuilder.getByteAddressBufferType(/*isRW*/ false);
|
|
@@ -503,8 +530,8 @@ TypeTranslator::translateSampledTypeToImageFormat(QualType sampledType) {
|
|
}
|
|
}
|
|
|
|
|
|
std::pair<uint32_t, uint32_t>
|
|
std::pair<uint32_t, uint32_t>
|
|
-TypeTranslator::getAlignmentAndSize(QualType type, uint32_t *stride,
|
|
|
|
- const bool isRowMajor) {
|
|
|
|
|
|
+TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
|
|
|
|
+ const bool isRowMajor, uint32_t *stride) {
|
|
// std140 layout rules:
|
|
// std140 layout rules:
|
|
|
|
|
|
// 1. If the member is a scalar consuming N basic machine units, the base
|
|
// 1. If the member is a scalar consuming N basic machine units, the base
|
|
@@ -555,10 +582,11 @@ TypeTranslator::getAlignmentAndSize(QualType type, uint32_t *stride,
|
|
// are laid out in order, according to rule (9).
|
|
// are laid out in order, according to rule (9).
|
|
const auto canonicalType = type.getCanonicalType();
|
|
const auto canonicalType = type.getCanonicalType();
|
|
if (canonicalType != type)
|
|
if (canonicalType != type)
|
|
- return getAlignmentAndSize(canonicalType, stride, isRowMajor);
|
|
|
|
|
|
+ return getAlignmentAndSize(canonicalType, rule, isRowMajor, stride);
|
|
|
|
|
|
if (const auto *typedefType = type->getAs<TypedefType>())
|
|
if (const auto *typedefType = type->getAs<TypedefType>())
|
|
- return getAlignmentAndSize(typedefType->desugar(), stride, isRowMajor);
|
|
|
|
|
|
+ return getAlignmentAndSize(typedefType->desugar(), rule, isRowMajor,
|
|
|
|
+ stride);
|
|
|
|
|
|
{ // Rule 1
|
|
{ // Rule 1
|
|
QualType ty = {};
|
|
QualType ty = {};
|
|
@@ -585,7 +613,7 @@ TypeTranslator::getAlignmentAndSize(QualType type, uint32_t *stride,
|
|
if (isVectorType(type, &elemType, &elemCount)) {
|
|
if (isVectorType(type, &elemType, &elemCount)) {
|
|
uint32_t size = 0;
|
|
uint32_t size = 0;
|
|
std::tie(std::ignore, size) =
|
|
std::tie(std::ignore, size) =
|
|
- getAlignmentAndSize(elemType, stride, isRowMajor);
|
|
|
|
|
|
+ getAlignmentAndSize(elemType, rule, isRowMajor, stride);
|
|
|
|
|
|
return {(elemCount == 3 ? 4 : elemCount) * size, elemCount * size};
|
|
return {(elemCount == 3 ? 4 : elemCount) * size, elemCount * size};
|
|
}
|
|
}
|
|
@@ -597,7 +625,7 @@ TypeTranslator::getAlignmentAndSize(QualType type, uint32_t *stride,
|
|
if (isMxNMatrix(type, &elemType, &rowCount, &colCount)) {
|
|
if (isMxNMatrix(type, &elemType, &rowCount, &colCount)) {
|
|
uint32_t alignment = 0, size = 0;
|
|
uint32_t alignment = 0, size = 0;
|
|
std::tie(alignment, std::ignore) =
|
|
std::tie(alignment, std::ignore) =
|
|
- getAlignmentAndSize(elemType, stride, isRowMajor);
|
|
|
|
|
|
+ getAlignmentAndSize(elemType, rule, isRowMajor, stride);
|
|
|
|
|
|
// Matrices are treated as arrays of vectors:
|
|
// Matrices are treated as arrays of vectors:
|
|
// The base alignment and array stride are set to match the base alignment
|
|
// The base alignment and array stride are set to match the base alignment
|
|
@@ -605,7 +633,9 @@ TypeTranslator::getAlignmentAndSize(QualType type, uint32_t *stride,
|
|
// up to the base alignment of a vec4.
|
|
// up to the base alignment of a vec4.
|
|
const uint32_t vecStorageSize = isRowMajor ? colCount : rowCount;
|
|
const uint32_t vecStorageSize = isRowMajor ? colCount : rowCount;
|
|
alignment *= (vecStorageSize == 3 ? 4 : vecStorageSize);
|
|
alignment *= (vecStorageSize == 3 ? 4 : vecStorageSize);
|
|
- roundToPow2(&alignment, kStd140Vec4Alignment);
|
|
|
|
|
|
+ if (rule == LayoutRule::GLSLStd140) {
|
|
|
|
+ roundToPow2(&alignment, kStd140Vec4Alignment);
|
|
|
|
+ }
|
|
*stride = alignment;
|
|
*stride = alignment;
|
|
size = (isRowMajor ? rowCount : colCount) * alignment;
|
|
size = (isRowMajor ? rowCount : colCount) * alignment;
|
|
|
|
|
|
@@ -621,7 +651,7 @@ TypeTranslator::getAlignmentAndSize(QualType type, uint32_t *stride,
|
|
for (const auto *field : structType->getDecl()->fields()) {
|
|
for (const auto *field : structType->getDecl()->fields()) {
|
|
uint32_t memberAlignment = 0, memberSize = 0;
|
|
uint32_t memberAlignment = 0, memberSize = 0;
|
|
std::tie(memberAlignment, memberSize) = getAlignmentAndSize(
|
|
std::tie(memberAlignment, memberSize) = getAlignmentAndSize(
|
|
- field->getType(), stride, field->hasAttr<HLSLRowMajorAttr>());
|
|
|
|
|
|
+ field->getType(), rule, field->hasAttr<HLSLRowMajorAttr>(), stride);
|
|
|
|
|
|
// The base alignment of the structure is N, where N is the largest
|
|
// The base alignment of the structure is N, where N is the largest
|
|
// base alignment value of any of its members...
|
|
// base alignment value of any of its members...
|
|
@@ -630,8 +660,10 @@ TypeTranslator::getAlignmentAndSize(QualType type, uint32_t *stride,
|
|
structSize += memberSize;
|
|
structSize += memberSize;
|
|
}
|
|
}
|
|
|
|
|
|
- // ... and rounded up to the base alignment of a vec4.
|
|
|
|
- roundToPow2(&maxAlignment, kStd140Vec4Alignment);
|
|
|
|
|
|
+ if (rule == LayoutRule::GLSLStd140) {
|
|
|
|
+ // ... and rounded up to the base alignment of a vec4.
|
|
|
|
+ roundToPow2(&maxAlignment, kStd140Vec4Alignment);
|
|
|
|
+ }
|
|
// The base offset of the member following the sub-structure is rounded up
|
|
// The base offset of the member following the sub-structure is rounded up
|
|
// to the next multiple of the base alignment of the structure.
|
|
// to the next multiple of the base alignment of the structure.
|
|
roundToPow2(&structSize, maxAlignment);
|
|
roundToPow2(&structSize, maxAlignment);
|
|
@@ -641,13 +673,15 @@ TypeTranslator::getAlignmentAndSize(QualType type, uint32_t *stride,
|
|
// Rule 4, 6, 8, and 10
|
|
// Rule 4, 6, 8, and 10
|
|
if (const auto *arrayType = astContext.getAsConstantArrayType(type)) {
|
|
if (const auto *arrayType = astContext.getAsConstantArrayType(type)) {
|
|
uint32_t alignment = 0, size = 0;
|
|
uint32_t alignment = 0, size = 0;
|
|
- std::tie(alignment, size) =
|
|
|
|
- getAlignmentAndSize(arrayType->getElementType(), stride, isRowMajor);
|
|
|
|
|
|
+ std::tie(alignment, size) = getAlignmentAndSize(arrayType->getElementType(),
|
|
|
|
+ rule, isRowMajor, stride);
|
|
|
|
|
|
- // The base alignment and array stride are set to match the base alignment
|
|
|
|
- // of a single array element, according to rules 1, 2, and 3, and rounded
|
|
|
|
- // up to the base alignment of a vec4.
|
|
|
|
- roundToPow2(&alignment, kStd140Vec4Alignment);
|
|
|
|
|
|
+ if (rule == LayoutRule::GLSLStd140) {
|
|
|
|
+ // The base alignment and array stride are set to match the base alignment
|
|
|
|
+ // of a single array element, according to rules 1, 2, and 3, and rounded
|
|
|
|
+ // up to the base alignment of a vec4.
|
|
|
|
+ roundToPow2(&alignment, kStd140Vec4Alignment);
|
|
|
|
+ }
|
|
// Need to round size up considering stride for scalar types
|
|
// Need to round size up considering stride for scalar types
|
|
roundToPow2(&size, alignment);
|
|
roundToPow2(&size, alignment);
|
|
*stride = size; // Use size instead of alignment here for Rule 10
|
|
*stride = size; // Use size instead of alignment here for Rule 10
|