[spirv] Add support for arrays of structured/byte buffers (#1257)

They are translated into, of course, (runtime) arrays of
structured/byte buffers.
This commit is contained in:
Lei Zhang 2018-05-03 13:36:09 -04:00 коммит произвёл GitHub
Родитель d63be91f5c
Коммит 2095fef62c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 89 добавлений и 22 удалений

Просмотреть файл

@ -578,6 +578,18 @@ HLSL Interpolation Modifier SPIR-V Decoration SPIR-V Capability
``sample`` ``Sample`` ``SampleRateShading``
=========================== ================= =====================
Arrays
------
Sized (either explicitly or implicitly) arrays are translated into SPIR-V
`OpTypeArray`. Unsized arrays are translated into `OpTypeRuntimeArray`.
Arrays, if used for external resources (residing in SPIR-V `Uniform` or
`UniformConstant` storage class), will need layout decorations like SPIR-V
`ArrayStride` decoration. For arrays of opaque types, e.g., HLSL textures
or samplers, we don't decorate with `ArrayStride` decorations since there is
no meaningful strides. Similarly for arrays of structured/byte buffers.
User-defined types
------------------

Просмотреть файл

@ -181,9 +181,11 @@ const DeclContext *isConstantTextureBufferDeclRef(const Expr *expr) {
/// Returns true if
/// * the given expr is an DeclRefExpr referencing a kind of structured or byte
/// buffer and it is non-alias one, or
/// buffer and it is non-alias one, or
/// * the given expr is an CallExpr returning a kind of structured or byte
/// buffer.
/// buffer.
/// * the given expr is an ArraySubscriptExpr referencing a kind of structured
/// or byte buffer.
///
/// Note: legalization specific code
bool isReferencingNonAliasStructuredOrByteBuffer(const Expr *expr) {
@ -195,6 +197,8 @@ bool isReferencingNonAliasStructuredOrByteBuffer(const Expr *expr) {
} else if (const auto *callExpr = dyn_cast<CallExpr>(expr)) {
if (TypeTranslator::isAKindOfStructuredOrByteBuffer(callExpr->getType()))
return true;
} else if (const auto *arrSubExpr = dyn_cast<ArraySubscriptExpr>(expr)) {
return isReferencingNonAliasStructuredOrByteBuffer(arrSubExpr->getBase());
}
return false;
}
@ -1258,11 +1262,16 @@ void SPIRVEmitter::doVarDecl(const VarDecl *decl) {
decl->getLocation());
}
if (const auto *arrayType =
astContext.getAsConstantArrayType(decl->getType())) {
if (TypeTranslator::isAKindOfStructuredOrByteBuffer(
arrayType->getElementType())) {
emitError("arrays of structured/byte buffers unsupported",
// Reject arrays of RW/append/consume structured buffers. They have assoicated
// counters, which are quite nasty to handle.
if (decl->getType()->isArrayType()) {
auto type = decl->getType();
do {
type = type->getAsArrayTypeUnsafe()->getElementType();
} while (type->isArrayType());
if (TypeTranslator::isRWAppendConsumeSBuffer(type)) {
emitError("arrays of RW/append/consume structured buffers unsupported",
decl->getLocation());
return;
}

Просмотреть файл

@ -623,10 +623,14 @@ uint32_t TypeTranslator::translateType(QualType type, LayoutRule rule) {
// Array type
if (const auto *arrayType = astContext.getAsArrayType(type)) {
const uint32_t elemType = translateType(arrayType->getElementType(), rule);
const auto elemType = arrayType->getElementType();
const uint32_t elemTypeId = translateType(elemType, rule);
llvm::SmallVector<const Decoration *, 4> decorations;
if (rule != LayoutRule::Void) {
if (rule != LayoutRule::Void &&
// We won't have stride information for structured/byte buffers since
// they contain runtime arrays.
!isAKindOfStructuredOrByteBuffer(elemType)) {
uint32_t stride = 0;
(void)getAlignmentAndSize(type, rule, &stride);
decorations.push_back(
@ -636,7 +640,7 @@ uint32_t TypeTranslator::translateType(QualType type, LayoutRule rule) {
if (const auto *caType = astContext.getAsConstantArrayType(type)) {
const auto size = static_cast<uint32_t>(caType->getSize().getZExtValue());
return theBuilder.getArrayType(
elemType, theBuilder.getConstantUint32(size), decorations);
elemTypeId, theBuilder.getConstantUint32(size), decorations);
} else {
assert(type->isIncompleteArrayType());
// Runtime arrays of resources needs additional capability.
@ -646,7 +650,7 @@ uint32_t TypeTranslator::translateType(QualType type, LayoutRule rule) {
theBuilder.requireCapability(
spv::Capability::RuntimeDescriptorArrayEXT);
}
return theBuilder.getRuntimeArrayType(elemType, decorations);
return theBuilder.getRuntimeArrayType(elemTypeId, decorations);
}
}
@ -760,6 +764,10 @@ bool TypeTranslator::isRWAppendConsumeSBuffer(QualType type) {
}
bool TypeTranslator::isAKindOfStructuredOrByteBuffer(QualType type) {
// Strip outer arrayness first
while (type->isArrayType())
type = type->getAsArrayTypeUnsafe()->getElementType();
if (const RecordType *recordType = type->getAs<RecordType>()) {
StringRef name = recordType->getDecl()->getName();
return name == "StructuredBuffer" || name == "RWStructuredBuffer" ||

Просмотреть файл

@ -5,18 +5,12 @@ struct T {
float3 b;
};
StructuredBuffer<T> myStructuredBuffer[3];
RWStructuredBuffer<T> myRWStructuredBuffer[4];
AppendStructuredBuffer<T> myAppendStructuredBuffer[2];
AppendStructuredBuffer<T> myAppendStructuredBuffer[];
ConsumeStructuredBuffer<T> myConsumeStructuredBuffer[2];
ByteAddressBuffer myBAB[2];
RWByteAddressBuffer myRWBAB[2];
void main() {}
// CHECK: :8:21: error: arrays of structured/byte buffers unsupported
// CHECK: :9:23: error: arrays of structured/byte buffers unsupported
// CHECK: :10:27: error: arrays of structured/byte buffers unsupported
// CHECK: :11:28: error: arrays of structured/byte buffers unsupported
// CHECK: :12:19: error: arrays of structured/byte buffers unsupported
// CHECK: :13:21: error: arrays of structured/byte buffers unsupported
// CHECK: :8:23: error: arrays of RW/append/consume structured buffers unsupported
// CHECK: :9:27: error: arrays of RW/append/consume structured buffers unsupported
// CHECK: :10:28: error: arrays of RW/append/consume structured buffers unsupported

Просмотреть файл

@ -0,0 +1,41 @@
// Run: %dxc -T ps_6_0 -E main
// CHECK: %_runtimearr_v4float = OpTypeRuntimeArray %v4float
// CHECK: %type_StructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float
// CHECK: %_arr_type_StructuredBuffer_v4float_uint_8 = OpTypeArray %type_StructuredBuffer_v4float %uint_8
// CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
// CHECK: %type_ByteAddressBuffer = OpTypeStruct %_runtimearr_uint
// CHECK: %_runtimearr_type_ByteAddressBuffer = OpTypeRuntimeArray %type_ByteAddressBuffer
// CHECK: %type_RWByteAddressBuffer = OpTypeStruct %_runtimearr_uint
// CHECK: %_arr_type_RWByteAddressBuffer_uint_4 = OpTypeArray %type_RWByteAddressBuffer %uint_4
// CHECK: %MySBuffer = OpVariable %_ptr_Uniform__arr_type_StructuredBuffer_v4float_uint_8 Uniform
StructuredBuffer<float4> MySBuffer[8];
// CHECK: %MyBABuffer = OpVariable %_ptr_Uniform__runtimearr_type_ByteAddressBuffer Uniform
ByteAddressBuffer MyBABuffer[];
// CHECK: %MyRWBABuffer = OpVariable %_ptr_Uniform__arr_type_RWByteAddressBuffer_uint_4 Uniform
RWByteAddressBuffer MyRWBABuffer[4];
float4 main(uint index : INDEX) : SV_Target {
// CHECK: [[ptr:%\d+]] = OpAccessChain %_ptr_Uniform_type_ByteAddressBuffer %MyBABuffer {{%\d+}}
// CHECK: OpAccessChain %_ptr_Uniform_uint [[ptr]] %uint_0 {{%\d+}}
uint val1 = MyBABuffer[index].Load(index);
// CHECK: [[ptr:%\d+]] = OpAccessChain %_ptr_Uniform_type_RWByteAddressBuffer %MyRWBABuffer {{%\d+}}
// CHECK: OpAccessChain %_ptr_Uniform_uint [[ptr]] %uint_0 {{%\d+}}
MyRWBABuffer[index].Store(index, val1);
// CHECK: [[ptr:%\d+]] = OpAccessChain %_ptr_Uniform_type_StructuredBuffer_v4float %MySBuffer {{%\d+}}
// CHECK: OpStore %localSBuffer [[ptr]]
StructuredBuffer<float4> localSBuffer = MySBuffer[index];
// CHECK: [[ptr:%\d+]] = OpLoad %_ptr_Uniform_type_StructuredBuffer_v4float %localSBuffer
// CHECK: OpAccessChain %_ptr_Uniform_v4float [[ptr]] %int_0 {{%\d+}}
float4 val2 = localSBuffer[index];
return val1 * val2;
}

Просмотреть файл

@ -69,7 +69,10 @@ TEST_F(FileTest, TextureBufferType) { runFileTest("type.texture-buffer.hlsl"); }
TEST_F(FileTest, StructuredBufferType) {
runFileTest("type.structured-buffer.hlsl");
}
TEST_F(FileTest, StructuredBufferArrayTypeError) {
TEST_F(FileTest, StructuredByteBufferArray) {
runFileTest("type.structured-buffer.array.hlsl");
}
TEST_F(FileTest, StructuredByteBufferArrayError) {
runFileTest("type.structured-buffer.array.error.hlsl", Expect::Failure);
}
TEST_F(FileTest, AppendStructuredBufferType) {