tint/intrinsics: Texture queries now return unsigned integer / vectors

To match the spec.

Also add a bunch of missing texture test cases to
src/tint/ast/builtin_texture_helper_test.cc. Fix all the tests that were
broken because these were not being exercised.

Fixed: tint:1526
Change-Id: I207b51d307bbdc054b595e0e0e0fd3330607e171
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106681
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton
2022-10-26 18:36:44 +00:00
committed by Dawn LUCI CQ
parent 980145bc16
commit 13f089095f
5443 changed files with 116933 additions and 115307 deletions

View File

@@ -5709,7 +5709,7 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
Source{}, builder_.Symbols().Register("textureDimensions"));
ExpressionList dims_args{GetImageExpression(inst)};
if (opcode == SpvOpImageQuerySizeLod) {
dims_args.Push(ToI32(MakeOperand(inst, 1)).expr);
dims_args.Push(MakeOperand(inst, 1).expr);
}
const ast::Expression* dims_call =
create<ast::CallExpression>(Source{}, dims_ident, dims_args);
@@ -5724,18 +5724,29 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
if (ast::IsTextureArray(dims)) {
auto* layers_ident = create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register("textureNumLayers"));
exprs.Push(create<ast::CallExpression>(Source{}, layers_ident,
utils::Vector{GetImageExpression(inst)}));
auto num_layers = create<ast::CallExpression>(
Source{}, layers_ident, utils::Vector{GetImageExpression(inst)});
exprs.Push(num_layers);
}
auto* result_type = parser_impl_.ConvertType(inst.type_id());
auto* unsigned_type = ty_.AsUnsigned(result_type);
TypedExpression expr = {
result_type,
builder_.Construct(Source{}, result_type->Build(builder_), std::move(exprs))};
unsigned_type,
// If `exprs` holds multiple expressions, then these are the calls to
// textureDimensions() and textureNumLayers(), and these need to be placed into a
// vector initializer - otherwise, just emit the single expression to omit an
// unnecessary cast.
(exprs.Length() > 1)
? builder_.Construct(Source{}, unsigned_type->Build(builder_), std::move(exprs))
: exprs[0],
};
expr = ToSignedIfUnsigned(expr);
return EmitConstDefOrWriteToHoistedVar(inst, expr);
}
case SpvOpImageQueryLod:
return Fail() << "WGSL does not support querying the level of detail of "
"an image: "
return Fail() << "WGSL does not support querying the level of detail of an image: "
<< inst.PrettyPrint();
case SpvOpImageQueryLevels:
case SpvOpImageQuerySamples: {
@@ -5746,9 +5757,10 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
const ast::Expression* ast_expr = create<ast::CallExpression>(
Source{}, levels_ident, utils::Vector{GetImageExpression(inst)});
auto* result_type = parser_impl_.ConvertType(inst.type_id());
// The SPIR-V result type must be integer scalar. The WGSL bulitin
// returns i32. If they aren't the same then convert the result.
if (!result_type->Is<I32>()) {
// The SPIR-V result type must be integer scalar.
// The WGSL bulitin returns u32.
// If they aren't the same then convert the result.
if (!result_type->Is<U32>()) {
ast_expr = builder_.Construct(Source{}, result_type->Build(builder_),
utils::Vector{ast_expr});
}

View File

@@ -956,17 +956,15 @@ class FunctionEmitter {
ExpressionList MakeCoordinateOperandsForImageAccess(
const spvtools::opt::Instruction& image_access);
/// Returns the given value as an I32. If it's already an I32 then this
/// return the given value. Otherwise, wrap the value in a TypeInitializer
/// expression.
/// Returns the given value as an i32. If it's already an i32 then simply returns @p value.
/// Otherwise, wrap the value in a TypeInitializer expression.
/// @param value the value to pass through or convert
/// @returns the value as an I32 value.
/// @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 TypeInitializer expression. Returns the value itself if the
/// value otherwise.
/// 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 TypeInitializer expression. Returns the
/// value itself if the value was already signed.
/// @param value the value to pass through or convert
/// @returns the value itself, or converted to signed integral
TypedExpression ToSignedIfUnsigned(TypedExpression value);

View File

@@ -2842,7 +2842,7 @@ INSTANTIATE_TEST_SUITE_P(
"%99 = OpImageQuerySize %v3int %im \n"
"%98 = OpImageRead %v4float %im %vi123\n",
R"(@group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20), textureNumLayers(x_20));)"}
R"(let x_99 : vec3<i32> = vec3<i32>(vec3<u32>(textureDimensions(x_20), textureNumLayers(x_20)));)"}
// 3D array storage image doesn't exist.
// Multisampled array
@@ -2898,7 +2898,7 @@ INSTANTIATE_TEST_SUITE_P(
// 2D array
{"%float 2D 0 1 0 1 Unknown", "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
R"(@group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20, i1), textureNumLayers(x_20));)"},
R"(let x_99 : vec3<i32> = vec3<i32>(vec3<u32>(textureDimensions(x_20, i1), textureNumLayers(x_20)));)"},
// There is no 3D array
@@ -2909,12 +2909,12 @@ INSTANTIATE_TEST_SUITE_P(
// https://github.com/gpuweb/gpuweb/issues/1345
{"%float Cube 0 1 0 1 Unknown", "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
R"(@group(2) @binding(1) var x_20 : texture_cube_array<f32>;)",
R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20, i1).xy, textureNumLayers(x_20));)"},
R"(let x_99 : vec3<i32> = vec3<i32>(vec3<u32>(textureDimensions(x_20, i1).xy, textureNumLayers(x_20)));)"},
// Depth 2D array
{"%float 2D 1 1 0 1 Unknown", "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
R"(@group(2) @binding(1) var x_20 : texture_depth_2d_array;)",
R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20, i1), textureNumLayers(x_20));)"},
R"(let x_99 : vec3<i32> = vec3<i32>(vec3<u32>(textureDimensions(x_20, i1), textureNumLayers(x_20)));)"},
// Depth Cube Array
//
@@ -2923,19 +2923,17 @@ INSTANTIATE_TEST_SUITE_P(
// https://github.com/gpuweb/gpuweb/issues/1345
{"%float Cube 1 1 0 1 Unknown", "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
R"(@group(2) @binding(1) var x_20 : texture_depth_cube_array;)",
R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20, i1).xy, textureNumLayers(x_20));)"}}));
R"(let x_99 : vec3<i32> = vec3<i32>(vec3<u32>(textureDimensions(x_20, i1).xy, textureNumLayers(x_20)));)"}}));
INSTANTIATE_TEST_SUITE_P(
// When the level-of-detail value is given as an unsigned
// integer, we must convert it before using it as an argument
// to textureDimensions.
// textureDimensions accepts both signed and unsigned the level-of-detail values.
ImageQuerySizeLod_NonArrayed_SignedResult_UnsignedLevel,
SpvParserHandleTest_SampledImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
{"%float 1D 0 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %int %im %u1\n",
R"(@group(2) @binding(1) var x_20 : texture_1d<f32>;)",
R"(let x_99 : i32 = i32(textureDimensions(x_20, i32(u1)));)"}}));
R"(let x_99 : i32 = i32(textureDimensions(x_20, u1));)"}}));
INSTANTIATE_TEST_SUITE_P(
// When SPIR-V wants the result type to be unsigned, we have to
@@ -2948,7 +2946,7 @@ INSTANTIATE_TEST_SUITE_P(
{"%float 1D 0 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %uint %im %i1\n",
R"(@group(2) @binding(1) var x_20 : texture_1d<f32>;)",
R"(let x_99 : u32 = u32(textureDimensions(x_20, i1));)"}}));
R"(let x_99 : i32 = i32(textureDimensions(x_20, i1));)"}}));
INSTANTIATE_TEST_SUITE_P(ImageQueryLevels_SignedResult,
SpvParserHandleTest_SampledImageAccessTest,
@@ -2961,47 +2959,47 @@ INSTANTIATE_TEST_SUITE_P(ImageQueryLevels_SignedResult,
// 2D
{"%float 2D 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
R"(let x_99 : i32 = textureNumLevels(x_20);)"},
R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"},
// 2D array
{"%float 2D 0 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
R"(let x_99 : i32 = textureNumLevels(x_20);)"},
R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"},
// 3D
{"%float 3D 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_3d<f32>;)",
R"(let x_99 : i32 = textureNumLevels(x_20);)"},
R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"},
// Cube
{"%float Cube 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_cube<f32>;)",
R"(let x_99 : i32 = textureNumLevels(x_20);)"},
R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"},
// Cube array
{"%float Cube 0 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_cube_array<f32>;)",
R"(let x_99 : i32 = textureNumLevels(x_20);)"},
R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"},
// depth 2d
{"%float 2D 1 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_depth_2d;)",
R"(let x_99 : i32 = textureNumLevels(x_20);)"},
R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"},
// depth 2d array
{"%float 2D 1 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_depth_2d_array;)",
R"(let x_99 : i32 = textureNumLevels(x_20);)"},
R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"},
// depth cube
{"%float Cube 1 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_depth_cube;)",
R"(let x_99 : i32 = textureNumLevels(x_20);)"},
R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"},
// depth cube array
{"%float Cube 1 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_depth_cube_array;)",
R"(let x_99 : i32 = textureNumLevels(x_20);)"}}));
R"(let x_99 : i32 = i32(textureNumLevels(x_20));)"}}));
INSTANTIATE_TEST_SUITE_P(
// Spot check that a type conversion is inserted when SPIR-V asks for
@@ -3011,7 +3009,7 @@ INSTANTIATE_TEST_SUITE_P(
::testing::ValuesIn(std::vector<ImageAccessCase>{
{"%float 2D 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %uint %im\n",
R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
R"(let x_99 : u32 = u32(textureNumLevels(x_20));)"}}));
R"(let x_99 : u32 = textureNumLevels(x_20);)"}}));
INSTANTIATE_TEST_SUITE_P(ImageQuerySamples_SignedResult,
SpvParserHandleTest_SampledImageAccessTest,
@@ -3019,21 +3017,21 @@ INSTANTIATE_TEST_SUITE_P(ImageQuerySamples_SignedResult,
// Multsample 2D
{"%float 2D 0 0 1 1 Unknown", "%99 = OpImageQuerySamples %int %im\n",
R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
R"(let x_99 : i32 = textureNumSamples(x_20);)"} // namespace
R"(let x_99 : i32 = i32(textureNumSamples(x_20));)"}
// Multisample 2D array
// Not in WebGPU
}));
INSTANTIATE_TEST_SUITE_P(
// Translation must inject a type coersion from signed to unsigned.
// Translation must inject a type coersion from unsigned to signed.
ImageQuerySamples_UnsignedResult,
SpvParserHandleTest_SampledImageAccessTest,
::testing::ValuesIn(std::vector<ImageAccessCase>{
// Multsample 2D
// Multisample 2D
{"%float 2D 0 0 1 1 Unknown", "%99 = OpImageQuerySamples %uint %im\n",
R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
R"(let x_99 : u32 = u32(textureNumSamples(x_20));)"}
R"(let x_99 : u32 = textureNumSamples(x_20);)"}
// Multisample 2D array
// Not in WebGPU

View File

@@ -444,6 +444,20 @@ const spirv::I32* TypeManager::I32() {
return state->i32_;
}
const Type* TypeManager::AsUnsigned(const Type* ty) {
return Switch(
ty, //
[&](const spirv::I32*) { return U32(); }, //
[&](const spirv::U32*) { return ty; }, //
[&](const spirv::Vector* vec) {
return Switch(
vec->type, //
[&](const spirv::I32*) { return Vector(U32(), vec->size); }, //
[&](const spirv::U32*) { return ty; } //
);
});
}
const spirv::Pointer* TypeManager::Pointer(const Type* el,
ast::AddressSpace address_space,
ast::Access access) {

View File

@@ -539,6 +539,11 @@ class TypeManager {
const spirv::F32* F32();
/// @return a I32 type. Repeated calls will return the same pointer.
const spirv::I32* I32();
/// @param ty the input type.
/// @returns the equivalent unsigned integer scalar or vector if @p ty is a scalar or vector,
/// otherwise nullptr.
const Type* AsUnsigned(const Type* ty);
/// @param ty the store type
/// @param address_space the pointer address space
/// @param access the declared access mode