From 7e539c353c2c0515a3c63447d2ea55b5f6650867 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Wed, 7 Jan 2026 08:10:48 +0000 Subject: [PATCH 01/11] Implement `vk::SampledTexture2D` type and `Sample` method. --- include/dxc/dxcapi.internal.h | 3 +- tools/clang/include/clang/AST/HlslTypes.h | 5 +++ .../clang/include/clang/SPIRV/AstTypeProbe.h | 3 ++ tools/clang/lib/AST/ASTContextHLSL.cpp | 30 +++++++++++++++++ tools/clang/lib/AST/HlslTypes.cpp | 9 +++++ tools/clang/lib/SPIRV/AstTypeProbe.cpp | 10 ++++++ tools/clang/lib/SPIRV/LowerTypeVisitor.cpp | 17 ++++++++++ tools/clang/lib/SPIRV/SpirvBuilder.cpp | 9 +++-- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 21 ++++++++++++ tools/clang/lib/Sema/SemaHLSL.cpp | 33 +++++++++++++++++-- .../CodeGenSPIRV/vk.sampledtexture2d.hlsl | 19 +++++++++++ .../vk.sampledtexture2d.no-type.hlsl | 19 +++++++++++ 12 files changed, 173 insertions(+), 5 deletions(-) create mode 100644 tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.no-type.hlsl diff --git a/include/dxc/dxcapi.internal.h b/include/dxc/dxcapi.internal.h index e2ab229b2f..7a83dd6d01 100644 --- a/include/dxc/dxcapi.internal.h +++ b/include/dxc/dxcapi.internal.h @@ -140,7 +140,8 @@ enum LEGAL_INTRINSIC_COMPTYPES { #ifdef ENABLE_SPIRV_CODEGEN LICOMPTYPE_VK_BUFFER_POINTER = 56, - LICOMPTYPE_COUNT = 57 + LICOMPTYPE_VK_SAMPLED_TEXTURE2D = 57, + LICOMPTYPE_COUNT = 58 #else LICOMPTYPE_COUNT = 56 #endif diff --git a/tools/clang/include/clang/AST/HlslTypes.h b/tools/clang/include/clang/AST/HlslTypes.h index 43c1effdb8..be728c3eb1 100644 --- a/tools/clang/include/clang/AST/HlslTypes.h +++ b/tools/clang/include/clang/AST/HlslTypes.h @@ -407,6 +407,10 @@ clang::CXXRecordDecl * DeclareVkBufferPointerType(clang::ASTContext &context, clang::DeclContext *declContext); +clang::CXXRecordDecl *DeclareVkSampledTexture2DType( + clang::ASTContext &context, clang::DeclContext *declContext, + clang::QualType float2Type, clang::QualType defaultTextureType); + clang::CXXRecordDecl *DeclareInlineSpirvType(clang::ASTContext &context, clang::DeclContext *declContext, llvm::StringRef typeName, @@ -547,6 +551,7 @@ bool IsPatchConstantFunctionDecl(const clang::FunctionDecl *FD); bool IsVKBufferPointerType(clang::QualType type); clang::QualType GetVKBufferPointerBufferType(clang::QualType type); unsigned GetVKBufferPointerAlignment(clang::QualType type); +bool IsVKSampledTexture2DType(clang::QualType type); #endif /// Adds a constructor declaration to the specified class diff --git a/tools/clang/include/clang/SPIRV/AstTypeProbe.h b/tools/clang/include/clang/SPIRV/AstTypeProbe.h index 45bff1bad4..1479075f12 100644 --- a/tools/clang/include/clang/SPIRV/AstTypeProbe.h +++ b/tools/clang/include/clang/SPIRV/AstTypeProbe.h @@ -257,6 +257,9 @@ bool isTexture(QualType); /// Texture2DMSArray type. bool isTextureMS(QualType); +/// \brief Returns true if the given type is an HLSL SampledTexture type. +bool isSampledTexture(QualType); + /// \brief Returns true if the given type is an HLSL RWTexture type. bool isRWTexture(QualType); diff --git a/tools/clang/lib/AST/ASTContextHLSL.cpp b/tools/clang/lib/AST/ASTContextHLSL.cpp index a524dfab7f..4224323d1f 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1372,6 +1372,36 @@ CXXRecordDecl *hlsl::DeclareNodeOrRecordType( } #ifdef ENABLE_SPIRV_CODEGEN +CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType( + ASTContext &context, DeclContext *declContext, QualType float2Type, + QualType defaultTextureType) { + // TODO(https://github.com/microsoft/DirectXShaderCompiler/issues/7979): Later + // generalize these to all SampledTexture types. + BuiltinTypeDeclBuilder Builder(declContext, "SampledTexture2D", + TagDecl::TagKind::TTK_Struct); + TemplateTypeParmDecl *TyParamDecl = + Builder.addTypeTemplateParam("SampledTextureType", defaultTextureType); + + Builder.startDefinition(); + + QualType paramType = QualType(TyParamDecl->getTypeForDecl(), 0); + CXXRecordDecl *recordDecl = Builder.getRecordDecl(); + + // Add Sample method + // sampledtype Sample(float2 location) + CXXMethodDecl *sampleDecl = CreateObjectFunctionDeclarationWithParams( + context, recordDecl, paramType, ArrayRef(float2Type), + ArrayRef(StringRef("location")), + context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), + /*isConst*/ true); + sampleDecl->addAttr(HLSLIntrinsicAttr::CreateImplicit( + context, "op", "", + static_cast(hlsl::IntrinsicOp::MOP_Sample))); + + Builder.completeDefinition(); + return recordDecl; +} + CXXRecordDecl *hlsl::DeclareVkBufferPointerType(ASTContext &context, DeclContext *declContext) { BuiltinTypeDeclBuilder Builder(declContext, "BufferPointer", diff --git a/tools/clang/lib/AST/HlslTypes.cpp b/tools/clang/lib/AST/HlslTypes.cpp index c8b3530c04..237cc2036c 100644 --- a/tools/clang/lib/AST/HlslTypes.cpp +++ b/tools/clang/lib/AST/HlslTypes.cpp @@ -821,6 +821,15 @@ unsigned GetVKBufferPointerAlignment(clang::QualType type) { "cannot get pointer alignment for type that is not a vk::BufferPointer"); return bpParams.getValue().second; } + +bool IsVKSampledTexture2DType(clang::QualType type) { + return type ->isRecordType() && + type->getAs() + ->getDecl() + ->getName() + .equals("SampledTexture2D"); +} + #endif QualType GetHLSLResourceResultType(QualType type) { diff --git a/tools/clang/lib/SPIRV/AstTypeProbe.cpp b/tools/clang/lib/SPIRV/AstTypeProbe.cpp index fda9a3ab3e..a6bd965aec 100644 --- a/tools/clang/lib/SPIRV/AstTypeProbe.cpp +++ b/tools/clang/lib/SPIRV/AstTypeProbe.cpp @@ -926,6 +926,16 @@ bool isTexture(QualType type) { return false; } +bool isSampledTexture(QualType type) { + if (const auto *rt = type->getAs()) { + const auto name = rt->getDecl()->getName(); + // TODO(https://github.com/microsoft/DirectXShaderCompiler/issues/7979): Add other sampled texture types as needed. + if (name == "SampledTexture2D") + return true; + } + return false; +} + bool isTextureMS(QualType type) { if (const auto *rt = type->getAs()) { const auto name = rt->getDecl()->getName(); diff --git a/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp b/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp index b660ea70df..bf45edba20 100644 --- a/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp +++ b/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp @@ -849,6 +849,23 @@ const SpirvType *LowerTypeVisitor::lowerVkTypeInVkNamespace( assert(visitedTypeStack.size() == visitedTypeStackSize); return pointerType; } + if (name == "SampledTexture2D") { + const auto sampledType = hlsl::GetHLSLResourceResultType(type); + auto loweredType = + lowerType(getElementType(astContext, sampledType), rule, + /*isRowMajor*/ llvm::None, srcLoc); + + // Treat bool textures as uint for compatibility with OpTypeImage. + if (loweredType == spvContext.getBoolType()) { + loweredType = spvContext.getUIntType(32); + } + + const auto *imageType = spvContext.getImageType( + loweredType, spv::Dim::Dim2D, ImageType::WithDepth::No, + false /* array */, false /* ms */, ImageType::WithSampler::Yes, + spv::ImageFormat::Unknown); + return spvContext.getSampledImageType(imageType); + } emitError("unknown type %0 in vk namespace", srcLoc) << type; return nullptr; } diff --git a/tools/clang/lib/SPIRV/SpirvBuilder.cpp b/tools/clang/lib/SPIRV/SpirvBuilder.cpp index 5169ee7b13..923c02ef42 100644 --- a/tools/clang/lib/SPIRV/SpirvBuilder.cpp +++ b/tools/clang/lib/SPIRV/SpirvBuilder.cpp @@ -620,8 +620,13 @@ SpirvInstruction *SpirvBuilder::createImageSample( assert(lod == nullptr || minLod == nullptr); // An OpSampledImage is required to do the image sampling. - auto *sampledImage = - createSampledImage(imageType, image, sampler, loc, range); + // An OpSampledImage is required to do the image sampling. + SpirvInstruction *sampledImage = nullptr; + if (isSampledTexture(imageType)) { + sampledImage = image; + } else { + sampledImage = createSampledImage(imageType, image, sampler, loc, range); + } const auto mask = composeImageOperandsMask( bias, lod, grad, constOffset, varOffset, constOffsets, sample, minLod); diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index c41e300975..cee8baf2f3 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -5834,6 +5834,12 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, // float2|3|4 Location // [, uint Status]); // + // For SampledTexture2D: + // DXGI_FORMAT Object.Sample(float Location + // [, int Offset] + // [, float Clamp] + // [, out uint Status]); + // // Other Texture types do not have a Gather method. const auto numArgs = expr->getNumArgs(); @@ -5857,6 +5863,21 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, const auto *imageExpr = expr->getImplicitObjectArgument(); const QualType imageType = imageExpr->getType(); + + if (isSampledTexture(imageType)) { + auto *sampledImage = loadIfGLValue(imageExpr); + auto *coordinate = doExpr(expr->getArg(0)); + const auto retType = expr->getDirectCallee()->getReturnType(); + return createImageSample(retType, imageType, sampledImage, /*sampler*/ nullptr, + coordinate, + /*compareVal*/ nullptr, /*bias*/ nullptr, + /*lod*/ nullptr, {nullptr, nullptr}, + /*constOffset*/ nullptr, /*varOffset*/ nullptr, + /*constOffsets*/ nullptr, /*sample*/ nullptr, + /*minLod*/ nullptr, /*residencyCodeId*/ nullptr, + loc, range); + } + auto *image = loadIfGLValue(imageExpr); auto *sampler = doExpr(expr->getArg(0)); auto *coordinate = doExpr(expr->getArg(1)); diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 925a9e5abf..1eafb73b9b 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -199,6 +199,7 @@ enum ArBasicKind { AR_OBJECT_VK_SPV_INTRINSIC_TYPE, AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID, AR_OBJECT_VK_BUFFER_POINTER, + AR_OBJECT_VK_SAMPLED_TEXTURE2D, #endif // ENABLE_SPIRV_CODEGEN // SPIRV change ends @@ -559,6 +560,7 @@ const UINT g_uBasicKindProps[] = { BPROP_OBJECT, // AR_OBJECT_VK_SPV_INTRINSIC_TYPE use recordType BPROP_OBJECT, // AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID use recordType BPROP_OBJECT, // AR_OBJECT_VK_BUFFER_POINTER use recordType + BPROP_OBJECT | BPROP_RBUFFER, // AR_OBJECT_VK_SAMPLED_TEXTURE2D #endif // ENABLE_SPIRV_CODEGEN // SPIRV change ends @@ -1267,6 +1269,8 @@ static const ArBasicKind g_LinAlgMatrixCT[] = {AR_OBJECT_LINALG_MATRIX, #ifdef ENABLE_SPIRV_CODEGEN static const ArBasicKind g_VKBufferPointerCT[] = {AR_OBJECT_VK_BUFFER_POINTER, AR_BASIC_UNKNOWN}; +static const ArBasicKind g_VKSampledTexture2DCT[] = {AR_OBJECT_VK_SAMPLED_TEXTURE2D, + AR_BASIC_UNKNOWN}; #endif // Basic kinds, indexed by a LEGAL_INTRINSIC_COMPTYPES value. @@ -1330,6 +1334,7 @@ const ArBasicKind *g_LegalIntrinsicCompTypes[] = { g_BuiltInTrianglePositionsCT, // LICOMPTYPE_BUILTIN_TRIANGLE_POSITIONS #ifdef ENABLE_SPIRV_CODEGEN g_VKBufferPointerCT, // LICOMPTYPE_VK_BUFFER_POINTER + g_VKSampledTexture2DCT, // LICOMPTYPE_VK_SAMPLED_TEXTURE2D #endif }; static_assert( @@ -1389,7 +1394,7 @@ static const ArBasicKind g_ArBasicKindsAsTypes[] = { AR_OBJECT_VK_SPIRV_TYPE, AR_OBJECT_VK_SPIRV_OPAQUE_TYPE, AR_OBJECT_VK_INTEGRAL_CONSTANT, AR_OBJECT_VK_LITERAL, AR_OBJECT_VK_SPV_INTRINSIC_TYPE, AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID, - AR_OBJECT_VK_BUFFER_POINTER, + AR_OBJECT_VK_BUFFER_POINTER, AR_OBJECT_VK_SAMPLED_TEXTURE2D, #endif // ENABLE_SPIRV_CODEGEN // SPIRV change ends @@ -1501,6 +1506,7 @@ static const uint8_t g_ArBasicKindsTemplateCount[] = { 1, // AR_OBJECT_VK_SPV_INTRINSIC_TYPE 1, // AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID 2, // AR_OBJECT_VK_BUFFER_POINTER + 1, // AR_OBJECT_VK_SAMPLED_TEXTURE2D #endif // ENABLE_SPIRV_CODEGEN // SPIRV change ends @@ -1654,6 +1660,7 @@ static const SubscriptOperatorRecord g_ArBasicKindsSubscripts[] = { {0, MipsFalse, SampleFalse}, // AR_OBJECT_VK_SPV_INTRINSIC_TYPE {0, MipsFalse, SampleFalse}, // AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID {0, MipsFalse, SampleFalse}, // AR_OBJECT_VK_BUFFER_POINTER + {0, MipsFalse, SampleFalse}, // AR_OBJECT_VK_SAMPLED_TEXTURE2D #endif // ENABLE_SPIRV_CODEGEN // SPIRV change ends @@ -1823,6 +1830,7 @@ static const char *g_ArBasicTypeNames[] = { "ext_type", "ext_result_id", "BufferPointer", + "SampledTexture2D", #endif // ENABLE_SPIRV_CODEGEN // SPIRV change ends @@ -3073,6 +3081,7 @@ class HLSLExternalSource : public ExternalSemaSource { ClassTemplateDecl *m_vkIntegralConstantTemplateDecl; ClassTemplateDecl *m_vkLiteralTemplateDecl; ClassTemplateDecl *m_vkBufferPointerTemplateDecl; + ClassTemplateDecl *m_vkSampledTexture2DTemplateDecl; // Declarations for Work Graph Output Record types ClassTemplateDecl *m_GroupNodeOutputRecordsTemplateDecl; @@ -4078,6 +4087,17 @@ class HLSLExternalSource : public ExternalSemaSource { recordDecl = DeclareVkBufferPointerType(*m_context, m_vkNSDecl); recordDecl->setImplicit(true); m_vkBufferPointerTemplateDecl = recordDecl->getDescribedClassTemplate(); + } else if (kind == AR_OBJECT_VK_SAMPLED_TEXTURE2D) { + if (!m_vkNSDecl) + continue; + QualType float2Type = + LookupVectorType(HLSLScalarType::HLSLScalarType_float, 2); + QualType float4Type = + LookupVectorType(HLSLScalarType::HLSLScalarType_float, 4); + recordDecl = DeclareVkSampledTexture2DType(*m_context, m_vkNSDecl, + float2Type, float4Type); + recordDecl->setImplicit(true); + m_vkSampledTexture2DTemplateDecl = recordDecl->getDescribedClassTemplate(); } #endif else if (templateArgCount == 0) { @@ -4191,7 +4211,8 @@ class HLSLExternalSource : public ExternalSemaSource { : m_matrixTemplateDecl(nullptr), m_vectorTemplateDecl(nullptr), m_vkIntegralConstantTemplateDecl(nullptr), m_vkLiteralTemplateDecl(nullptr), - m_vkBufferPointerTemplateDecl(nullptr), m_hlslNSDecl(nullptr), + m_vkBufferPointerTemplateDecl(nullptr), + m_vkSampledTexture2DTemplateDecl(nullptr), m_hlslNSDecl(nullptr), m_vkNSDecl(nullptr), m_dxNSDecl(nullptr), m_context(nullptr), m_sema(nullptr), m_hlslStringTypedef(nullptr) { memset(m_matrixTypes, 0, sizeof(m_matrixTypes)); @@ -5526,6 +5547,14 @@ class HLSLExternalSource : public ExternalSemaSource { recordType->getDecl()->getName().equals("SpirvOpaqueType"))) { return true; } +#endif +#ifdef ENABLE_SPIRV_CODEGEN + if (const auto *namespaceDecl = dyn_cast( + recordType->getDecl()->getDeclContext()); + namespaceDecl && namespaceDecl->getName().equals("vk") && + recordType->getDecl()->getName().equals("SampledTexture2D")) { + return true; + } #endif m_sema->Diag(argLoc, diag::err_hlsl_unsupported_object_context) << type << static_cast(TypeDiagContext::TypeParameter); diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl new file mode 100644 index 0000000000..e706c28ede --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl @@ -0,0 +1,19 @@ +// RUN: %dxc -T ps_6_0 -E main %s -spirv | FileCheck %s + +// CHECK: [[type_2d_image:%[a-zA-Z0-9_]+]] = OpTypeImage %float 2D 0 0 0 1 Unknown +// CHECK: [[type_sampled_image:%[a-zA-Z0-9_]+]] = OpTypeSampledImage [[type_2d_image]] +// CHECK: [[ptr_type:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[type_sampled_image]] + +// CHECK: [[tex:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type]] UniformConstant +// CHECK: [[in_var_TEXCOORD:%[a-zA-Z0-9_]+]] = OpVariable %_ptr_Input_v2float Input +// CHECK: [[out_var_SV_Target:%[a-zA-Z0-9_]+]] = OpVariable %_ptr_Output_v4float Output + +vk::SampledTexture2D tex : register(t0); + +float4 main(float2 uv : TEXCOORD) : SV_Target { +// CHECK: [[tex_coord:%[a-zA-Z0-9_]+]] = OpLoad %v2float [[in_var_TEXCOORD]] +// CHECK: [[tex_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image]] [[tex]] +// CHECK: [[sampled_result:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4float [[tex_load]] [[tex_coord]] None +// CHECK: OpStore [[out_var_SV_Target]] [[sampled_result]] + return tex.Sample(uv); +} diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.no-type.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.no-type.hlsl new file mode 100644 index 0000000000..61dff3dd54 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.no-type.hlsl @@ -0,0 +1,19 @@ +// RUN: %dxc -T ps_6_0 -E main %s -spirv | FileCheck %s + +// CHECK: [[type_2d_image:%[a-zA-Z0-9_]+]] = OpTypeImage %float 2D 0 0 0 1 Unknown +// CHECK: [[type_sampled_image:%[a-zA-Z0-9_]+]] = OpTypeSampledImage [[type_2d_image]] +// CHECK: [[ptr_type:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[type_sampled_image]] + +// CHECK: [[tex:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type]] UniformConstant +// CHECK: [[in_var_TEXCOORD:%[a-zA-Z0-9_]+]] = OpVariable %_ptr_Input_v2float Input +// CHECK: [[out_var_SV_Target:%[a-zA-Z0-9_]+]] = OpVariable %_ptr_Output_v4float Output + +vk::SampledTexture2D tex : register(t0); + +float4 main(float2 uv : TEXCOORD) : SV_Target { +// CHECK: [[tex_coord:%[a-zA-Z0-9_]+]] = OpLoad %v2float [[in_var_TEXCOORD]] +// CHECK: [[tex_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image]] [[tex]] +// CHECK: [[sampled_result:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4float [[tex_load]] [[tex_coord]] None +// CHECK: OpStore [[out_var_SV_Target]] [[sampled_result]] + return tex.Sample(uv); +} From d44b6ee20f3dd9af7bc012735eeaf066205a839a Mon Sep 17 00:00:00 2001 From: luciechoi Date: Thu, 8 Jan 2026 04:09:29 +0000 Subject: [PATCH 02/11] Implement optional arguments --- tools/clang/include/clang/AST/HlslTypes.h | 4 +- .../clang/include/clang/SPIRV/SpirvBuilder.h | 3 + tools/clang/lib/AST/ASTContextHLSL.cpp | 51 ++++++++++++++-- tools/clang/lib/AST/HlslTypes.cpp | 9 --- tools/clang/lib/SPIRV/SpirvBuilder.cpp | 4 +- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 60 ++++++++++++------- tools/clang/lib/Sema/SemaHLSL.cpp | 14 ++--- .../CodeGenSPIRV/texture.array.sample.hlsl | 12 ++-- .../test/CodeGenSPIRV/texture.sample.hlsl | 8 +-- .../CodeGenSPIRV/vk.sampledtexture2d.hlsl | 59 +++++++++++++----- .../vk.sampledtexture2d.no-type.hlsl | 19 ------ 11 files changed, 152 insertions(+), 91 deletions(-) delete mode 100644 tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.no-type.hlsl diff --git a/tools/clang/include/clang/AST/HlslTypes.h b/tools/clang/include/clang/AST/HlslTypes.h index be728c3eb1..b681d6f979 100644 --- a/tools/clang/include/clang/AST/HlslTypes.h +++ b/tools/clang/include/clang/AST/HlslTypes.h @@ -409,7 +409,8 @@ DeclareVkBufferPointerType(clang::ASTContext &context, clang::CXXRecordDecl *DeclareVkSampledTexture2DType( clang::ASTContext &context, clang::DeclContext *declContext, - clang::QualType float2Type, clang::QualType defaultTextureType); + clang::QualType float2Type, clang::QualType int2Type, + clang::QualType float4Type); clang::CXXRecordDecl *DeclareInlineSpirvType(clang::ASTContext &context, clang::DeclContext *declContext, @@ -551,7 +552,6 @@ bool IsPatchConstantFunctionDecl(const clang::FunctionDecl *FD); bool IsVKBufferPointerType(clang::QualType type); clang::QualType GetVKBufferPointerBufferType(clang::QualType type); unsigned GetVKBufferPointerAlignment(clang::QualType type); -bool IsVKSampledTexture2DType(clang::QualType type); #endif /// Adds a constructor declaration to the specified class diff --git a/tools/clang/include/clang/SPIRV/SpirvBuilder.h b/tools/clang/include/clang/SPIRV/SpirvBuilder.h index 122f461a5f..ef4535695d 100644 --- a/tools/clang/include/clang/SPIRV/SpirvBuilder.h +++ b/tools/clang/include/clang/SPIRV/SpirvBuilder.h @@ -287,6 +287,9 @@ class SpirvBuilder { /// If compareVal is given a non-zero value, *Dref* variants of OpImageSample* /// will be generated. /// + /// If imageType is not a sampled image type, the OpSampledImage* instructions + /// will be generated. + /// /// If lod or grad is given a non-zero value, *ExplicitLod variants of /// OpImageSample* will be generated; otherwise, *ImplicitLod variant will /// be generated. diff --git a/tools/clang/lib/AST/ASTContextHLSL.cpp b/tools/clang/lib/AST/ASTContextHLSL.cpp index 4224323d1f..41fcb10302 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1372,13 +1372,15 @@ CXXRecordDecl *hlsl::DeclareNodeOrRecordType( } #ifdef ENABLE_SPIRV_CODEGEN -CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType( - ASTContext &context, DeclContext *declContext, QualType float2Type, - QualType defaultTextureType) { - // TODO(https://github.com/microsoft/DirectXShaderCompiler/issues/7979): Later - // generalize these to all SampledTexture types. +CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType(ASTContext &context, + DeclContext *declContext, + QualType float2Type, + QualType int2Type, + QualType float4Type) { BuiltinTypeDeclBuilder Builder(declContext, "SampledTexture2D", TagDecl::TagKind::TTK_Struct); + + QualType defaultTextureType = float4Type; TemplateTypeParmDecl *TyParamDecl = Builder.addTypeTemplateParam("SampledTextureType", defaultTextureType); @@ -1387,8 +1389,10 @@ CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType( QualType paramType = QualType(TyParamDecl->getTypeForDecl(), 0); CXXRecordDecl *recordDecl = Builder.getRecordDecl(); + QualType floatType = context.FloatTy; + QualType uintType = context.UnsignedIntTy; // Add Sample method - // sampledtype Sample(float2 location) + // Sample(location) CXXMethodDecl *sampleDecl = CreateObjectFunctionDeclarationWithParams( context, recordDecl, paramType, ArrayRef(float2Type), ArrayRef(StringRef("location")), @@ -1397,6 +1401,41 @@ CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType( sampleDecl->addAttr(HLSLIntrinsicAttr::CreateImplicit( context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); + sampleDecl->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); + + // Sample(location, offset) + QualType params2[] = {float2Type, int2Type}; + StringRef names2[] = {"location", "offset"}; + CXXMethodDecl *sampleDecl2 = CreateObjectFunctionDeclarationWithParams( + context, recordDecl, paramType, params2, names2, + context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), + /*isConst*/ true); + sampleDecl2->addAttr(HLSLIntrinsicAttr::CreateImplicit( + context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); + sampleDecl2->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); + + // Sample(location, offset, clamp) + QualType params3[] = {float2Type, int2Type, floatType}; + StringRef names3[] = {"location", "offset", "clamp"}; + CXXMethodDecl *sampleDecl3 = CreateObjectFunctionDeclarationWithParams( + context, recordDecl, paramType, params3, names3, + context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), + /*isConst*/ true); + sampleDecl3->addAttr(HLSLIntrinsicAttr::CreateImplicit( + context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); + sampleDecl3->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); + + // Sample(location, offset, clamp, status) + QualType params4[] = {float2Type, int2Type, floatType, + context.getLValueReferenceType(uintType)}; + StringRef names4[] = {"location", "offset", "clamp", "status"}; + CXXMethodDecl *sampleDecl4 = CreateObjectFunctionDeclarationWithParams( + context, recordDecl, paramType, params4, names4, + context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), + /*isConst*/ true); + sampleDecl4->addAttr(HLSLIntrinsicAttr::CreateImplicit( + context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); + sampleDecl4->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); Builder.completeDefinition(); return recordDecl; diff --git a/tools/clang/lib/AST/HlslTypes.cpp b/tools/clang/lib/AST/HlslTypes.cpp index 237cc2036c..c8b3530c04 100644 --- a/tools/clang/lib/AST/HlslTypes.cpp +++ b/tools/clang/lib/AST/HlslTypes.cpp @@ -821,15 +821,6 @@ unsigned GetVKBufferPointerAlignment(clang::QualType type) { "cannot get pointer alignment for type that is not a vk::BufferPointer"); return bpParams.getValue().second; } - -bool IsVKSampledTexture2DType(clang::QualType type) { - return type ->isRecordType() && - type->getAs() - ->getDecl() - ->getName() - .equals("SampledTexture2D"); -} - #endif QualType GetHLSLResourceResultType(QualType type) { diff --git a/tools/clang/lib/SPIRV/SpirvBuilder.cpp b/tools/clang/lib/SPIRV/SpirvBuilder.cpp index 923c02ef42..2fd60e514d 100644 --- a/tools/clang/lib/SPIRV/SpirvBuilder.cpp +++ b/tools/clang/lib/SPIRV/SpirvBuilder.cpp @@ -620,9 +620,11 @@ SpirvInstruction *SpirvBuilder::createImageSample( assert(lod == nullptr || minLod == nullptr); // An OpSampledImage is required to do the image sampling. - // An OpSampledImage is required to do the image sampling. + // 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); diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index cee8baf2f3..fe7310021f 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -5845,21 +5845,6 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, const auto numArgs = expr->getNumArgs(); const auto loc = expr->getExprLoc(); const auto range = expr->getSourceRange(); - const bool hasStatusArg = - expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType(); - - SpirvInstruction *clamp = nullptr; - if (numArgs > 2 && expr->getArg(2)->getType()->isFloatingType()) - clamp = doExpr(expr->getArg(2)); - else if (numArgs > 3 && expr->getArg(3)->getType()->isFloatingType()) - clamp = doExpr(expr->getArg(3)); - const bool hasClampArg = (clamp != 0); - const auto status = - hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : nullptr; - - // Subtract 1 for status (if it exists), subtract 1 for clamp (if it exists), - // and subtract 2 for sampler_state and location. - const bool hasOffsetArg = numArgs - hasStatusArg - hasClampArg - 2 > 0; const auto *imageExpr = expr->getImplicitObjectArgument(); const QualType imageType = imageExpr->getType(); @@ -5867,15 +5852,28 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, if (isSampledTexture(imageType)) { auto *sampledImage = loadIfGLValue(imageExpr); auto *coordinate = doExpr(expr->getArg(0)); + SpirvInstruction *constOffset = nullptr; + SpirvInstruction *varOffset = nullptr; + SpirvInstruction *clamp = nullptr; + SpirvInstruction *status = nullptr; + + if (numArgs > 1) { + handleOffsetInMethodCall(expr, 1, &constOffset, &varOffset); + } + if (numArgs > 2) { + clamp = doExpr(expr->getArg(2)); + } + if (numArgs > 3) { + status = doExpr(expr->getArg(3)); + } + const auto retType = expr->getDirectCallee()->getReturnType(); - return createImageSample(retType, imageType, sampledImage, /*sampler*/ nullptr, - coordinate, - /*compareVal*/ nullptr, /*bias*/ nullptr, - /*lod*/ nullptr, {nullptr, nullptr}, - /*constOffset*/ nullptr, /*varOffset*/ nullptr, - /*constOffsets*/ nullptr, /*sample*/ nullptr, - /*minLod*/ nullptr, /*residencyCodeId*/ nullptr, - loc, range); + return createImageSample( + retType, imageType, sampledImage, /*sampler*/ nullptr, coordinate, + /*compareVal*/ nullptr, /*bias*/ nullptr, + /*lod*/ nullptr, {nullptr, nullptr}, constOffset, varOffset, + /*constOffsets*/ nullptr, /*sample*/ nullptr, + /*minLod*/ clamp, status, loc, range); } auto *image = loadIfGLValue(imageExpr); @@ -5883,6 +5881,22 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, auto *coordinate = doExpr(expr->getArg(1)); // .Sample()/.Gather() may have a third optional paramter for offset. SpirvInstruction *constOffset = nullptr, *varOffset = nullptr; + + const bool hasStatusArg = + expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType(); + + SpirvInstruction *clamp = nullptr; + if (numArgs > 2 && expr->getArg(2)->getType()->isFloatingType()) + clamp = doExpr(expr->getArg(2)); + else if (numArgs > 3 && expr->getArg(3)->getType()->isFloatingType()) + clamp = doExpr(expr->getArg(3)); + const bool hasClampArg = (clamp != 0); + const auto status = + hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : nullptr; + + // Subtract 1 for status (if it exists), subtract 1 for clamp (if it exists), + // and subtract 2 for sampler_state and location. + const bool hasOffsetArg = numArgs - hasStatusArg - hasClampArg - 2 > 0; if (hasOffsetArg) handleOffsetInMethodCall(expr, 2, &constOffset, &varOffset); diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 1eafb73b9b..107d220854 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -4090,14 +4090,14 @@ class HLSLExternalSource : public ExternalSemaSource { } else if (kind == AR_OBJECT_VK_SAMPLED_TEXTURE2D) { if (!m_vkNSDecl) continue; - QualType float2Type = - LookupVectorType(HLSLScalarType::HLSLScalarType_float, 2); - QualType float4Type = - LookupVectorType(HLSLScalarType::HLSLScalarType_float, 4); - recordDecl = DeclareVkSampledTexture2DType(*m_context, m_vkNSDecl, - float2Type, float4Type); + recordDecl = DeclareVkSampledTexture2DType( + *m_context, m_vkNSDecl, + LookupVectorType(HLSLScalarType::HLSLScalarType_float, 2), + LookupVectorType(HLSLScalarType::HLSLScalarType_int, 2), + LookupVectorType(HLSLScalarType::HLSLScalarType_float, 4)); recordDecl->setImplicit(true); - m_vkSampledTexture2DTemplateDecl = recordDecl->getDescribedClassTemplate(); + m_vkSampledTexture2DTemplateDecl = + recordDecl->getDescribedClassTemplate(); } #endif else if (templateArgCount == 0) { diff --git a/tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl b/tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl index 0420b2af96..a900ea9cf8 100644 --- a/tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl +++ b/tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl @@ -42,9 +42,9 @@ float4 main() : SV_Target { float4 val3 = t3.Sample(gSampler, float4(0.5, 0.25, 0.125, 1)); float clamp; -// CHECK: [[clamp:%[0-9]+]] = OpLoad %float %clamp -// CHECK-NEXT: [[t1_0:%[0-9]+]] = OpLoad %type_1d_image_array %t1 +// CHECK: [[t1_0:%[0-9]+]] = OpLoad %type_1d_image_array %t1 // CHECK-NEXT: [[gSampler_2:%[0-9]+]] = OpLoad %type_sampler %gSampler +// CHECK-NEXT: [[clamp:%[0-9]+]] = OpLoad %float %clamp // CHECK-NEXT: [[sampledImg_2:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1_0]] [[gSampler_2]] // CHECK-NEXT: {{%[0-9]+}} = OpImageSampleImplicitLod %v4float [[sampledImg_2]] [[v2fc]] ConstOffset|MinLod %int_1 [[clamp]] float4 val4 = t1.Sample(gSampler, float2(0.5, 1), 1, clamp); @@ -56,10 +56,10 @@ float4 main() : SV_Target { float4 val5 = t3.Sample(gSampler, float4(0.5, 0.25, 0.125, 1), /*clamp*/ 1.5); uint status; -// CHECK: [[clamp_0:%[0-9]+]] = OpLoad %float %clamp -// CHECK-NEXT: [[t1_1:%[0-9]+]] = OpLoad %type_1d_image_array %t1 -// CHECK-NEXT: [[gSampler_4:%[0-9]+]] = OpLoad %type_sampler %gSampler -// CHECK-NEXT: [[sampledImg_4:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1_1]] [[gSampler_4]] +// CHECK: [[t1_1:%[0-9]+]] = OpLoad %type_1d_image_array %t1 +// CHECK-NEXT: [[gSampler_4:%[0-9]+]] = OpLoad %type_sampler %gSampler +// CHECK-NEXT: [[clamp_0:%[0-9]+]] = OpLoad %float %clamp +// CHECK-NEXT: [[sampledImg_4:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1_1]] [[gSampler_4]] // CHECK-NEXT: [[structResult:%[0-9]+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg_4]] [[v2fc]] ConstOffset|MinLod %int_1 [[clamp_0]] // CHECK-NEXT: [[status:%[0-9]+]] = OpCompositeExtract %uint [[structResult]] 0 // CHECK-NEXT: OpStore %status [[status]] diff --git a/tools/clang/test/CodeGenSPIRV/texture.sample.hlsl b/tools/clang/test/CodeGenSPIRV/texture.sample.hlsl index 6a847c3442..404f06ef86 100644 --- a/tools/clang/test/CodeGenSPIRV/texture.sample.hlsl +++ b/tools/clang/test/CodeGenSPIRV/texture.sample.hlsl @@ -51,9 +51,9 @@ float4 main(int2 offset: A) : SV_Target { float4 val4 = t4.Sample(gSampler, float3(0.5, 0.25, 0.3)); float clamp; -// CHECK: [[clamp:%[0-9]+]] = OpLoad %float %clamp -// CHECK-NEXT: [[t2_0:%[0-9]+]] = OpLoad %type_2d_image %t2 +// CHECK: [[t2_0:%[0-9]+]] = OpLoad %type_2d_image %t2 // CHECK-NEXT: [[gSampler_3:%[0-9]+]] = OpLoad %type_sampler %gSampler +// CHECK-NEXT: [[clamp:%[0-9]+]] = OpLoad %float %clamp // CHECK-NEXT: [[sampledImg_3:%[0-9]+]] = OpSampledImage %type_sampled_image_0 [[t2_0]] [[gSampler_3]] // CHECK-NEXT: {{%[0-9]+}} = OpImageSampleImplicitLod %v4float [[sampledImg_3]] [[v2fc]] ConstOffset|MinLod [[v2ic]] [[clamp]] float4 val5 = t2.Sample(gSampler, float2(0.5, 0.25), int2(2, 3), clamp); @@ -65,9 +65,9 @@ float4 main(int2 offset: A) : SV_Target { float4 val6 = t4.Sample(gSampler, float3(0.5, 0.25, 0.3), /*clamp*/ 2.0f); uint status; -// CHECK: [[clamp_0:%[0-9]+]] = OpLoad %float %clamp -// CHECK-NEXT: [[t2_1:%[0-9]+]] = OpLoad %type_2d_image %t2 +// CHECK: [[t2_1:%[0-9]+]] = OpLoad %type_2d_image %t2 // CHECK-NEXT: [[gSampler_5:%[0-9]+]] = OpLoad %type_sampler %gSampler +// CHECK-NEXT: [[clamp_0:%[0-9]+]] = OpLoad %float %clamp // CHECK-NEXT: [[sampledImg_5:%[0-9]+]] = OpSampledImage %type_sampled_image_0 [[t2_1]] [[gSampler_5]] // CHECK-NEXT: [[structResult:%[0-9]+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg_5]] [[v2fc]] ConstOffset|MinLod [[v2ic]] [[clamp_0]] // CHECK-NEXT: [[status:%[0-9]+]] = OpCompositeExtract %uint [[structResult]] 0 diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl index e706c28ede..c00aa7b51c 100644 --- a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl @@ -1,19 +1,50 @@ -// RUN: %dxc -T ps_6_0 -E main %s -spirv | FileCheck %s +// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv | FileCheck %s -// CHECK: [[type_2d_image:%[a-zA-Z0-9_]+]] = OpTypeImage %float 2D 0 0 0 1 Unknown -// CHECK: [[type_sampled_image:%[a-zA-Z0-9_]+]] = OpTypeSampledImage [[type_2d_image]] -// CHECK: [[ptr_type:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[type_sampled_image]] +// CHECK: OpCapability MinLod +// CHECK: OpCapability SparseResidency -// CHECK: [[tex:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type]] UniformConstant -// CHECK: [[in_var_TEXCOORD:%[a-zA-Z0-9_]+]] = OpVariable %_ptr_Input_v2float Input -// CHECK: [[out_var_SV_Target:%[a-zA-Z0-9_]+]] = OpVariable %_ptr_Output_v4float Output +// CHECK: [[v2fc:%[0-9]+]] = OpConstantComposite %v2float %float_0_5 %float_0_25 +// CHECK: [[v2ic:%[0-9]+]] = OpConstantComposite %v2int %int_2 %int_3 -vk::SampledTexture2D tex : register(t0); +// 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]] -float4 main(float2 uv : TEXCOORD) : SV_Target { -// CHECK: [[tex_coord:%[a-zA-Z0-9_]+]] = OpLoad %v2float [[in_var_TEXCOORD]] -// CHECK: [[tex_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image]] [[tex]] -// CHECK: [[sampled_result:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4float [[tex_load]] [[tex_coord]] None -// CHECK: OpStore [[out_var_SV_Target]] [[sampled_result]] - return tex.Sample(uv); +// 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: [[tex1:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_1]] UniformConstant +// CHECK: [[tex2:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_1]] UniformConstant +// CHECK: [[tex3:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_2]] UniformConstant + +vk::SampledTexture2D tex1 : register(t0); +vk::SampledTexture2D tex2 : register(t1); +vk::SampledTexture2D tex3 : register(t2); + +float4 main() : SV_Target { +// CHECK: [[tex1_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex1]] +// CHECK: [[sampled_result1:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4float [[tex1_load]] [[v2fc]] None + float4 val1 = tex1.Sample(float2(0.5, 0.25)); + +// CHECK: [[tex2_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex2]] +// CHECK: [[sampled_result2:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4float [[tex2_load]] [[v2fc]] ConstOffset [[v2ic]] + float4 val2 = tex2.Sample(float2(0.5, 0.25), int2(2, 3)); + +// CHECK: [[tex3_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex2]] +// CHECK: [[sampled_result3:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4float [[tex3_load]] [[v2fc]] ConstOffset|MinLod [[v2ic]] %float_1 + float4 val3 = tex2.Sample(float2(0.5, 0.25), int2(2, 3), 1.0f); + +// CHECK: [[tex4_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex2]] +// CHECK: [[sampled_result4:%[a-zA-Z0-9_]+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[tex4_load]] [[v2fc]] ConstOffset|MinLod [[v2ic]] %float_1 +// CHECK: [[status_0:%[a-zA-Z0-9_]+]] = OpCompositeExtract %uint [[sampled_result4]] 0 +// CHECK: OpStore %status [[status_0]] + uint status; + float4 val4 = tex2.Sample(float2(0.5, 0.25), int2(2, 3), 1.0f, status); + +// CHECK: [[tex5_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_2]] [[tex3]] +// CHECK: [[sampled_result5:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4uint [[tex5_load]] [[v2fc]] None +// CHECK: [[val5:%[a-zA-Z0-9_]+]] = OpCompositeExtract %uint [[sampled_result5]] 0 + uint val5 = tex3.Sample(float2(0.5, 0.25)); + return 1.0; } diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.no-type.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.no-type.hlsl deleted file mode 100644 index 61dff3dd54..0000000000 --- a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.no-type.hlsl +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %dxc -T ps_6_0 -E main %s -spirv | FileCheck %s - -// CHECK: [[type_2d_image:%[a-zA-Z0-9_]+]] = OpTypeImage %float 2D 0 0 0 1 Unknown -// CHECK: [[type_sampled_image:%[a-zA-Z0-9_]+]] = OpTypeSampledImage [[type_2d_image]] -// CHECK: [[ptr_type:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[type_sampled_image]] - -// CHECK: [[tex:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type]] UniformConstant -// CHECK: [[in_var_TEXCOORD:%[a-zA-Z0-9_]+]] = OpVariable %_ptr_Input_v2float Input -// CHECK: [[out_var_SV_Target:%[a-zA-Z0-9_]+]] = OpVariable %_ptr_Output_v4float Output - -vk::SampledTexture2D tex : register(t0); - -float4 main(float2 uv : TEXCOORD) : SV_Target { -// CHECK: [[tex_coord:%[a-zA-Z0-9_]+]] = OpLoad %v2float [[in_var_TEXCOORD]] -// CHECK: [[tex_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image]] [[tex]] -// CHECK: [[sampled_result:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4float [[tex_load]] [[tex_coord]] None -// CHECK: OpStore [[out_var_SV_Target]] [[sampled_result]] - return tex.Sample(uv); -} From f65f4c9dfa5955c4923f01486caf1bd5d9319ce1 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Fri, 9 Jan 2026 10:20:08 +0000 Subject: [PATCH 03/11] Implement CalculateLevelOfDetail --- tools/clang/lib/AST/ASTContextHLSL.cpp | 12 ++++++++++ tools/clang/lib/SPIRV/SpirvEmitter.cpp | 24 +++++++++++++------ .../vk.sampledtexture.calculate-lod.hlsl | 21 ++++++++++++++++ ...e2d.hlsl => vk.sampledtexture.sample.hlsl} | 0 4 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 tools/clang/test/CodeGenSPIRV/vk.sampledtexture.calculate-lod.hlsl rename tools/clang/test/CodeGenSPIRV/{vk.sampledtexture2d.hlsl => vk.sampledtexture.sample.hlsl} (100%) diff --git a/tools/clang/lib/AST/ASTContextHLSL.cpp b/tools/clang/lib/AST/ASTContextHLSL.cpp index 41fcb10302..c79fc29ea3 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1437,6 +1437,18 @@ CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType(ASTContext &context, context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); sampleDecl4->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); + // CalculateLevelOfDetail(location) + CXXMethodDecl *lodDecl = CreateObjectFunctionDeclarationWithParams( + context, recordDecl, floatType, ArrayRef(float2Type), + ArrayRef(StringRef("location")), + context.DeclarationNames.getIdentifier( + &context.Idents.get("CalculateLevelOfDetail")), + /*isConst*/ true); + lodDecl->addAttr(HLSLIntrinsicAttr::CreateImplicit( + context, "op", "", + static_cast(hlsl::IntrinsicOp::MOP_CalculateLevelOfDetail))); + lodDecl->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); + Builder.completeDefinition(); return recordDecl; } diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index fe7310021f..2a5c783ab3 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -4473,15 +4473,25 @@ SpirvEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr, // Texture2D(Array).CalculateLevelOfDetail(SamplerState S, float2 xy); // TextureCube(Array).CalculateLevelOfDetail(SamplerState S, float3 xyz); // Texture3D.CalculateLevelOfDetail(SamplerState S, float3 xyz); + // SampledTexture2D.CalculateLevelOfDetail(float2 xy); // Return type is always a single float (LOD). - assert(expr->getNumArgs() == 2u); - const auto *object = expr->getImplicitObjectArgument(); - auto *objectInfo = loadIfGLValue(object); - auto *samplerState = doExpr(expr->getArg(0)); - auto *coordinate = doExpr(expr->getArg(1)); - auto *sampledImage = spvBuilder.createSampledImage( - object->getType(), objectInfo, samplerState, expr->getExprLoc()); + const auto *imageExpr = expr->getImplicitObjectArgument(); + const QualType imageType = imageExpr->getType(); + // numarg is 1 if isSampledTexture(imageType). otherwise 2. + assert(expr->getNumArgs() == (isSampledTexture(imageType) ? 1u : 2u)); + + auto *objectInfo = loadIfGLValue(imageExpr); + auto *samplerState = + isSampledTexture(imageType) ? nullptr : doExpr(expr->getArg(0)); + auto *coordinate = isSampledTexture(imageType) ? doExpr(expr->getArg(0)) + : doExpr(expr->getArg(1)); + + auto *sampledImage = + isSampledTexture(imageType) + ? objectInfo + : spvBuilder.createSampledImage(imageExpr->getType(), objectInfo, + samplerState, expr->getExprLoc()); // The result type of OpImageQueryLod must be a float2. const QualType queryResultType = diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.calculate-lod.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.calculate-lod.hlsl new file mode 100644 index 0000000000..01d3efb5aa --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.calculate-lod.hlsl @@ -0,0 +1,21 @@ +// RUN: %dxc -T ps_6_0 -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]] 0 + float lod = t1.CalculateLevelOfDetail(xy); +} diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl similarity index 100% rename from tools/clang/test/CodeGenSPIRV/vk.sampledtexture2d.hlsl rename to tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl From c65cf4d36ce607ee8a273156af0182bd30e532d0 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Fri, 9 Jan 2026 10:51:51 +0000 Subject: [PATCH 04/11] formatting --- tools/clang/lib/AST/ASTContextHLSL.cpp | 3 +-- tools/clang/lib/SPIRV/AstTypeProbe.cpp | 3 ++- tools/clang/lib/SPIRV/LowerTypeVisitor.cpp | 5 ++--- tools/clang/lib/Sema/SemaHLSL.cpp | 6 +++--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/tools/clang/lib/AST/ASTContextHLSL.cpp b/tools/clang/lib/AST/ASTContextHLSL.cpp index c79fc29ea3..c090e46fc5 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1399,8 +1399,7 @@ CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType(ASTContext &context, context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), /*isConst*/ true); sampleDecl->addAttr(HLSLIntrinsicAttr::CreateImplicit( - context, "op", "", - static_cast(hlsl::IntrinsicOp::MOP_Sample))); + context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); sampleDecl->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); // Sample(location, offset) diff --git a/tools/clang/lib/SPIRV/AstTypeProbe.cpp b/tools/clang/lib/SPIRV/AstTypeProbe.cpp index a6bd965aec..48c3012501 100644 --- a/tools/clang/lib/SPIRV/AstTypeProbe.cpp +++ b/tools/clang/lib/SPIRV/AstTypeProbe.cpp @@ -929,7 +929,8 @@ bool isTexture(QualType type) { bool isSampledTexture(QualType type) { if (const auto *rt = type->getAs()) { const auto name = rt->getDecl()->getName(); - // TODO(https://github.com/microsoft/DirectXShaderCompiler/issues/7979): Add other sampled texture types as needed. + // TODO(https://github.com/microsoft/DirectXShaderCompiler/issues/7979): Add + // other sampled texture types as needed. if (name == "SampledTexture2D") return true; } diff --git a/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp b/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp index bf45edba20..d9ddc3428b 100644 --- a/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp +++ b/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp @@ -851,9 +851,8 @@ const SpirvType *LowerTypeVisitor::lowerVkTypeInVkNamespace( } if (name == "SampledTexture2D") { const auto sampledType = hlsl::GetHLSLResourceResultType(type); - auto loweredType = - lowerType(getElementType(astContext, sampledType), rule, - /*isRowMajor*/ llvm::None, srcLoc); + auto loweredType = lowerType(getElementType(astContext, sampledType), rule, + /*isRowMajor*/ llvm::None, srcLoc); // Treat bool textures as uint for compatibility with OpTypeImage. if (loweredType == spvContext.getBoolType()) { diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 107d220854..4f18b634aa 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -1269,8 +1269,8 @@ static const ArBasicKind g_LinAlgMatrixCT[] = {AR_OBJECT_LINALG_MATRIX, #ifdef ENABLE_SPIRV_CODEGEN static const ArBasicKind g_VKBufferPointerCT[] = {AR_OBJECT_VK_BUFFER_POINTER, AR_BASIC_UNKNOWN}; -static const ArBasicKind g_VKSampledTexture2DCT[] = {AR_OBJECT_VK_SAMPLED_TEXTURE2D, - AR_BASIC_UNKNOWN}; +static const ArBasicKind g_VKSampledTexture2DCT[] = { + AR_OBJECT_VK_SAMPLED_TEXTURE2D, AR_BASIC_UNKNOWN}; #endif // Basic kinds, indexed by a LEGAL_INTRINSIC_COMPTYPES value. @@ -1333,7 +1333,7 @@ const ArBasicKind *g_LegalIntrinsicCompTypes[] = { g_LinAlgCT, // LICOMPTYPE_LINALG g_BuiltInTrianglePositionsCT, // LICOMPTYPE_BUILTIN_TRIANGLE_POSITIONS #ifdef ENABLE_SPIRV_CODEGEN - g_VKBufferPointerCT, // LICOMPTYPE_VK_BUFFER_POINTER + g_VKBufferPointerCT, // LICOMPTYPE_VK_BUFFER_POINTER g_VKSampledTexture2DCT, // LICOMPTYPE_VK_SAMPLED_TEXTURE2D #endif }; From 656176aebfb7a995762401f2e9b4236678b7cdd5 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Thu, 22 Jan 2026 22:05:59 +0000 Subject: [PATCH 05/11] Address comments --- tools/clang/include/clang/AST/HlslTypes.h | 6 +- .../clang/Basic/DiagnosticSemaKinds.td | 3 + .../clang/include/clang/SPIRV/SpirvBuilder.h | 5 +- tools/clang/lib/AST/ASTContextHLSL.cpp | 63 +++++++------ tools/clang/lib/SPIRV/LowerTypeVisitor.cpp | 6 +- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 94 +++++++++---------- tools/clang/lib/Sema/SemaHLSL.cpp | 44 ++++++++- .../CodeGenSPIRV/texture.array.sample.hlsl | 12 +-- .../test/CodeGenSPIRV/texture.sample.hlsl | 8 +- .../SemaHLSL/vk.sampledtexture.error.hlsl | 26 +++++ 10 files changed, 167 insertions(+), 100 deletions(-) create mode 100644 tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl diff --git a/tools/clang/include/clang/AST/HlslTypes.h b/tools/clang/include/clang/AST/HlslTypes.h index b681d6f979..2f4afe673a 100644 --- a/tools/clang/include/clang/AST/HlslTypes.h +++ b/tools/clang/include/clang/AST/HlslTypes.h @@ -407,10 +407,10 @@ clang::CXXRecordDecl * DeclareVkBufferPointerType(clang::ASTContext &context, clang::DeclContext *declContext); -clang::CXXRecordDecl *DeclareVkSampledTexture2DType( +clang::CXXRecordDecl *DeclareVkSampledTextureType( clang::ASTContext &context, clang::DeclContext *declContext, - clang::QualType float2Type, clang::QualType int2Type, - clang::QualType float4Type); + llvm::StringRef hlslTypeName, clang::QualType defaultParamType, + clang::QualType coordinateType, clang::QualType offsetType); clang::CXXRecordDecl *DeclareInlineSpirvType(clang::ASTContext &context, clang::DeclContext *declContext, diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7e25e99d46..8622af4d9f 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7617,6 +7617,9 @@ def err_hlsl_unsupported_typedbuffer_template_parameter : Error< "elements of typed buffers and textures must be scalars or vectors">; def err_hlsl_unsupported_typedbuffer_template_parameter_size : Error< "elements of typed buffers and textures must fit in four 32-bit quantities">; +def err_hlsl_unsupported_vk_sampledtexture_template_parameter + : Error<"%0 cannot be used as a type parameter where it must be of type " + "float, int, uint or their vector equivalents">; def err_hlsl_unsupported_payload_access_qualifier : Error< "payload access qualifiers are only allowed for member variables of a payload structure">; def err_hlsl_unsupported_payload_access_qualifier_struct : Error< diff --git a/tools/clang/include/clang/SPIRV/SpirvBuilder.h b/tools/clang/include/clang/SPIRV/SpirvBuilder.h index ef4535695d..f2d0ddf4ca 100644 --- a/tools/clang/include/clang/SPIRV/SpirvBuilder.h +++ b/tools/clang/include/clang/SPIRV/SpirvBuilder.h @@ -287,8 +287,9 @@ class SpirvBuilder { /// If compareVal is given a non-zero value, *Dref* variants of OpImageSample* /// will be generated. /// - /// If imageType is not a sampled image type, the OpSampledImage* instructions - /// will be generated. + /// If the of `image` is a sampled image, then that image will be sampled. + /// In this case, `sampler` must be `nullptr`. If `image` is not a sampled + /// image, a sampled image will be create by combining `image` and `sampler`. /// /// If lod or grad is given a non-zero value, *ExplicitLod variants of /// OpImageSample* will be generated; otherwise, *ImplicitLod variant will diff --git a/tools/clang/lib/AST/ASTContextHLSL.cpp b/tools/clang/lib/AST/ASTContextHLSL.cpp index c090e46fc5..86ebf10bac 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1372,29 +1372,15 @@ CXXRecordDecl *hlsl::DeclareNodeOrRecordType( } #ifdef ENABLE_SPIRV_CODEGEN -CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType(ASTContext &context, - DeclContext *declContext, - QualType float2Type, - QualType int2Type, - QualType float4Type) { - BuiltinTypeDeclBuilder Builder(declContext, "SampledTexture2D", - TagDecl::TagKind::TTK_Struct); - - QualType defaultTextureType = float4Type; - TemplateTypeParmDecl *TyParamDecl = - Builder.addTypeTemplateParam("SampledTextureType", defaultTextureType); - - Builder.startDefinition(); - - QualType paramType = QualType(TyParamDecl->getTypeForDecl(), 0); - CXXRecordDecl *recordDecl = Builder.getRecordDecl(); - +static void AddSampleFunction(ASTContext &context, CXXRecordDecl *recordDecl, + QualType returnType, QualType coordinateType, + QualType offsetType) { QualType floatType = context.FloatTy; QualType uintType = context.UnsignedIntTy; - // Add Sample method + // Sample(location) CXXMethodDecl *sampleDecl = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, paramType, ArrayRef(float2Type), + context, recordDecl, returnType, ArrayRef(coordinateType), ArrayRef(StringRef("location")), context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), /*isConst*/ true); @@ -1403,10 +1389,10 @@ CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType(ASTContext &context, sampleDecl->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); // Sample(location, offset) - QualType params2[] = {float2Type, int2Type}; + QualType params2[] = {coordinateType, offsetType}; StringRef names2[] = {"location", "offset"}; CXXMethodDecl *sampleDecl2 = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, paramType, params2, names2, + context, recordDecl, returnType, params2, names2, context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), /*isConst*/ true); sampleDecl2->addAttr(HLSLIntrinsicAttr::CreateImplicit( @@ -1414,10 +1400,10 @@ CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType(ASTContext &context, sampleDecl2->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); // Sample(location, offset, clamp) - QualType params3[] = {float2Type, int2Type, floatType}; + QualType params3[] = {coordinateType, offsetType, floatType}; StringRef names3[] = {"location", "offset", "clamp"}; CXXMethodDecl *sampleDecl3 = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, paramType, params3, names3, + context, recordDecl, returnType, params3, names3, context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), /*isConst*/ true); sampleDecl3->addAttr(HLSLIntrinsicAttr::CreateImplicit( @@ -1425,20 +1411,25 @@ CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType(ASTContext &context, sampleDecl3->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); // Sample(location, offset, clamp, status) - QualType params4[] = {float2Type, int2Type, floatType, + QualType params4[] = {coordinateType, offsetType, floatType, context.getLValueReferenceType(uintType)}; StringRef names4[] = {"location", "offset", "clamp", "status"}; CXXMethodDecl *sampleDecl4 = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, paramType, params4, names4, + context, recordDecl, returnType, params4, names4, context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), /*isConst*/ true); sampleDecl4->addAttr(HLSLIntrinsicAttr::CreateImplicit( context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); sampleDecl4->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); +} + +static void AddCalculateLevelOfDetailFunction(ASTContext &context, + CXXRecordDecl *recordDecl, + QualType coordinateType) { + QualType floatType = context.FloatTy; - // CalculateLevelOfDetail(location) CXXMethodDecl *lodDecl = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, floatType, ArrayRef(float2Type), + context, recordDecl, floatType, ArrayRef(coordinateType), ArrayRef(StringRef("location")), context.DeclarationNames.getIdentifier( &context.Idents.get("CalculateLevelOfDetail")), @@ -1447,6 +1438,24 @@ CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType(ASTContext &context, context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_CalculateLevelOfDetail))); lodDecl->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); +} + +CXXRecordDecl *hlsl::DeclareVkSampledTextureType( + ASTContext &context, DeclContext *declContext, llvm::StringRef hlslTypeName, + QualType defaultParamType, QualType coordinateType, QualType offsetType) { + BuiltinTypeDeclBuilder Builder(declContext, hlslTypeName, + TagDecl::TagKind::TTK_Struct); + + TemplateTypeParmDecl *TyParamDecl = + Builder.addTypeTemplateParam("SampledTextureType", defaultParamType); + + Builder.startDefinition(); + + QualType paramType = QualType(TyParamDecl->getTypeForDecl(), 0); + CXXRecordDecl *recordDecl = Builder.getRecordDecl(); + + AddSampleFunction(context, recordDecl, paramType, coordinateType, offsetType); + AddCalculateLevelOfDetailFunction(context, recordDecl, coordinateType); Builder.completeDefinition(); return recordDecl; diff --git a/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp b/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp index d9ddc3428b..38d2adf166 100644 --- a/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp +++ b/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp @@ -854,7 +854,8 @@ const SpirvType *LowerTypeVisitor::lowerVkTypeInVkNamespace( auto loweredType = lowerType(getElementType(astContext, sampledType), rule, /*isRowMajor*/ llvm::None, srcLoc); - // Treat bool textures as uint for compatibility with OpTypeImage. + // Bool does not have a defined size in SPIR-V, so it cannot be + // used in the external interface. if (loweredType == spvContext.getBoolType()) { loweredType = spvContext.getUIntType(32); } @@ -908,7 +909,8 @@ LowerTypeVisitor::lowerResourceType(QualType type, SpirvLayoutRule rule, auto loweredType = lowerType(getElementType(astContext, sampledType), rule, /*isRowMajor*/ llvm::None, srcLoc); - // Treat bool textures as uint for compatibility with OpTypeImage. + // Bool does not have a defined size in SPIR-V, so it cannot be + // used in the external interface. if (loweredType == spvContext.getBoolType()) { loweredType = spvContext.getUIntType(32); } diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 2a5c783ab3..1f90260bec 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -4482,16 +4482,18 @@ SpirvEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr, assert(expr->getNumArgs() == (isSampledTexture(imageType) ? 1u : 2u)); auto *objectInfo = loadIfGLValue(imageExpr); - auto *samplerState = - isSampledTexture(imageType) ? nullptr : doExpr(expr->getArg(0)); - auto *coordinate = isSampledTexture(imageType) ? doExpr(expr->getArg(0)) - : doExpr(expr->getArg(1)); - auto *sampledImage = - isSampledTexture(imageType) - ? objectInfo - : spvBuilder.createSampledImage(imageExpr->getType(), objectInfo, - samplerState, expr->getExprLoc()); + SpirvInstruction *samplerState, *coordinate, *sampledImage; + if (isSampledTexture) { + samplerState = nullptr; + coordinate = doExpr(expr->getArg(0)); + sampledImage = objectInfo; + } else { + samplerState = doExpr(expr->getArg(0)); + coordinate = doExpr(expr->getArg(1)); + sampledImage = spvBuilder.createSampledImage( + imageExpr->getType(), objectInfo, samplerState, expr->getExprLoc()); + } // The result type of OpImageQueryLod must be a float2. const QualType queryResultType = @@ -5851,64 +5853,52 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, // [, out uint Status]); // // Other Texture types do not have a Gather method. - const auto numArgs = expr->getNumArgs(); const auto loc = expr->getExprLoc(); const auto range = expr->getSourceRange(); + const bool hasStatusArg = + expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType(); const auto *imageExpr = expr->getImplicitObjectArgument(); const QualType imageType = imageExpr->getType(); - - if (isSampledTexture(imageType)) { - auto *sampledImage = loadIfGLValue(imageExpr); - auto *coordinate = doExpr(expr->getArg(0)); - SpirvInstruction *constOffset = nullptr; - SpirvInstruction *varOffset = nullptr; - SpirvInstruction *clamp = nullptr; - SpirvInstruction *status = nullptr; - - if (numArgs > 1) { - handleOffsetInMethodCall(expr, 1, &constOffset, &varOffset); - } - if (numArgs > 2) { - clamp = doExpr(expr->getArg(2)); - } - if (numArgs > 3) { - status = doExpr(expr->getArg(3)); - } - - const auto retType = expr->getDirectCallee()->getReturnType(); - return createImageSample( - retType, imageType, sampledImage, /*sampler*/ nullptr, coordinate, - /*compareVal*/ nullptr, /*bias*/ nullptr, - /*lod*/ nullptr, {nullptr, nullptr}, constOffset, varOffset, - /*constOffsets*/ nullptr, /*sample*/ nullptr, - /*minLod*/ clamp, status, loc, range); + const bool isImageSampledTexture = isSampledTexture(imageType); + + int samplerIndex, clampIndex, coordIndex, offsetIndex; + if (isImageSampledTexture) { + samplerIndex = -1; // non-existant + coordIndex = 0; + offsetIndex = 1; + clampIndex = 2; + } else { + samplerIndex = 0; + coordIndex = 1; + offsetIndex = 2; + clampIndex = 3; } - auto *image = loadIfGLValue(imageExpr); - auto *sampler = doExpr(expr->getArg(0)); - auto *coordinate = doExpr(expr->getArg(1)); - // .Sample()/.Gather() may have a third optional paramter for offset. - SpirvInstruction *constOffset = nullptr, *varOffset = nullptr; - - const bool hasStatusArg = - expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType(); - SpirvInstruction *clamp = nullptr; - if (numArgs > 2 && expr->getArg(2)->getType()->isFloatingType()) - clamp = doExpr(expr->getArg(2)); - else if (numArgs > 3 && expr->getArg(3)->getType()->isFloatingType()) - clamp = doExpr(expr->getArg(3)); + if (numArgs > offsetIndex && + expr->getArg(offsetIndex)->getType()->isFloatingType()) + clamp = doExpr(expr->getArg(offsetIndex)); + else if (numArgs > offsetIndex + 1 && + expr->getArg(offsetIndex + 1)->getType()->isFloatingType()) + clamp = doExpr(expr->getArg(offsetIndex + 1)); const bool hasClampArg = (clamp != 0); const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : nullptr; + auto *image = loadIfGLValue(imageExpr); + SpirvInstruction *sampler = + samplerIndex >= 0 ? doExpr(expr->getArg(samplerIndex)) : nullptr; + auto *coordinate = doExpr(expr->getArg(coordIndex)); + // .Sample()/.Gather() may have a third optional paramter for offset. + SpirvInstruction *constOffset = nullptr, *varOffset = nullptr; // Subtract 1 for status (if it exists), subtract 1 for clamp (if it exists), - // and subtract 2 for sampler_state and location. - const bool hasOffsetArg = numArgs - hasStatusArg - hasClampArg - 2 > 0; + // and subtract offsetIndex for sampler_state (if exists) location. + const bool hasOffsetArg = + numArgs - hasStatusArg - hasClampArg - offsetIndex > 0; if (hasOffsetArg) - handleOffsetInMethodCall(expr, 2, &constOffset, &varOffset); + handleOffsetInMethodCall(expr, offsetIndex, &constOffset, &varOffset); const auto retType = expr->getDirectCallee()->getReturnType(); if (isSample) { diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 4f18b634aa..20bddf8130 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -4090,11 +4090,11 @@ class HLSLExternalSource : public ExternalSemaSource { } else if (kind == AR_OBJECT_VK_SAMPLED_TEXTURE2D) { if (!m_vkNSDecl) continue; - recordDecl = DeclareVkSampledTexture2DType( - *m_context, m_vkNSDecl, + recordDecl = DeclareVkSampledTextureType( + *m_context, m_vkNSDecl, "SampledTexture2D", + LookupVectorType(HLSLScalarType::HLSLScalarType_float, 4), LookupVectorType(HLSLScalarType::HLSLScalarType_float, 2), - LookupVectorType(HLSLScalarType::HLSLScalarType_int, 2), - LookupVectorType(HLSLScalarType::HLSLScalarType_float, 4)); + LookupVectorType(HLSLScalarType::HLSLScalarType_int, 2)); recordDecl->setImplicit(true); m_vkSampledTexture2DTemplateDecl = recordDecl->getDescribedClassTemplate(); @@ -5718,6 +5718,42 @@ class HLSLExternalSource : public ExternalSemaSource { } } + } else if (Template->getQualifiedNameAsString() == "vk::SampledTexture2D") { + if (TemplateArgList.size() == 1) { + const TemplateArgumentLoc &ArgLoc = TemplateArgList[0]; + const TemplateArgument &Arg = ArgLoc.getArgument(); + if (Arg.getKind() == TemplateArgument::ArgKind::Type) { + QualType ArgType = Arg.getAsType(); + if (!ArgType->isDependentType()) { + QualType EltTy = ArgType; + if (IsVectorType(m_sema, ArgType)) { + EltTy = hlsl::GetHLSLVecElementType(ArgType); + } + + bool isAllowedType = false; + if (const BuiltinType *BT = EltTy->getAs()) { + switch (BT->getKind()) { + case BuiltinType::Float: + case BuiltinType::Int: + case BuiltinType::UInt: + isAllowedType = true; + break; + default: + break; + } + } + + if (!isAllowedType) { + m_sema->Diag( + ArgLoc.getLocation(), + diag:: + err_hlsl_unsupported_vk_sampledtexture_template_parameter) + << ArgType; + return true; + } + } + } + } } else if (Template->getTemplatedDecl()->hasAttr()) { DXASSERT(TemplateArgList.size() == 1, diff --git a/tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl b/tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl index a900ea9cf8..0420b2af96 100644 --- a/tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl +++ b/tools/clang/test/CodeGenSPIRV/texture.array.sample.hlsl @@ -42,9 +42,9 @@ float4 main() : SV_Target { float4 val3 = t3.Sample(gSampler, float4(0.5, 0.25, 0.125, 1)); float clamp; -// CHECK: [[t1_0:%[0-9]+]] = OpLoad %type_1d_image_array %t1 +// CHECK: [[clamp:%[0-9]+]] = OpLoad %float %clamp +// CHECK-NEXT: [[t1_0:%[0-9]+]] = OpLoad %type_1d_image_array %t1 // CHECK-NEXT: [[gSampler_2:%[0-9]+]] = OpLoad %type_sampler %gSampler -// CHECK-NEXT: [[clamp:%[0-9]+]] = OpLoad %float %clamp // CHECK-NEXT: [[sampledImg_2:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1_0]] [[gSampler_2]] // CHECK-NEXT: {{%[0-9]+}} = OpImageSampleImplicitLod %v4float [[sampledImg_2]] [[v2fc]] ConstOffset|MinLod %int_1 [[clamp]] float4 val4 = t1.Sample(gSampler, float2(0.5, 1), 1, clamp); @@ -56,10 +56,10 @@ float4 main() : SV_Target { float4 val5 = t3.Sample(gSampler, float4(0.5, 0.25, 0.125, 1), /*clamp*/ 1.5); uint status; -// CHECK: [[t1_1:%[0-9]+]] = OpLoad %type_1d_image_array %t1 -// CHECK-NEXT: [[gSampler_4:%[0-9]+]] = OpLoad %type_sampler %gSampler -// CHECK-NEXT: [[clamp_0:%[0-9]+]] = OpLoad %float %clamp -// CHECK-NEXT: [[sampledImg_4:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1_1]] [[gSampler_4]] +// CHECK: [[clamp_0:%[0-9]+]] = OpLoad %float %clamp +// CHECK-NEXT: [[t1_1:%[0-9]+]] = OpLoad %type_1d_image_array %t1 +// CHECK-NEXT: [[gSampler_4:%[0-9]+]] = OpLoad %type_sampler %gSampler +// CHECK-NEXT: [[sampledImg_4:%[0-9]+]] = OpSampledImage %type_sampled_image [[t1_1]] [[gSampler_4]] // CHECK-NEXT: [[structResult:%[0-9]+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg_4]] [[v2fc]] ConstOffset|MinLod %int_1 [[clamp_0]] // CHECK-NEXT: [[status:%[0-9]+]] = OpCompositeExtract %uint [[structResult]] 0 // CHECK-NEXT: OpStore %status [[status]] diff --git a/tools/clang/test/CodeGenSPIRV/texture.sample.hlsl b/tools/clang/test/CodeGenSPIRV/texture.sample.hlsl index 404f06ef86..6a847c3442 100644 --- a/tools/clang/test/CodeGenSPIRV/texture.sample.hlsl +++ b/tools/clang/test/CodeGenSPIRV/texture.sample.hlsl @@ -51,9 +51,9 @@ float4 main(int2 offset: A) : SV_Target { float4 val4 = t4.Sample(gSampler, float3(0.5, 0.25, 0.3)); float clamp; -// CHECK: [[t2_0:%[0-9]+]] = OpLoad %type_2d_image %t2 +// CHECK: [[clamp:%[0-9]+]] = OpLoad %float %clamp +// CHECK-NEXT: [[t2_0:%[0-9]+]] = OpLoad %type_2d_image %t2 // CHECK-NEXT: [[gSampler_3:%[0-9]+]] = OpLoad %type_sampler %gSampler -// CHECK-NEXT: [[clamp:%[0-9]+]] = OpLoad %float %clamp // CHECK-NEXT: [[sampledImg_3:%[0-9]+]] = OpSampledImage %type_sampled_image_0 [[t2_0]] [[gSampler_3]] // CHECK-NEXT: {{%[0-9]+}} = OpImageSampleImplicitLod %v4float [[sampledImg_3]] [[v2fc]] ConstOffset|MinLod [[v2ic]] [[clamp]] float4 val5 = t2.Sample(gSampler, float2(0.5, 0.25), int2(2, 3), clamp); @@ -65,9 +65,9 @@ float4 main(int2 offset: A) : SV_Target { float4 val6 = t4.Sample(gSampler, float3(0.5, 0.25, 0.3), /*clamp*/ 2.0f); uint status; -// CHECK: [[t2_1:%[0-9]+]] = OpLoad %type_2d_image %t2 +// CHECK: [[clamp_0:%[0-9]+]] = OpLoad %float %clamp +// CHECK-NEXT: [[t2_1:%[0-9]+]] = OpLoad %type_2d_image %t2 // CHECK-NEXT: [[gSampler_5:%[0-9]+]] = OpLoad %type_sampler %gSampler -// CHECK-NEXT: [[clamp_0:%[0-9]+]] = OpLoad %float %clamp // CHECK-NEXT: [[sampledImg_5:%[0-9]+]] = OpSampledImage %type_sampled_image_0 [[t2_1]] [[gSampler_5]] // CHECK-NEXT: [[structResult:%[0-9]+]] = OpImageSparseSampleImplicitLod %SparseResidencyStruct [[sampledImg_5]] [[v2fc]] ConstOffset|MinLod [[v2ic]] [[clamp_0]] // CHECK-NEXT: [[status:%[0-9]+]] = OpCompositeExtract %uint [[structResult]] 0 diff --git a/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl b/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl new file mode 100644 index 0000000000..317878db26 --- /dev/null +++ b/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl @@ -0,0 +1,26 @@ +// REQUIRES: spirv +// RUN: %dxc -T ps_6_0 -E main -spirv -verify %s + +struct MyStruct { + float4 a; +}; + +[[vk::binding(0, 0)]] +vk::SampledTexture2D tex1; // expected-error {{'MyStruct' cannot be used as a type parameter where it must be of type float, int, uint or their vector equivalents}} + +[[vk::binding(1, 0)]] +vk::SampledTexture2D tex2; // expected-error {{'float [4]' cannot be used as a type parameter where it must be of type float, int, uint or their vector equivalents}} + +[[vk::binding(2, 0)]] +vk::SampledTexture2D tex3; + +[[vk::binding(3, 0)]] +vk::SampledTexture2D tex4; + +[[vk::binding(4, 0)]] +vk::SampledTexture2D tex5; + +[[vk::binding(5, 0)]] +vk::SampledTexture2D tex6; + +void main() {} From 835188e7354552dff8cf33da59c7b0a6aa48311a Mon Sep 17 00:00:00 2001 From: luciechoi Date: Tue, 27 Jan 2026 17:30:03 +0000 Subject: [PATCH 06/11] Address comments --- .../clang/Basic/DiagnosticSemaKinds.td | 8 ++- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 38 ++++++------- tools/clang/lib/Sema/SemaHLSL.cpp | 54 +++---------------- .../SemaHLSL/vk.sampledtexture.error.hlsl | 4 +- 4 files changed, 28 insertions(+), 76 deletions(-) diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8622af4d9f..0b5a66eb03 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7615,11 +7615,9 @@ def err_hlsl_unsupported_buffer_slot_target_specific : Error< "user defined constant buffer slots cannot be target specific">; def err_hlsl_unsupported_typedbuffer_template_parameter : Error< "elements of typed buffers and textures must be scalars or vectors">; -def err_hlsl_unsupported_typedbuffer_template_parameter_size : Error< - "elements of typed buffers and textures must fit in four 32-bit quantities">; -def err_hlsl_unsupported_vk_sampledtexture_template_parameter - : Error<"%0 cannot be used as a type parameter where it must be of type " - "float, int, uint or their vector equivalents">; +def err_hlsl_unsupported_typedbuffer_template_parameter_size + : Error<"elements of typed buffers and textures must fit in four 32-bit " + "quantities">; def err_hlsl_unsupported_payload_access_qualifier : Error< "payload access qualifiers are only allowed for member variables of a payload structure">; def err_hlsl_unsupported_payload_access_qualifier_struct : Error< diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 1f90260bec..67283a2fcc 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -4473,9 +4473,10 @@ SpirvEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr, // Texture2D(Array).CalculateLevelOfDetail(SamplerState S, float2 xy); // TextureCube(Array).CalculateLevelOfDetail(SamplerState S, float3 xyz); // Texture3D.CalculateLevelOfDetail(SamplerState S, float3 xyz); - // SampledTexture2D.CalculateLevelOfDetail(float2 xy); // Return type is always a single float (LOD). - + // + // Their SampledTexture variants have the same signature without the + // sampler_state parameter. const auto *imageExpr = expr->getImplicitObjectArgument(); const QualType imageType = imageExpr->getType(); // numarg is 1 if isSampledTexture(imageType). otherwise 2. @@ -4484,7 +4485,7 @@ SpirvEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr, auto *objectInfo = loadIfGLValue(imageExpr); SpirvInstruction *samplerState, *coordinate, *sampledImage; - if (isSampledTexture) { + if (isSampledTexture(imageType)) { samplerState = nullptr; coordinate = doExpr(expr->getArg(0)); sampledImage = objectInfo; @@ -5829,6 +5830,9 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, // [, float Clamp] // [, out uint Status]); // + // Their SampledTexture variants have the same signature without the + // sampler_state parameter. + // // For TextureCube and TextureCubeArray: // DXGI_FORMAT Object.Sample(sampler_state S, // float Location @@ -5846,12 +5850,6 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, // float2|3|4 Location // [, uint Status]); // - // For SampledTexture2D: - // DXGI_FORMAT Object.Sample(float Location - // [, int Offset] - // [, float Clamp] - // [, out uint Status]); - // // Other Texture types do not have a Gather method. const auto numArgs = expr->getNumArgs(); const auto loc = expr->getExprLoc(); @@ -5863,26 +5861,22 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, const QualType imageType = imageExpr->getType(); const bool isImageSampledTexture = isSampledTexture(imageType); - int samplerIndex, clampIndex, coordIndex, offsetIndex; + int samplerIndex, coordIndex; if (isImageSampledTexture) { samplerIndex = -1; // non-existant coordIndex = 0; - offsetIndex = 1; - clampIndex = 2; } else { samplerIndex = 0; coordIndex = 1; - offsetIndex = 2; - clampIndex = 3; } SpirvInstruction *clamp = nullptr; - if (numArgs > offsetIndex && - expr->getArg(offsetIndex)->getType()->isFloatingType()) - clamp = doExpr(expr->getArg(offsetIndex)); - else if (numArgs > offsetIndex + 1 && - expr->getArg(offsetIndex + 1)->getType()->isFloatingType()) - clamp = doExpr(expr->getArg(offsetIndex + 1)); + if (numArgs > coordIndex + 1 && + expr->getArg(coordIndex + 1)->getType()->isFloatingType()) + clamp = doExpr(expr->getArg(coordIndex + 1)); + else if (numArgs > coordIndex + 2 && + expr->getArg(coordIndex + 2)->getType()->isFloatingType()) + clamp = doExpr(expr->getArg(coordIndex + 2)); const bool hasClampArg = (clamp != 0); const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : nullptr; @@ -5896,9 +5890,9 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, // Subtract 1 for status (if it exists), subtract 1 for clamp (if it exists), // and subtract offsetIndex for sampler_state (if exists) location. const bool hasOffsetArg = - numArgs - hasStatusArg - hasClampArg - offsetIndex > 0; + numArgs - hasStatusArg - hasClampArg - coordIndex > 1; if (hasOffsetArg) - handleOffsetInMethodCall(expr, offsetIndex, &constOffset, &varOffset); + handleOffsetInMethodCall(expr, coordIndex + 1, &constOffset, &varOffset); const auto retType = expr->getDirectCallee()->getReturnType(); if (isSample) { diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 20bddf8130..55c9f13e3d 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -3081,7 +3081,7 @@ class HLSLExternalSource : public ExternalSemaSource { ClassTemplateDecl *m_vkIntegralConstantTemplateDecl; ClassTemplateDecl *m_vkLiteralTemplateDecl; ClassTemplateDecl *m_vkBufferPointerTemplateDecl; - ClassTemplateDecl *m_vkSampledTexture2DTemplateDecl; + ClassTemplateDecl *m_vkSampledTextureTemplateDecl; // Declarations for Work Graph Output Record types ClassTemplateDecl *m_GroupNodeOutputRecordsTemplateDecl; @@ -4096,7 +4096,11 @@ class HLSLExternalSource : public ExternalSemaSource { LookupVectorType(HLSLScalarType::HLSLScalarType_float, 2), LookupVectorType(HLSLScalarType::HLSLScalarType_int, 2)); recordDecl->setImplicit(true); - m_vkSampledTexture2DTemplateDecl = + Attr = HLSLResourceAttr::CreateImplicit( + *m_context, (unsigned)DXIL::ResourceKind::Texture2D, + (unsigned)DXIL::ResourceClass::SRV); + recordDecl->addAttr(Attr); + m_vkSampledTextureTemplateDecl = recordDecl->getDescribedClassTemplate(); } #endif @@ -4212,7 +4216,7 @@ class HLSLExternalSource : public ExternalSemaSource { m_vkIntegralConstantTemplateDecl(nullptr), m_vkLiteralTemplateDecl(nullptr), m_vkBufferPointerTemplateDecl(nullptr), - m_vkSampledTexture2DTemplateDecl(nullptr), m_hlslNSDecl(nullptr), + m_vkSampledTextureTemplateDecl(nullptr), m_hlslNSDecl(nullptr), m_vkNSDecl(nullptr), m_dxNSDecl(nullptr), m_context(nullptr), m_sema(nullptr), m_hlslStringTypedef(nullptr) { memset(m_matrixTypes, 0, sizeof(m_matrixTypes)); @@ -5547,14 +5551,6 @@ class HLSLExternalSource : public ExternalSemaSource { recordType->getDecl()->getName().equals("SpirvOpaqueType"))) { return true; } -#endif -#ifdef ENABLE_SPIRV_CODEGEN - if (const auto *namespaceDecl = dyn_cast( - recordType->getDecl()->getDeclContext()); - namespaceDecl && namespaceDecl->getName().equals("vk") && - recordType->getDecl()->getName().equals("SampledTexture2D")) { - return true; - } #endif m_sema->Diag(argLoc, diag::err_hlsl_unsupported_object_context) << type << static_cast(TypeDiagContext::TypeParameter); @@ -5718,42 +5714,6 @@ class HLSLExternalSource : public ExternalSemaSource { } } - } else if (Template->getQualifiedNameAsString() == "vk::SampledTexture2D") { - if (TemplateArgList.size() == 1) { - const TemplateArgumentLoc &ArgLoc = TemplateArgList[0]; - const TemplateArgument &Arg = ArgLoc.getArgument(); - if (Arg.getKind() == TemplateArgument::ArgKind::Type) { - QualType ArgType = Arg.getAsType(); - if (!ArgType->isDependentType()) { - QualType EltTy = ArgType; - if (IsVectorType(m_sema, ArgType)) { - EltTy = hlsl::GetHLSLVecElementType(ArgType); - } - - bool isAllowedType = false; - if (const BuiltinType *BT = EltTy->getAs()) { - switch (BT->getKind()) { - case BuiltinType::Float: - case BuiltinType::Int: - case BuiltinType::UInt: - isAllowedType = true; - break; - default: - break; - } - } - - if (!isAllowedType) { - m_sema->Diag( - ArgLoc.getLocation(), - diag:: - err_hlsl_unsupported_vk_sampledtexture_template_parameter) - << ArgType; - return true; - } - } - } - } } else if (Template->getTemplatedDecl()->hasAttr()) { DXASSERT(TemplateArgList.size() == 1, diff --git a/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl b/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl index 317878db26..e4613dda9d 100644 --- a/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl +++ b/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl @@ -6,10 +6,10 @@ struct MyStruct { }; [[vk::binding(0, 0)]] -vk::SampledTexture2D tex1; // expected-error {{'MyStruct' cannot be used as a type parameter where it must be of type float, int, uint or their vector equivalents}} +vk::SampledTexture2D tex1; // expected-error {{elements of typed buffers and textures must be scalars or vectors}} [[vk::binding(1, 0)]] -vk::SampledTexture2D tex2; // expected-error {{'float [4]' cannot be used as a type parameter where it must be of type float, int, uint or their vector equivalents}} +vk::SampledTexture2D tex2; // expected-error {{elements of typed buffers and textures must be scalars or vectors}} [[vk::binding(2, 0)]] vk::SampledTexture2D tex3; From ea9aa7c9d98c70f0e496e90c4b5b567ff9f4dbf5 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Tue, 27 Jan 2026 20:37:17 +0000 Subject: [PATCH 07/11] address comments --- tools/clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 ++--- tools/clang/lib/SPIRV/SpirvBuilder.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0b5a66eb03..7e25e99d46 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7615,9 +7615,8 @@ def err_hlsl_unsupported_buffer_slot_target_specific : Error< "user defined constant buffer slots cannot be target specific">; def err_hlsl_unsupported_typedbuffer_template_parameter : Error< "elements of typed buffers and textures must be scalars or vectors">; -def err_hlsl_unsupported_typedbuffer_template_parameter_size - : Error<"elements of typed buffers and textures must fit in four 32-bit " - "quantities">; +def err_hlsl_unsupported_typedbuffer_template_parameter_size : Error< + "elements of typed buffers and textures must fit in four 32-bit quantities">; def err_hlsl_unsupported_payload_access_qualifier : Error< "payload access qualifiers are only allowed for member variables of a payload structure">; def err_hlsl_unsupported_payload_access_qualifier_struct : Error< diff --git a/tools/clang/lib/SPIRV/SpirvBuilder.cpp b/tools/clang/lib/SPIRV/SpirvBuilder.cpp index 2fd60e514d..7ce0508585 100644 --- a/tools/clang/lib/SPIRV/SpirvBuilder.cpp +++ b/tools/clang/lib/SPIRV/SpirvBuilder.cpp @@ -621,7 +621,7 @@ SpirvInstruction *SpirvBuilder::createImageSample( // An OpSampledImage is required to do the image sampling. // Skip creating OpSampledImage if the imageType is a sampled texture. - SpirvInstruction *sampledImage = nullptr; + SpirvInstruction *sampledImage; if (isSampledTexture(imageType)) { assert(!sampler && "sampler must be null when sampling from a sampled texture"); From 73f0ebd655b19741363db05ea142643380d7b37c Mon Sep 17 00:00:00 2001 From: luciechoi Date: Thu, 5 Feb 2026 22:05:01 +0000 Subject: [PATCH 08/11] Re-implement type and function declaration using auto-generation --- tools/clang/include/clang/AST/HlslTypes.h | 3 +- tools/clang/lib/AST/ASTContextHLSL.cpp | 83 ++----------------- tools/clang/lib/Sema/SemaHLSL.cpp | 19 +++-- .../vk.sampledtexture.sample.hlsl | 16 ++-- .../SemaHLSL/vk.sampledtexture.error.hlsl | 26 ------ .../vk.sampledtexture.struct.error.hlsl | 10 +++ utils/hct/gen_intrin_main.txt | 8 ++ utils/hct/hctdb.py | 2 +- 8 files changed, 46 insertions(+), 121 deletions(-) delete mode 100644 tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl create mode 100644 tools/clang/test/SemaHLSL/vk.sampledtexture.struct.error.hlsl diff --git a/tools/clang/include/clang/AST/HlslTypes.h b/tools/clang/include/clang/AST/HlslTypes.h index 2f4afe673a..610d844616 100644 --- a/tools/clang/include/clang/AST/HlslTypes.h +++ b/tools/clang/include/clang/AST/HlslTypes.h @@ -409,8 +409,7 @@ DeclareVkBufferPointerType(clang::ASTContext &context, clang::CXXRecordDecl *DeclareVkSampledTextureType( clang::ASTContext &context, clang::DeclContext *declContext, - llvm::StringRef hlslTypeName, clang::QualType defaultParamType, - clang::QualType coordinateType, clang::QualType offsetType); + llvm::StringRef hlslTypeName, clang::QualType defaultParamType); clang::CXXRecordDecl *DeclareInlineSpirvType(clang::ASTContext &context, clang::DeclContext *declContext, diff --git a/tools/clang/lib/AST/ASTContextHLSL.cpp b/tools/clang/lib/AST/ASTContextHLSL.cpp index 86ebf10bac..9e60ce123c 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1372,77 +1372,12 @@ CXXRecordDecl *hlsl::DeclareNodeOrRecordType( } #ifdef ENABLE_SPIRV_CODEGEN -static void AddSampleFunction(ASTContext &context, CXXRecordDecl *recordDecl, - QualType returnType, QualType coordinateType, - QualType offsetType) { - QualType floatType = context.FloatTy; - QualType uintType = context.UnsignedIntTy; - - // Sample(location) - CXXMethodDecl *sampleDecl = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, returnType, ArrayRef(coordinateType), - ArrayRef(StringRef("location")), - context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), - /*isConst*/ true); - sampleDecl->addAttr(HLSLIntrinsicAttr::CreateImplicit( - context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); - sampleDecl->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); - - // Sample(location, offset) - QualType params2[] = {coordinateType, offsetType}; - StringRef names2[] = {"location", "offset"}; - CXXMethodDecl *sampleDecl2 = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, returnType, params2, names2, - context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), - /*isConst*/ true); - sampleDecl2->addAttr(HLSLIntrinsicAttr::CreateImplicit( - context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); - sampleDecl2->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); - - // Sample(location, offset, clamp) - QualType params3[] = {coordinateType, offsetType, floatType}; - StringRef names3[] = {"location", "offset", "clamp"}; - CXXMethodDecl *sampleDecl3 = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, returnType, params3, names3, - context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), - /*isConst*/ true); - sampleDecl3->addAttr(HLSLIntrinsicAttr::CreateImplicit( - context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); - sampleDecl3->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); - - // Sample(location, offset, clamp, status) - QualType params4[] = {coordinateType, offsetType, floatType, - context.getLValueReferenceType(uintType)}; - StringRef names4[] = {"location", "offset", "clamp", "status"}; - CXXMethodDecl *sampleDecl4 = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, returnType, params4, names4, - context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), - /*isConst*/ true); - sampleDecl4->addAttr(HLSLIntrinsicAttr::CreateImplicit( - context, "op", "", static_cast(hlsl::IntrinsicOp::MOP_Sample))); - sampleDecl4->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); -} - -static void AddCalculateLevelOfDetailFunction(ASTContext &context, - CXXRecordDecl *recordDecl, - QualType coordinateType) { - QualType floatType = context.FloatTy; - - CXXMethodDecl *lodDecl = CreateObjectFunctionDeclarationWithParams( - context, recordDecl, floatType, ArrayRef(coordinateType), - ArrayRef(StringRef("location")), - context.DeclarationNames.getIdentifier( - &context.Idents.get("CalculateLevelOfDetail")), - /*isConst*/ true); - lodDecl->addAttr(HLSLIntrinsicAttr::CreateImplicit( - context, "op", "", - static_cast(hlsl::IntrinsicOp::MOP_CalculateLevelOfDetail))); - lodDecl->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); -} - -CXXRecordDecl *hlsl::DeclareVkSampledTextureType( - ASTContext &context, DeclContext *declContext, llvm::StringRef hlslTypeName, - QualType defaultParamType, QualType coordinateType, QualType offsetType) { +CXXRecordDecl *hlsl::DeclareVkSampledTextureType(ASTContext &context, + DeclContext *declContext, + llvm::StringRef hlslTypeName, + QualType defaultParamType) { + // TODO(https://github.com/microsoft/DirectXShaderCompiler/issues/7979): Later + // generalize these to all SampledTexture types. BuiltinTypeDeclBuilder Builder(declContext, hlslTypeName, TagDecl::TagKind::TTK_Struct); @@ -1454,10 +1389,10 @@ CXXRecordDecl *hlsl::DeclareVkSampledTextureType( QualType paramType = QualType(TyParamDecl->getTypeForDecl(), 0); CXXRecordDecl *recordDecl = Builder.getRecordDecl(); - AddSampleFunction(context, recordDecl, paramType, coordinateType, offsetType); - AddCalculateLevelOfDetailFunction(context, recordDecl, coordinateType); + if (auto *tmpl = recordDecl->getDescribedClassTemplate()) { + tmpl->setImplicit(true); + } - Builder.completeDefinition(); return recordDecl; } diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 55c9f13e3d..fb7d21acaa 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -2483,6 +2483,12 @@ static void GetIntrinsicMethods(ArBasicKind kind, *intrinsics = g_RayQueryMethods; *intrinsicCount = _countof(g_RayQueryMethods); break; +#ifdef ENABLE_SPIRV_CODEGEN + case AR_OBJECT_VK_SAMPLED_TEXTURE2D: + *intrinsics = g_VkSampledTexture2DMethods; + *intrinsicCount = _countof(g_VkSampledTexture2DMethods); + break; +#endif case AR_OBJECT_HIT_OBJECT: *intrinsics = g_DxHitObjectMethods; *intrinsicCount = _countof(g_DxHitObjectMethods); @@ -4090,18 +4096,15 @@ class HLSLExternalSource : public ExternalSemaSource { } else if (kind == AR_OBJECT_VK_SAMPLED_TEXTURE2D) { if (!m_vkNSDecl) continue; + QualType float4Type = + LookupVectorType(HLSLScalarType::HLSLScalarType_float, 4); recordDecl = DeclareVkSampledTextureType( - *m_context, m_vkNSDecl, "SampledTexture2D", - LookupVectorType(HLSLScalarType::HLSLScalarType_float, 4), - LookupVectorType(HLSLScalarType::HLSLScalarType_float, 2), - LookupVectorType(HLSLScalarType::HLSLScalarType_int, 2)); + *m_context, m_vkNSDecl, "SampledTexture2D", float4Type); recordDecl->setImplicit(true); - Attr = HLSLResourceAttr::CreateImplicit( - *m_context, (unsigned)DXIL::ResourceKind::Texture2D, - (unsigned)DXIL::ResourceClass::SRV); - recordDecl->addAttr(Attr); m_vkSampledTextureTemplateDecl = recordDecl->getDescribedClassTemplate(); + if (m_vkSampledTextureTemplateDecl) + m_vkSampledTextureTemplateDecl->setImplicit(true); } #endif else if (templateArgCount == 0) { diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl index c00aa7b51c..b13091167a 100644 --- a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl @@ -10,17 +10,13 @@ // 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: [[tex1:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_1]] UniformConstant // CHECK: [[tex2:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_1]] UniformConstant -// CHECK: [[tex3:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_2]] UniformConstant +// CHECK: [[tex3:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_1]] UniformConstant vk::SampledTexture2D tex1 : register(t0); vk::SampledTexture2D tex2 : register(t1); -vk::SampledTexture2D tex3 : register(t2); +vk::SampledTexture2D tex3 : register(t2); float4 main() : SV_Target { // CHECK: [[tex1_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex1]] @@ -42,9 +38,9 @@ float4 main() : SV_Target { uint status; float4 val4 = tex2.Sample(float2(0.5, 0.25), int2(2, 3), 1.0f, status); -// CHECK: [[tex5_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_2]] [[tex3]] -// CHECK: [[sampled_result5:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4uint [[tex5_load]] [[v2fc]] None -// CHECK: [[val5:%[a-zA-Z0-9_]+]] = OpCompositeExtract %uint [[sampled_result5]] 0 - uint val5 = tex3.Sample(float2(0.5, 0.25)); +// CHECK: [[tex5_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex3]] +// CHECK: [[sampled_result5:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4float [[tex5_load]] [[v2fc]] None +// CHECK: [[val5:%[a-zA-Z0-9_]+]] = OpVectorShuffle %v2float [[sampled_result5]] [[sampled_result5]] 0 1 + float2 val5 = tex3.Sample(float2(0.5, 0.25)); return 1.0; } diff --git a/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl b/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl deleted file mode 100644 index e4613dda9d..0000000000 --- a/tools/clang/test/SemaHLSL/vk.sampledtexture.error.hlsl +++ /dev/null @@ -1,26 +0,0 @@ -// REQUIRES: spirv -// RUN: %dxc -T ps_6_0 -E main -spirv -verify %s - -struct MyStruct { - float4 a; -}; - -[[vk::binding(0, 0)]] -vk::SampledTexture2D tex1; // expected-error {{elements of typed buffers and textures must be scalars or vectors}} - -[[vk::binding(1, 0)]] -vk::SampledTexture2D tex2; // expected-error {{elements of typed buffers and textures must be scalars or vectors}} - -[[vk::binding(2, 0)]] -vk::SampledTexture2D tex3; - -[[vk::binding(3, 0)]] -vk::SampledTexture2D tex4; - -[[vk::binding(4, 0)]] -vk::SampledTexture2D tex5; - -[[vk::binding(5, 0)]] -vk::SampledTexture2D tex6; - -void main() {} diff --git a/tools/clang/test/SemaHLSL/vk.sampledtexture.struct.error.hlsl b/tools/clang/test/SemaHLSL/vk.sampledtexture.struct.error.hlsl new file mode 100644 index 0000000000..6f1db1f871 --- /dev/null +++ b/tools/clang/test/SemaHLSL/vk.sampledtexture.struct.error.hlsl @@ -0,0 +1,10 @@ +// RUN: %dxc -T ps_6_0 -E main %s -spirv -fcgl -verify + +struct Struct { float f; }; + +vk::SampledTexture2D t; + +float4 main(float2 f2 : F2) : SV_TARGET +{ + return t.Sample(f2); // expected-error {{cannot Sample from resource containing}} expected-error {{cannot initialize return object}} +} diff --git a/utils/hct/gen_intrin_main.txt b/utils/hct/gen_intrin_main.txt index 5f61b5b6ab..f799ee2810 100644 --- a/utils/hct/gen_intrin_main.txt +++ b/utils/hct/gen_intrin_main.txt @@ -1234,3 +1234,11 @@ $classT [[]] SubpassLoad(in int sample) : subpassinputms_load; } namespace // SPIRV Change Ends + +namespace VkSampledTexture2DMethods { + $classT [[ro]] Sample(in float<2> x) : tex2d_t; + $classT [[ro]] Sample(in float<2> x, in int<2> o) : tex2d_t_o; + $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; +} namespace diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 69fd14be6b..09a688fd39 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -9696,7 +9696,7 @@ def load_intrinsics(self, intrinsic_defs): acceleration_struct | ray_desc | RayQuery | DxHitObject | Node\w* | RWNode\w* | EmptyNode\w* | AnyNodeOutput\w* | NodeOutputRecord\w* | GroupShared\w* | - VkBufferPointer | LinAlgMatrix + VkBufferPointer | LinAlgMatrix | VkSampledTexture2D $)""", flags=re.VERBOSE, ) From a5a2386c0b41047dec7cd07c00fbb37d454b9971 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Mon, 9 Feb 2026 18:13:34 +0000 Subject: [PATCH 09/11] Bring back uint test and increase shader module version --- .../CodeGenSPIRV/vk.sampledtexture.sample.hlsl | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl index b13091167a..ee4051f45c 100644 --- a/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl @@ -1,4 +1,4 @@ -// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv | FileCheck %s +// RUN: %dxc -T ps_6_7 -E main -fcgl %s -spirv | FileCheck %s // CHECK: OpCapability MinLod // CHECK: OpCapability SparseResidency @@ -10,13 +10,17 @@ // 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: [[tex1:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_1]] UniformConstant // CHECK: [[tex2:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_1]] UniformConstant -// CHECK: [[tex3:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_1]] UniformConstant +// CHECK: [[tex3:%[a-zA-Z0-9_]+]] = OpVariable [[ptr_type_2]] UniformConstant vk::SampledTexture2D tex1 : register(t0); vk::SampledTexture2D tex2 : register(t1); -vk::SampledTexture2D tex3 : register(t2); +vk::SampledTexture2D tex3 : register(t2); float4 main() : SV_Target { // CHECK: [[tex1_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex1]] @@ -38,9 +42,9 @@ float4 main() : SV_Target { uint status; float4 val4 = tex2.Sample(float2(0.5, 0.25), int2(2, 3), 1.0f, status); -// CHECK: [[tex5_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_1]] [[tex3]] -// CHECK: [[sampled_result5:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4float [[tex5_load]] [[v2fc]] None -// CHECK: [[val5:%[a-zA-Z0-9_]+]] = OpVectorShuffle %v2float [[sampled_result5]] [[sampled_result5]] 0 1 - float2 val5 = tex3.Sample(float2(0.5, 0.25)); +// CHECK: [[tex5_load:%[a-zA-Z0-9_]+]] = OpLoad [[type_sampled_image_2]] [[tex3]] +// CHECK: [[sampled_result5:%[a-zA-Z0-9_]+]] = OpImageSampleImplicitLod %v4uint [[tex5_load]] [[v2fc]] None +// CHECK: [[val5:%[a-zA-Z0-9_]+]] = OpCompositeExtract %uint [[sampled_result5]] 0 + uint val5 = tex3.Sample(float2(0.5, 0.25)); return 1.0; } From 076cf2c124f5b2a51c78cc15a3d125bb758c4882 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Mon, 9 Feb 2026 18:38:15 +0000 Subject: [PATCH 10/11] Remove unncessary setImplicit --- tools/clang/include/clang/SPIRV/SpirvBuilder.h | 6 +++--- tools/clang/lib/AST/ASTContextHLSL.cpp | 4 ---- tools/clang/lib/Sema/SemaHLSL.cpp | 3 --- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/tools/clang/include/clang/SPIRV/SpirvBuilder.h b/tools/clang/include/clang/SPIRV/SpirvBuilder.h index f2d0ddf4ca..868c978c35 100644 --- a/tools/clang/include/clang/SPIRV/SpirvBuilder.h +++ b/tools/clang/include/clang/SPIRV/SpirvBuilder.h @@ -287,9 +287,9 @@ class SpirvBuilder { /// If compareVal is given a non-zero value, *Dref* variants of OpImageSample* /// will be generated. /// - /// If the of `image` is a sampled image, then that image will be sampled. - /// In this case, `sampler` must be `nullptr`. If `image` is not a sampled - /// image, a sampled image will be create by combining `image` and `sampler`. + /// If sampler is set, it defines the sampler along *image* to create the + /// combined image sampler. Otherwise, the *image* parameter must point to a + /// sampled image. /// /// If lod or grad is given a non-zero value, *ExplicitLod variants of /// OpImageSample* will be generated; otherwise, *ImplicitLod variant will diff --git a/tools/clang/lib/AST/ASTContextHLSL.cpp b/tools/clang/lib/AST/ASTContextHLSL.cpp index 9e60ce123c..1482d09a3f 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1389,10 +1389,6 @@ CXXRecordDecl *hlsl::DeclareVkSampledTextureType(ASTContext &context, QualType paramType = QualType(TyParamDecl->getTypeForDecl(), 0); CXXRecordDecl *recordDecl = Builder.getRecordDecl(); - if (auto *tmpl = recordDecl->getDescribedClassTemplate()) { - tmpl->setImplicit(true); - } - return recordDecl; } diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index fb7d21acaa..d41816a8a2 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -4100,11 +4100,8 @@ class HLSLExternalSource : public ExternalSemaSource { LookupVectorType(HLSLScalarType::HLSLScalarType_float, 4); recordDecl = DeclareVkSampledTextureType( *m_context, m_vkNSDecl, "SampledTexture2D", float4Type); - recordDecl->setImplicit(true); m_vkSampledTextureTemplateDecl = recordDecl->getDescribedClassTemplate(); - if (m_vkSampledTextureTemplateDecl) - m_vkSampledTextureTemplateDecl->setImplicit(true); } #endif else if (templateArgCount == 0) { From a573ec563aa3690239a3c3fa61a7010e2e6f6750 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Thu, 12 Feb 2026 16:56:13 +0000 Subject: [PATCH 11/11] Fix compiler warning --- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 67283a2fcc..f77e9ac82b 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -5861,7 +5861,8 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, const QualType imageType = imageExpr->getType(); const bool isImageSampledTexture = isSampledTexture(imageType); - int samplerIndex, coordIndex; + int samplerIndex; + uint32_t coordIndex; if (isImageSampledTexture) { samplerIndex = -1; // non-existant coordIndex = 0;