[spirv] Support TextureBuffer/ConstantBuffer arrays. (#1166)
This commit is contained in:
Родитель
66a8998f87
Коммит
3c511a0959
|
@ -469,9 +469,10 @@ uint32_t DeclResultIdMapper::getMatrixStructType(const VarDecl *matVar,
|
|||
structName, {}, decorations);
|
||||
}
|
||||
|
||||
uint32_t DeclResultIdMapper::createVarOfExplicitLayoutStruct(
|
||||
const DeclContext *decl, const ContextUsageKind usageKind,
|
||||
llvm::StringRef typeName, llvm::StringRef varName) {
|
||||
uint32_t DeclResultIdMapper::createStructOrStructArrayVarOfExplicitLayout(
|
||||
const DeclContext *decl, uint32_t arraySize,
|
||||
const ContextUsageKind usageKind, llvm::StringRef typeName,
|
||||
llvm::StringRef varName) {
|
||||
// cbuffers are translated into OpTypeStruct with Block decoration.
|
||||
// tbuffers are translated into OpTypeStruct with BufferBlock decoration.
|
||||
// PushConstants are translated into OpTypeStruct with Block decoration.
|
||||
|
@ -525,26 +526,32 @@ uint32_t DeclResultIdMapper::createVarOfExplicitLayoutStruct(
|
|||
}
|
||||
|
||||
// Get the type for the whole struct
|
||||
const uint32_t structType =
|
||||
uint32_t resultType =
|
||||
theBuilder.getStructType(fieldTypes, typeName, fieldNames, decorations);
|
||||
|
||||
// Make an array if requested.
|
||||
if (arraySize)
|
||||
resultType = theBuilder.getArrayType(
|
||||
resultType, theBuilder.getConstantUint32(arraySize));
|
||||
|
||||
// Register the <type-id> for this decl
|
||||
ctBufferPCTypeIds[decl] = structType;
|
||||
ctBufferPCTypeIds[decl] = resultType;
|
||||
|
||||
const auto sc = usageKind == ContextUsageKind::PushConstant
|
||||
? spv::StorageClass::PushConstant
|
||||
: spv::StorageClass::Uniform;
|
||||
|
||||
// Create the variable for the whole struct
|
||||
return theBuilder.addModuleVar(structType, sc, varName);
|
||||
// Create the variable for the whole struct / struct array.
|
||||
return theBuilder.addModuleVar(resultType, sc, varName);
|
||||
}
|
||||
|
||||
uint32_t DeclResultIdMapper::createCTBuffer(const HLSLBufferDecl *decl) {
|
||||
const auto usageKind =
|
||||
decl->isCBuffer() ? ContextUsageKind::CBuffer : ContextUsageKind::TBuffer;
|
||||
const std::string structName = "type." + decl->getName().str();
|
||||
const uint32_t bufferVar = createVarOfExplicitLayoutStruct(
|
||||
decl, usageKind, structName, decl->getName());
|
||||
// The front-end does not allow arrays of cbuffer/tbuffer.
|
||||
const uint32_t bufferVar = createStructOrStructArrayVarOfExplicitLayout(
|
||||
decl, /*arraySize*/ 0, usageKind, structName, decl->getName());
|
||||
|
||||
// We still register all VarDecls seperately here. All the VarDecls are
|
||||
// mapped to the <result-id> of the buffer object, which means when querying
|
||||
|
@ -572,6 +579,16 @@ uint32_t DeclResultIdMapper::createCTBuffer(const HLSLBufferDecl *decl) {
|
|||
|
||||
uint32_t DeclResultIdMapper::createCTBuffer(const VarDecl *decl) {
|
||||
const auto *recordType = decl->getType()->getAs<RecordType>();
|
||||
uint32_t arraySize = 0;
|
||||
|
||||
// In case we have an array of ConstantBuffer/TextureBuffer:
|
||||
if (!recordType) {
|
||||
if (const auto *arrayType =
|
||||
astContext.getAsConstantArrayType(decl->getType())) {
|
||||
recordType = arrayType->getElementType()->getAs<RecordType>();
|
||||
arraySize = static_cast<uint32_t>(arrayType->getSize().getZExtValue());
|
||||
}
|
||||
}
|
||||
assert(recordType);
|
||||
const auto *context = cast<HLSLBufferDecl>(decl->getDeclContext());
|
||||
const auto usageKind = context->isCBuffer() ? ContextUsageKind::CBuffer
|
||||
|
@ -581,8 +598,9 @@ uint32_t DeclResultIdMapper::createCTBuffer(const VarDecl *decl) {
|
|||
context->isCBuffer() ? "ConstantBuffer." : "TextureBuffer.";
|
||||
const std::string structName = "type." + std::string(ctBufferName) +
|
||||
recordType->getDecl()->getName().str();
|
||||
const uint32_t bufferVar = createVarOfExplicitLayoutStruct(
|
||||
recordType->getDecl(), usageKind, structName, decl->getName());
|
||||
|
||||
const uint32_t bufferVar = createStructOrStructArrayVarOfExplicitLayout(
|
||||
recordType->getDecl(), arraySize, usageKind, structName, decl->getName());
|
||||
|
||||
// We register the VarDecl here.
|
||||
astDecls[decl] =
|
||||
|
@ -598,14 +616,15 @@ uint32_t DeclResultIdMapper::createCTBuffer(const VarDecl *decl) {
|
|||
}
|
||||
|
||||
uint32_t DeclResultIdMapper::createPushConstant(const VarDecl *decl) {
|
||||
// The front-end errors out if non-struct type push constant is used.
|
||||
const auto *recordType = decl->getType()->getAs<RecordType>();
|
||||
assert(recordType);
|
||||
|
||||
const std::string structName =
|
||||
"type.PushConstant." + recordType->getDecl()->getName().str();
|
||||
const uint32_t var = createVarOfExplicitLayoutStruct(
|
||||
recordType->getDecl(), ContextUsageKind::PushConstant, structName,
|
||||
decl->getName());
|
||||
const uint32_t var = createStructOrStructArrayVarOfExplicitLayout(
|
||||
recordType->getDecl(), /*arraySize*/ 0, ContextUsageKind::PushConstant,
|
||||
structName, decl->getName());
|
||||
|
||||
// Register the VarDecl
|
||||
astDecls[decl] = SpirvEvalInfo(var)
|
||||
|
@ -622,8 +641,9 @@ void DeclResultIdMapper::createGlobalsCBuffer(const VarDecl *var) {
|
|||
return;
|
||||
|
||||
const auto *context = var->getDeclContext();
|
||||
const uint32_t globals = createVarOfExplicitLayoutStruct(
|
||||
context, ContextUsageKind::Globals, "type.$Globals", "$Globals");
|
||||
const uint32_t globals = createStructOrStructArrayVarOfExplicitLayout(
|
||||
context, /*arraySize*/ 0, ContextUsageKind::Globals, "type.$Globals",
|
||||
"$Globals");
|
||||
|
||||
resourceVars.emplace_back(globals, ResourceVar::Category::Other, nullptr,
|
||||
nullptr, nullptr);
|
||||
|
|
|
@ -527,10 +527,9 @@ private:
|
|||
/// depending on the usage kind.
|
||||
///
|
||||
/// Panics if the DeclContext is neither HLSLBufferDecl or RecordDecl.
|
||||
uint32_t createVarOfExplicitLayoutStruct(const DeclContext *decl,
|
||||
ContextUsageKind usageKind,
|
||||
llvm::StringRef typeName,
|
||||
llvm::StringRef varName);
|
||||
uint32_t createStructOrStructArrayVarOfExplicitLayout(
|
||||
const DeclContext *decl, uint32_t arraySize, ContextUsageKind usageKind,
|
||||
llvm::StringRef typeName, llvm::StringRef varName);
|
||||
|
||||
/// A struct containing information about a particular HLSL semantic.
|
||||
struct SemanticInfo {
|
||||
|
|
|
@ -1194,6 +1194,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",
|
||||
decl->getLocation());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (decl->hasAttr<VKConstantIdAttr>()) {
|
||||
// This is a VarDecl for specialization constant.
|
||||
createSpecConstant(decl);
|
||||
|
|
|
@ -14,23 +14,40 @@ struct T {
|
|||
|
||||
|
||||
ConstantBuffer<T> MyCbuffer : register(b1);
|
||||
ConstantBuffer<T> MyCbufferArray[5] : register(b2);
|
||||
|
||||
float main() : A {
|
||||
// CHECK: [[a:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[a]]
|
||||
float main() : A{
|
||||
// CHECK: [[a:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[a]]
|
||||
|
||||
// CHECK: [[b:%\d+]] = OpAccessChain %_ptr_Uniform_v2float %MyCbuffer %int_1
|
||||
// CHECK-NEXT: [[b0:%\d+]] = OpAccessChain %_ptr_Uniform_float [[b]] %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[b0]]
|
||||
// CHECK: [[b:%\d+]] = OpAccessChain %_ptr_Uniform_v2float %MyCbuffer %int_1
|
||||
// CHECK-NEXT: [[b0:%\d+]] = OpAccessChain %_ptr_Uniform_float [[b]] %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[b0]]
|
||||
|
||||
// CHECK: [[c12:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_2 %uint_1 %uint_2
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[c12]]
|
||||
// CHECK: [[c12:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_2 %uint_1 %uint_2
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[c12]]
|
||||
|
||||
// CHECK: [[s:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_3 %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[s]]
|
||||
// CHECK: [[s:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_3 %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[s]]
|
||||
|
||||
// CHECK: [[t:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_4 %int_3
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[t]]
|
||||
return MyCbuffer.a + MyCbuffer.b.x + MyCbuffer.c[1][2] + MyCbuffer.s.f + MyCbuffer.t[3] +
|
||||
// CHECK: [[a:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbufferArray %int_4 %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[a]]
|
||||
|
||||
// CHECK: [[b:%\d+]] = OpAccessChain %_ptr_Uniform_v2float %MyCbufferArray %int_3 %int_1
|
||||
// CHECK-NEXT: [[b0:%\d+]] = OpAccessChain %_ptr_Uniform_float [[b]] %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[b0]]
|
||||
|
||||
// CHECK: [[c12:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbufferArray %int_2 %int_2 %uint_1 %uint_2
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[c12]]
|
||||
|
||||
// CHECK: [[s:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbufferArray %int_1 %int_3 %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[s]]
|
||||
|
||||
// CHECK: [[t:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbufferArray %int_0 %int_4 %int_3
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[t]]
|
||||
MyCbufferArray[4].a + MyCbufferArray[3].b.x + MyCbufferArray[2].c[1][2] + MyCbufferArray[1].s.f + MyCbufferArray[0].t[3];
|
||||
|
||||
// CHECK: [[t:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_4 %int_3
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[t]]
|
||||
return MyCbuffer.a + MyCbuffer.b.x + MyCbuffer.c[1][2] + MyCbuffer.s.f + MyCbuffer.t[3];
|
||||
}
|
||||
|
||||
|
|
|
@ -14,22 +14,39 @@ struct T {
|
|||
|
||||
|
||||
TextureBuffer<T> MyTB : register(t1);
|
||||
TextureBuffer<T> MyTBArray[5] : register(t2);
|
||||
|
||||
float main() : A {
|
||||
// CHECK: [[a:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyTB %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[a]]
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[a]]
|
||||
|
||||
// CHECK: [[b:%\d+]] = OpAccessChain %_ptr_Uniform_v2float %MyTB %int_1
|
||||
// CHECK: [[b:%\d+]] = OpAccessChain %_ptr_Uniform_v2float %MyTB %int_1
|
||||
// CHECK-NEXT: [[b0:%\d+]] = OpAccessChain %_ptr_Uniform_float [[b]] %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[b0]]
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[b0]]
|
||||
|
||||
// CHECK: [[c12:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyTB %int_2 %uint_1 %uint_2
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[c12]]
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[c12]]
|
||||
|
||||
// CHECK: [[s:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyTB %int_3 %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[s]]
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[s]]
|
||||
|
||||
// CHECK: [[t:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyTB %int_4 %int_3
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[t]]
|
||||
return MyTB.a + MyTB.b.x + MyTB.c[1][2] + MyTB.s.f + MyTB.t[3];
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[t]]
|
||||
return MyTB.a + MyTB.b.x + MyTB.c[1][2] + MyTB.s.f + MyTB.t[3] +
|
||||
// CHECK: [[a:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyTBArray %int_4 %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[a]]
|
||||
|
||||
// CHECK: [[b:%\d+]] = OpAccessChain %_ptr_Uniform_v2float %MyTBArray %int_3 %int_1
|
||||
// CHECK-NEXT: [[b0:%\d+]] = OpAccessChain %_ptr_Uniform_float [[b]] %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[b0]]
|
||||
|
||||
// CHECK: [[c12:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyTBArray %int_2 %int_2 %uint_1 %uint_2
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[c12]]
|
||||
|
||||
// CHECK: [[s:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyTBArray %int_1 %int_3 %int_0
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[s]]
|
||||
|
||||
// CHECK: [[t:%\d+]] = OpAccessChain %_ptr_Uniform_float %MyTBArray %int_0 %int_4 %int_3
|
||||
// CHECK-NEXT: {{%\d+}} = OpLoad %float [[t]]
|
||||
MyTBArray[4].a + MyTBArray[3].b.x + MyTBArray[2].c[1][2] + MyTBArray[1].s.f + MyTBArray[0].t[3];
|
||||
}
|
||||
|
|
|
@ -10,13 +10,15 @@
|
|||
|
||||
// CHECK: OpName %MyCbuffer "MyCbuffer"
|
||||
// CHECK: OpName %AnotherCBuffer "AnotherCBuffer"
|
||||
|
||||
// CHECK: OpDecorate %type_ConstantBuffer_T Block
|
||||
|
||||
struct S {
|
||||
float f1;
|
||||
float3 f2;
|
||||
};
|
||||
|
||||
// CHECK: %type_ConstantBuffer_T = OpTypeStruct %uint %int %v2uint %mat3v4float %S %_arr_float_uint_4
|
||||
// CHECK: %_ptr_Uniform_type_ConstantBuffer_T = OpTypePointer Uniform %type_ConstantBuffer_T
|
||||
struct T {
|
||||
bool a;
|
||||
int b;
|
||||
|
@ -26,10 +28,16 @@ struct T {
|
|||
float t[4];
|
||||
};
|
||||
|
||||
// CHECK: %_ptr_Uniform_type_ConstantBuffer_T = OpTypePointer Uniform %type_ConstantBuffer_T
|
||||
// CHECK: %_arr_type_ConstantBuffer_T_uint_2 = OpTypeArray %type_ConstantBuffer_T %uint_2
|
||||
// CHECK: %_ptr_Uniform__arr_type_ConstantBuffer_T_uint_2 = OpTypePointer Uniform %_arr_type_ConstantBuffer_T_uint_2
|
||||
|
||||
// CHECK: %MyCbuffer = OpVariable %_ptr_Uniform_type_ConstantBuffer_T Uniform
|
||||
ConstantBuffer<T> MyCbuffer : register(b1);
|
||||
// CHECK: %AnotherCBuffer = OpVariable %_ptr_Uniform_type_ConstantBuffer_T Uniform
|
||||
ConstantBuffer<T> AnotherCBuffer : register(b2);
|
||||
// CHECK: %MyConstantBufferArray = OpVariable %_ptr_Uniform__arr_type_ConstantBuffer_T_uint_2 Uniform
|
||||
ConstantBuffer<T> MyConstantBufferArray[2] : register(b3);
|
||||
|
||||
void main() {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Run: %dxc -T ps_6_0 -E main
|
||||
|
||||
struct T {
|
||||
float a;
|
||||
float3 b;
|
||||
};
|
||||
|
||||
StructuredBuffer<T> myStructuredBuffer[3];
|
||||
RWStructuredBuffer<T> myRWStructuredBuffer[4];
|
||||
AppendStructuredBuffer<T> myAppendStructuredBuffer[2];
|
||||
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
|
|
@ -11,13 +11,14 @@
|
|||
// CHECK: OpName %MyTbuffer "MyTbuffer"
|
||||
// CHECK: OpName %AnotherTBuffer "AnotherTBuffer"
|
||||
|
||||
// CHECK: OpDecorate %type_TextureBuffer_T BufferBlock
|
||||
|
||||
struct S {
|
||||
float f1;
|
||||
float3 f2;
|
||||
};
|
||||
|
||||
// CHECK: %type_TextureBuffer_T = OpTypeStruct %uint %int %v2uint %mat3v4float %S %_arr_float_uint_4
|
||||
// CHECK: %_ptr_Uniform_type_TextureBuffer_T = OpTypePointer Uniform %type_TextureBuffer_T
|
||||
struct T {
|
||||
bool a;
|
||||
int b;
|
||||
|
@ -27,11 +28,18 @@ struct T {
|
|||
float t[4];
|
||||
};
|
||||
|
||||
// CHECK: %_ptr_Uniform_type_TextureBuffer_T = OpTypePointer Uniform %type_TextureBuffer_T
|
||||
// CEHCK: %_arr_type_TextureBuffer_T_uint_3 = OpTypeArray %type_TextureBuffer_T %uint_3
|
||||
// CEHCK: %_ptr_Uniform__arr_type_TextureBuffer_T_uint_3 = OpTypePointer Uniform %_arr_type_TextureBuffer_T_uint_3
|
||||
|
||||
// CHECK: %MyTbuffer = OpVariable %_ptr_Uniform_type_TextureBuffer_T Uniform
|
||||
TextureBuffer<T> MyTbuffer : register(t1);
|
||||
|
||||
// CHECK: %AnotherTBuffer = OpVariable %_ptr_Uniform_type_TextureBuffer_T Uniform
|
||||
TextureBuffer<T> AnotherTBuffer : register(t2);
|
||||
|
||||
// CHECK: %myTextureBufferArray = OpVariable %_ptr_Uniform__arr_type_TextureBuffer_T_uint_3 Uniform
|
||||
TextureBuffer<T> myTextureBufferArray[3] : register(t3);
|
||||
|
||||
void main() {
|
||||
}
|
||||
|
|
|
@ -68,6 +68,9 @@ TEST_F(FileTest, TextureBufferType) { runFileTest("type.texture-buffer.hlsl"); }
|
|||
TEST_F(FileTest, StructuredBufferType) {
|
||||
runFileTest("type.structured-buffer.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, StructuredBufferArrayTypeError) {
|
||||
runFileTest("type.structured-buffer.array.error.hlsl", Expect::Failure);
|
||||
}
|
||||
TEST_F(FileTest, AppendStructuredBufferType) {
|
||||
runFileTest("type.append-structured-buffer.hlsl");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче