spirv-reader: support OpImageQuerySize
Change-Id: I27ad580ae84f18a69b31700f56bbbcf59d3818e6
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/39680
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: David Neto <dneto@google.com>
Auto-Submit: David Neto <dneto@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index e5ede5f..e2e5e41 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -524,6 +524,18 @@
case SpvOpImageRead:
case SpvOpImageWrite:
case SpvOpImageFetch:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+// @param opcode a SPIR-V opcode
+// @returns true if the given instruction is an image query instruction
+bool IsImageQuery(SpvOp opcode) {
+ switch (opcode) {
+ case SpvOpImageQuerySize:
case SpvOpImageQuerySizeLod:
case SpvOpImageQueryLevels:
case SpvOpImageQuerySamples:
@@ -2937,6 +2949,10 @@
return EmitImageAccess(inst);
}
+ if (IsImageQuery(inst.opcode())) {
+ return EmitImageQuery(inst);
+ }
+
switch (inst.opcode()) {
case SpvOpNop:
return true;
@@ -4349,6 +4365,48 @@
return success();
}
+bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
+ const spvtools::opt::Instruction* image = GetImage(inst);
+ if (!image) {
+ return false;
+ }
+ auto* texture_type = GetImageType(*image);
+ if (!texture_type) {
+ return false;
+ }
+
+ const auto opcode = inst.opcode();
+ switch (opcode) {
+ case SpvOpImageQuerySize: {
+ ast::ExpressionList exprs;
+ // Invoke textureDimensions.
+ // If the texture is arrayed, combine with the result from
+ // textureNumLayers.
+ auto* dims_ident = create<ast::IdentifierExpression>(
+ Source{}, builder_.Symbols().Register("textureDimensions"));
+ exprs.push_back(create<ast::CallExpression>(
+ Source{}, dims_ident, ast::ExpressionList{GetImageExpression(inst)}));
+ if (type::IsTextureArray(texture_type->dim())) {
+ auto* layers_ident = create<ast::IdentifierExpression>(
+ Source{}, builder_.Symbols().Register("textureNumLayers"));
+ exprs.push_back(create<ast::CallExpression>(
+ Source{}, layers_ident, ast::ExpressionList{GetImageExpression(inst)}));
+ }
+ auto* result_type = parser_impl_.ConvertType(inst.type_id());
+ TypedExpression expr = {
+ result_type,
+ create<ast::TypeConstructorExpression>(Source{}, result_type, exprs)};
+ return EmitConstDefOrWriteToHoistedVar(inst, expr);
+ }
+ case SpvOpImageQuerySizeLod: // TODO(dneto)
+ case SpvOpImageQueryLevels: // TODO(dneto)
+ case SpvOpImageQuerySamples: // TODO(dneto)
+ default:
+ break;
+ }
+ return Fail() << "unhandled image query: " << inst.PrettyPrint();
+}
+
ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
const spvtools::opt::Instruction& inst) {
if (!parser_impl_.success()) {
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index 5eff0df..fe6ceaf 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -897,6 +897,11 @@
/// @returns an expression
bool EmitImageAccess(const spvtools::opt::Instruction& inst);
+ /// Emits statements to implement a SPIR-V image query.
+ /// @param inst the SPIR-V instruction
+ /// @returns an expression
+ bool EmitImageQuery(const spvtools::opt::Instruction& inst);
+
/// Converts the given texel to match the type required for the storage
/// texture with the given type. This can generate a swizzle to retain
/// only the first few components of the texel vector, and maybe a bitcast
diff --git a/src/reader/spirv/parser_impl_handle_test.cc b/src/reader/spirv/parser_impl_handle_test.cc
index 4a226ac..0a7143e 100644
--- a/src/reader/spirv/parser_impl_handle_test.cc
+++ b/src/reader/spirv/parser_impl_handle_test.cc
@@ -3670,6 +3670,260 @@
}
})"}}));
+INSTANTIATE_TEST_SUITE_P(
+ ImageQuerySize_NonArrayed_SignedResult,
+ // ImageQuerySize requires storage image or multisampled
+ // For storage image, use another instruction to indicate whether it
+ // is readonly or writeonly.
+ SpvParserTest_SampledImageAccessTest,
+ ::testing::ValuesIn(std::vector<ImageAccessCase>{
+ // 1D storage image
+ {"%float 1D 0 0 0 2 Rgba32f",
+ "%99 = OpImageQuerySize %int %im \n"
+ "%98 = OpImageRead %v4float %im %i1\n",
+ R"(Variable{
+ Decorations{
+ GroupDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __access_control_read_only__storage_texture_1d_rgba32float
+ })",
+ R"(VariableDeclStatement{
+ VariableConst{
+ x_99
+ none
+ __i32
+ {
+ TypeConstructor[not set]{
+ __i32
+ Call[not set]{
+ Identifier[not set]{textureDimensions}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ }
+ }
+ }
+ })"},
+ // 2D storage image
+ {"%float 2D 0 0 0 2 Rgba32f",
+ "%99 = OpImageQuerySize %v2int %im \n"
+ "%98 = OpImageRead %v4float %im %vi12\n",
+ R"(Variable{
+ Decorations{
+ GroupDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __access_control_read_only__storage_texture_2d_rgba32float
+ })",
+ R"(VariableDeclStatement{
+ VariableConst{
+ x_99
+ none
+ __vec_2__i32
+ {
+ TypeConstructor[not set]{
+ __vec_2__i32
+ Call[not set]{
+ Identifier[not set]{textureDimensions}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ }
+ }
+ }
+ })"},
+ // 3D storage image
+ {"%float 3D 0 0 0 2 Rgba32f",
+ "%99 = OpImageQuerySize %v3int %im \n"
+ "%98 = OpImageRead %v4float %im %vi123\n",
+ R"(Variable{
+ Decorations{
+ GroupDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __access_control_read_only__storage_texture_3d_rgba32float
+ })",
+ R"(VariableDeclStatement{
+ VariableConst{
+ x_99
+ none
+ __vec_3__i32
+ {
+ TypeConstructor[not set]{
+ __vec_3__i32
+ Call[not set]{
+ Identifier[not set]{textureDimensions}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ }
+ }
+ }
+ })"},
+
+ // Multisampled
+ {"%float 2D 0 0 1 1 Unknown",
+ "%99 = OpImageQuerySize %v2int %im \n"
+ "%98 = OpImageRead %v4float %im %vi12\n",
+ R"(Variable{
+ Decorations{
+ GroupDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __multisampled_texture_2d__f32
+ })",
+ R"(VariableDeclStatement{
+ VariableConst{
+ x_99
+ none
+ __vec_2__i32
+ {
+ TypeConstructor[not set]{
+ __vec_2__i32
+ Call[not set]{
+ Identifier[not set]{textureDimensions}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ }
+ }
+ }
+ })"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+ ImageQuerySize_Arrayed_SignedResult,
+ // ImageQuerySize requires storage image or multisampled
+ // For storage image, use another instruction to indicate whether it
+ // is readonly or writeonly.
+ SpvParserTest_SampledImageAccessTest,
+ ::testing::ValuesIn(std::vector<ImageAccessCase>{
+ // 1D array storage image
+ {"%float 1D 0 1 0 2 Rgba32f",
+ "%99 = OpImageQuerySize %v2int %im \n"
+ "%98 = OpImageRead %v4float %im %vi12\n",
+ R"(Variable{
+ Decorations{
+ GroupDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __access_control_read_only__storage_texture_1d_array_rgba32float
+ })",
+ R"(VariableDeclStatement{
+ VariableConst{
+ x_99
+ none
+ __vec_2__i32
+ {
+ TypeConstructor[not set]{
+ __vec_2__i32
+ Call[not set]{
+ Identifier[not set]{textureDimensions}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ Call[not set]{
+ Identifier[not set]{textureNumLayers}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ }
+ }
+ }
+ })"},
+ // 2D array storage image
+ {"%float 2D 0 1 0 2 Rgba32f",
+ "%99 = OpImageQuerySize %v3int %im \n"
+ "%98 = OpImageRead %v4float %im %vi123\n",
+ R"(Variable{
+ Decorations{
+ GroupDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __access_control_read_only__storage_texture_2d_array_rgba32float
+ })",
+ R"(VariableDeclStatement{
+ VariableConst{
+ x_99
+ none
+ __vec_3__i32
+ {
+ TypeConstructor[not set]{
+ __vec_3__i32
+ Call[not set]{
+ Identifier[not set]{textureDimensions}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ Call[not set]{
+ Identifier[not set]{textureNumLayers}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ }
+ }
+ }
+ })"},
+ // 3D array storage image doesn't exist.
+
+ // Multisampled array
+ {"%float 2D 0 1 1 1 Unknown",
+ "%99 = OpImageQuerySize %v3int %im \n"
+ "%98 = OpImageRead %v4float %im %vi123\n",
+ R"(Variable{
+ Decorations{
+ GroupDecoration{2}
+ BindingDecoration{1}
+ }
+ x_20
+ uniform_constant
+ __multisampled_texture_2d_array__f32
+ })",
+ R"(VariableDeclStatement{
+ VariableConst{
+ x_99
+ none
+ __vec_3__i32
+ {
+ TypeConstructor[not set]{
+ __vec_3__i32
+ Call[not set]{
+ Identifier[not set]{textureDimensions}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ Call[not set]{
+ Identifier[not set]{textureNumLayers}
+ (
+ Identifier[not set]{x_20}
+ )
+ }
+ }
+ }
+ }
+ })"}}));
+
struct ImageCoordsCase {
// SPIR-V image type, excluding result ID and opcode
std::string spirv_image_type_details;