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>
This commit is contained in:
parent
4e91325bf0
commit
eb913d3829
|
@ -350,6 +350,44 @@ ast::Intrinsic GetIntrinsic(SpvOp opcode) {
|
|||
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 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
|||
|
||||
// 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 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
|||
}
|
||||
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 @@ void FunctionEmitter::ApplySourceForInstruction(
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -259,6 +259,17 @@ struct DefInfo {
|
|||
/// 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 @@ class FunctionEmitter {
|
|||
/// @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
|
||||
|
|
|
@ -1102,16 +1102,26 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
|||
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();
|
||||
}
|
||||
if (!ast_type->IsPointer()) {
|
||||
return Fail() << "variable with ID " << var.result_id()
|
||||
<< " has non-pointer type " << 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();
|
||||
}
|
||||
}
|
||||
|
||||
auto* ast_store_type = ast_type->AsPointer()->type();
|
||||
auto ast_storage_class = ast_type->AsPointer()->storage_class();
|
||||
auto* ast_var =
|
||||
|
|
|
@ -48,10 +48,13 @@ std::string CommonTypes() {
|
|||
%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 @@ std::string CommonTypes() {
|
|||
%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 @@ INSTANTIATE_TEST_SUITE_P(
|
|||
"%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
|
||||
|
|
Loading…
Reference in New Issue