-
Notifications
You must be signed in to change notification settings - Fork 828
[SPIR-V] Add vk::SampledTexture2D resource type and .Sample(), .CalculateLevelOfDetail() method.
#8047
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[SPIR-V] Add vk::SampledTexture2D resource type and .Sample(), .CalculateLevelOfDetail() method.
#8047
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1369,6 +1369,86 @@ CXXRecordDecl *hlsl::DeclareNodeOrRecordType( | |
| } | ||
|
|
||
| #ifdef ENABLE_SPIRV_CODEGEN | ||
| CXXRecordDecl *hlsl::DeclareVkSampledTexture2DType(ASTContext &context, | ||
| DeclContext *declContext, | ||
| QualType float2Type, | ||
| QualType int2Type, | ||
| QualType float4Type) { | ||
|
Comment on lines
+1374
to
+1376
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you planning on make this function more general? For example could float2Type become CoordinateType? Then for Textur3D it is just a float? If not, why pass these in as parameters? Could we simplify the interface an build them in this function? |
||
| 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<QualType>(float2Type), | ||
| ArrayRef<StringRef>(StringRef("location")), | ||
| context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), | ||
| /*isConst*/ true); | ||
| sampleDecl->addAttr(HLSLIntrinsicAttr::CreateImplicit( | ||
| context, "op", "", static_cast<int>(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<int>(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<int>(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, | ||
|
Comment on lines
+1402
to
+1429
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function will be come very big. Could you break it up into smaller functions? This block could be its own. Call it |
||
| context.DeclarationNames.getIdentifier(&context.Idents.get("Sample")), | ||
| /*isConst*/ true); | ||
| sampleDecl4->addAttr(HLSLIntrinsicAttr::CreateImplicit( | ||
| context, "op", "", static_cast<int>(hlsl::IntrinsicOp::MOP_Sample))); | ||
| sampleDecl4->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); | ||
|
|
||
| // CalculateLevelOfDetail(location) | ||
| CXXMethodDecl *lodDecl = CreateObjectFunctionDeclarationWithParams( | ||
| context, recordDecl, floatType, ArrayRef<QualType>(float2Type), | ||
| ArrayRef<StringRef>(StringRef("location")), | ||
| context.DeclarationNames.getIdentifier( | ||
| &context.Idents.get("CalculateLevelOfDetail")), | ||
| /*isConst*/ true); | ||
| lodDecl->addAttr(HLSLIntrinsicAttr::CreateImplicit( | ||
| context, "op", "", | ||
| static_cast<int>(hlsl::IntrinsicOp::MOP_CalculateLevelOfDetail))); | ||
| lodDecl->addAttr(HLSLCXXOverloadAttr::CreateImplicit(context)); | ||
|
|
||
| Builder.completeDefinition(); | ||
| return recordDecl; | ||
| } | ||
|
|
||
| CXXRecordDecl *hlsl::DeclareVkBufferPointerType(ASTContext &context, | ||
| DeclContext *declContext) { | ||
| BuiltinTypeDeclBuilder Builder(declContext, "BufferPointer", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not about compatibility with OpTypeImage. Bool does not have a defined size in SPIR-V, so it cannot be used in the external interface. |
||
| if (loweredType == spvContext.getBoolType()) { | ||
| loweredType = spvContext.getUIntType(32); | ||
| } | ||
|
|
||
| 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; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
Comment on lines
+4462
to
+4469
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are checking |
||
| ? 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)); | ||
| } | ||
|
Comment on lines
+5848
to
+5856
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You eventually going to have to add all of the checks below when you add all of the appropriate overload. We should try to avoid adding duplicating the argument parsing here. You could try doing: Then all of the later accesses become to expr->getArg(offset + ); For example: This will avoid repeating the logic. |
||
|
|
||
| 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); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is confusing. Can you rephrase?
You'll need to fix the formatting.