[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:
Родитель
d63be91f5c
Коммит
2095fef62c
|
@ -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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче