Skip to content

Commit 1e61add

Browse files
authored
[SPIR-V] Add vk::SampledTexture2D resource type and .Sample(), .CalculateLevelOfDetail() method. (microsoft#8047)
Part of microsoft#7979 - Add `SampledTexture2D` resource type in the `vk` namespace. - Add `.Sample(float2 location)` method. - Add default type parameter `float4`. - Allow optional arguments `int2 offset, float clamp, uint status`. - Add `.CalculateLevelOfDetail(float2 location)` method.
1 parent 6e0f2de commit 1e61add

15 files changed

Lines changed: 241 additions & 29 deletions

include/dxc/dxcapi.internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ enum LEGAL_INTRINSIC_COMPTYPES {
140140

141141
#ifdef ENABLE_SPIRV_CODEGEN
142142
LICOMPTYPE_VK_BUFFER_POINTER = 56,
143-
LICOMPTYPE_COUNT = 57
143+
LICOMPTYPE_VK_SAMPLED_TEXTURE2D = 57,
144+
LICOMPTYPE_COUNT = 58
144145
#else
145146
LICOMPTYPE_COUNT = 56
146147
#endif

tools/clang/include/clang/AST/HlslTypes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,10 @@ clang::CXXRecordDecl *
407407
DeclareVkBufferPointerType(clang::ASTContext &context,
408408
clang::DeclContext *declContext);
409409

410+
clang::CXXRecordDecl *DeclareVkSampledTextureType(
411+
clang::ASTContext &context, clang::DeclContext *declContext,
412+
llvm::StringRef hlslTypeName, clang::QualType defaultParamType);
413+
410414
clang::CXXRecordDecl *DeclareInlineSpirvType(clang::ASTContext &context,
411415
clang::DeclContext *declContext,
412416
llvm::StringRef typeName,

tools/clang/include/clang/SPIRV/AstTypeProbe.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ bool isTexture(QualType);
257257
/// Texture2DMSArray type.
258258
bool isTextureMS(QualType);
259259

260+
/// \brief Returns true if the given type is an HLSL SampledTexture type.
261+
bool isSampledTexture(QualType);
262+
260263
/// \brief Returns true if the given type is an HLSL RWTexture type.
261264
bool isRWTexture(QualType);
262265

tools/clang/include/clang/SPIRV/SpirvBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@ class SpirvBuilder {
287287
/// If compareVal is given a non-zero value, *Dref* variants of OpImageSample*
288288
/// will be generated.
289289
///
290+
/// If sampler is set, it defines the sampler along *image* to create the
291+
/// combined image sampler. Otherwise, the *image* parameter must point to a
292+
/// sampled image.
293+
///
290294
/// If lod or grad is given a non-zero value, *ExplicitLod variants of
291295
/// OpImageSample* will be generated; otherwise, *ImplicitLod variant will
292296
/// be generated.

tools/clang/lib/AST/ASTContextHLSL.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,26 @@ CXXRecordDecl *hlsl::DeclareNodeOrRecordType(
13721372
}
13731373

13741374
#ifdef ENABLE_SPIRV_CODEGEN
1375+
CXXRecordDecl *hlsl::DeclareVkSampledTextureType(ASTContext &context,
1376+
DeclContext *declContext,
1377+
llvm::StringRef hlslTypeName,
1378+
QualType defaultParamType) {
1379+
// TODO(https://github.com/microsoft/DirectXShaderCompiler/issues/7979): Later
1380+
// generalize these to all SampledTexture types.
1381+
BuiltinTypeDeclBuilder Builder(declContext, hlslTypeName,
1382+
TagDecl::TagKind::TTK_Struct);
1383+
1384+
TemplateTypeParmDecl *TyParamDecl =
1385+
Builder.addTypeTemplateParam("SampledTextureType", defaultParamType);
1386+
1387+
Builder.startDefinition();
1388+
1389+
QualType paramType = QualType(TyParamDecl->getTypeForDecl(), 0);
1390+
CXXRecordDecl *recordDecl = Builder.getRecordDecl();
1391+
1392+
return recordDecl;
1393+
}
1394+
13751395
CXXRecordDecl *hlsl::DeclareVkBufferPointerType(ASTContext &context,
13761396
DeclContext *declContext) {
13771397
BuiltinTypeDeclBuilder Builder(declContext, "BufferPointer",

tools/clang/lib/SPIRV/AstTypeProbe.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,17 @@ bool isTexture(QualType type) {
926926
return false;
927927
}
928928

929+
bool isSampledTexture(QualType type) {
930+
if (const auto *rt = type->getAs<RecordType>()) {
931+
const auto name = rt->getDecl()->getName();
932+
// TODO(https://github.com/microsoft/DirectXShaderCompiler/issues/7979): Add
933+
// other sampled texture types as needed.
934+
if (name == "SampledTexture2D")
935+
return true;
936+
}
937+
return false;
938+
}
939+
929940
bool isTextureMS(QualType type) {
930941
if (const auto *rt = type->getAs<RecordType>()) {
931942
const auto name = rt->getDecl()->getName();

tools/clang/lib/SPIRV/LowerTypeVisitor.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,23 @@ const SpirvType *LowerTypeVisitor::lowerVkTypeInVkNamespace(
849849
assert(visitedTypeStack.size() == visitedTypeStackSize);
850850
return pointerType;
851851
}
852+
if (name == "SampledTexture2D") {
853+
const auto sampledType = hlsl::GetHLSLResourceResultType(type);
854+
auto loweredType = lowerType(getElementType(astContext, sampledType), rule,
855+
/*isRowMajor*/ llvm::None, srcLoc);
856+
857+
// Bool does not have a defined size in SPIR-V, so it cannot be
858+
// used in the external interface.
859+
if (loweredType == spvContext.getBoolType()) {
860+
loweredType = spvContext.getUIntType(32);
861+
}
862+
863+
const auto *imageType = spvContext.getImageType(
864+
loweredType, spv::Dim::Dim2D, ImageType::WithDepth::No,
865+
false /* array */, false /* ms */, ImageType::WithSampler::Yes,
866+
spv::ImageFormat::Unknown);
867+
return spvContext.getSampledImageType(imageType);
868+
}
852869
emitError("unknown type %0 in vk namespace", srcLoc) << type;
853870
return nullptr;
854871
}
@@ -892,7 +909,8 @@ LowerTypeVisitor::lowerResourceType(QualType type, SpirvLayoutRule rule,
892909
auto loweredType =
893910
lowerType(getElementType(astContext, sampledType), rule,
894911
/*isRowMajor*/ llvm::None, srcLoc);
895-
// Treat bool textures as uint for compatibility with OpTypeImage.
912+
// Bool does not have a defined size in SPIR-V, so it cannot be
913+
// used in the external interface.
896914
if (loweredType == spvContext.getBoolType()) {
897915
loweredType = spvContext.getUIntType(32);
898916
}

tools/clang/lib/SPIRV/SpirvBuilder.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,15 @@ SpirvInstruction *SpirvBuilder::createImageSample(
620620
assert(lod == nullptr || minLod == nullptr);
621621

622622
// An OpSampledImage is required to do the image sampling.
623-
auto *sampledImage =
624-
createSampledImage(imageType, image, sampler, loc, range);
623+
// Skip creating OpSampledImage if the imageType is a sampled texture.
624+
SpirvInstruction *sampledImage;
625+
if (isSampledTexture(imageType)) {
626+
assert(!sampler &&
627+
"sampler must be null when sampling from a sampled texture");
628+
sampledImage = image;
629+
} else {
630+
sampledImage = createSampledImage(imageType, image, sampler, loc, range);
631+
}
625632

626633
const auto mask = composeImageOperandsMask(
627634
bias, lod, grad, constOffset, varOffset, constOffsets, sample, minLod);

tools/clang/lib/SPIRV/SpirvEmitter.cpp

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4474,14 +4474,27 @@ SpirvEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr,
44744474
// TextureCube(Array).CalculateLevelOfDetail(SamplerState S, float3 xyz);
44754475
// Texture3D.CalculateLevelOfDetail(SamplerState S, float3 xyz);
44764476
// Return type is always a single float (LOD).
4477-
assert(expr->getNumArgs() == 2u);
4478-
const auto *object = expr->getImplicitObjectArgument();
4479-
auto *objectInfo = loadIfGLValue(object);
4480-
auto *samplerState = doExpr(expr->getArg(0));
4481-
auto *coordinate = doExpr(expr->getArg(1));
4477+
//
4478+
// Their SampledTexture variants have the same signature without the
4479+
// sampler_state parameter.
4480+
const auto *imageExpr = expr->getImplicitObjectArgument();
4481+
const QualType imageType = imageExpr->getType();
4482+
// numarg is 1 if isSampledTexture(imageType). otherwise 2.
4483+
assert(expr->getNumArgs() == (isSampledTexture(imageType) ? 1u : 2u));
4484+
4485+
auto *objectInfo = loadIfGLValue(imageExpr);
44824486

4483-
auto *sampledImage = spvBuilder.createSampledImage(
4484-
object->getType(), objectInfo, samplerState, expr->getExprLoc());
4487+
SpirvInstruction *samplerState, *coordinate, *sampledImage;
4488+
if (isSampledTexture(imageType)) {
4489+
samplerState = nullptr;
4490+
coordinate = doExpr(expr->getArg(0));
4491+
sampledImage = objectInfo;
4492+
} else {
4493+
samplerState = doExpr(expr->getArg(0));
4494+
coordinate = doExpr(expr->getArg(1));
4495+
sampledImage = spvBuilder.createSampledImage(
4496+
imageExpr->getType(), objectInfo, samplerState, expr->getExprLoc());
4497+
}
44854498

44864499
// The result type of OpImageQueryLod must be a float2.
44874500
const QualType queryResultType =
@@ -5817,6 +5830,9 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr,
58175830
// [, float Clamp]
58185831
// [, out uint Status]);
58195832
//
5833+
// Their SampledTexture variants have the same signature without the
5834+
// sampler_state parameter.
5835+
//
58205836
// For TextureCube and TextureCubeArray:
58215837
// DXGI_FORMAT Object.Sample(sampler_state S,
58225838
// float Location
@@ -5835,35 +5851,49 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr,
58355851
// [, uint Status]);
58365852
//
58375853
// Other Texture types do not have a Gather method.
5838-
58395854
const auto numArgs = expr->getNumArgs();
58405855
const auto loc = expr->getExprLoc();
58415856
const auto range = expr->getSourceRange();
58425857
const bool hasStatusArg =
58435858
expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
58445859

5860+
const auto *imageExpr = expr->getImplicitObjectArgument();
5861+
const QualType imageType = imageExpr->getType();
5862+
const bool isImageSampledTexture = isSampledTexture(imageType);
5863+
5864+
int samplerIndex;
5865+
uint32_t coordIndex;
5866+
if (isImageSampledTexture) {
5867+
samplerIndex = -1; // non-existant
5868+
coordIndex = 0;
5869+
} else {
5870+
samplerIndex = 0;
5871+
coordIndex = 1;
5872+
}
5873+
58455874
SpirvInstruction *clamp = nullptr;
5846-
if (numArgs > 2 && expr->getArg(2)->getType()->isFloatingType())
5847-
clamp = doExpr(expr->getArg(2));
5848-
else if (numArgs > 3 && expr->getArg(3)->getType()->isFloatingType())
5849-
clamp = doExpr(expr->getArg(3));
5875+
if (numArgs > coordIndex + 1 &&
5876+
expr->getArg(coordIndex + 1)->getType()->isFloatingType())
5877+
clamp = doExpr(expr->getArg(coordIndex + 1));
5878+
else if (numArgs > coordIndex + 2 &&
5879+
expr->getArg(coordIndex + 2)->getType()->isFloatingType())
5880+
clamp = doExpr(expr->getArg(coordIndex + 2));
58505881
const bool hasClampArg = (clamp != 0);
58515882
const auto status =
58525883
hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : nullptr;
58535884

5854-
// Subtract 1 for status (if it exists), subtract 1 for clamp (if it exists),
5855-
// and subtract 2 for sampler_state and location.
5856-
const bool hasOffsetArg = numArgs - hasStatusArg - hasClampArg - 2 > 0;
5857-
5858-
const auto *imageExpr = expr->getImplicitObjectArgument();
5859-
const QualType imageType = imageExpr->getType();
58605885
auto *image = loadIfGLValue(imageExpr);
5861-
auto *sampler = doExpr(expr->getArg(0));
5862-
auto *coordinate = doExpr(expr->getArg(1));
5886+
SpirvInstruction *sampler =
5887+
samplerIndex >= 0 ? doExpr(expr->getArg(samplerIndex)) : nullptr;
5888+
auto *coordinate = doExpr(expr->getArg(coordIndex));
58635889
// .Sample()/.Gather() may have a third optional paramter for offset.
58645890
SpirvInstruction *constOffset = nullptr, *varOffset = nullptr;
5891+
// Subtract 1 for status (if it exists), subtract 1 for clamp (if it exists),
5892+
// and subtract offsetIndex for sampler_state (if exists) location.
5893+
const bool hasOffsetArg =
5894+
numArgs - hasStatusArg - hasClampArg - coordIndex > 1;
58655895
if (hasOffsetArg)
5866-
handleOffsetInMethodCall(expr, 2, &constOffset, &varOffset);
5896+
handleOffsetInMethodCall(expr, coordIndex + 1, &constOffset, &varOffset);
58675897

58685898
const auto retType = expr->getDirectCallee()->getReturnType();
58695899
if (isSample) {

tools/clang/lib/Sema/SemaHLSL.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ enum ArBasicKind {
199199
AR_OBJECT_VK_SPV_INTRINSIC_TYPE,
200200
AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID,
201201
AR_OBJECT_VK_BUFFER_POINTER,
202+
AR_OBJECT_VK_SAMPLED_TEXTURE2D,
202203
#endif // ENABLE_SPIRV_CODEGEN
203204
// SPIRV change ends
204205

@@ -559,6 +560,7 @@ const UINT g_uBasicKindProps[] = {
559560
BPROP_OBJECT, // AR_OBJECT_VK_SPV_INTRINSIC_TYPE use recordType
560561
BPROP_OBJECT, // AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID use recordType
561562
BPROP_OBJECT, // AR_OBJECT_VK_BUFFER_POINTER use recordType
563+
BPROP_OBJECT | BPROP_RBUFFER, // AR_OBJECT_VK_SAMPLED_TEXTURE2D
562564
#endif // ENABLE_SPIRV_CODEGEN
563565
// SPIRV change ends
564566

@@ -1267,6 +1269,8 @@ static const ArBasicKind g_LinAlgMatrixCT[] = {AR_OBJECT_LINALG_MATRIX,
12671269
#ifdef ENABLE_SPIRV_CODEGEN
12681270
static const ArBasicKind g_VKBufferPointerCT[] = {AR_OBJECT_VK_BUFFER_POINTER,
12691271
AR_BASIC_UNKNOWN};
1272+
static const ArBasicKind g_VKSampledTexture2DCT[] = {
1273+
AR_OBJECT_VK_SAMPLED_TEXTURE2D, AR_BASIC_UNKNOWN};
12701274
#endif
12711275

12721276
// Basic kinds, indexed by a LEGAL_INTRINSIC_COMPTYPES value.
@@ -1329,7 +1333,8 @@ const ArBasicKind *g_LegalIntrinsicCompTypes[] = {
13291333
g_LinAlgCT, // LICOMPTYPE_LINALG
13301334
g_BuiltInTrianglePositionsCT, // LICOMPTYPE_BUILTIN_TRIANGLE_POSITIONS
13311335
#ifdef ENABLE_SPIRV_CODEGEN
1332-
g_VKBufferPointerCT, // LICOMPTYPE_VK_BUFFER_POINTER
1336+
g_VKBufferPointerCT, // LICOMPTYPE_VK_BUFFER_POINTER
1337+
g_VKSampledTexture2DCT, // LICOMPTYPE_VK_SAMPLED_TEXTURE2D
13331338
#endif
13341339
};
13351340
static_assert(
@@ -1389,7 +1394,7 @@ static const ArBasicKind g_ArBasicKindsAsTypes[] = {
13891394
AR_OBJECT_VK_SPIRV_TYPE, AR_OBJECT_VK_SPIRV_OPAQUE_TYPE,
13901395
AR_OBJECT_VK_INTEGRAL_CONSTANT, AR_OBJECT_VK_LITERAL,
13911396
AR_OBJECT_VK_SPV_INTRINSIC_TYPE, AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID,
1392-
AR_OBJECT_VK_BUFFER_POINTER,
1397+
AR_OBJECT_VK_BUFFER_POINTER, AR_OBJECT_VK_SAMPLED_TEXTURE2D,
13931398
#endif // ENABLE_SPIRV_CODEGEN
13941399
// SPIRV change ends
13951400

@@ -1501,6 +1506,7 @@ static const uint8_t g_ArBasicKindsTemplateCount[] = {
15011506
1, // AR_OBJECT_VK_SPV_INTRINSIC_TYPE
15021507
1, // AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID
15031508
2, // AR_OBJECT_VK_BUFFER_POINTER
1509+
1, // AR_OBJECT_VK_SAMPLED_TEXTURE2D
15041510
#endif // ENABLE_SPIRV_CODEGEN
15051511
// SPIRV change ends
15061512

@@ -1654,6 +1660,7 @@ static const SubscriptOperatorRecord g_ArBasicKindsSubscripts[] = {
16541660
{0, MipsFalse, SampleFalse}, // AR_OBJECT_VK_SPV_INTRINSIC_TYPE
16551661
{0, MipsFalse, SampleFalse}, // AR_OBJECT_VK_SPV_INTRINSIC_RESULT_ID
16561662
{0, MipsFalse, SampleFalse}, // AR_OBJECT_VK_BUFFER_POINTER
1663+
{0, MipsFalse, SampleFalse}, // AR_OBJECT_VK_SAMPLED_TEXTURE2D
16571664
#endif // ENABLE_SPIRV_CODEGEN
16581665
// SPIRV change ends
16591666

@@ -1823,6 +1830,7 @@ static const char *g_ArBasicTypeNames[] = {
18231830
"ext_type",
18241831
"ext_result_id",
18251832
"BufferPointer",
1833+
"SampledTexture2D",
18261834
#endif // ENABLE_SPIRV_CODEGEN
18271835
// SPIRV change ends
18281836

@@ -2475,6 +2483,12 @@ static void GetIntrinsicMethods(ArBasicKind kind,
24752483
*intrinsics = g_RayQueryMethods;
24762484
*intrinsicCount = _countof(g_RayQueryMethods);
24772485
break;
2486+
#ifdef ENABLE_SPIRV_CODEGEN
2487+
case AR_OBJECT_VK_SAMPLED_TEXTURE2D:
2488+
*intrinsics = g_VkSampledTexture2DMethods;
2489+
*intrinsicCount = _countof(g_VkSampledTexture2DMethods);
2490+
break;
2491+
#endif
24782492
case AR_OBJECT_HIT_OBJECT:
24792493
*intrinsics = g_DxHitObjectMethods;
24802494
*intrinsicCount = _countof(g_DxHitObjectMethods);
@@ -3073,6 +3087,7 @@ class HLSLExternalSource : public ExternalSemaSource {
30733087
ClassTemplateDecl *m_vkIntegralConstantTemplateDecl;
30743088
ClassTemplateDecl *m_vkLiteralTemplateDecl;
30753089
ClassTemplateDecl *m_vkBufferPointerTemplateDecl;
3090+
ClassTemplateDecl *m_vkSampledTextureTemplateDecl;
30763091

30773092
// Declarations for Work Graph Output Record types
30783093
ClassTemplateDecl *m_GroupNodeOutputRecordsTemplateDecl;
@@ -4078,6 +4093,15 @@ class HLSLExternalSource : public ExternalSemaSource {
40784093
recordDecl = DeclareVkBufferPointerType(*m_context, m_vkNSDecl);
40794094
recordDecl->setImplicit(true);
40804095
m_vkBufferPointerTemplateDecl = recordDecl->getDescribedClassTemplate();
4096+
} else if (kind == AR_OBJECT_VK_SAMPLED_TEXTURE2D) {
4097+
if (!m_vkNSDecl)
4098+
continue;
4099+
QualType float4Type =
4100+
LookupVectorType(HLSLScalarType::HLSLScalarType_float, 4);
4101+
recordDecl = DeclareVkSampledTextureType(
4102+
*m_context, m_vkNSDecl, "SampledTexture2D", float4Type);
4103+
m_vkSampledTextureTemplateDecl =
4104+
recordDecl->getDescribedClassTemplate();
40814105
}
40824106
#endif
40834107
else if (templateArgCount == 0) {
@@ -4191,7 +4215,8 @@ class HLSLExternalSource : public ExternalSemaSource {
41914215
: m_matrixTemplateDecl(nullptr), m_vectorTemplateDecl(nullptr),
41924216
m_vkIntegralConstantTemplateDecl(nullptr),
41934217
m_vkLiteralTemplateDecl(nullptr),
4194-
m_vkBufferPointerTemplateDecl(nullptr), m_hlslNSDecl(nullptr),
4218+
m_vkBufferPointerTemplateDecl(nullptr),
4219+
m_vkSampledTextureTemplateDecl(nullptr), m_hlslNSDecl(nullptr),
41954220
m_vkNSDecl(nullptr), m_dxNSDecl(nullptr), m_context(nullptr),
41964221
m_sema(nullptr), m_hlslStringTypedef(nullptr) {
41974222
memset(m_matrixTypes, 0, sizeof(m_matrixTypes));

0 commit comments

Comments
 (0)