spirv-reader: Start emitting sampled image builtins
- Emit (non-depth) sampler variables
- Emit sampled texture variables
- Test emission of textureSample, textureBias, textureLevel
TODO: convert unsigned offset parameter to signed. crbug.com/tint/348
TODO: support arrayed access, where we have to split out the array index
into a separate operand. crbug.com/tint/349
TODO: for explicit-lod sampling, we may have to convert coordinates to
floating point. crbug.com/tint/346
Bug: tint:109
Change-Id: I12558f99473ca234ce0d09a87fc0c2f4730497bc
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/33342
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Auto-Submit: David Neto <dneto@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 57192d5..8276813 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -350,6 +350,44 @@
return ast::Intrinsic::kNone;
}
+// @param opcode a SPIR-V opcode
+// @returns true if the given instruction is an image access instruction
+// whose first input operand is an OpSampledImage value.
+bool IsSampledImageAccess(SpvOp opcode) {
+ switch (opcode) {
+ case SpvOpImageSampleImplicitLod:
+ case SpvOpImageSampleExplicitLod:
+ case SpvOpImageSampleDrefImplicitLod:
+ case SpvOpImageSampleDrefExplicitLod:
+ case SpvOpImageGather:
+ case SpvOpImageDrefGather:
+ case SpvOpImageQueryLod:
+ return true;
+ default:
+ // WGSL doesn't have *Proj* texturing.
+ break;
+ }
+ return false;
+}
+
+// @param opcode a SPIR-V opcode
+// @returns true if the given instruction is an image access instruction
+// whose first input operand is an OpImage value.
+bool IsRawImageAccess(SpvOp opcode) {
+ switch (opcode) {
+ case SpvOpImageRead:
+ case SpvOpImageWrite:
+ case SpvOpImageFetch:
+ case SpvOpImageQuerySizeLod:
+ case SpvOpImageQueryLevels:
+ case SpvOpImageQuerySamples:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
// @returns the merge block ID for the given basic block, or 0 if there is none.
uint32_t MergeFor(const spvtools::opt::BasicBlock& bb) {
// Get the OpSelectionMerge or OpLoopMerge instruction, if any.
@@ -2597,27 +2635,37 @@
// Handle combinatorial instructions.
const auto* def_info = GetDefInfo(result_id);
- auto combinatorial_expr = MaybeEmitCombinatorialValue(inst);
- if (combinatorial_expr.expr != nullptr) {
- if (def_info == nullptr) {
- return Fail() << "internal error: result ID %" << result_id
- << " is missing a def_info";
+ if (def_info) {
+ if (def_info->skip_generation) {
+ return true;
}
- if (def_info->requires_hoisted_def || def_info->requires_named_const_def ||
- def_info->num_uses != 1) {
- // Generate a const definition or an assignment to a hoisted definition
- // now and later use the const or variable name at the uses of this value.
- return EmitConstDefOrWriteToHoistedVar(inst, combinatorial_expr);
+ auto combinatorial_expr = MaybeEmitCombinatorialValue(inst);
+ if (combinatorial_expr.expr != nullptr) {
+ if (def_info->requires_hoisted_def ||
+ def_info->requires_named_const_def || def_info->num_uses != 1) {
+ // Generate a const definition or an assignment to a hoisted definition
+ // now and later use the const or variable name at the uses of this
+ // value.
+ return EmitConstDefOrWriteToHoistedVar(inst, combinatorial_expr);
+ }
+ // It is harmless to defer emitting the expression until it's used.
+ // Any supporting statements have already been emitted.
+ singly_used_values_.insert(std::make_pair(result_id, combinatorial_expr));
+ return success();
}
- // It is harmless to defer emitting the expression until it's used.
- // Any supporting statements have already been emitted.
- singly_used_values_.insert(std::make_pair(result_id, combinatorial_expr));
- return success();
}
if (failed()) {
return false;
}
+ if (IsSampledImageAccess(inst.opcode())) {
+ return EmitSampledImageAccess(inst);
+ }
+ if (IsRawImageAccess(inst.opcode())) {
+ return Fail() << "raw image access is not implemented yet:"
+ << inst.PrettyPrint();
+ }
+
switch (inst.opcode()) {
case SpvOpNop:
return true;
@@ -3195,34 +3243,45 @@
}
def_info_[result_id] = std::make_unique<DefInfo>(inst, block_pos, index);
index++;
+ auto& info = def_info_[result_id];
// Determine storage class for pointer values. Do this in order because
// we might rely on the storage class for a previously-visited definition.
// Logical pointers can't be transmitted through OpPhi, so remaining
// pointer definitions are SSA values, and their definitions must be
// visited before their uses.
- auto& storage_class = def_info_[result_id]->storage_class;
const auto* type = type_mgr_->GetType(inst.type_id());
- if (type && type->AsPointer()) {
- const auto* ast_type = parser_impl_.ConvertType(inst.type_id());
- if (ast_type && ast_type->AsPointer()) {
- storage_class = ast_type->AsPointer()->storage_class();
+ if (type) {
+ if (type->AsPointer()) {
+ const auto* ast_type = parser_impl_.ConvertType(inst.type_id());
+ if (ast_type && ast_type->AsPointer()) {
+ info->storage_class = ast_type->AsPointer()->storage_class();
+ }
+ switch (inst.opcode()) {
+ case SpvOpUndef:
+ case SpvOpVariable:
+ // Keep the default decision based on the result type.
+ break;
+ case SpvOpAccessChain:
+ case SpvOpCopyObject:
+ // Inherit from the first operand. We need this so we can pick up
+ // a remapped storage buffer.
+ info->storage_class = GetStorageClassForPointerValue(
+ inst.GetSingleWordInOperand(0));
+ break;
+ default:
+ return Fail()
+ << "pointer defined in function from unknown opcode: "
+ << inst.PrettyPrint();
+ }
+ if (info->storage_class == ast::StorageClass::kUniformConstant) {
+ info->skip_generation = true;
+ }
}
- switch (inst.opcode()) {
- case SpvOpUndef:
- case SpvOpVariable:
- // Keep the default decision based on the result type.
- break;
- case SpvOpAccessChain:
- case SpvOpCopyObject:
- // Inherit from the first operand. We need this so we can pick up
- // a remapped storage buffer.
- storage_class =
- GetStorageClassForPointerValue(inst.GetSingleWordInOperand(0));
- break;
- default:
- return Fail() << "pointer defined in function from unknown opcode: "
- << inst.PrettyPrint();
+ if (type->AsSampler() || type->AsImage() || type->AsSampledImage()) {
+ // Defer code generation until the instruction that actually acts on
+ // the image.
+ info->skip_generation = true;
}
}
}
@@ -3563,6 +3622,99 @@
}
}
+bool FunctionEmitter::EmitSampledImageAccess(
+ const spvtools::opt::Instruction& inst) {
+ auto* result_type = parser_impl_.ConvertType(inst.type_id());
+
+ // The sampled image operand is always first.
+ const auto sampled_image_id = inst.GetSingleWordInOperand(0);
+ const auto* sampler =
+ parser_impl_.GetMemoryObjectDeclarationForHandle(sampled_image_id, false);
+ const auto* image =
+ parser_impl_.GetMemoryObjectDeclarationForHandle(sampled_image_id, true);
+
+ if (!sampler) {
+ return Fail() << "interal error: couldn't find sampler for "
+ << inst.PrettyPrint();
+ }
+ if (!image) {
+ return Fail() << "interal error: couldn't find image for "
+ << inst.PrettyPrint();
+ }
+
+ ast::ExpressionList params;
+ params.push_back(
+ create<ast::IdentifierExpression>(namer_.Name(image->result_id())));
+ params.push_back(
+ create<ast::IdentifierExpression>(namer_.Name(sampler->result_id())));
+
+ // Push the coordinates operand.
+ // TODO(dneto): For explicit-Lod variations, we may have to convert from
+ // integral coordinates to floating point coordinates.
+ // TODO(dneto): For arrayed access, split off the array layer.
+ params.push_back(MakeOperand(inst, 1).expr);
+ uint32_t arg_index = 2;
+
+ std::string builtin_name;
+ switch (inst.opcode()) {
+ case SpvOpImageSampleImplicitLod:
+ case SpvOpImageSampleExplicitLod:
+ builtin_name = "textureSample";
+ break;
+ case SpvOpImageGather:
+ case SpvOpImageDrefGather:
+ return Fail() << " image gather is not yet supported";
+ case SpvOpImageQueryLod:
+ return Fail() << " image query Lod is not yet supported";
+ default:
+ return Fail() << "internal error: sampled image access";
+ }
+
+ // Loop over the image operands, looking for extra operands to the builtin.
+ // Except we uroll the loop.
+ const auto num_args = inst.NumInOperands();
+ uint32_t image_operands_mask = 0;
+ if (arg_index < num_args) {
+ image_operands_mask = inst.GetSingleWordInOperand(arg_index);
+ arg_index++;
+ }
+ if (arg_index < num_args &&
+ (image_operands_mask & SpvImageOperandsBiasMask)) {
+ builtin_name += "Bias";
+ params.push_back(MakeOperand(inst, arg_index).expr);
+ image_operands_mask ^= SpvImageOperandsBiasMask;
+ arg_index++;
+ }
+ if (arg_index < num_args && (image_operands_mask & SpvImageOperandsLodMask)) {
+ builtin_name += "Level";
+ params.push_back(MakeOperand(inst, arg_index).expr);
+ image_operands_mask ^= SpvImageOperandsLodMask;
+ arg_index++;
+ }
+ if (arg_index + 1 < num_args &&
+ (image_operands_mask & SpvImageOperandsGradMask)) {
+ builtin_name += "Grad";
+ params.push_back(MakeOperand(inst, arg_index).expr);
+ params.push_back(MakeOperand(inst, arg_index + 1).expr);
+ image_operands_mask ^= SpvImageOperandsGradMask;
+ arg_index += 2;
+ }
+ if (arg_index < num_args &&
+ (image_operands_mask & SpvImageOperandsConstOffsetMask)) {
+ params.push_back(MakeOperand(inst, arg_index).expr);
+ image_operands_mask ^= SpvImageOperandsConstOffsetMask;
+ arg_index++;
+ }
+ if (image_operands_mask) {
+ return Fail() << "unsupported image operands (" << image_operands_mask
+ << "): " << inst.PrettyPrint();
+ }
+
+ auto* ident = create<ast::IdentifierExpression>(builtin_name);
+ auto* call_expr = create<ast::CallExpression>(ident, std::move(params));
+ return EmitConstDefOrWriteToHoistedVar(inst, {result_type, call_expr});
+}
+
} // namespace spirv
} // namespace reader
} // namespace tint
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index 3211dc9..cfebe80 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -259,6 +259,17 @@
/// that needs to be remapped to StorageBuffer storage class.
/// This is kNone for non-pointers.
ast::StorageClass storage_class = ast::StorageClass::kNone;
+
+ /// Should this instruction be skipped when generating code?
+ /// This is true for any intermediate value which is an sampler, image,
+ /// or sampled image, or any pointer to such object. Code is generated
+ /// for those objects only when emitting the image instructions that access
+ /// the image (read, write, sample, gather, fetch, or query). For example,
+ /// when encountering an OpImageSampleExplicitLod, a call to the
+ /// textureSampleLevel builtin function will be emitted, and the call will
+ /// directly reference the underlying texture and sampler (variable or
+ /// function parameter).
+ bool skip_generation = false;
};
inline std::ostream& operator<<(std::ostream& o, const DefInfo& di) {
@@ -693,6 +704,12 @@
/// @returns an expression
TypedExpression MakeIntrinsicCall(const spvtools::opt::Instruction& inst);
+ /// Emits a texture builtin function call for a SPIR-V instruction that
+ /// accesses a sampled image.
+ /// @param inst the SPIR-V instruction
+ /// @returns an expression
+ bool EmitSampledImageAccess(const spvtools::opt::Instruction& inst);
+
/// Returns an expression for an OpSelect, if its operands are scalars
/// or vectors. These translate directly to WGSL select. Otherwise, return
/// an expression with a null owned expression
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 4c7e867..4ea1e21 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -1102,16 +1102,26 @@
if (!success_) {
return false;
}
- auto* ast_type = id_to_type_[type_id];
- if (ast_type == nullptr) {
- return Fail() << "internal error: failed to register Tint AST type for "
- "SPIR-V type with ID: "
- << var.type_id();
+ ast::type::Type* ast_type = nullptr;
+ if (spirv_storage_class == SpvStorageClassUniformConstant) {
+ // These are opaque handles: samplers or textures
+ ast_type = GetTypeForHandleVar(var);
+ if (!ast_type) {
+ return false;
+ }
+ } else {
+ ast_type = id_to_type_[type_id];
+ if (ast_type == nullptr) {
+ return Fail() << "internal error: failed to register Tint AST type for "
+ "SPIR-V type with ID: "
+ << var.type_id();
+ }
+ if (!ast_type->IsPointer()) {
+ return Fail() << "variable with ID " << var.result_id()
+ << " has non-pointer type " << var.type_id();
+ }
}
- if (!ast_type->IsPointer()) {
- return Fail() << "variable with ID " << var.result_id()
- << " has non-pointer type " << var.type_id();
- }
+
auto* ast_store_type = ast_type->AsPointer()->type();
auto ast_storage_class = ast_type->AsPointer()->storage_class();
auto* ast_var =
diff --git a/src/reader/spirv/parser_impl_handle_test.cc b/src/reader/spirv/parser_impl_handle_test.cc
index 1d28d1d..06109be 100644
--- a/src/reader/spirv/parser_impl_handle_test.cc
+++ b/src/reader/spirv/parser_impl_handle_test.cc
@@ -48,10 +48,13 @@
%uint = OpTypeInt 32 0
%int = OpTypeInt 32 1
+ %int_3 = OpConstant %uint 3
+ %int_4 = OpConstant %uint 4
%uint_1 = OpConstant %uint 1
%uint_2 = OpConstant %uint 2
%uint_100 = OpConstant %uint 100
+ %v2int = OpTypeVector %int 2
%v2uint = OpTypeVector %uint 2
%v4uint = OpTypeVector %uint 4
%v4int = OpTypeVector %int 4
@@ -60,11 +63,13 @@
%v4float = OpTypeVector %float 4
%float_null = OpConstantNull %float
+ %float_7 = OpConstant %float 7
%v2float_null = OpConstantNull %v2float
%v3float_null = OpConstantNull %v3float
%v4float_null = OpConstantNull %v4float
%depth = OpConstant %float 0.2
+ %offsets2d = OpConstantComposite %v2int %int_3 %int_4
; Define types for all sampler and texture types that can map to WGSL,
; modulo texel formats for storage textures. For now, we limit
@@ -1054,6 +1059,472 @@
"%uint %im",
"Usage(Texture( is_sampled ms ))"}));
+// Test emission of handle variables.
+
+struct DeclSampledImageCase {
+ std::string inst; // The provoking image access instruction.
+ std::string var_decl; // WGSL variable declaration
+ std::string texture_builtin; // WGSL texture usage.
+};
+inline std::ostream& operator<<(std::ostream& out,
+ const DeclSampledImageCase& c) {
+ out << "UsageSampledImageCase(" << c.inst << "\n"
+ << c.var_decl << "\n"
+ << c.texture_builtin << ")";
+ return out;
+}
+
+using SpvParserTest_DeclHandle_SampledImage =
+ SpvParserTestBase<::testing::TestWithParam<DeclSampledImageCase>>;
+
+TEST_P(SpvParserTest_DeclHandle_SampledImage, Variable) {
+ const auto assembly = Preamble() + R"(
+ OpDecorate %10 DescriptorSet 0
+ OpDecorate %10 Binding 0
+ OpDecorate %20 DescriptorSet 2
+ OpDecorate %20 Binding 1
+)" + CommonTypes() + R"(
+ %si_ty = OpTypeSampledImage %f_texture_2d
+ %coords = OpConstantNull %v2float
+
+ %10 = OpVariable %ptr_sampler UniformConstant
+ %20 = OpVariable %ptr_f_texture_2d UniformConstant
+
+ %main = OpFunction %void None %voidfn
+ %entry = OpLabel
+
+ %sam = OpLoad %sampler %10
+ %im = OpLoad %f_texture_2d %20
+ %sampled_image = OpSampledImage %si_ty %im %sam
+)" + GetParam().inst + R"(
+
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+ EXPECT_TRUE(p->error().empty()) << p->error();
+ const auto module = p->module().to_str();
+ EXPECT_THAT(module, HasSubstr(GetParam().var_decl))
+ << "DECLARATIONS ARE BAD " << module;
+ EXPECT_THAT(module, HasSubstr(GetParam().texture_builtin))
+ << "TEXTURE BUILTIN IS BAD " << module << assembly;
+}
+
+// TODO(dneto): Test variable declaration and texture builtins provoked by
+// use of an image access instruction inside helper function.
+TEST_P(SpvParserTest_RegisterHandleUsage_SampledImage, DISABLED_FunctionParam) {
+ const auto assembly = Preamble() + CommonTypes() + R"(
+ %f_ty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_2d
+ %si_ty = OpTypeSampledImage %f_texture_2d
+ %coords = OpConstantNull %v2float
+ %component = OpConstant %uint 1
+
+ %10 = OpVariable %ptr_sampler UniformConstant
+ %20 = OpVariable %ptr_f_texture_2d UniformConstant
+
+ %func = OpFunction %void None %f_ty
+ %110 = OpFunctionParameter %ptr_sampler
+ %120 = OpFunctionParameter %ptr_f_texture_2d
+ %func_entry = OpLabel
+ %sam = OpLoad %sampler %110
+ %im = OpLoad %f_texture_2d %120
+ %sampled_image = OpSampledImage %si_ty %im %sam
+
+)" + GetParam().inst + R"(
+
+ OpReturn
+ OpFunctionEnd
+
+ %main = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %foo = OpFunctionCall %void %func %10 %20
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildInternalModule()) << p->error() << assembly << std::endl;
+ EXPECT_TRUE(p->RegisterHandleUsage()) << p->error() << assembly << std::endl;
+ EXPECT_TRUE(p->error().empty()) << p->error() << assembly << std::endl;
+ Usage su = p->GetHandleUsage(10);
+ Usage iu = p->GetHandleUsage(20);
+
+ EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_usage));
+ EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DISABLED_ImageGather,
+ SpvParserTest_DeclHandle_SampledImage,
+ ::testing::ValuesIn(std::vector<DeclSampledImageCase>{
+ // TODO(dneto): OpImageGather
+ // TODO(dneto): OpImageGather with ConstOffset (signed and unsigned)
+ // TODO(dneto): OpImageGather with Offset (signed and unsigned)
+ // TODO(dneto): OpImageGather with Offsets (signed and unsigned)
+ }));
+
+INSTANTIATE_TEST_SUITE_P(
+ DISABLED_ImageDrefGather,
+ SpvParserTest_DeclHandle_SampledImage,
+ ::testing::ValuesIn(std::vector<DeclSampledImageCase>{
+ // TODO(dneto): OpImageDrefGather
+ // TODO(dneto): OpImageDrefGather with ConstOffset (signed and
+ // unsigned)
+ // TODO(dneto): OpImageDrefGather with Offset (signed and unsigned)
+ // TODO(dneto): OpImageDrefGather with Offsets (signed and unsigned)
+ }));
+
+INSTANTIATE_TEST_SUITE_P(
+ ImageSampleImplicitLod,
+ SpvParserTest_DeclHandle_SampledImage,
+ ::testing::Values(
+
+ // OpImageSampleImplicitLod
+ DeclSampledImageCase{"%result = OpImageSampleImplicitLod "
+ "%v4float %sampled_image %coords",
+ R"(
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{0}
+ BindingDecoration{0}
+ }
+ x_10
+ uniform_constant
+ __sampler_sampler
+ }
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __sampled_texture_2d__f32
+ })",
+ R"(
+ Call[not set]{
+ Identifier[not set]{textureSample}
+ (
+ Identifier[not set]{x_20}
+ Identifier[not set]{x_10}
+ TypeConstructor[not set]{
+ __vec_2__f32
+ ScalarConstructor[not set]{0.000000}
+ ScalarConstructor[not set]{0.000000}
+ }
+ )
+ })"},
+
+ // OpImageSampleImplicitLod with ConstOffset
+ DeclSampledImageCase{
+ "%result = OpImageSampleImplicitLod "
+ "%v4float %sampled_image %coords ConstOffset %offsets2d",
+ R"(
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{0}
+ BindingDecoration{0}
+ }
+ x_10
+ uniform_constant
+ __sampler_sampler
+ }
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __sampled_texture_2d__f32
+ })",
+ R"(
+ Call[not set]{
+ Identifier[not set]{textureSample}
+ (
+ Identifier[not set]{x_20}
+ Identifier[not set]{x_10}
+ TypeConstructor[not set]{
+ __vec_2__f32
+ ScalarConstructor[not set]{0.000000}
+ ScalarConstructor[not set]{0.000000}
+ }
+ TypeConstructor[not set]{
+ __vec_2__i32
+ ScalarConstructor[not set]{3}
+ ScalarConstructor[not set]{4}
+ }
+ )
+ })"},
+
+ // OpImageSampleImplicitLod with Bias
+ DeclSampledImageCase{"%result = OpImageSampleImplicitLod "
+ "%v4float %sampled_image %coords Bias %float_7",
+ R"(
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{0}
+ BindingDecoration{0}
+ }
+ x_10
+ uniform_constant
+ __sampler_sampler
+ }
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __sampled_texture_2d__f32
+ })",
+ R"(
+ Call[not set]{
+ Identifier[not set]{textureSampleBias}
+ (
+ Identifier[not set]{x_20}
+ Identifier[not set]{x_10}
+ TypeConstructor[not set]{
+ __vec_2__f32
+ ScalarConstructor[not set]{0.000000}
+ ScalarConstructor[not set]{0.000000}
+ }
+ ScalarConstructor[not set]{7.000000}
+ )
+ })"},
+
+ // OpImageSampleImplicitLod with Bias and ConstOffset
+ // TODO(dneto): OpImageSampleImplicitLod with Bias and unsigned
+ // ConstOffset
+ DeclSampledImageCase{"%result = OpImageSampleImplicitLod "
+ "%v4float %sampled_image %coords Bias|ConstOffset "
+ "%float_7 %offsets2d",
+ R"(
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{0}
+ BindingDecoration{0}
+ }
+ x_10
+ uniform_constant
+ __sampler_sampler
+ }
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __sampled_texture_2d__f32
+ })",
+ R"(
+ Call[not set]{
+ Identifier[not set]{textureSampleBias}
+ (
+ Identifier[not set]{x_20}
+ Identifier[not set]{x_10}
+ TypeConstructor[not set]{
+ __vec_2__f32
+ ScalarConstructor[not set]{0.000000}
+ ScalarConstructor[not set]{0.000000}
+ }
+ ScalarConstructor[not set]{7.000000}
+ TypeConstructor[not set]{
+ __vec_2__i32
+ ScalarConstructor[not set]{3}
+ ScalarConstructor[not set]{4}
+ }
+ )
+ })"}
+
+ ));
+
+INSTANTIATE_TEST_SUITE_P(
+ DISABLED_ImageSampleDrefImplicitLod,
+ SpvParserTest_DeclHandle_SampledImage,
+ ::testing::ValuesIn(std::vector<DeclSampledImageCase>{
+ // TODO(dneto): ImageSampleDrefImplicitLod
+ // TODO(dneto): ImageSampleDrefImplicitLod with ConstOffset (signed and
+ // unsigned)
+ // TODO(dneto): ImageSampleDrefImplicitLod with Bias
+ // TODO(dneto): ImageSampleDrefImplicitLod with Biase and ConstOffset
+ // (signed and unsigned)
+ }));
+
+INSTANTIATE_TEST_SUITE_P(
+ DisabledimageSampleExplicitLod,
+ SpvParserTest_DeclHandle_SampledImage,
+ ::testing::Values(
+
+ // OpImageSampleExplicitLod - using Lod
+ DeclSampledImageCase{"%result = OpImageSampleExplicitLod "
+ "%v4float %sampled_image %coords Lod %float_null",
+ R"(
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{0}
+ BindingDecoration{0}
+ }
+ x_10
+ uniform_constant
+ __sampler_sampler
+ }
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __sampled_texture_2d__f32
+ })",
+ R"(
+ Call[not set]{
+ Identifier[not set]{textureSampleLevel}
+ (
+ Identifier[not set]{x_20}
+ Identifier[not set]{x_10}
+ TypeConstructor[not set]{
+ __vec_2__f32
+ ScalarConstructor[not set]{0.000000}
+ ScalarConstructor[not set]{0.000000}
+ }
+ ScalarConstructor[not set]{0.000000}
+ )
+ })"},
+
+ // OpImageSampleExplicitLod - using Lod and ConstOffset
+ // TODO(dneto) OpImageSampleExplicitLod - using Lod and unsigned
+ // ConstOffset
+ DeclSampledImageCase{"%result = OpImageSampleExplicitLod "
+ "%v4float %sampled_image %coords Lod|ConstOffset "
+ "%float_null %offsets2d",
+ R"(
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{0}
+ BindingDecoration{0}
+ }
+ x_10
+ uniform_constant
+ __sampler_sampler
+ }
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __sampled_texture_2d__f32
+ })",
+ R"(
+ Call[not set]{
+ Identifier[not set]{textureSampleLevel}
+ (
+ Identifier[not set]{x_20}
+ Identifier[not set]{x_10}
+ TypeConstructor[not set]{
+ __vec_2__f32
+ ScalarConstructor[not set]{0.000000}
+ ScalarConstructor[not set]{0.000000}
+ }
+ ScalarConstructor[not set]{0.000000}
+ TypeConstructor[not set]{
+ __vec_2__i32
+ ScalarConstructor[not set]{3}
+ ScalarConstructor[not set]{4}
+ }
+ )
+ })"},
+
+ // OpImageSampleExplicitLod - using Grad
+ DeclSampledImageCase{
+ "%result = OpImageSampleExplicitLod "
+ "%v4float %sampled_image %coords Grad %float_7 %float_null",
+ R"(
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{0}
+ BindingDecoration{0}
+ }
+ x_10
+ uniform_constant
+ __sampler_sampler
+ }
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __sampled_texture_2d__f32
+ })",
+ R"(
+ Call[not set]{
+ Identifier[not set]{textureSampleGrad}
+ (
+ Identifier[not set]{x_20}
+ Identifier[not set]{x_10}
+ TypeConstructor[not set]{
+ __vec_2__f32
+ ScalarConstructor[not set]{0.000000}
+ ScalarConstructor[not set]{0.000000}
+ }
+ ScalarConstructor[not set]{7.000000}
+ ScalarConstructor[not set]{0.000000}
+ )
+ })"},
+
+ // OpImageSampleExplicitLod - using Grad and ConstOffset
+ // TODO(dneto): OpImageSampleExplicitLod - using Grad and unsigned
+ // ConstOffset
+ DeclSampledImageCase{"%result = OpImageSampleExplicitLod "
+ "%v4float %sampled_image %coords Grad|ConstOffset "
+ "%float_7 %float_null %offsets2d",
+ R"(
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{0}
+ BindingDecoration{0}
+ }
+ x_10
+ uniform_constant
+ __sampler_sampler
+ }
+ DecoratedVariable{
+ Decorations{
+ SetDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __sampled_texture_2d__f32
+ })",
+ R"(
+ Call[not set]{
+ Identifier[not set]{textureSampleGrad}
+ (
+ Identifier[not set]{x_20}
+ Identifier[not set]{x_10}
+ TypeConstructor[not set]{
+ __vec_2__f32
+ ScalarConstructor[not set]{0.000000}
+ ScalarConstructor[not set]{0.000000}
+ }
+ ScalarConstructor[not set]{7.000000}
+ ScalarConstructor[not set]{0.000000}
+ TypeConstructor[not set]{
+ __vec_2__i32
+ ScalarConstructor[not set]{3}
+ ScalarConstructor[not set]{4}
+ }
+ )
+ })"}));
+
} // namespace
} // namespace spirv
} // namespace reader