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;
|
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.
|
// @returns the merge block ID for the given basic block, or 0 if there is none.
|
||||||
uint32_t MergeFor(const spvtools::opt::BasicBlock& bb) {
|
uint32_t MergeFor(const spvtools::opt::BasicBlock& bb) {
|
||||||
// Get the OpSelectionMerge or OpLoopMerge instruction, if any.
|
// Get the OpSelectionMerge or OpLoopMerge instruction, if any.
|
||||||
|
@ -2597,16 +2635,17 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
||||||
|
|
||||||
// Handle combinatorial instructions.
|
// Handle combinatorial instructions.
|
||||||
const auto* def_info = GetDefInfo(result_id);
|
const auto* def_info = GetDefInfo(result_id);
|
||||||
|
if (def_info) {
|
||||||
|
if (def_info->skip_generation) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
auto combinatorial_expr = MaybeEmitCombinatorialValue(inst);
|
auto combinatorial_expr = MaybeEmitCombinatorialValue(inst);
|
||||||
if (combinatorial_expr.expr != nullptr) {
|
if (combinatorial_expr.expr != nullptr) {
|
||||||
if (def_info == nullptr) {
|
if (def_info->requires_hoisted_def ||
|
||||||
return Fail() << "internal error: result ID %" << result_id
|
def_info->requires_named_const_def || def_info->num_uses != 1) {
|
||||||
<< " is missing a def_info";
|
|
||||||
}
|
|
||||||
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
|
// 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.
|
// now and later use the const or variable name at the uses of this
|
||||||
|
// value.
|
||||||
return EmitConstDefOrWriteToHoistedVar(inst, combinatorial_expr);
|
return EmitConstDefOrWriteToHoistedVar(inst, combinatorial_expr);
|
||||||
}
|
}
|
||||||
// It is harmless to defer emitting the expression until it's used.
|
// It is harmless to defer emitting the expression until it's used.
|
||||||
|
@ -2614,10 +2653,19 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
||||||
singly_used_values_.insert(std::make_pair(result_id, combinatorial_expr));
|
singly_used_values_.insert(std::make_pair(result_id, combinatorial_expr));
|
||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (failed()) {
|
if (failed()) {
|
||||||
return false;
|
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()) {
|
switch (inst.opcode()) {
|
||||||
case SpvOpNop:
|
case SpvOpNop:
|
||||||
return true;
|
return true;
|
||||||
|
@ -3195,18 +3243,19 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
||||||
}
|
}
|
||||||
def_info_[result_id] = std::make_unique<DefInfo>(inst, block_pos, index);
|
def_info_[result_id] = std::make_unique<DefInfo>(inst, block_pos, index);
|
||||||
index++;
|
index++;
|
||||||
|
auto& info = def_info_[result_id];
|
||||||
|
|
||||||
// Determine storage class for pointer values. Do this in order because
|
// Determine storage class for pointer values. Do this in order because
|
||||||
// we might rely on the storage class for a previously-visited definition.
|
// we might rely on the storage class for a previously-visited definition.
|
||||||
// Logical pointers can't be transmitted through OpPhi, so remaining
|
// Logical pointers can't be transmitted through OpPhi, so remaining
|
||||||
// pointer definitions are SSA values, and their definitions must be
|
// pointer definitions are SSA values, and their definitions must be
|
||||||
// visited before their uses.
|
// visited before their uses.
|
||||||
auto& storage_class = def_info_[result_id]->storage_class;
|
|
||||||
const auto* type = type_mgr_->GetType(inst.type_id());
|
const auto* type = type_mgr_->GetType(inst.type_id());
|
||||||
if (type && type->AsPointer()) {
|
if (type) {
|
||||||
|
if (type->AsPointer()) {
|
||||||
const auto* ast_type = parser_impl_.ConvertType(inst.type_id());
|
const auto* ast_type = parser_impl_.ConvertType(inst.type_id());
|
||||||
if (ast_type && ast_type->AsPointer()) {
|
if (ast_type && ast_type->AsPointer()) {
|
||||||
storage_class = ast_type->AsPointer()->storage_class();
|
info->storage_class = ast_type->AsPointer()->storage_class();
|
||||||
}
|
}
|
||||||
switch (inst.opcode()) {
|
switch (inst.opcode()) {
|
||||||
case SpvOpUndef:
|
case SpvOpUndef:
|
||||||
|
@ -3217,13 +3266,23 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
||||||
case SpvOpCopyObject:
|
case SpvOpCopyObject:
|
||||||
// Inherit from the first operand. We need this so we can pick up
|
// Inherit from the first operand. We need this so we can pick up
|
||||||
// a remapped storage buffer.
|
// a remapped storage buffer.
|
||||||
storage_class =
|
info->storage_class = GetStorageClassForPointerValue(
|
||||||
GetStorageClassForPointerValue(inst.GetSingleWordInOperand(0));
|
inst.GetSingleWordInOperand(0));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return Fail() << "pointer defined in function from unknown opcode: "
|
return Fail()
|
||||||
|
<< "pointer defined in function from unknown opcode: "
|
||||||
<< inst.PrettyPrint();
|
<< inst.PrettyPrint();
|
||||||
}
|
}
|
||||||
|
if (info->storage_class == ast::StorageClass::kUniformConstant) {
|
||||||
|
info->skip_generation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 spirv
|
||||||
} // namespace reader
|
} // namespace reader
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -259,6 +259,17 @@ struct DefInfo {
|
||||||
/// that needs to be remapped to StorageBuffer storage class.
|
/// that needs to be remapped to StorageBuffer storage class.
|
||||||
/// This is kNone for non-pointers.
|
/// This is kNone for non-pointers.
|
||||||
ast::StorageClass storage_class = ast::StorageClass::kNone;
|
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) {
|
inline std::ostream& operator<<(std::ostream& o, const DefInfo& di) {
|
||||||
|
@ -693,6 +704,12 @@ class FunctionEmitter {
|
||||||
/// @returns an expression
|
/// @returns an expression
|
||||||
TypedExpression MakeIntrinsicCall(const spvtools::opt::Instruction& inst);
|
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
|
/// Returns an expression for an OpSelect, if its operands are scalars
|
||||||
/// or vectors. These translate directly to WGSL select. Otherwise, return
|
/// or vectors. These translate directly to WGSL select. Otherwise, return
|
||||||
/// an expression with a null owned expression
|
/// an expression with a null owned expression
|
||||||
|
|
|
@ -1102,7 +1102,15 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
||||||
if (!success_) {
|
if (!success_) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto* ast_type = id_to_type_[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) {
|
if (ast_type == nullptr) {
|
||||||
return Fail() << "internal error: failed to register Tint AST type for "
|
return Fail() << "internal error: failed to register Tint AST type for "
|
||||||
"SPIR-V type with ID: "
|
"SPIR-V type with ID: "
|
||||||
|
@ -1112,6 +1120,8 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
||||||
return Fail() << "variable with ID " << var.result_id()
|
return Fail() << "variable with ID " << var.result_id()
|
||||||
<< " has non-pointer type " << var.type_id();
|
<< " has non-pointer type " << var.type_id();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto* ast_store_type = ast_type->AsPointer()->type();
|
auto* ast_store_type = ast_type->AsPointer()->type();
|
||||||
auto ast_storage_class = ast_type->AsPointer()->storage_class();
|
auto ast_storage_class = ast_type->AsPointer()->storage_class();
|
||||||
auto* ast_var =
|
auto* ast_var =
|
||||||
|
|
|
@ -48,10 +48,13 @@ std::string CommonTypes() {
|
||||||
%uint = OpTypeInt 32 0
|
%uint = OpTypeInt 32 0
|
||||||
%int = OpTypeInt 32 1
|
%int = OpTypeInt 32 1
|
||||||
|
|
||||||
|
%int_3 = OpConstant %uint 3
|
||||||
|
%int_4 = OpConstant %uint 4
|
||||||
%uint_1 = OpConstant %uint 1
|
%uint_1 = OpConstant %uint 1
|
||||||
%uint_2 = OpConstant %uint 2
|
%uint_2 = OpConstant %uint 2
|
||||||
%uint_100 = OpConstant %uint 100
|
%uint_100 = OpConstant %uint 100
|
||||||
|
|
||||||
|
%v2int = OpTypeVector %int 2
|
||||||
%v2uint = OpTypeVector %uint 2
|
%v2uint = OpTypeVector %uint 2
|
||||||
%v4uint = OpTypeVector %uint 4
|
%v4uint = OpTypeVector %uint 4
|
||||||
%v4int = OpTypeVector %int 4
|
%v4int = OpTypeVector %int 4
|
||||||
|
@ -60,11 +63,13 @@ std::string CommonTypes() {
|
||||||
%v4float = OpTypeVector %float 4
|
%v4float = OpTypeVector %float 4
|
||||||
|
|
||||||
%float_null = OpConstantNull %float
|
%float_null = OpConstantNull %float
|
||||||
|
%float_7 = OpConstant %float 7
|
||||||
%v2float_null = OpConstantNull %v2float
|
%v2float_null = OpConstantNull %v2float
|
||||||
%v3float_null = OpConstantNull %v3float
|
%v3float_null = OpConstantNull %v3float
|
||||||
%v4float_null = OpConstantNull %v4float
|
%v4float_null = OpConstantNull %v4float
|
||||||
|
|
||||||
%depth = OpConstant %float 0.2
|
%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,
|
; Define types for all sampler and texture types that can map to WGSL,
|
||||||
; modulo texel formats for storage textures. For now, we limit
|
; modulo texel formats for storage textures. For now, we limit
|
||||||
|
@ -1054,6 +1059,472 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
"%uint %im",
|
"%uint %im",
|
||||||
"Usage(Texture( is_sampled ms ))"}));
|
"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
|
||||||
} // namespace spirv
|
} // namespace spirv
|
||||||
} // namespace reader
|
} // namespace reader
|
||||||
|
|
Loading…
Reference in New Issue