diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index f77e9ac82b..bfeab5f376 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -4328,7 +4328,18 @@ SpirvEmitter::processBufferTextureGetDimensions(const CXXMemberCallExpr *expr) { const Expr *mipLevel = nullptr, *numLevels = nullptr, *numSamples = nullptr; assert(isTexture(type) || isRWTexture(type) || isBuffer(type) || - isRWBuffer(type)); + isRWBuffer(type) || isSampledTexture(type)); + if (isSampledTexture(type)) { + LowerTypeVisitor lowerTypeVisitor(astContext, spvContext, spirvOptions, + spvBuilder); + const SpirvType *spvType = lowerTypeVisitor.lowerType( + type, SpirvLayoutRule::Void, llvm::None, expr->getExprLoc()); + // Get image type based on type, assuming type is a sampledimage type + const auto *sampledType = cast(spvType); + const SpirvType *imgType = sampledType->getImageType(); + objectInstr = spvBuilder.createUnaryOp(spv::Op::OpImage, imgType, + objectInstr, expr->getExprLoc()); + } // For Texture1D, arguments are either: // a) width @@ -4362,6 +4373,9 @@ SpirvEmitter::processBufferTextureGetDimensions(const CXXMemberCallExpr *expr) { // a) width, height, elements // b) MipLevel, width, height, elements, NumLevels + // SampledTexture types follow the same rules above, as + // this method doesn't require a Sampler argument. + // Note: SPIR-V Spec requires return type of OpImageQuerySize(Lod) to be a // scalar/vector of integers. SPIR-V Spec also requires return type of // OpImageQueryLevels and OpImageQuerySamples to be scalar integers. @@ -4379,6 +4393,7 @@ SpirvEmitter::processBufferTextureGetDimensions(const CXXMemberCallExpr *expr) { if ((typeName == "Texture1D" && numArgs > 1) || (typeName == "Texture2D" && numArgs > 2) || + (typeName == "SampledTexture2D" && numArgs > 2) || (typeName == "TextureCube" && numArgs > 2) || (typeName == "Texture3D" && numArgs > 3) || (typeName == "Texture1DArray" && numArgs > 2) || @@ -4417,7 +4432,7 @@ SpirvEmitter::processBufferTextureGetDimensions(const CXXMemberCallExpr *expr) { // Only Texture types use ImageQuerySizeLod. // TextureMS, RWTexture, Buffers, RWBuffers use ImageQuerySize. SpirvInstruction *lod = nullptr; - if (isTexture(type) && !numSamples) { + if ((isTexture(type) || isSampledTexture(type)) && !numSamples) { if (mipLevel) { // For Texture types when mipLevel argument is present. lod = doExpr(mipLevel, range); @@ -6433,7 +6448,8 @@ SpirvInstruction * SpirvEmitter::processGetDimensions(const CXXMemberCallExpr *expr) { const auto objectType = expr->getImplicitObjectArgument()->getType(); if (isTexture(objectType) || isRWTexture(objectType) || - isBuffer(objectType) || isRWBuffer(objectType)) { + isBuffer(objectType) || isRWBuffer(objectType) || + isSampledTexture(objectType)) { return processBufferTextureGetDimensions(expr); } else if (isByteAddressBuffer(objectType) || isRWByteAddressBuffer(objectType) || diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.get-dimensions.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.get-dimensions.hlsl new file mode 100644 index 0000000000..cf98bd8649 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.get-dimensions.hlsl @@ -0,0 +1,94 @@ +// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv | FileCheck %s +// RUN: not %dxc -T ps_6_0 -E main -fcgl %s -spirv -DERROR 2>&1 | FileCheck %s --check-prefix=ERROR + +// CHECK: OpCapability ImageQuery + +vk::SampledTexture2D t1; + +void main() { + uint mipLevel = 1; + uint width, height, numLevels; + +// CHECK: [[t1_load:%[0-9]+]] = OpLoad %type_sampled_image %t1 +// CHECK-NEXT: [[image1:%[0-9]+]] = OpImage %type_2d_image [[t1_load]] +// CHECK-NEXT: [[query1:%[0-9]+]] = OpImageQuerySizeLod %v2uint [[image1]] %int_0 +// CHECK-NEXT: [[query1_0:%[0-9]+]] = OpCompositeExtract %uint [[query1]] 0 +// CHECK-NEXT: OpStore %width [[query1_0]] +// CHECK-NEXT: [[query1_1:%[0-9]+]] = OpCompositeExtract %uint [[query1]] 1 +// CHECK-NEXT: OpStore %height [[query1_1]] + t1.GetDimensions(width, height); + +// CHECK: [[t1_load:%[0-9]+]] = OpLoad %type_sampled_image %t1 +// CHECK-NEXT: [[image2:%[0-9]+]] = OpImage %type_2d_image [[t1_load]] +// CHECK-NEXT: [[mip:%[0-9]+]] = OpLoad %uint %mipLevel +// CHECK-NEXT: [[query2:%[0-9]+]] = OpImageQuerySizeLod %v2uint [[image2]] [[mip]] +// CHECK-NEXT: [[query2_0:%[0-9]+]] = OpCompositeExtract %uint [[query2]] 0 +// CHECK-NEXT: OpStore %width [[query2_0]] +// CHECK-NEXT: [[query2_1:%[0-9]+]] = OpCompositeExtract %uint [[query2]] 1 +// CHECK-NEXT: OpStore %height [[query2_1]] +// CHECK-NEXT: [[query_level_2:%[0-9]+]] = OpImageQueryLevels %uint [[image2]] +// CHECK-NEXT: OpStore %numLevels [[query_level_2]] + t1.GetDimensions(mipLevel, width, height, numLevels); + + float f_width, f_height, f_numLevels; +// CHECK: [[t1_load:%[0-9]+]] = OpLoad %type_sampled_image %t1 +// CHECK-NEXT: [[image1:%[0-9]+]] = OpImage %type_2d_image [[t1_load]] +// CHECK-NEXT: [[query1:%[0-9]+]] = OpImageQuerySizeLod %v2uint [[image1]] %int_0 +// CHECK-NEXT: [[query1_0:%[0-9]+]] = OpCompositeExtract %uint [[query1]] 0 +// CHECK-NEXT: [[f_query1_0:%[0-9]+]] = OpConvertUToF %float [[query1_0]] +// CHECK-NEXT: OpStore %f_width [[f_query1_0]] +// CHECK-NEXT: [[query1_1:%[0-9]+]] = OpCompositeExtract %uint [[query1]] 1 +// CHECK-NEXT: [[f_query1_1:%[0-9]+]] = OpConvertUToF %float [[query1_1]] +// CHECK-NEXT: OpStore %f_height [[f_query1_1]] + t1.GetDimensions(f_width, f_height); + +// CHECK: [[t1_load:%[0-9]+]] = OpLoad %type_sampled_image %t1 +// CHECK-NEXT: [[image2:%[0-9]+]] = OpImage %type_2d_image [[t1_load]] +// CHECK-NEXT: [[mip:%[0-9]+]] = OpLoad %uint %mipLevel +// CHECK-NEXT: [[query2:%[0-9]+]] = OpImageQuerySizeLod %v2uint [[image2]] [[mip]] +// CHECK-NEXT: [[query2_0:%[0-9]+]] = OpCompositeExtract %uint [[query2]] 0 +// CHECK-NEXT: [[f_query2_0:%[0-9]+]] = OpConvertUToF %float [[query2_0]] +// CHECK-NEXT: OpStore %f_width [[f_query2_0]] +// CHECK-NEXT: [[query2_1:%[0-9]+]] = OpCompositeExtract %uint [[query2]] 1 +// CHECK-NEXT: [[f_query2_1:%[0-9]+]] = OpConvertUToF %float [[query2_1]] +// CHECK-NEXT: OpStore %f_height [[f_query2_1]] +// CHECK-NEXT: [[query_level_2:%[0-9]+]] = OpImageQueryLevels %uint [[image2]] +// CHECK-NEXT: [[f_query_level_2:%[0-9]+]] = OpConvertUToF %float [[query_level_2]] +// CHECK-NEXT: OpStore %f_numLevels [[f_query_level_2]] + t1.GetDimensions(mipLevel, f_width, f_height, f_numLevels); + + int i_width, i_height, i_numLevels; +// CHECK: [[t1_load:%[0-9]+]] = OpLoad %type_sampled_image %t1 +// CHECK-NEXT: [[image1:%[0-9]+]] = OpImage %type_2d_image [[t1_load]] +// CHECK-NEXT: [[query1:%[0-9]+]] = OpImageQuerySizeLod %v2uint [[image1]] %int_0 +// CHECK-NEXT: [[query1_0:%[0-9]+]] = OpCompositeExtract %uint [[query1]] 0 +// CHECK-NEXT: [[query_0_int:%[0-9]+]] = OpBitcast %int [[query1_0]] +// CHECK-NEXT: OpStore %i_width [[query_0_int]] +// CHECK-NEXT: [[query1_1:%[0-9]+]] = OpCompositeExtract %uint [[query1]] 1 +// CHECK-NEXT: [[query_1_int:%[0-9]+]] = OpBitcast %int [[query1_1]] +// CHECK-NEXT: OpStore %i_height [[query_1_int]] + t1.GetDimensions(i_width, i_height); + +// CHECK: [[t1_load:%[0-9]+]] = OpLoad %type_sampled_image %t1 +// CHECK-NEXT: [[image2:%[0-9]+]] = OpImage %type_2d_image [[t1_load]] +// CHECK-NEXT: [[mip:%[0-9]+]] = OpLoad %uint %mipLevel +// CHECK-NEXT: [[query2:%[0-9]+]] = OpImageQuerySizeLod %v2uint [[image2]] [[mip]] +// CHECK-NEXT: [[query2_0:%[0-9]+]] = OpCompositeExtract %uint [[query2]] 0 +// CHECK-NEXT: [[query_0_int:%[0-9]+]] = OpBitcast %int [[query2_0]] +// CHECK-NEXT: OpStore %i_width [[query_0_int]] +// CHECK-NEXT: [[query2_1:%[0-9]+]] = OpCompositeExtract %uint [[query2]] 1 +// CHECK-NEXT: [[query_1_int:%[0-9]+]] = OpBitcast %int [[query2_1]] +// CHECK-NEXT: OpStore %i_height [[query_1_int]] +// CHECK-NEXT: [[query_level_2:%[0-9]+]] = OpImageQueryLevels %uint [[image2]] +// CHECK-NEXT: [[query_level_2_int:%[0-9]+]] = OpBitcast %int [[query_level_2]] +// CHECK-NEXT: OpStore %i_numLevels [[query_level_2_int]] + t1.GetDimensions(mipLevel, i_width, i_height, i_numLevels); + +#ifdef ERROR +// ERROR: error: Output argument must be an l-value + t1.GetDimensions(mipLevel, 0, height, numLevels); + +// ERROR: error: Output argument must be an l-value + t1.GetDimensions(width, 20); +#endif +} \ No newline at end of file diff --git a/utils/hct/gen_intrin_main.txt b/utils/hct/gen_intrin_main.txt index 4d5d5126c8..899124e896 100644 --- a/utils/hct/gen_intrin_main.txt +++ b/utils/hct/gen_intrin_main.txt @@ -1243,4 +1243,8 @@ namespace VkSampledTexture2DMethods { $match<0, -1> void<4> [[ro]] Gather(in float<2> x) : tex2d_t_gather; $match<0, -1> void<4> [[ro]] Gather(in float<2> x, in int<2> o) : tex2d_t_gather_o; $match<0, -1> void<4> [[]] Gather(in float<2> x, in int<2> o, out uint_only status) : tex2d_t_gather_o_s; + void [[]] GetDimensions(in uint x, out uint_only width, out $type2 height, out $type2 levels) : resinfo_uint; + void [[]] GetDimensions(in uint x, out float_like width, out $type2 height, out $type2 levels) : resinfo; + void [[]] GetDimensions(out uint_only width, out $type1 height) : resinfo_uint_o; + void [[]] GetDimensions(out float_like width, out $type1 height) : resinfo_o; } namespace