From 4c34d2736429bbc658c4d5ce511ce4e84a9b2743 Mon Sep 17 00:00:00 2001 From: Lucie Choi Date: Fri, 13 Feb 2026 20:28:27 -0800 Subject: [PATCH] Gather, CalculateLevelOfDetailUnclamped --- .../clang/include/clang/SPIRV/SpirvBuilder.h | 4 ++ tools/clang/lib/SPIRV/SpirvBuilder.cpp | 11 ++++- ...ampledtexture.calculate-lod-unclamped.hlsl | 21 ++++++++++ .../vk.sampledtexture.gather.hlsl | 42 +++++++++++++++++++ utils/hct/gen_intrin_main.txt | 4 ++ 5 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 tools/clang/test/CodeGenSPIRV/vk.sampledtexture.calculate-lod-unclamped.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/vk.sampledtexture.gather.hlsl diff --git a/tools/clang/include/clang/SPIRV/SpirvBuilder.h b/tools/clang/include/clang/SPIRV/SpirvBuilder.h index 868c978c35..6d02c07866 100644 --- a/tools/clang/include/clang/SPIRV/SpirvBuilder.h +++ b/tools/clang/include/clang/SPIRV/SpirvBuilder.h @@ -339,6 +339,10 @@ class SpirvBuilder { /// \brief Creates SPIR-V instructions for gathering the given image. /// + /// If the of `image` is a sampled image, then that image will be gathered. + /// In this case, `sampler` must be `nullptr`. If `image` is not a sampled + /// image, a sampled image will be created by combining `image` and `sampler`. + /// /// If compareVal is given a non-null value, OpImageDrefGather or /// OpImageSparseDrefGather will be generated; otherwise, OpImageGather or /// OpImageSparseGather will be generated. diff --git a/tools/clang/lib/SPIRV/SpirvBuilder.cpp b/tools/clang/lib/SPIRV/SpirvBuilder.cpp index 7ce0508585..a85916d106 100644 --- a/tools/clang/lib/SPIRV/SpirvBuilder.cpp +++ b/tools/clang/lib/SPIRV/SpirvBuilder.cpp @@ -714,8 +714,15 @@ SpirvInstruction *SpirvBuilder::createImageGather( assert(insertPoint && "null insert point"); // An OpSampledImage is required to do the image sampling. - auto *sampledImage = - createSampledImage(imageType, image, sampler, loc, range); + // Skip creating OpSampledImage if the imageType is a sampled texture. + SpirvInstruction *sampledImage = nullptr; + if (isSampledTexture(imageType)) { + assert(!sampler && + "sampler must be null when sampling from a sampled texture"); + sampledImage = image; + } else { + sampledImage = createSampledImage(imageType, image, sampler, loc, range); + } // TODO: Update ImageGather to accept minLod if necessary. const auto mask = composeImageOperandsMask( diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.calculate-lod-unclamped.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.calculate-lod-unclamped.hlsl new file mode 100644 index 0000000000..aebc57738b --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.calculate-lod-unclamped.hlsl @@ -0,0 +1,21 @@ +// RUN: %dxc -T ps_6_8 -E main -fcgl %s -spirv | FileCheck %s + +// CHECK: OpCapability ImageQuery + +vk::SampledTexture2D t1 : register(t0); + +// CHECK: %type_2d_image = OpTypeImage %float 2D 0 0 0 1 Unknown +// CHECK: %type_sampled_image = OpTypeSampledImage %type_2d_image +// CHECK: [[ptr:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant %type_sampled_image + +// CHECK: %t1 = OpVariable [[ptr]] UniformConstant + +void main() { + float2 xy = float2(0.5, 0.5); + +//CHECK: [[tex1:%[a-zA-Z0-9_]+]] = OpLoad %type_sampled_image %t1 +//CHECK-NEXT: [[xy_load:%[a-zA-Z0-9_]+]] = OpLoad %v2float %xy +//CHECK-NEXT: [[query:%[a-zA-Z0-9_]+]] = OpImageQueryLod %v2float [[tex1]] [[xy_load]] +//CHECK-NEXT: {{%[0-9]+}} = OpCompositeExtract %float [[query]] 1 + float lod1 = t1.CalculateLevelOfDetailUnclamped(xy); +} \ No newline at end of file diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.gather.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.gather.hlsl new file mode 100644 index 0000000000..f7a26c153a --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.gather.hlsl @@ -0,0 +1,42 @@ +// RUN: %dxc -T ps_6_7 -E main -fcgl %s -spirv | FileCheck %s + +// CHECK: OpCapability SparseResidency + +// CHECK: [[v2fc:%[0-9]+]] = OpConstantComposite %v2float %float_0_5 %float_0_25 +// CHECK: [[v2ic:%[0-9]+]] = OpConstantComposite %v2int %int_2 %int_3 + +// CHECK: [[type_2d_image_1:%[a-zA-Z0-9_]+]] = OpTypeImage %float 2D 0 0 0 1 Unknown +// CHECK: [[type_sampled_image_1:%[a-zA-Z0-9_]+]] = OpTypeSampledImage [[type_2d_image_1]] +// CHECK: [[ptr_type_1:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[type_sampled_image_1]] + +// CHECK: [[type_2d_image_2:%[a-zA-Z0-9_]+]] = OpTypeImage %uint 2D 0 0 0 1 Unknown +// CHECK: [[type_sampled_image_2:%[a-zA-Z0-9_]+]] = OpTypeSampledImage [[type_2d_image_2]] +// CHECK: [[ptr_type_2:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[type_sampled_image_2]] + +// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float + +// CHECK: [[tex1:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_1]] UniformConstant +// CHECK: [[tex2:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_2]] UniformConstant + +vk::SampledTexture2D tex1 : register(t1); +vk::SampledTexture2D tex2 : register(t2); + +float4 main() : SV_Target { + +// CHECK: [[tex1_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex1]] +// CHECK: [[val1:%[a-zA-Z0-9_]+]] = OpImageGather %v4float [[tex1_load]] [[v2fc]] %int_0 None + float4 val1 = tex1.Gather(float2(0.5, 0.25)); + +// CHECK: [[tex2_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_2]] [[tex2]] +// CHECK: [[val2:%[a-zA-Z0-9_]+]] = OpImageGather %v4uint [[tex2_load]] [[v2fc]] %int_0 ConstOffset [[v2ic]] + uint4 val2 = tex2.Gather(float2(0.5, 0.25), int2(2, 3)); + +// CHECK: [[tex3_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex1]] +// CHECK: [[val3:%[a-zA-Z0-9_]+]] = OpImageSparseGather %SparseResidencyStruct [[tex3_load]] [[v2fc]] %int_0 ConstOffset [[v2ic]] +// CHECK: [[status_0:%[a-zA-Z0-9_]+]] = OpCompositeExtract %uint [[val3]] 0 +// CHECK: OpStore %status [[status_0]] + uint status; + float4 val3 = tex1.Gather(float2(0.5, 0.25), int2(2, 3), status); + + return 1.0; +} diff --git a/utils/hct/gen_intrin_main.txt b/utils/hct/gen_intrin_main.txt index 1a0d3b7a3b..4d5d5126c8 100644 --- a/utils/hct/gen_intrin_main.txt +++ b/utils/hct/gen_intrin_main.txt @@ -1239,4 +1239,8 @@ namespace VkSampledTexture2DMethods { $classT [[ro]] Sample(in float<2> x, in int<2> o, in float clamp) : tex2d_t_o_cl; $classT [[]] Sample(in float<2> x, in int<2> o, in float clamp, out uint_only status) : tex2d_t_o_cl_s; float [[ro]] CalculateLevelOfDetail(in float<2> x) : tex2d_t_calc_lod; + float [[ro]] CalculateLevelOfDetailUnclamped(in float<2> x) : tex2d_t_calc_lod_unclamped; + $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; } namespace