spirv-reader: convert coordinate type when unsigned

In SPIR-V, coordinates for ImageRead, ImageFetch, ImageWrite are
integral.  When they are unsigned, they must be converted to signed.

Fix tests for image sampling and dref sampling that used integer
coordinates. SPIR-V requires them to be floating point.

Bug: tint:109
Fixed: tint:346
Change-Id: If33c8970b9d8f7d934d3e582194fe6ed83eff7e8
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/35560
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Auto-Submit: David Neto <dneto@google.com>
This commit is contained in:
David Neto 2020-12-14 17:31:37 +00:00 committed by Commit Bot service account
parent 24bbbbb25f
commit 2353bd0d3d
3 changed files with 490 additions and 110 deletions

View File

@ -3868,11 +3868,6 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
arg_index++;
// Push the coordinates operands.
// TODO(dneto): For explicit-Lod variations, we may have to convert from
// integral coordinates to floating point coordinates.
// In WGSL, integer (unnormalized) coordinates are only used for texture
// fetch (textureLoad on sampled image) or textureLoad or textureStore
// on storage images.
auto coords = MakeCoordinateOperandsForImageAccess(inst);
if (coords.empty()) {
return false;
@ -3951,15 +3946,13 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
}
if (arg_index < num_args && (image_operands_mask & SpvImageOperandsLodMask)) {
builtin_name += "Level";
auto* lod_operand = MakeOperand(inst, arg_index).expr;
// When sampling from a depth texture, the Lod operand must be an unsigned
// integer.
TypedExpression lod = MakeOperand(inst, arg_index);
// When sampling from a depth texture, the Lod operand must be an I32.
if (texture_type->Is<ast::type::DepthTexture>()) {
// Convert it to a signed integer type.
lod_operand = create<ast::TypeConstructorExpression>(
Source{}, create<ast::type::I32>(), ast::ExpressionList{lod_operand});
lod = ToI32(lod);
}
params.push_back(lod_operand);
params.push_back(lod.expr);
image_operands_mask ^= SpvImageOperandsLodMask;
arg_index++;
}
@ -4053,6 +4046,17 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
return {};
}
// In SPIR-V for Shader, coordinates are:
// - floating point for sampling, dref sampling, gather, dref gather
// - integral for fetch, read, write
// In WGSL:
// - floating point for sampling, dref sampling, gather, dref gather
// - signed integral for textureLoad, textureStore
//
// The only conversions we have to do for WGSL are:
// - When the coordinates are unsigned integral, convert them to signed.
// - Array index is always i32
// The coordinates parameter is always in position 1.
TypedExpression raw_coords(MakeOperand(inst, 1));
if (!raw_coords.type) {
@ -4107,11 +4111,13 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
assert(num_axes <= 3);
const auto num_coords_required = num_axes + (is_arrayed ? 1 : 0);
uint32_t num_coords_supplied = 0;
if (raw_coords.type->is_float_scalar() ||
raw_coords.type->is_integer_scalar()) {
auto* component_type = raw_coords.type;
if (component_type->is_float_scalar() ||
component_type->is_integer_scalar()) {
num_coords_supplied = 1;
} else if (auto* vec_ty = raw_coords.type->As<ast::type::Vector>()) {
num_coords_supplied = vec_ty->size();
} else if (auto* vec_type = raw_coords.type->As<ast::type::Vector>()) {
component_type = vec_type->type();
num_coords_supplied = vec_type->size();
}
if (num_coords_supplied == 0) {
Fail() << "bad or unsupported coordinate type for image access: "
@ -4127,29 +4133,41 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
ast::ExpressionList result;
// TODO(dneto): Convert coordinate component type if needed.
// Generates the expression for the WGSL coordinates, when it is a prefix
// swizzle with num_axes. If the result would be unsigned, also converts
// it to a signed value of the same shape (scalar or vector).
// Use a lambda to make it easy to only generate the expressions when we
// will actually use them.
auto prefix_swizzle_expr = [this, num_axes, component_type,
raw_coords]() -> ast::Expression* {
auto* swizzle_type =
(num_axes == 1) ? component_type
: create<ast::type::Vector>(component_type, num_axes);
auto* swizzle = create<ast::MemberAccessorExpression>(
Source{}, raw_coords.expr, PrefixSwizzle(num_axes));
return ToSignedIfUnsigned({swizzle_type, swizzle}).expr;
};
if (is_arrayed) {
// The source must be a vector, because it has enough components and has an
// array component. Use a vector swizzle to get the first `num_axes`
// components.
result.push_back(create<ast::MemberAccessorExpression>(
Source{}, raw_coords.expr, PrefixSwizzle(num_axes)));
// The source must be a vector. It has at least one coordinate component
// and it must have an array component. Use a vector swizzle to get the
// first `num_axes` components.
result.push_back(prefix_swizzle_expr());
// Now get the array index.
ast::Expression* array_index = create<ast::MemberAccessorExpression>(
Source{}, raw_coords.expr, Swizzle(num_axes));
// Convert it to a signed integer type.
result.push_back(create<ast::TypeConstructorExpression>(
Source{}, create<ast::type::I32>(), ast::ExpressionList{array_index}));
// Convert it to a signed integer type, if needed
result.push_back(ToI32({component_type, array_index}).expr);
} else {
if (num_coords_supplied == num_coords_required) {
// Pass the value through.
result.push_back(std::move(raw_coords.expr));
// Pass the value through, with possible unsigned->signed conversion.
result.push_back(ToSignedIfUnsigned(raw_coords).expr);
} else {
// There are more coordinates supplied than needed. So the source type is
// a vector. Use a vector swizzle to get the first `num_axes` components.
result.push_back(create<ast::MemberAccessorExpression>(
Source{}, raw_coords.expr, PrefixSwizzle(num_axes)));
// There are more coordinates supplied than needed. So the source type
// is a vector. Use a vector swizzle to get the first `num_axes`
// components.
result.push_back(prefix_swizzle_expr());
}
}
return result;
@ -4249,6 +4267,18 @@ TypedExpression FunctionEmitter::ToI32(TypedExpression value) {
Source{}, i32_, ast::ExpressionList{value.expr})};
}
TypedExpression FunctionEmitter::ToSignedIfUnsigned(TypedExpression value) {
if (!value.type || !value.type->is_unsigned_scalar_or_vector()) {
return value;
}
if (auto* vec_type = value.type->As<ast::type::Vector>()) {
auto* new_type = create<ast::type::Vector>(i32_, vec_type->size());
return {new_type, create<ast::TypeConstructorExpression>(
Source{}, new_type, ast::ExpressionList{value.expr})};
}
return ToI32(value);
}
FunctionEmitter::FunctionDeclaration::FunctionDeclaration() = default;
FunctionEmitter::FunctionDeclaration::~FunctionDeclaration() = default;

View File

@ -701,6 +701,14 @@ class FunctionEmitter {
/// @returns the value as an I32 value.
TypedExpression ToI32(TypedExpression value);
/// Returns the given value as a signed integer type of the same shape
/// if the value is unsigned scalar or vector, by wrapping the value
/// with a TypeConstructor expression. Returns the value itself if the
/// value otherwise.
/// @param value the value to pass through or convert
/// @returns the value itself, or converted to signed integral
TypedExpression ToSignedIfUnsigned(TypedExpression value);
private:
/// FunctionDeclaration contains the parsed information for a function header.
struct FunctionDeclaration {

View File

@ -2389,7 +2389,7 @@ INSTANTIATE_TEST_SUITE_P(
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// OpImageWrite with no extra params
{"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vu12 %vf1234",
{"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vi12 %vf1234",
R"(
Variable{
Decorations{
@ -2404,13 +2404,13 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Identifier[not set]{vf1234}
)
})"},
// OpImageWrite with ConstOffset
{"%float 2D 0 0 0 2 Rgba32f",
"OpImageWrite %im %vu12 %vf1234 ConstOffset %offsets2d",
"OpImageWrite %im %vi12 %vf1234 ConstOffset %offsets2d",
R"(
Variable{
Decorations{
@ -2425,7 +2425,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Identifier[not set]{vf1234}
Identifier[not set]{offsets2d}
)
@ -2439,7 +2439,7 @@ INSTANTIATE_TEST_SUITE_P(
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// Source 1 component, dest 1 component
{"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %f1",
{"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vi12 %f1",
R"(
Variable{
Decorations{
@ -2454,12 +2454,12 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Identifier[not set]{f1}
)
})"},
// Source 2 component, dest 1 component
{"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf12",
{"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vi12 %vf12",
R"(
Variable{
Decorations{
@ -2474,7 +2474,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf12}
Identifier[not set]{x}
@ -2482,7 +2482,7 @@ INSTANTIATE_TEST_SUITE_P(
)
})"},
// Source 3 component, dest 1 component
{"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf123",
{"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vi12 %vf123",
R"(
Variable{
Decorations{
@ -2497,7 +2497,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{x}
@ -2505,7 +2505,7 @@ INSTANTIATE_TEST_SUITE_P(
)
})"},
// Source 4 component, dest 1 component
{"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf1234",
{"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vi12 %vf1234",
R"(
Variable{
Decorations{
@ -2520,7 +2520,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf1234}
Identifier[not set]{x}
@ -2528,7 +2528,7 @@ INSTANTIATE_TEST_SUITE_P(
)
})"},
// Source 2 component, dest 2 component
{"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vu12 %vf12",
{"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vi12 %vf12",
R"(
Variable{
Decorations{
@ -2543,12 +2543,12 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Identifier[not set]{vf12}
)
})"},
// Source 3 component, dest 2 component
{"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vu12 %vf123",
{"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vi12 %vf123",
R"(
Variable{
Decorations{
@ -2563,7 +2563,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{xy}
@ -2571,7 +2571,7 @@ INSTANTIATE_TEST_SUITE_P(
)
})"},
// Source 4 component, dest 2 component
{"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vu12 %vf1234",
{"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vi12 %vf1234",
R"(
Variable{
Decorations{
@ -2586,7 +2586,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
MemberAccessor[not set]{
Identifier[not set]{vf1234}
Identifier[not set]{xy}
@ -2595,7 +2595,7 @@ INSTANTIATE_TEST_SUITE_P(
})"},
// WGSL does not support 3-component storage textures.
// Source 4 component, dest 4 component
{"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vu12 %vf1234",
{"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vi12 %vf1234",
R"(
Variable{
Decorations{
@ -2610,7 +2610,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Identifier[not set]{vf1234}
)
})"}}));
@ -2761,7 +2761,7 @@ INSTANTIATE_TEST_SUITE_P(
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// Sampled type is unsigned int, texel is unsigned int
{"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vu12 %vu1234",
{"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vi12 %vu1234",
R"(
Variable{
Decorations{
@ -2776,12 +2776,12 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Identifier[not set]{vu1234}
)
})"},
// Sampled type is unsigned int, texel is signed int
{"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vu12 %vi1234",
{"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vi12 %vi1234",
R"(
Variable{
Decorations{
@ -2796,14 +2796,14 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Bitcast[not set]<__vec_4__u32>{
Identifier[not set]{vi1234}
}
)
})"},
// Sampled type is signed int, texel is unsigned int
{"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vu12 %vu1234",
{"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vi12 %vu1234",
R"(
Variable{
Decorations{
@ -2818,14 +2818,14 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Bitcast[not set]<__vec_4__i32>{
Identifier[not set]{vu1234}
}
)
})"},
// Sampled type is signed int, texel is signed int
{"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vu12 %vi1234",
{"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vi12 %vi1234",
R"(
Variable{
Decorations{
@ -2840,7 +2840,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureStore}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Identifier[not set]{vi1234}
)
})"}}));
@ -2850,7 +2850,7 @@ INSTANTIATE_TEST_SUITE_P(
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// OpImageRead with no extra params
{"%float 2D 0 0 0 2 Rgba32f", "%99 = OpImageRead %v4float %im %vu12",
{"%float 2D 0 0 0 2 Rgba32f", "%99 = OpImageRead %v4float %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -2870,7 +2870,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
@ -2878,7 +2878,7 @@ INSTANTIATE_TEST_SUITE_P(
})"},
// OpImageRead with ConstOffset
{"%float 2D 0 0 0 2 Rgba32f",
"%99 = OpImageRead %v4float %im %vu12 ConstOffset %offsets2d",
"%99 = OpImageRead %v4float %im %vi12 ConstOffset %offsets2d",
R"(Variable{
Decorations{
SetDecoration{2}
@ -2898,7 +2898,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Identifier[not set]{offsets2d}
)
}
@ -2911,7 +2911,7 @@ INSTANTIATE_TEST_SUITE_P(
SpvParserTest_ImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// OpImageFetch with no extra params
{"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vu12",
{"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -2931,7 +2931,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
@ -2940,7 +2940,7 @@ INSTANTIATE_TEST_SUITE_P(
// OpImageFetch with ConstOffset
// TODO(dneto): Seems this is not valid in WGSL.
{"%float 2D 0 0 0 1 Unknown",
"%99 = OpImageFetch %v4float %im %vu12 ConstOffset %offsets2d",
"%99 = OpImageFetch %v4float %im %vi12 ConstOffset %offsets2d",
R"(Variable{
Decorations{
SetDecoration{2}
@ -2960,7 +2960,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
Identifier[not set]{offsets2d}
)
}
@ -3030,13 +3030,10 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{vi123}
Identifier[not set]{xy}
}
TypeConstructor[not set]{
__i32
MemberAccessor[not set]{
Identifier[not set]{vi123}
Identifier[not set]{z}
}
}
Identifier[not set]{i1}
)
}
@ -3099,7 +3096,7 @@ INSTANTIATE_TEST_SUITE_P(
//
// OpImageFetch requires no conversion, float -> v4float
{"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vu12",
{"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3119,14 +3116,14 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageFetch requires no conversion, uint -> v4uint
{"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vu12",
{"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3146,14 +3143,14 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageFetch requires conversion, uint -> v4int
{"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vu12",
{"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3174,7 +3171,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
@ -3182,7 +3179,7 @@ INSTANTIATE_TEST_SUITE_P(
}
})"},
// OpImageFetch requires no conversion, int -> v4int
{"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vu12",
{"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3202,14 +3199,14 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageFetch requires conversion, int -> v4uint
{"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vu12",
{"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3230,7 +3227,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
@ -3243,7 +3240,7 @@ INSTANTIATE_TEST_SUITE_P(
//
// OpImageRead requires no conversion, float -> v4float
{"%float 2D 0 0 0 1 Rgba32f", "%99 = OpImageRead %v4float %im %vu12",
{"%float 2D 0 0 0 1 Rgba32f", "%99 = OpImageRead %v4float %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3263,14 +3260,14 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageRead requires no conversion, uint -> v4uint
{"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4uint %im %vu12",
{"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4uint %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3290,14 +3287,14 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageRead requires conversion, uint -> v4int
{"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4int %im %vu12",
{"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4int %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3318,7 +3315,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
@ -3326,7 +3323,7 @@ INSTANTIATE_TEST_SUITE_P(
}
})"},
// OpImageRead requires no conversion, int -> v4int
{"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4int %im %vu12",
{"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4int %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3346,14 +3343,14 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
}
})"},
// OpImageRead requires conversion, int -> v4uint
{"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4uint %im %vu12",
{"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4uint %im %vi12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3374,7 +3371,7 @@ INSTANTIATE_TEST_SUITE_P(
Identifier[not set]{textureLoad}
(
Identifier[not set]{x_20}
Identifier[not set]{vu12}
Identifier[not set]{vi12}
)
}
}
@ -3388,7 +3385,7 @@ INSTANTIATE_TEST_SUITE_P(
// OpImageSampleImplicitLod requires no conversion, float -> v4float
{"%float 2D 0 0 0 1 Unknown",
"%99 = OpImageSampleImplicitLod %v4float %sampled_image %vu12",
"%99 = OpImageSampleImplicitLod %v4float %sampled_image %vf12",
R"(
Variable{
Decorations{
@ -3419,7 +3416,7 @@ INSTANTIATE_TEST_SUITE_P(
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
Identifier[not set]{vu12}
Identifier[not set]{vf12}
)
}
}
@ -3427,7 +3424,7 @@ INSTANTIATE_TEST_SUITE_P(
})"},
// OpImageSampleImplicitLod requires no conversion, uint -> v4uint
{"%uint 2D 0 0 0 1 Unknown",
"%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vu12",
"%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vf12",
R"(
Variable{
Decorations{
@ -3458,7 +3455,7 @@ INSTANTIATE_TEST_SUITE_P(
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
Identifier[not set]{vu12}
Identifier[not set]{vf12}
)
}
}
@ -3466,7 +3463,7 @@ INSTANTIATE_TEST_SUITE_P(
})"},
// OpImageSampleImplicitLod requires conversion, uint -> v4int
{"%uint 2D 0 0 0 1 Unknown",
"%99 = OpImageSampleImplicitLod %v4int %sampled_image %vu12",
"%99 = OpImageSampleImplicitLod %v4int %sampled_image %vf12",
R"(
Variable{
Decorations{
@ -3498,7 +3495,7 @@ INSTANTIATE_TEST_SUITE_P(
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
Identifier[not set]{vu12}
Identifier[not set]{vf12}
)
}
}
@ -3507,7 +3504,7 @@ INSTANTIATE_TEST_SUITE_P(
})"},
// OpImageSampleImplicitLod requires no conversion, int -> v4int
{"%int 2D 0 0 0 1 Unknown",
"%99 = OpImageSampleImplicitLod %v4int %sampled_image %vu12",
"%99 = OpImageSampleImplicitLod %v4int %sampled_image %vf12",
R"(
Variable{
Decorations{
@ -3538,7 +3535,7 @@ INSTANTIATE_TEST_SUITE_P(
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
Identifier[not set]{vu12}
Identifier[not set]{vf12}
)
}
}
@ -3546,7 +3543,7 @@ INSTANTIATE_TEST_SUITE_P(
})"},
// OpImageSampleImplicitLod requires conversion, int -> v4uint
{"%int 2D 0 0 0 1 Unknown",
"%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vu12",
"%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vf12",
R"(Variable{
Decorations{
SetDecoration{2}
@ -3568,7 +3565,7 @@ INSTANTIATE_TEST_SUITE_P(
(
Identifier[not set]{x_20}
Identifier[not set]{x_10}
Identifier[not set]{vu12}
Identifier[not set]{vf12}
)
}
}
@ -3604,6 +3601,14 @@ TEST_P(SpvParserTest_ImageCoordsTest, MakeCoordinateOperandsForImageAccess) {
OpExecutionMode %100 OriginUpperLeft
OpName %float_var "float_var"
OpName %ptr_float "ptr_float"
OpName %i1 "i1"
OpName %vi12 "vi12"
OpName %vi123 "vi123"
OpName %vi1234 "vi1234"
OpName %u1 "u1"
OpName %vu12 "vu12"
OpName %vu123 "vu123"
OpName %vu1234 "vu1234"
OpName %f1 "f1"
OpName %vf12 "vf12"
OpName %vf123 "vf123"
@ -3635,6 +3640,16 @@ TEST_P(SpvParserTest_ImageCoordsTest, MakeCoordinateOperandsForImageAccess) {
%float_var = OpVariable %ptr_float Function
%i1 = OpCopyObject %int %int_1
%vi12 = OpCopyObject %v2int %the_vi12
%vi123 = OpCopyObject %v3int %the_vi123
%vi1234 = OpCopyObject %v4int %the_vi1234
%u1 = OpCopyObject %uint %uint_1
%vu12 = OpCopyObject %v2uint %the_vu12
%vu123 = OpCopyObject %v3uint %the_vu123
%vu1234 = OpCopyObject %v4uint %the_vu1234
%f1 = OpCopyObject %float %float_1
%vf12 = OpCopyObject %v2float %the_vf12
%vf123 = OpCopyObject %v3float %the_vf123
@ -3912,6 +3927,333 @@ INSTANTIATE_TEST_SUITE_P(Good_CubeArray,
}
)"}}}));
INSTANTIATE_TEST_SUITE_P(
PreserveFloatCoords_NonArrayed,
// In SPIR-V, sampling and dref sampling operations use floating point
// coordinates. Prove that we preserve floating point-ness.
// Test across all such instructions.
SpvParserTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
// Scalar cases
{"%float 1D 0 0 0 1 Unknown",
"%result = OpImageSampleImplicitLod %v4float %sampled_image %f1",
"",
{"Identifier[not set]{f1}\n"}},
{"%float 1D 0 0 0 1 Unknown",
"%result = OpImageSampleExplicitLod %v4float %sampled_image %f1 Lod "
"%f1",
"",
{"Identifier[not set]{f1}\n"}},
// WGSL does not support depth textures with 1D coordinates
// Vector cases
{"%float 2D 0 0 0 1 Unknown",
"%result = OpImageSampleImplicitLod %v4float %sampled_image %vf12",
"",
{"Identifier[not set]{vf12}\n"}},
{"%float 2D 0 0 0 1 Unknown",
"%result = OpImageSampleExplicitLod %v4float %sampled_image %vf12 Lod "
"%f1",
"",
{"Identifier[not set]{vf12}\n"}},
{"%float 2D 1 0 0 1 Unknown",
"%result = OpImageSampleDrefImplicitLod %v4float %sampled_image %vf12 "
"%depth",
"",
{"Identifier[not set]{vf12}\n"}},
{"%float 2D 1 0 0 1 Unknown",
"%result = OpImageSampleDrefExplicitLod %v4float %sampled_image %vf12 "
"%depth Lod %f1",
"",
{"Identifier[not set]{vf12}\n"}},
}));
INSTANTIATE_TEST_SUITE_P(
PreserveFloatCoords_Arrayed,
// In SPIR-V, sampling and dref sampling operations use floating point
// coordinates. Prove that we preserve floating point-ness of the
// coordinate part, but convert the array index to signed integer. Test
// across all such instructions.
SpvParserTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
{"%float 2D 0 1 0 1 Unknown",
"%result = OpImageSampleImplicitLod %v4float %sampled_image %vf123",
"",
{
R"(MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{xy}
}
)",
R"(TypeConstructor[not set]{
__i32
MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{z}
}
}
)"}},
{"%float 2D 0 1 0 1 Unknown",
"%result = OpImageSampleExplicitLod %v4float %sampled_image %vf123 "
"Lod %f1",
"",
{
R"(MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{xy}
}
)",
R"(TypeConstructor[not set]{
__i32
MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{z}
}
}
)"}},
{"%float 2D 1 1 0 1 Unknown",
"%result = OpImageSampleDrefImplicitLod %v4float %sampled_image "
"%vf123 %depth",
"",
{
R"(MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{xy}
}
)",
R"(TypeConstructor[not set]{
__i32
MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{z}
}
}
)"}},
{"%float 2D 1 1 0 1 Unknown",
"%result = OpImageSampleDrefExplicitLod %v4float %sampled_image "
"%vf123 %depth Lod %f1",
"",
{
R"(MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{xy}
}
)",
R"(TypeConstructor[not set]{
__i32
MemberAccessor[not set]{
Identifier[not set]{vf123}
Identifier[not set]{z}
}
}
)"}}}));
INSTANTIATE_TEST_SUITE_P(
PreserveIntCoords_NonArrayed,
// In SPIR-V, image read, fetch, and write use integer coordinates.
// Prove that we preserve signed integer coordinates.
SpvParserTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
// Scalar cases
{"%float 1D 0 0 0 1 Unknown",
"%result = OpImageFetch %float %im %i1",
"",
{"Identifier[not set]{i1}\n"}},
{"%float 1D 0 0 0 2 R32f",
"%result = OpImageRead %float %im %i1",
"",
{"Identifier[not set]{i1}\n"}},
{"%float 1D 0 0 0 2 R32f",
"OpImageWrite %im %i1 %float_1",
"",
{"Identifier[not set]{i1}\n"}},
// Vector cases
{"%float 2D 0 0 0 1 Unknown",
"%result = OpImageFetch %float %im %vi12",
"",
{"Identifier[not set]{vi12}\n"}},
{"%float 2D 0 0 0 2 R32f",
"%result = OpImageRead %float %im %vi12",
"",
{"Identifier[not set]{vi12}\n"}},
{"%float 2D 0 0 0 2 R32f",
"OpImageWrite %im %vi12 %float_1",
"",
{"Identifier[not set]{vi12}\n"}}}));
INSTANTIATE_TEST_SUITE_P(
PreserveIntCoords_Arrayed,
// In SPIR-V, image read, fetch, and write use integer coordinates.
// Prove that we preserve signed integer coordinates.
SpvParserTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
{"%float 2D 0 1 0 1 Unknown",
"%result = OpImageFetch %float %im %vi123",
"",
{
R"(MemberAccessor[not set]{
Identifier[not set]{vi123}
Identifier[not set]{xy}
}
)",
R"(MemberAccessor[not set]{
Identifier[not set]{vi123}
Identifier[not set]{z}
}
)"}},
{"%float 2D 0 1 0 2 R32f",
"%result = OpImageRead %float %im %vi123",
"",
{
R"(MemberAccessor[not set]{
Identifier[not set]{vi123}
Identifier[not set]{xy}
}
)",
R"(MemberAccessor[not set]{
Identifier[not set]{vi123}
Identifier[not set]{z}
}
)"}},
{"%float 2D 0 1 0 2 R32f",
"OpImageWrite %im %vi123 %float_1",
"",
{
R"(MemberAccessor[not set]{
Identifier[not set]{vi123}
Identifier[not set]{xy}
}
)",
R"(MemberAccessor[not set]{
Identifier[not set]{vi123}
Identifier[not set]{z}
}
)"}}}));
INSTANTIATE_TEST_SUITE_P(
ConvertUintCoords_NonArrayed,
// In SPIR-V, image read, fetch, and write use integer coordinates.
// Prove that we convert unsigned integer coordinates to signed.
SpvParserTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
// Scalar cases
{"%float 1D 0 0 0 1 Unknown",
"%result = OpImageFetch %float %im %u1",
"",
{R"(TypeConstructor[not set]{
__i32
Identifier[not set]{u1}
}
)"}},
{"%float 1D 0 0 0 2 R32f",
"%result = OpImageRead %float %im %u1",
"",
{R"(TypeConstructor[not set]{
__i32
Identifier[not set]{u1}
}
)"}},
{"%float 1D 0 0 0 2 R32f",
"OpImageWrite %im %u1 %float_1",
"",
{R"(TypeConstructor[not set]{
__i32
Identifier[not set]{u1}
}
)"}},
// Vector cases
{"%float 2D 0 0 0 1 Unknown",
"%result = OpImageFetch %float %im %vu12",
"",
{R"(TypeConstructor[not set]{
__vec_2__i32
Identifier[not set]{vu12}
}
)"}},
{"%float 2D 0 0 0 2 R32f",
"%result = OpImageRead %float %im %vu12",
"",
{R"(TypeConstructor[not set]{
__vec_2__i32
Identifier[not set]{vu12}
}
)"}},
{"%float 2D 0 0 0 2 R32f",
"OpImageWrite %im %vu12 %float_1",
"",
{R"(TypeConstructor[not set]{
__vec_2__i32
Identifier[not set]{vu12}
}
)"}}}));
INSTANTIATE_TEST_SUITE_P(
ConvertUintCoords_Arrayed,
// In SPIR-V, image read, fetch, and write use integer coordinates.
// Prove that we convert unsigned integer coordinates to signed.
SpvParserTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
{"%float 2D 0 1 0 1 Unknown",
"%result = OpImageFetch %float %im %vu123",
"",
{
R"(TypeConstructor[not set]{
__vec_2__i32
MemberAccessor[not set]{
Identifier[not set]{vu123}
Identifier[not set]{xy}
}
}
)",
R"(TypeConstructor[not set]{
__i32
MemberAccessor[not set]{
Identifier[not set]{vu123}
Identifier[not set]{z}
}
}
)"}},
{"%float 2D 0 1 0 2 R32f",
"%result = OpImageRead %float %im %vu123",
"",
{
R"(TypeConstructor[not set]{
__vec_2__i32
MemberAccessor[not set]{
Identifier[not set]{vu123}
Identifier[not set]{xy}
}
}
)",
R"(TypeConstructor[not set]{
__i32
MemberAccessor[not set]{
Identifier[not set]{vu123}
Identifier[not set]{z}
}
}
)"}},
{"%float 2D 0 1 0 2 R32f",
"OpImageWrite %im %vu123 %float_1",
"",
{
R"(TypeConstructor[not set]{
__vec_2__i32
MemberAccessor[not set]{
Identifier[not set]{vu123}
Identifier[not set]{xy}
}
}
)",
R"(TypeConstructor[not set]{
__i32
MemberAccessor[not set]{
Identifier[not set]{vu123}
Identifier[not set]{z}
}
}
)"}}}));
INSTANTIATE_TEST_SUITE_P(
BadInstructions,
SpvParserTest_ImageCoordsTest,
@ -3924,7 +4266,7 @@ INSTANTIATE_TEST_SUITE_P(
{"%float 1D 0 0 0 1 Unknown",
"%50 = OpCopyObject %float %float_1",
"internal error: couldn't find image for "
"%50 = OpCopyObject %9 %36",
"%50 = OpCopyObject %18 %44",
{}},
{"%float 1D 0 0 0 1 Unknown",
"OpStore %float_var %float_1",
@ -3939,40 +4281,40 @@ INSTANTIATE_TEST_SUITE_P(
Bad_Coordinate,
SpvParserTest_ImageCoordsTest,
::testing::ValuesIn(std::vector<ImageCoordsCase>{
{"%float 2D 0 0 0 1 Unknown",
{"%float 1D 0 0 0 1 Unknown",
"%result = OpImageSampleImplicitLod "
// bad type for coordinate: not a number
"%v4float %sampled_image %float_var",
"bad or unsupported coordinate type for image access: %63 = "
"OpImageSampleImplicitLod %34 %62 %1",
"bad or unsupported coordinate type for image access: %71 = "
"OpImageSampleImplicitLod %42 %70 %1",
{}},
{"%float 1D 0 1 0 1 Unknown", // 1DArray
"%result = OpImageSampleImplicitLod "
// 1 component, but need 2
"%v4float %sampled_image %f1",
"image access required 2 coordinate components, but only 1 provided, "
"in: %63 = OpImageSampleImplicitLod %34 %62 %3",
"in: %71 = OpImageSampleImplicitLod %42 %70 %12",
{}},
{"%float 2D 0 0 0 1 Unknown", // 2D
"%result = OpImageSampleImplicitLod "
// 1 component, but need 2
"%v4float %sampled_image %f1",
"image access required 2 coordinate components, but only 1 provided, "
"in: %63 = OpImageSampleImplicitLod %34 %62 %3",
"in: %71 = OpImageSampleImplicitLod %42 %70 %12",
{}},
{"%float 2D 0 1 0 1 Unknown", // 2DArray
"%result = OpImageSampleImplicitLod "
// 2 component, but need 3
"%v4float %sampled_image %vf12",
"image access required 3 coordinate components, but only 2 provided, "
"in: %63 = OpImageSampleImplicitLod %34 %62 %4",
"in: %71 = OpImageSampleImplicitLod %42 %70 %13",
{}},
{"%float 3D 0 0 0 1 Unknown", // 3D
"%result = OpImageSampleImplicitLod "
// 2 components, but need 3
"%v4float %sampled_image %vf12",
"image access required 3 coordinate components, but only 2 provided, "
"in: %63 = OpImageSampleImplicitLod %34 %62 %4",
"in: %71 = OpImageSampleImplicitLod %42 %70 %13",
{}},
}));