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..b681d6f979 100644 --- a/tools/clang/include/clang/AST/HlslTypes.h +++ b/tools/clang/include/clang/AST/HlslTypes.h @@ -407,6 +407,11 @@ clang::CXXRecordDecl * DeclareVkBufferPointerType(clang::ASTContext &context, clang::DeclContext *declContext); +clang::CXXRecordDecl *DeclareVkSampledTexture2DType( + clang::ASTContext &context, clang::DeclContext *declContext, + clang::QualType float2Type, clang::QualType int2Type, + clang::QualType float4Type); + clang::CXXRecordDecl *DeclareInlineSpirvType(clang::ASTContext &context, clang::DeclContext *declContext, llvm::StringRef typeName, 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/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 913b28ced8..6f6285b119 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -1369,6 +1369,86 @@ 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(); + + QualType floatType = context.FloatTy; + QualType uintType = context.UnsignedIntTy; + // Add Sample method + // Sample(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))); + 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)); + + // 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; +} + CXXRecordDecl *hlsl::DeclareVkBufferPointerType(ASTContext &context, DeclContext *declContext) { BuiltinTypeDeclBuilder Builder(declContext, "BufferPointer", diff --git a/tools/clang/lib/SPIRV/AstTypeProbe.cpp b/tools/clang/lib/SPIRV/AstTypeProbe.cpp index fda9a3ab3e..48c3012501 100644 --- a/tools/clang/lib/SPIRV/AstTypeProbe.cpp +++ b/tools/clang/lib/SPIRV/AstTypeProbe.cpp @@ -926,6 +926,17 @@ 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..d9ddc3428b 100644 --- a/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp +++ b/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp @@ -849,6 +849,22 @@ 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..bf30deea5a 100644 --- a/tools/clang/lib/SPIRV/SpirvBuilder.cpp +++ b/tools/clang/lib/SPIRV/SpirvBuilder.cpp @@ -620,8 +620,15 @@ 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); + // 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); + } 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..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 = @@ -5812,11 +5822,54 @@ 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(); const auto range = expr->getSourceRange(); + + 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); + } + + 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(); @@ -5832,14 +5885,6 @@ SpirvEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr, // 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(); - 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; if (hasOffsetArg) handleOffsetInMethodCall(expr, 2, &constOffset, &varOffset); diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index e9c8c90a2d..975e9f2b4f 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. @@ -1310,7 +1314,8 @@ 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 }; 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; + 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(); } #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/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.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.sampledtexture.sample.hlsl b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl new file mode 100644 index 0000000000..c00aa7b51c --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/vk.sampledtexture.sample.hlsl @@ -0,0 +1,50 @@ +// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv | FileCheck %s + +// CHECK: OpCapability MinLod +// CHECK: OpCapability SparseResidency + +// CHECK: [[v2fc:%[0-9]+]] = OpConstantComposite %v2float %float_0_5 %float_0_25 +// CHECK: [[v2ic:%[0-9]+]] = OpConstantComposite %v2int %int_2 %int_3 + +// CHECK: [[type_2d_image_1:%[a-zA-Z0-9_]+]] = OpTypeImage %float 2D 0 0 0 1 Unknown +// CHECK: [[type_sampled_image_1:%[a-zA-Z0-9_]+]] = OpTypeSampledImage [[type_2d_image_1]] +// CHECK: [[ptr_type_1:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[type_sampled_image_1]] + +// CHECK: [[type_2d_image_2:%[a-zA-Z0-9_]+]] = OpTypeImage %uint 2D 0 0 0 1 Unknown +// CHECK: [[type_sampled_image_2:%[a-zA-Z0-9_]+]] = OpTypeSampledImage [[type_2d_image_2]] +// CHECK: [[ptr_type_2:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[type_sampled_image_2]] + +// CHECK: [[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; +}