[spirv] Support TextureBuffer/ConstantBuffer arrays. (#1166)

This commit is contained in:
Ehsan 2018-03-22 13:53:24 -04:00 коммит произвёл GitHub
Родитель 66a8998f87
Коммит 3c511a0959
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 147 добавлений и 43 удалений

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

@ -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");
}