From 6b09a407bb9f4dace790d25bbb85bd9e6edd115d Mon Sep 17 00:00:00 2001 From: Ehsan Date: Wed, 23 Aug 2017 12:15:11 -0400 Subject: [PATCH] [spirv] Support translation of Buffer & RWBuffer (#588) --- .../clang/include/clang/SPIRV/ModuleBuilder.h | 4 +- tools/clang/lib/SPIRV/ModuleBuilder.cpp | 42 +++++++- tools/clang/lib/SPIRV/TypeTranslator.cpp | 39 +++++++- tools/clang/lib/SPIRV/TypeTranslator.h | 4 + .../clang/test/CodeGenSPIRV/type.buffer.hlsl | 97 +++++++++++++++++++ .../CodeGenSPIRV/vk.binding.explicit.hlsl | 10 ++ .../CodeGenSPIRV/vk.binding.implicit.hlsl | 8 ++ .../CodeGenSPIRV/vk.binding.register.hlsl | 8 ++ .../unittests/SPIRV/CodeGenSPIRVTest.cpp | 1 + 9 files changed, 207 insertions(+), 6 deletions(-) create mode 100644 tools/clang/test/CodeGenSPIRV/type.buffer.hlsl diff --git a/tools/clang/include/clang/SPIRV/ModuleBuilder.h b/tools/clang/include/clang/SPIRV/ModuleBuilder.h index f0038db6e..d1825596b 100644 --- a/tools/clang/include/clang/SPIRV/ModuleBuilder.h +++ b/tools/clang/include/clang/SPIRV/ModuleBuilder.h @@ -291,7 +291,9 @@ public: Type::DecorationSet decorations = {}); uint32_t getFunctionType(uint32_t returnType, llvm::ArrayRef paramTypes); - uint32_t getImageType(uint32_t sampledType, spv::Dim, bool isArray); + uint32_t getImageType(uint32_t sampledType, spv::Dim, uint32_t depth, + bool isArray, uint32_t ms = 0, uint32_t sampled = 1, + spv::ImageFormat format = spv::ImageFormat::Unknown); uint32_t getSamplerType(); uint32_t getSampledImageType(uint32_t imageType); uint32_t getByteAddressBufferType(bool isRW); diff --git a/tools/clang/lib/SPIRV/ModuleBuilder.cpp b/tools/clang/lib/SPIRV/ModuleBuilder.cpp index 1a3d71fd6..e0052cd43 100644 --- a/tools/clang/lib/SPIRV/ModuleBuilder.cpp +++ b/tools/clang/lib/SPIRV/ModuleBuilder.cpp @@ -622,13 +622,47 @@ uint32_t ModuleBuilder::getFunctionType(uint32_t returnType, } uint32_t ModuleBuilder::getImageType(uint32_t sampledType, spv::Dim dim, - bool isArray) { - const Type *type = Type::getImage(theContext, sampledType, dim, - /*depth*/ 0, isArray, /*ms*/ 0, - /*sampled*/ 1, spv::ImageFormat::Unknown); + uint32_t depth, bool isArray, uint32_t ms, + uint32_t sampled, + spv::ImageFormat format) { + const Type *type = Type::getImage(theContext, sampledType, dim, depth, + isArray, ms, sampled, format); const uint32_t typeId = theContext.getResultIdForType(type); theModule.addType(type, typeId); + switch (format) { + case spv::ImageFormat::Rg32f: + case spv::ImageFormat::Rg16f: + case spv::ImageFormat::R11fG11fB10f: + case spv::ImageFormat::R16f: + case spv::ImageFormat::Rgba16: + case spv::ImageFormat::Rgb10A2: + case spv::ImageFormat::Rg16: + case spv::ImageFormat::Rg8: + case spv::ImageFormat::R16: + case spv::ImageFormat::R8: + case spv::ImageFormat::Rgba16Snorm: + case spv::ImageFormat::Rg16Snorm: + case spv::ImageFormat::Rg8Snorm: + case spv::ImageFormat::R16Snorm: + case spv::ImageFormat::R8Snorm: + case spv::ImageFormat::Rg32i: + case spv::ImageFormat::Rg16i: + case spv::ImageFormat::Rg8i: + case spv::ImageFormat::R16i: + case spv::ImageFormat::R8i: + case spv::ImageFormat::Rgb10a2ui: + case spv::ImageFormat::Rg32ui: + case spv::ImageFormat::Rg16ui: + case spv::ImageFormat::Rg8ui: + case spv::ImageFormat::R16ui: + case spv::ImageFormat::R8ui: + requireCapability(spv::Capability::StorageImageExtendedFormats); + } + + if (dim == spv::Dim::Buffer) + requireCapability(spv::Capability::SampledBuffer); + const char *dimStr = ""; switch (dim) { case spv::Dim::Dim1D: diff --git a/tools/clang/lib/SPIRV/TypeTranslator.cpp b/tools/clang/lib/SPIRV/TypeTranslator.cpp index a5ff3d39f..d6a4e030f 100644 --- a/tools/clang/lib/SPIRV/TypeTranslator.cpp +++ b/tools/clang/lib/SPIRV/TypeTranslator.cpp @@ -432,7 +432,7 @@ uint32_t TypeTranslator::translateResourceType(QualType type) { theBuilder.requireCapability(spv::Capability::Sampled1D); const auto sampledType = hlsl::GetHLSLResourceResultType(type); return theBuilder.getImageType(translateType(getElementType(sampledType)), - dim, isArray); + dim, /*depth*/ 0, isArray); } } @@ -450,9 +450,46 @@ uint32_t TypeTranslator::translateResourceType(QualType type) { return theBuilder.getByteAddressBufferType(/*isRW*/ true); } + // Buffer and RWBuffer types + if (name == "Buffer" || name == "RWBuffer") { + theBuilder.requireCapability(spv::Capability::SampledBuffer); + const auto sampledType = hlsl::GetHLSLResourceResultType(type); + const auto format = translateSampledTypeToImageFormat(sampledType); + return theBuilder.getImageType( + translateType(getElementType(sampledType)), spv::Dim::Buffer, + /*depth*/ 0, /*isArray*/ 0, /*ms*/ 0, + /*sampled*/ name == "Buffer" ? 1 : 2, format); + } return 0; } +spv::ImageFormat +TypeTranslator::translateSampledTypeToImageFormat(QualType sampledType) { + uint32_t elemCount = 1; + QualType ty = {}; + if (isScalarType(sampledType, &ty) || + isVectorType(sampledType, &ty, &elemCount)) { + if (const auto *builtinType = ty->getAs()) { + switch (builtinType->getKind()) { + case BuiltinType::Int: + return elemCount == 1 ? spv::ImageFormat::R32i + : elemCount == 2 ? spv::ImageFormat::Rg32i + : spv::ImageFormat::Rgba32i; + case BuiltinType::UInt: + return elemCount == 1 ? spv::ImageFormat::R32ui + : elemCount == 2 ? spv::ImageFormat::Rg32ui + : spv::ImageFormat::Rgba32ui; + case BuiltinType::Float: + return elemCount == 1 ? spv::ImageFormat::R32f + : elemCount == 2 ? spv::ImageFormat::Rg32f + : spv::ImageFormat::Rgba32f; + } + } + } + emitError("Unimplemented resource result type was used."); + return spv::ImageFormat::Unknown; +} + std::pair TypeTranslator::getAlignmentAndSize(QualType type, uint32_t *stride, const bool isRowMajor) { diff --git a/tools/clang/lib/SPIRV/TypeTranslator.h b/tools/clang/lib/SPIRV/TypeTranslator.h index 23330c83a..19c03ec46 100644 --- a/tools/clang/lib/SPIRV/TypeTranslator.h +++ b/tools/clang/lib/SPIRV/TypeTranslator.h @@ -144,6 +144,10 @@ private: std::pair getAlignmentAndSize(QualType type, uint32_t *stride, bool isRowMajor); + /// \bried For the given sampled type, returns the corresponding image format + /// that can be used to create an image object. + spv::ImageFormat translateSampledTypeToImageFormat(QualType type); + private: ASTContext &astContext; ModuleBuilder &theBuilder; diff --git a/tools/clang/test/CodeGenSPIRV/type.buffer.hlsl b/tools/clang/test/CodeGenSPIRV/type.buffer.hlsl new file mode 100644 index 000000000..47739b427 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/type.buffer.hlsl @@ -0,0 +1,97 @@ +// Run: %dxc -T ps_6_0 -E main + +// CHECK: OpCapability SampledBuffer +// CHECK: OpCapability StorageImageExtendedFormats + +// CHECK: %type_buffer_image = OpTypeImage %int Buffer 0 0 0 1 R32i +// CHECK: %_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image +Buffer intbuf; +// CHECK: %type_buffer_image_0 = OpTypeImage %uint Buffer 0 0 0 1 R32ui +// CHECK: %_ptr_UniformConstant_type_buffer_image_0 = OpTypePointer UniformConstant %type_buffer_image_0 +Buffer uintbuf; +// CHECK: %type_buffer_image_1 = OpTypeImage %float Buffer 0 0 0 1 R32f +// CHECK: %_ptr_UniformConstant_type_buffer_image_1 = OpTypePointer UniformConstant %type_buffer_image_1 +Buffer floatbuf; + +// CHECK: %type_buffer_image_2 = OpTypeImage %int Buffer 0 0 0 2 R32i +// CHECK: %_ptr_UniformConstant_type_buffer_image_2 = OpTypePointer UniformConstant %type_buffer_image_2 +RWBuffer intrwbuf; +// CHECK: %type_buffer_image_3 = OpTypeImage %uint Buffer 0 0 0 2 R32ui +// CHECK: %_ptr_UniformConstant_type_buffer_image_3 = OpTypePointer UniformConstant %type_buffer_image_3 +RWBuffer uintrwbuf; +// CHECK: %type_buffer_image_4 = OpTypeImage %float Buffer 0 0 0 2 R32f +// CHECK: %_ptr_UniformConstant_type_buffer_image_4 = OpTypePointer UniformConstant %type_buffer_image_4 +RWBuffer floatrwbuf; + +// CHECK: %type_buffer_image_5 = OpTypeImage %int Buffer 0 0 0 1 Rg32i +// CHECK: %_ptr_UniformConstant_type_buffer_image_5 = OpTypePointer UniformConstant %type_buffer_image_5 +Buffer int2buf; +// CHECK: %type_buffer_image_6 = OpTypeImage %uint Buffer 0 0 0 1 Rg32ui +// CHECK: %_ptr_UniformConstant_type_buffer_image_6 = OpTypePointer UniformConstant %type_buffer_image_6 +Buffer uint2buf; +// CHECK: %type_buffer_image_7 = OpTypeImage %float Buffer 0 0 0 1 Rg32f +// CHECK: %_ptr_UniformConstant_type_buffer_image_7 = OpTypePointer UniformConstant %type_buffer_image_7 +Buffer float2buf; + +// CHECK: %type_buffer_image_8 = OpTypeImage %int Buffer 0 0 0 2 Rg32i +// CHECK: %_ptr_UniformConstant_type_buffer_image_8 = OpTypePointer UniformConstant %type_buffer_image_8 +RWBuffer int2rwbuf; +// CHECK: %type_buffer_image_9 = OpTypeImage %uint Buffer 0 0 0 2 Rg32ui +// CHECK: %_ptr_UniformConstant_type_buffer_image_9 = OpTypePointer UniformConstant %type_buffer_image_9 +RWBuffer uint2rwbuf; +// CHECK: %type_buffer_image_10 = OpTypeImage %float Buffer 0 0 0 2 Rg32f +// CHECK: %_ptr_UniformConstant_type_buffer_image_10 = OpTypePointer UniformConstant %type_buffer_image_10 +RWBuffer float2rwbuf; + +// CHECK: %type_buffer_image_11 = OpTypeImage %int Buffer 0 0 0 1 Rgba32i +// CHECK: %_ptr_UniformConstant_type_buffer_image_11 = OpTypePointer UniformConstant %type_buffer_image_11 +Buffer int3buf; +Buffer int4buf; +// CHECK: %type_buffer_image_12 = OpTypeImage %uint Buffer 0 0 0 1 Rgba32ui +// CHECK: %_ptr_UniformConstant_type_buffer_image_12 = OpTypePointer UniformConstant %type_buffer_image_12 +Buffer uint3buf; +Buffer uint4buf; +// CHECK: %type_buffer_image_13 = OpTypeImage %float Buffer 0 0 0 1 Rgba32f +// CHECK: %_ptr_UniformConstant_type_buffer_image_13 = OpTypePointer UniformConstant %type_buffer_image_13 +Buffer float3buf; +Buffer float4buf; + +// CHECK: %type_buffer_image_14 = OpTypeImage %int Buffer 0 0 0 2 Rgba32i +// CHECK: %_ptr_UniformConstant_type_buffer_image_14 = OpTypePointer UniformConstant %type_buffer_image_14 +RWBuffer int3rwbuf; +RWBuffer int4rwbuf; +// CHECK: %type_buffer_image_15 = OpTypeImage %uint Buffer 0 0 0 2 Rgba32ui +// CHECK: %_ptr_UniformConstant_type_buffer_image_15 = OpTypePointer UniformConstant %type_buffer_image_15 +RWBuffer uint3rwbuf; +RWBuffer uint4rwbuf; +// CHECK: %type_buffer_image_16 = OpTypeImage %float Buffer 0 0 0 2 Rgba32f +// CHECK: %_ptr_UniformConstant_type_buffer_image_16 = OpTypePointer UniformConstant %type_buffer_image_16 +RWBuffer float3rwbuf; +RWBuffer float4rwbuf; + +// CHECK: %intbuf = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant +// CHECK: %uintbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_0 UniformConstant +// CHECK: %floatbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_1 UniformConstant +// CHECK: %intrwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_2 UniformConstant +// CHECK: %uintrwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_3 UniformConstant +// CHECK: %floatrwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_4 UniformConstant +// CHECK: %int2buf = OpVariable %_ptr_UniformConstant_type_buffer_image_5 UniformConstant +// CHECK: %uint2buf = OpVariable %_ptr_UniformConstant_type_buffer_image_6 UniformConstant +// CHECK: %float2buf = OpVariable %_ptr_UniformConstant_type_buffer_image_7 UniformConstant +// CHECK: %int2rwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_8 UniformConstant +// CHECK: %uint2rwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_9 UniformConstant +// CHECK: %float2rwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_10 UniformConstant +// CHECK: %int3buf = OpVariable %_ptr_UniformConstant_type_buffer_image_11 UniformConstant +// CHECK: %int4buf = OpVariable %_ptr_UniformConstant_type_buffer_image_11 UniformConstant +// CHECK: %uint3buf = OpVariable %_ptr_UniformConstant_type_buffer_image_12 UniformConstant +// CHECK: %uint4buf = OpVariable %_ptr_UniformConstant_type_buffer_image_12 UniformConstant +// CHECK: %float3buf = OpVariable %_ptr_UniformConstant_type_buffer_image_13 UniformConstant +// CHECK: %float4buf = OpVariable %_ptr_UniformConstant_type_buffer_image_13 UniformConstant +// CHECK: %int3rwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_14 UniformConstant +// CHECK: %int4rwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_14 UniformConstant +// CHECK: %uint3rwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_15 UniformConstant +// CHECK: %uint4rwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_15 UniformConstant +// CHECK: %float3rwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_16 UniformConstant +// CHECK: %float4rwbuf = OpVariable %_ptr_UniformConstant_type_buffer_image_16 UniformConstant + +void main() {} diff --git a/tools/clang/test/CodeGenSPIRV/vk.binding.explicit.hlsl b/tools/clang/test/CodeGenSPIRV/vk.binding.explicit.hlsl index 1669ebfd7..3d839bd6b 100644 --- a/tools/clang/test/CodeGenSPIRV/vk.binding.explicit.hlsl +++ b/tools/clang/test/CodeGenSPIRV/vk.binding.explicit.hlsl @@ -20,6 +20,16 @@ Texture2D texture1; [[vk::binding(2, 2)]] Texture3D texture2 : register(t0, space0); +// CHECK: OpDecorate %myBuffer DescriptorSet 2 +// CHECK-NEXT: OpDecorate %myBuffer Binding 3 +[[vk::binding(3, 2)]] +Buffer myBuffer : register(t1, space0); + +// CHECK: OpDecorate %myRWBuffer DescriptorSet 1 +// CHECK-NEXT: OpDecorate %myRWBuffer Binding 4 +[[vk::binding(4, 1)]] +RWBuffer myRWBuffer : register(u0, space1); + // TODO: support [[vk::binding()]] on cbuffer float4 main() : SV_Target { diff --git a/tools/clang/test/CodeGenSPIRV/vk.binding.implicit.hlsl b/tools/clang/test/CodeGenSPIRV/vk.binding.implicit.hlsl index a2b4cbde5..65d95f9da 100644 --- a/tools/clang/test/CodeGenSPIRV/vk.binding.implicit.hlsl +++ b/tools/clang/test/CodeGenSPIRV/vk.binding.implicit.hlsl @@ -22,6 +22,14 @@ cbuffer myCbuffer { float4 stuff; } +// CHECK: OpDecorate %myBuffer DescriptorSet 0 +// CHECK-NEXT: OpDecorate %myBuffer Binding 5 +Buffer myBuffer; + +// CHECK: OpDecorate %myRWBuffer DescriptorSet 0 +// CHECK-NEXT: OpDecorate %myRWBuffer Binding 6 +RWBuffer myRWBuffer; + float4 main() : SV_Target { return 1.0; } diff --git a/tools/clang/test/CodeGenSPIRV/vk.binding.register.hlsl b/tools/clang/test/CodeGenSPIRV/vk.binding.register.hlsl index db832eb40..5565e7af9 100644 --- a/tools/clang/test/CodeGenSPIRV/vk.binding.register.hlsl +++ b/tools/clang/test/CodeGenSPIRV/vk.binding.register.hlsl @@ -34,6 +34,14 @@ cbuffer myCbuffer : register(b1, space3) { float4 stuff; } +// CHECK: OpDecorate %myBuffer DescriptorSet 0 +// CHECK-NEXT: OpDecorate %myBuffer Binding 3 +Buffer myBuffer : register(t3, space0); + +// CHECK: OpDecorate %myRWBuffer DescriptorSet 1 +// CHECK-NEXT: OpDecorate %myRWBuffer Binding 4 +RWBuffer myRWBuffer : register(u4, space1); + float4 main() : SV_Target { return 1.0; } diff --git a/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp b/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp index 1a26a618b..811585474 100644 --- a/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp +++ b/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp @@ -47,6 +47,7 @@ TEST_F(FileTest, ArrayTypes) { runFileTest("type.array.hlsl"); } TEST_F(FileTest, TypedefTypes) { runFileTest("type.typedef.hlsl"); } TEST_F(FileTest, SamplerTypes) { runFileTest("type.sampler.hlsl"); } TEST_F(FileTest, TextureTypes) { runFileTest("type.texture.hlsl"); } +TEST_F(FileTest, BufferType) { runFileTest("type.buffer.hlsl"); } TEST_F(FileTest, CBufferType) { runFileTest("type.cbuffer.hlsl"); } TEST_F(FileTest, ByteAddressBufferTypes) { runFileTest("type.byte-address-buffer.hlsl");