[llvm-branch-commits] [clang] [NFC][HLSL] Refactor texture type declaration (PR #219561)
Deric C. via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Aug 28 11:51:53 PDT 2026
https://github.com/Icohedron created https://github.com/llvm/llvm-project/pull/219561
Fixes https://github.com/llvm/llvm-project/issues/219542
Refactors texture type declaration in `HLSLExternalSemaSource.cpp` so that new
texture types can more easily be added without adding a bunch of new helper
functions.
This is accomplished with the introduction of a new `TextureTypeInfo` struct and
to record the properties of each texture type, as well as its capabilities
indicated by the `TexCap` bitmask enum.
Adding a new texture type to be declared should, in most cases, only require
appending a new entry to the static `TextureTypes` array of `TextureTypeInfo`.
Assisted by: Claude Opus 5
---
<sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
>From b08dda47d66d4b20494fc824d6b740bb4ca90370 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Fri, 28 Aug 2026 11:40:44 -0700
Subject: [PATCH] [NFC][HLSL] Refactor texture type declaration
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 363 +++++++++-------------
1 file changed, 150 insertions(+), 213 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index e8a6147e20a3f..14442876a0467 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -24,6 +24,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaHLSL.h"
+#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -254,99 +255,134 @@ static BuiltinTypeDeclBuilder setupSamplerType(CXXRecordDecl *Decl, Sema &S) {
.addStaticInitializationFunctions(false);
}
-/// Set up common members and attributes for texture types
+namespace {
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+/// Which members a texture type has. Overloads within a member family
+/// (e.g., offset overloads for samplers) follow from ResourceDimension.
+enum class TexCap : uint32_t {
+ Load = 1u << 0, // Load(int<N+1>) taking a mip level
+ LoadMS = 1u << 1, // Load(int<N>, int sampleIndex) on a multisampled type
+ LoadRW = 1u << 2, // Load(int<N>) on a writable texture
+ Subscript = 1u << 3, // operator[]
+ Mips = 1u << 4, // mips[]
+ Sample = 1u << 5, // Sample, SampleBias, SampleGrad, SampleLevel
+ SampleCmp = 1u << 6, // SampleCmp, SampleCmpLevelZero
+ Gather = 1u << 7, // Gather*, GatherCmp*
+ CalcLOD = 1u << 8, // CalculateLevelOfDetail, ...Unclamped
+ GetDims = 1u << 9, // GetDimensions
+
+ // TODO: multisampled types need an MS-specific GetDimensions
+ // https://github.com/llvm/wg-hlsl/issues/347
+
+ LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/GetDims)
+};
+
+/// How a type's template parameters are spelled. Independent of its
+/// capabilities; also decides which types get a vector partial specialization.
+enum class TemplateShape {
+ ElementType, // template<typename T = float4>
+ ElementTypeAndSampleCount, // template<typename T, uint N>
+};
+
+struct TextureTypeInfo {
+ const char *Name;
+ ResourceClass RC;
+ ResourceDimension Dim;
+ bool IsArray;
+ bool IsROV;
+ TemplateShape Shape;
+ TexCap Caps;
+
+ bool has(TexCap C) const { return (Caps & C) != TexCap{}; }
+ bool hasSampleCount() const {
+ return Shape == TemplateShape::ElementTypeAndSampleCount;
+ }
+};
+} // namespace
+
+static const TextureTypeInfo TextureTypes[] = {
+ {"Texture2D", ResourceClass::SRV, ResourceDimension::Dim2D,
+ /*IsArray=*/false, /*IsROV=*/false, TemplateShape::ElementType,
+ TexCap::Load | TexCap::Subscript | TexCap::Mips | TexCap::Sample |
+ TexCap::SampleCmp | TexCap::CalcLOD | TexCap::Gather |
+ TexCap::GetDims},
+ {"RWTexture2D", ResourceClass::UAV, ResourceDimension::Dim2D,
+ /*IsArray=*/false, /*IsROV=*/false, TemplateShape::ElementType,
+ TexCap::LoadRW | TexCap::Subscript | TexCap::GetDims},
+ {"Texture2DArray", ResourceClass::SRV, ResourceDimension::Dim2D,
+ /*IsArray=*/true, /*IsROV=*/false, TemplateShape::ElementType,
+ TexCap::Load | TexCap::Subscript | TexCap::Mips | TexCap::Sample |
+ TexCap::SampleCmp | TexCap::CalcLOD | TexCap::Gather |
+ TexCap::GetDims},
+ {"RWTexture2DArray", ResourceClass::UAV, ResourceDimension::Dim2D,
+ /*IsArray=*/true, /*IsROV=*/false, TemplateShape::ElementType,
+ TexCap::LoadRW | TexCap::Subscript | TexCap::GetDims},
+ {"Texture2DMS", ResourceClass::SRV, ResourceDimension::Dim2D,
+ /*IsArray=*/false, /*IsROV=*/false,
+ TemplateShape::ElementTypeAndSampleCount,
+ TexCap::LoadMS | TexCap::Subscript},
+ {"TextureCube", ResourceClass::SRV, ResourceDimension::Cube,
+ /*IsArray=*/false, /*IsROV=*/false, TemplateShape::ElementType,
+ TexCap::Sample | TexCap::SampleCmp | TexCap::CalcLOD | TexCap::Gather |
+ TexCap::GetDims},
+ {"TextureCubeArray", ResourceClass::SRV, ResourceDimension::Cube,
+ /*IsArray=*/true, /*IsROV=*/false, TemplateShape::ElementType,
+ TexCap::Sample | TexCap::SampleCmp | TexCap::CalcLOD | TexCap::Gather |
+ TexCap::GetDims},
+};
+
static BuiltinTypeDeclBuilder setupTextureType(CXXRecordDecl *Decl, Sema &S,
- ResourceClass RC, bool IsROV,
- bool IsArray,
- ResourceDimension Dim) {
- return BuiltinTypeDeclBuilder(S, Decl)
- .addTextureHandle(RC, IsROV, IsArray, Dim)
- .addTextureLoadMethods(Dim, IsArray)
- .addArraySubscriptOperators(Dim, IsArray)
- .addMipsMember(Dim)
- .addDefaultHandleConstructor()
- .addCopyConstructor()
- .addCopyAssignmentOperator()
- .addStaticInitializationFunctions(false)
- .addSampleMethods(Dim, IsArray)
- .addSampleBiasMethods(Dim, IsArray)
- .addSampleGradMethods(Dim, IsArray)
- .addSampleLevelMethods(Dim, IsArray)
- .addSampleCmpMethods(Dim, IsArray)
- .addSampleCmpLevelZeroMethods(Dim, IsArray)
- .addCalculateLodMethods(Dim)
- .addGetDimensionsMethods(Dim)
- .addGatherMethods(Dim, IsArray)
- .addGatherCmpMethods(Dim, IsArray);
-}
+ const TextureTypeInfo &T) {
+ const ResourceDimension Dim = T.Dim;
+ const bool IsArray = T.IsArray;
+
+ Expr *SampleCountExpr = nullptr;
+ if (T.hasSampleCount()) {
+ ClassTemplateDecl *CTD = Decl->getDescribedClassTemplate();
+ assert(CTD && "multisampled texture must be a class template");
+ // Parameter 1 is the N in Texture2DMS<T, N>.
+ auto *NTTP = cast<NonTypeTemplateParmDecl>(
+ CTD->getTemplateParameters()->getParam(1));
+ SampleCountExpr =
+ S.BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, SourceLocation());
+ }
-/// Set up RWTexture type: UAV texture with only operator[] (uint2, read/write),
-/// Load and GetDimensions (no sample/gather/mips/LOD).
-static BuiltinTypeDeclBuilder setupRWTextureType(CXXRecordDecl *Decl, Sema &S,
- bool IsArray,
- ResourceDimension Dim) {
- return BuiltinTypeDeclBuilder(S, Decl)
- .addTextureHandle(ResourceClass::UAV, /*IsROV=*/false, IsArray, Dim)
- .addRWTextureLoadMethods(Dim, IsArray)
- .addArraySubscriptOperators(Dim, IsArray)
- .addGetDimensionsMethods(Dim)
- .addDefaultHandleConstructor()
+ BuiltinTypeDeclBuilder B(S, Decl);
+ B.addTextureHandle(T.RC, T.IsROV, IsArray, Dim, SampleCountExpr);
+
+ if (T.has(TexCap::Load))
+ B.addTextureLoadMethods(Dim, IsArray);
+ if (T.has(TexCap::LoadMS))
+ B.addTextureLoadMSMethods(Dim, IsArray);
+ if (T.has(TexCap::LoadRW))
+ B.addRWTextureLoadMethods(Dim, IsArray);
+ if (T.has(TexCap::Subscript))
+ B.addArraySubscriptOperators(Dim, IsArray);
+ if (T.has(TexCap::Mips))
+ B.addMipsMember(Dim);
+
+ B.addDefaultHandleConstructor()
.addCopyConstructor()
.addCopyAssignmentOperator()
.addStaticInitializationFunctions(false);
-}
-/// Set up TextureCube and TextureCubeArray types: SRV cube textures. Locations
-/// are direction vectors into the cube rather than texel coordinates, so cube
-/// textures have no Load, no operator[] and no mips member. Their sampling and
-/// gather methods also have no offset overloads.
-static BuiltinTypeDeclBuilder setupTextureCubeType(CXXRecordDecl *Decl, Sema &S,
- bool IsArray) {
- const ResourceDimension Dim = ResourceDimension::Cube;
- return BuiltinTypeDeclBuilder(S, Decl)
- .addTextureHandle(ResourceClass::SRV, /*IsROV=*/false, IsArray, Dim)
- .addDefaultHandleConstructor()
- .addCopyConstructor()
- .addCopyAssignmentOperator()
- .addStaticInitializationFunctions(false)
- .addSampleMethods(Dim, IsArray)
- .addSampleBiasMethods(Dim, IsArray)
- .addSampleGradMethods(Dim, IsArray)
- .addSampleLevelMethods(Dim, IsArray)
- .addSampleCmpMethods(Dim, IsArray)
- .addSampleCmpLevelZeroMethods(Dim, IsArray)
- .addCalculateLodMethods(Dim)
- .addGetDimensionsMethods(Dim)
- .addGatherMethods(Dim, IsArray)
- .addGatherCmpMethods(Dim, IsArray);
-}
-
-/// Set up Texture2DMS (multisampled) type: SRV texture with only operator[]
-/// and sample-indexed Load. It does not support sampling, gather, LOD, or mips.
-static BuiltinTypeDeclBuilder setupMSTextureType(CXXRecordDecl *Decl, Sema &S,
- bool IsArray,
- ResourceDimension Dim) {
- ClassTemplateDecl *CTD = Decl->getDescribedClassTemplate();
- assert(CTD && "multisampled texture must be a class template");
-
- // Parameter 1 is the N in Texture2DMS<T, N>.
- auto *NTTP =
- cast<NonTypeTemplateParmDecl>(CTD->getTemplateParameters()->getParam(1));
- Expr *SampleCountExpr =
- S.BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, SourceLocation());
-
- return BuiltinTypeDeclBuilder(S, Decl)
- .addTextureHandle(ResourceClass::SRV, /*IsROV=*/false, IsArray, Dim,
- SampleCountExpr)
- .addTextureLoadMSMethods(Dim, IsArray)
- .addArraySubscriptOperators(Dim, IsArray)
- // TODO: Add MS-specific GetDimensions (with a NumberOfSamples output);
- // the generic addGetDimensionsMethods is mip-based and unsuitable here.
- // https://github.com/llvm/wg-hlsl/issues/347
- .addDefaultHandleConstructor()
- .addCopyConstructor()
- .addCopyAssignmentOperator()
- .addStaticInitializationFunctions(false);
+ if (T.has(TexCap::Sample))
+ B.addSampleMethods(Dim, IsArray)
+ .addSampleBiasMethods(Dim, IsArray)
+ .addSampleGradMethods(Dim, IsArray)
+ .addSampleLevelMethods(Dim, IsArray);
+ if (T.has(TexCap::SampleCmp))
+ B.addSampleCmpMethods(Dim, IsArray)
+ .addSampleCmpLevelZeroMethods(Dim, IsArray);
+ if (T.has(TexCap::CalcLOD))
+ B.addCalculateLodMethods(Dim);
+ if (T.has(TexCap::GetDims))
+ B.addGetDimensionsMethods(Dim);
+ if (T.has(TexCap::Gather))
+ B.addGatherMethods(Dim, IsArray).addGatherCmpMethods(Dim, IsArray);
+
+ return B;
}
// Add a partial specialization for a template. The `TextureTemplate` is
@@ -742,132 +778,33 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
});
QualType Float4Ty = AST.getExtVectorType(AST.FloatTy, 4);
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2D")
- .addSimpleTemplateParams({"element_type"}, {Float4Ty},
- TypedBufferConcept)
- .finalizeForwardDeclaration();
-
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupTextureType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,
- /*IsArray=*/false, ResourceDimension::Dim2D)
- .completeDefinition();
- });
-
- auto *PartialSpec = addVectorTexturePartialSpecialization(
- *SemaPtr, HLSLNamespace, Decl->getDescribedClassTemplate());
- onCompletion(PartialSpec, [this](CXXRecordDecl *Decl) {
- setupTextureType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,
- /*IsArray=*/false, ResourceDimension::Dim2D)
- .completeDefinition();
- });
-
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWTexture2D")
- .addSimpleTemplateParams({"element_type"}, {Float4Ty},
- TypedBufferConcept)
- .finalizeForwardDeclaration();
-
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupRWTextureType(Decl, *SemaPtr, /*IsArray=*/false,
- ResourceDimension::Dim2D)
- .completeDefinition();
- });
-
- auto *PartialSpecRW = addVectorTexturePartialSpecialization(
- *SemaPtr, HLSLNamespace, Decl->getDescribedClassTemplate());
- onCompletion(PartialSpecRW, [this](CXXRecordDecl *Decl) {
- setupRWTextureType(Decl, *SemaPtr, /*IsArray=*/false,
- ResourceDimension::Dim2D)
- .completeDefinition();
- });
-
- // Texture2DArray — same as Texture2D but IsArray=true
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2DArray")
- .addSimpleTemplateParams({"element_type"}, {Float4Ty},
- TypedBufferConcept)
- .finalizeForwardDeclaration();
-
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupTextureType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,
- /*IsArray=*/true, ResourceDimension::Dim2D)
- .completeDefinition();
- });
-
- auto *PartialSpec2DA = addVectorTexturePartialSpecialization(
- *SemaPtr, HLSLNamespace, Decl->getDescribedClassTemplate());
- onCompletion(PartialSpec2DA, [this](CXXRecordDecl *Decl) {
- setupTextureType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,
- /*IsArray=*/true, ResourceDimension::Dim2D)
- .completeDefinition();
- });
-
- // RWTexture2DArray — same as RWTexture2D but IsArray=true
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWTexture2DArray")
- .addSimpleTemplateParams({"element_type"}, {Float4Ty},
- TypedBufferConcept)
- .finalizeForwardDeclaration();
-
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupRWTextureType(Decl, *SemaPtr, /*IsArray=*/true,
- ResourceDimension::Dim2D)
- .completeDefinition();
- });
-
- auto *PartialSpecRW2DA = addVectorTexturePartialSpecialization(
- *SemaPtr, HLSLNamespace, Decl->getDescribedClassTemplate());
- onCompletion(PartialSpecRW2DA, [this](CXXRecordDecl *Decl) {
- setupRWTextureType(Decl, *SemaPtr, /*IsArray=*/true,
- ResourceDimension::Dim2D)
- .completeDefinition();
- });
-
- // Texture2DMS — like Texture2D but multisampled, and the element type has no
- // default argument.
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2DMS")
- .addMSTextureTemplateParams("element_type", "sample_count",
- TypedBufferConcept)
- .finalizeForwardDeclaration();
-
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupMSTextureType(Decl, *SemaPtr, /*IsArray=*/false,
- ResourceDimension::Dim2D)
- .completeDefinition();
- });
-
- // TextureCube — SRV cube texture. Locations are float3 direction vectors.
- // Cube textures do not support Load, operator[], mips or offsets.
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "TextureCube")
- .addSimpleTemplateParams({"element_type"}, {Float4Ty},
- TypedBufferConcept)
- .finalizeForwardDeclaration();
-
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupTextureCubeType(Decl, *SemaPtr, /*IsArray=*/false)
- .completeDefinition();
- });
-
- auto *PartialSpecCube = addVectorTexturePartialSpecialization(
- *SemaPtr, HLSLNamespace, Decl->getDescribedClassTemplate());
- onCompletion(PartialSpecCube, [this](CXXRecordDecl *Decl) {
- setupTextureCubeType(Decl, *SemaPtr, /*IsArray=*/false)
- .completeDefinition();
- });
-
- // TextureCubeArray — same as TextureCube but IsArray=true, so locations gain
- // an array slice and are float4.
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "TextureCubeArray")
- .addSimpleTemplateParams({"element_type"}, {Float4Ty},
- TypedBufferConcept)
- .finalizeForwardDeclaration();
-
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupTextureCubeType(Decl, *SemaPtr, /*IsArray=*/true).completeDefinition();
- });
-
- auto *PartialSpecCubeArray = addVectorTexturePartialSpecialization(
- *SemaPtr, HLSLNamespace, Decl->getDescribedClassTemplate());
- onCompletion(PartialSpecCubeArray, [this](CXXRecordDecl *Decl) {
- setupTextureCubeType(Decl, *SemaPtr, /*IsArray=*/true).completeDefinition();
- });
+ for (const TextureTypeInfo &T : TextureTypes) {
+ BuiltinTypeDeclBuilder TexBuilder(*SemaPtr, HLSLNamespace, T.Name);
+ switch (T.Shape) {
+ case TemplateShape::ElementType:
+ TexBuilder.addSimpleTemplateParams({"element_type"}, {Float4Ty},
+ TypedBufferConcept);
+ break;
+ case TemplateShape::ElementTypeAndSampleCount:
+ TexBuilder.addMSTextureTemplateParams("element_type", "sample_count",
+ TypedBufferConcept);
+ break;
+ }
+ Decl = TexBuilder.finalizeForwardDeclaration();
+
+ onCompletion(Decl, [this, &T](CXXRecordDecl *Decl) {
+ setupTextureType(Decl, *SemaPtr, T).completeDefinition();
+ });
+
+ if (T.Shape != TemplateShape::ElementType)
+ continue;
+
+ CXXRecordDecl *PartialSpec = addVectorTexturePartialSpecialization(
+ *SemaPtr, HLSLNamespace, Decl->getDescribedClassTemplate());
+ onCompletion(PartialSpec, [this, &T](CXXRecordDecl *Decl) {
+ setupTextureType(Decl, *SemaPtr, T).completeDefinition();
+ });
+ }
}
// Build a single overload of an HLSL atomic intrinsic in the hlsl namespace.
More information about the llvm-branch-commits
mailing list