From 6c73c17c1796dc089d67cc592dad01e2abc21b92 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Wed, 7 Jan 2026 08:10:48 +0000 Subject: [PATCH 1/4] 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 46a485206e..780b35ced9 100644 --- a/include/dxc/dxcapi.internal.h +++ b/include/dxc/dxcapi.internal.h @@ -136,7 +136,8 @@ enum LEGAL_INTRINSIC_COMPTYPES { #ifdef ENABLE_SPIRV_CODEGEN LICOMPTYPE_VK_BUFFER_POINTER = 54, - LICOMPTYPE_COUNT = 55 + LICOMPTYPE_VK_SAMPLED_TEXTURE2D = 55, + LICOMPTYPE_COUNT = 56 #else LICOMPTYPE_COUNT = 54 #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 913b28ced8..48211ff3c9 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1369,6 +1369,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 00c18a81a9..1638feb7ae 100644 --- a/tools/clang/lib/AST/HlslTypes.cpp +++ b/tools/clang/lib/AST/HlslTypes.cpp @@ -817,6 +817,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 86701f48fd..e78125c819 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 2c8b8a3440..1e9a0d96e6 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -5812,6 +5812,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(); @@ -5835,6 +5841,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 e9c8c90a2d..ab5610468d 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -198,6 +198,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 @@ -554,6 +555,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 @@ -1250,6 +1252,8 @@ static const ArBasicKind g_DxHitObjectCT[] = {AR_OBJECT_HIT_OBJECT, #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. @@ -1311,6 +1315,7 @@ const ArBasicKind *g_LegalIntrinsicCompTypes[] = { g_LinAlgCT, // LICOMPTYPE_LINALG #ifdef ENABLE_SPIRV_CODEGEN g_VKBufferPointerCT, // LICOMPTYPE_VK_BUFFER_POINTER + g_VKSampledTexture2DCT, // LICOMPTYPE_VK_SAMPLED_TEXTURE2D #endif }; static_assert( @@ -1370,7 +1375,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 @@ -1478,6 +1483,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 @@ -1627,6 +1633,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 @@ -1792,6 +1799,7 @@ static const char *g_ArBasicTypeNames[] = { "ext_type", "ext_result_id", "BufferPointer", + "SampledTexture2D", #endif // ENABLE_SPIRV_CODEGEN // SPIRV change ends @@ -3013,6 +3021,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; @@ -4004,6 +4013,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) { @@ -4117,7 +4137,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)); @@ -5444,6 +5465,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 4c95db36e11fd73abba15c6bf6405542aa26eed2 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Thu, 8 Jan 2026 04:09:29 +0000 Subject: [PATCH 2/4] 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 1d012568d6..dadea97be5 100644 --- a/tools/clang/include/clang/SPIRV/SpirvBuilder.h +++ b/tools/clang/include/clang/SPIRV/SpirvBuilder.h @@ -286,6 +286,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 48211ff3c9..10b572f82d 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1369,13 +1369,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); @@ -1384,8 +1386,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")), @@ -1394,6 +1398,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 1638feb7ae..00c18a81a9 100644 --- a/tools/clang/lib/AST/HlslTypes.cpp +++ b/tools/clang/lib/AST/HlslTypes.cpp @@ -817,15 +817,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 e78125c819..bf30deea5a 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 1e9a0d96e6..76b45cbc7e 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -5823,21 +5823,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(); @@ -5845,15 +5830,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); @@ -5861,6 +5859,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 ab5610468d..1f24f62584 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -4016,14 +4016,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 03b6051ba258d66c69201d10445fb477617d8512 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Fri, 9 Jan 2026 10:20:08 +0000 Subject: [PATCH 3/4] 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 10b572f82d..1d3f94d36c 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1434,6 +1434,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 76b45cbc7e..af065f66d5 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -4451,15 +4451,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 389cd0ff76ce8e4ac27b76210710ea7d5fc85256 Mon Sep 17 00:00:00 2001 From: luciechoi Date: Fri, 9 Jan 2026 10:51:51 +0000 Subject: [PATCH 4/4] 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 1d3f94d36c..6f6285b119 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1396,8 +1396,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 1f24f62584..975e9f2b4f 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -1252,8 +1252,8 @@ static const ArBasicKind g_DxHitObjectCT[] = {AR_OBJECT_HIT_OBJECT, #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. @@ -1314,7 +1314,7 @@ const ArBasicKind *g_LegalIntrinsicCompTypes[] = { g_RayQueryCT, // LICOMPTYPE_RAY_QUERY g_LinAlgCT, // LICOMPTYPE_LINALG #ifdef ENABLE_SPIRV_CODEGEN - g_VKBufferPointerCT, // LICOMPTYPE_VK_BUFFER_POINTER + g_VKBufferPointerCT, // LICOMPTYPE_VK_BUFFER_POINTER g_VKSampledTexture2DCT, // LICOMPTYPE_VK_SAMPLED_TEXTURE2D #endif };