Implement textureNumLayers() SPIR-V reader TODO Bug: tint:140 Bug: tint:437 Change-Id: Id397f5f07a2f18f365dc9c2d588e619cea8f89dc Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/37844 Reviewed-by: dan sinclair <dsinclair@chromium.org> Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/ast/intrinsic.cc b/src/ast/intrinsic.cc index 73f3ab3..3f6f8ac 100644 --- a/src/ast/intrinsic.cc +++ b/src/ast/intrinsic.cc
@@ -21,211 +21,220 @@ /// The emitted name matches the spelling in the WGSL spec. /// including case. switch (i) { + case Intrinsic::kNone: + return out; case Intrinsic::kAbs: out << "abs"; - break; + return out; case Intrinsic::kAcos: out << "acos"; - break; + return out; case Intrinsic::kAll: out << "all"; - break; + return out; case Intrinsic::kAny: out << "any"; - break; + return out; case Intrinsic::kArrayLength: out << "arrayLength"; - break; + return out; case Intrinsic::kAsin: out << "asin"; - break; + return out; case Intrinsic::kAtan: out << "atan"; - break; + return out; case Intrinsic::kAtan2: out << "atan2"; - break; + return out; case Intrinsic::kCeil: out << "ceil"; - break; + return out; case Intrinsic::kClamp: out << "clamp"; - break; + return out; case Intrinsic::kCos: out << "cos"; - break; + return out; case Intrinsic::kCosh: out << "cosh"; - break; + return out; case Intrinsic::kCountOneBits: out << "countOneBits"; - break; + return out; case Intrinsic::kCross: out << "cross"; - break; + return out; case Intrinsic::kDeterminant: out << "determinant"; - break; + return out; case Intrinsic::kDistance: out << "distance"; - break; + return out; case Intrinsic::kDot: out << "dot"; - break; + return out; case Intrinsic::kDpdx: out << "dpdx"; - break; + return out; case Intrinsic::kDpdxCoarse: out << "dpdxCoarse"; - break; + return out; case Intrinsic::kDpdxFine: out << "dpdxFine"; - break; + return out; case Intrinsic::kDpdy: out << "dpdy"; - break; + return out; case Intrinsic::kDpdyCoarse: out << "dpdyCoarse"; - break; + return out; case Intrinsic::kDpdyFine: out << "dpdyFine"; - break; + return out; case Intrinsic::kExp: out << "exp"; - break; + return out; case Intrinsic::kExp2: out << "exp2"; - break; + return out; case Intrinsic::kFaceForward: out << "faceForward"; - break; + return out; case Intrinsic::kFloor: out << "floor"; - break; + return out; case Intrinsic::kFma: out << "fma"; - break; + return out; case Intrinsic::kFract: out << "fract"; - break; + return out; case Intrinsic::kFrexp: out << "frexp"; - break; + return out; case Intrinsic::kFwidth: out << "fwidth"; - break; + return out; case Intrinsic::kFwidthCoarse: out << "fwidthCoarse"; - break; + return out; case Intrinsic::kFwidthFine: out << "fwidthFine"; - break; + return out; case Intrinsic::kInverseSqrt: out << "inverseSqrt"; - break; + return out; case Intrinsic::kIsFinite: out << "isFinite"; - break; + return out; case Intrinsic::kIsInf: out << "isInf"; - break; + return out; case Intrinsic::kIsNan: out << "isNan"; - break; + return out; case Intrinsic::kIsNormal: out << "isNormal"; - break; + return out; case Intrinsic::kLdexp: out << "ldexp"; - break; + return out; case Intrinsic::kLength: out << "length"; - break; + return out; case Intrinsic::kLog: out << "log"; - break; + return out; case Intrinsic::kLog2: out << "log2"; - break; + return out; case Intrinsic::kMax: out << "max"; - break; + return out; case Intrinsic::kMin: out << "min"; - break; + return out; case Intrinsic::kMix: out << "mix"; - break; + return out; case Intrinsic::kModf: out << "modf"; - break; + return out; case Intrinsic::kNormalize: out << "normalize"; - break; + return out; case Intrinsic::kPow: out << "pow"; - break; + return out; case Intrinsic::kReflect: out << "reflect"; - break; + return out; case Intrinsic::kReverseBits: out << "reverseBits"; - break; + return out; case Intrinsic::kRound: out << "round"; - break; + return out; case Intrinsic::kSelect: out << "select"; - break; + return out; case Intrinsic::kSign: out << "sign"; - break; + return out; case Intrinsic::kSin: out << "sin"; - break; + return out; case Intrinsic::kSinh: out << "sinh"; - break; + return out; case Intrinsic::kSmoothStep: out << "smoothStep"; - break; + return out; case Intrinsic::kSqrt: out << "sqrt"; - break; + return out; case Intrinsic::kStep: out << "step"; - break; + return out; case Intrinsic::kTan: out << "tan"; - break; + return out; case Intrinsic::kTanh: out << "tanh"; - break; + return out; + case Intrinsic::kTextureDimensions: + out << "textureDimensions"; + return out; case Intrinsic::kTextureLoad: out << "textureLoad"; - break; + return out; + case Intrinsic::kTextureNumLayers: + out << "textureNumLayers"; + return out; case Intrinsic::kTextureSample: out << "textureSample"; - break; + return out; case Intrinsic::kTextureSampleBias: out << "textureSampleBias"; - break; + return out; case Intrinsic::kTextureSampleCompare: out << "textureSampleCompare"; - break; + return out; case Intrinsic::kTextureSampleGrad: out << "textureSampleGrad"; - break; + return out; case Intrinsic::kTextureSampleLevel: out << "textureSampleLevel"; - break; + return out; + case Intrinsic::kTextureStore: + out << "textureStore"; + return out; case Intrinsic::kTrunc: out << "trunc"; - break; - default: - out << "Unknown"; - break; + return out; } + out << "Unknown"; return out; } @@ -260,7 +269,7 @@ bool IsTextureIntrinsic(Intrinsic i) { return i == Intrinsic::kTextureDimensions || i == Intrinsic::kTextureLoad || - i == Intrinsic::kTextureSample || + i == Intrinsic::kTextureNumLayers || i == Intrinsic::kTextureSample || i == Intrinsic::kTextureSampleLevel || i == Intrinsic::kTextureSampleBias || i == Intrinsic::kTextureSampleCompare || @@ -268,7 +277,8 @@ } bool IsImageQueryIntrinsic(Intrinsic i) { - return i == ast::Intrinsic::kTextureDimensions; + return i == ast::Intrinsic::kTextureDimensions || + i == Intrinsic::kTextureNumLayers; } } // namespace intrinsic
diff --git a/src/ast/intrinsic.h b/src/ast/intrinsic.h index 9de55b1..36eb5ad 100644 --- a/src/ast/intrinsic.h +++ b/src/ast/intrinsic.h
@@ -85,6 +85,7 @@ kTanh, kTextureDimensions, kTextureLoad, + kTextureNumLayers, kTextureSample, kTextureSampleBias, kTextureSampleCompare,
diff --git a/src/ast/intrinsic_texture_helper_test.cc b/src/ast/intrinsic_texture_helper_test.cc index 7d06193..ac3c61a 100644 --- a/src/ast/intrinsic_texture_helper_test.cc +++ b/src/ast/intrinsic_texture_helper_test.cc
@@ -542,6 +542,86 @@ [](Builder* b) { return b->ExprList("texture"); }, }, { + ValidTextureOverload::kNumLayers1dArray, + "textureNumLayers(t : texture_1d_array<T>) -> i32", + TextureKind::kRegular, + type::SamplerKind::kSampler, + type::TextureDimension::k1dArray, + TextureDataType::kF32, + "textureNumLayers", + [](Builder* b) { return b->ExprList("texture"); }, + }, + { + ValidTextureOverload::kNumLayers2dArray, + "textureNumLayers(t : texture_2d_array<T>) -> i32", + TextureKind::kRegular, + type::SamplerKind::kSampler, + type::TextureDimension::k2dArray, + TextureDataType::kF32, + "textureNumLayers", + [](Builder* b) { return b->ExprList("texture"); }, + }, + { + ValidTextureOverload::kNumLayersCubeArray, + "textureNumLayers(t : texture_cube_array<T>) -> i32", + TextureKind::kRegular, + type::SamplerKind::kSampler, + type::TextureDimension::kCubeArray, + TextureDataType::kF32, + "textureNumLayers", + [](Builder* b) { return b->ExprList("texture"); }, + }, + { + ValidTextureOverload::kNumLayersMultisampled_2dArray, + "textureNumLayers(t : texture_multisampled_2d_array<T>) -> i32", + TextureKind::kMultisampled, + type::SamplerKind::kSampler, + type::TextureDimension::k2dArray, + TextureDataType::kF32, + "textureNumLayers", + [](Builder* b) { return b->ExprList("texture"); }, + }, + { + ValidTextureOverload::kNumLayersDepth2dArray, + "textureNumLayers(t : texture_depth_2d_array) -> i32", + TextureKind::kDepth, + type::SamplerKind::kSampler, + type::TextureDimension::k2dArray, + TextureDataType::kF32, + "textureNumLayers", + [](Builder* b) { return b->ExprList("texture"); }, + }, + { + ValidTextureOverload::kNumLayersDepthCubeArray, + "textureNumLayers(t : texture_depth_cube_array) -> i32", + TextureKind::kDepth, + type::SamplerKind::kSampler, + type::TextureDimension::kCubeArray, + TextureDataType::kF32, + "textureNumLayers", + [](Builder* b) { return b->ExprList("texture"); }, + }, + { + ValidTextureOverload::kNumLayersStorageWO1dArray, + "textureNumLayers(t : texture_storage_1d_array<F>) -> i32", + ast::AccessControl::kWriteOnly, + ast::type::ImageFormat::kRgba32Float, + type::TextureDimension::k1dArray, + TextureDataType::kF32, + "textureNumLayers", + [](Builder* b) { return b->ExprList("texture"); }, + }, + { + ValidTextureOverload::kNumLayersStorageWO2dArray, + "textureNumLayers(t : texture_storage_2d_array<F>) -> i32", + ast::AccessControl::kWriteOnly, + ast::type::ImageFormat::kRgba32Float, + type::TextureDimension::k2dArray, + TextureDataType::kF32, + "textureNumLayers", + [](Builder* b) { return b->ExprList("texture"); }, + }, + { ValidTextureOverload::kSample1dF32, "textureSample(t : texture_1d<f32>,\n" " s : sampler,\n"
diff --git a/src/ast/intrinsic_texture_helper_test.h b/src/ast/intrinsic_texture_helper_test.h index fae5a2a..ca0d655 100644 --- a/src/ast/intrinsic_texture_helper_test.h +++ b/src/ast/intrinsic_texture_helper_test.h
@@ -69,6 +69,14 @@ kDimensionsStorageWO2d, kDimensionsStorageWO2dArray, kDimensionsStorageWO3d, + kNumLayers1dArray, + kNumLayers2dArray, + kNumLayersCubeArray, + kNumLayersMultisampled_2dArray, + kNumLayersDepth2dArray, + kNumLayersDepthCubeArray, + kNumLayersStorageWO1dArray, + kNumLayersStorageWO2dArray, kSample1dF32, kSample1dArrayF32, kSample2dF32,
diff --git a/src/type_determiner.cc b/src/type_determiner.cc index 8f3f64b..57ba101 100644 --- a/src/type_determiner.cc +++ b/src/type_determiner.cc
@@ -566,6 +566,9 @@ param.idx.level = param.count++; } break; + case ast::Intrinsic::kTextureNumLayers: + param.idx.texture = param.count++; + break; case ast::Intrinsic::kTextureLoad: param.idx.texture = param.count++; param.idx.coords = param.count++; @@ -669,46 +672,54 @@ // Set the function return type ast::type::Type* return_type = nullptr; - if (ident->intrinsic() == ast::Intrinsic::kTextureDimensions) { - auto* i32 = mod_->create<ast::type::I32>(); - switch (texture->dim()) { - default: - set_error(expr->source(), "invalid texture dimensions"); - break; - case ast::type::TextureDimension::k1d: - case ast::type::TextureDimension::k1dArray: - return_type = i32; - break; - case ast::type::TextureDimension::k2d: - case ast::type::TextureDimension::k2dArray: - return_type = mod_->create<ast::type::Vector>(i32, 2); - break; - case ast::type::TextureDimension::k3d: - case ast::type::TextureDimension::kCube: - case ast::type::TextureDimension::kCubeArray: - return_type = mod_->create<ast::type::Vector>(i32, 3); - break; - } - } else if (ident->intrinsic() == ast::Intrinsic::kTextureStore) { - return_type = mod_->create<ast::type::Void>(); - } else { - if (texture->Is<ast::type::DepthTexture>()) { - return_type = mod_->create<ast::type::F32>(); - } else { - ast::type::Type* type = nullptr; - if (auto* storage = texture->As<ast::type::StorageTexture>()) { - type = storage->type(); - } else if (auto* sampled = texture->As<ast::type::SampledTexture>()) { - type = sampled->type(); - } else if (auto* msampled = - texture->As<ast::type::MultisampledTexture>()) { - type = msampled->type(); - } else { - set_error(expr->source(), - "unknown texture type for texture sampling"); - return false; + switch (ident->intrinsic()) { + case ast::Intrinsic::kTextureDimensions: { + auto* i32 = mod_->create<ast::type::I32>(); + switch (texture->dim()) { + default: + set_error(expr->source(), "invalid texture dimensions"); + break; + case ast::type::TextureDimension::k1d: + case ast::type::TextureDimension::k1dArray: + return_type = i32; + break; + case ast::type::TextureDimension::k2d: + case ast::type::TextureDimension::k2dArray: + return_type = mod_->create<ast::type::Vector>(i32, 2); + break; + case ast::type::TextureDimension::k3d: + case ast::type::TextureDimension::kCube: + case ast::type::TextureDimension::kCubeArray: + return_type = mod_->create<ast::type::Vector>(i32, 3); + break; } - return_type = mod_->create<ast::type::Vector>(type, 4); + break; + } + case ast::Intrinsic::kTextureNumLayers: + return_type = mod_->create<ast::type::I32>(); + break; + case ast::Intrinsic::kTextureStore: + return_type = mod_->create<ast::type::Void>(); + break; + default: { + if (texture->Is<ast::type::DepthTexture>()) { + return_type = mod_->create<ast::type::F32>(); + } else { + ast::type::Type* type = nullptr; + if (auto* storage = texture->As<ast::type::StorageTexture>()) { + type = storage->type(); + } else if (auto* sampled = texture->As<ast::type::SampledTexture>()) { + type = sampled->type(); + } else if (auto* msampled = + texture->As<ast::type::MultisampledTexture>()) { + type = msampled->type(); + } else { + set_error(expr->source(), + "unknown texture type for texture sampling"); + return false; + } + return_type = mod_->create<ast::type::Vector>(type, 4); + } } } expr->func()->set_result_type(return_type); @@ -1021,6 +1032,8 @@ ident->set_intrinsic(ast::Intrinsic::kTanh); } else if (name == "textureDimensions") { ident->set_intrinsic(ast::Intrinsic::kTextureDimensions); + } else if (name == "textureNumLayers") { + ident->set_intrinsic(ast::Intrinsic::kTextureNumLayers); } else if (name == "textureLoad") { ident->set_intrinsic(ast::Intrinsic::kTextureLoad); } else if (name == "textureStore") {
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc index 300cc99..dcd3519 100644 --- a/src/type_determiner_test.cc +++ b/src/type_determiner_test.cc
@@ -1764,6 +1764,7 @@ IntrinsicData{"tanh", ast::Intrinsic::kTanh}, IntrinsicData{"textureDimensions", ast::Intrinsic::kTextureDimensions}, IntrinsicData{"textureLoad", ast::Intrinsic::kTextureLoad}, + IntrinsicData{"textureNumLayers", ast::Intrinsic::kTextureNumLayers}, IntrinsicData{"textureSample", ast::Intrinsic::kTextureSample}, IntrinsicData{"textureSampleBias", ast::Intrinsic::kTextureSampleBias}, IntrinsicData{"textureSampleCompare", @@ -2928,6 +2929,15 @@ case ValidTextureOverload::kDimensionsStorageWO2dArray: case ValidTextureOverload::kDimensionsStorageWO3d: return R"(textureDimensions(texture))"; + case ValidTextureOverload::kNumLayers1dArray: + case ValidTextureOverload::kNumLayers2dArray: + case ValidTextureOverload::kNumLayersCubeArray: + case ValidTextureOverload::kNumLayersMultisampled_2dArray: + case ValidTextureOverload::kNumLayersDepth2dArray: + case ValidTextureOverload::kNumLayersDepthCubeArray: + case ValidTextureOverload::kNumLayersStorageWO1dArray: + case ValidTextureOverload::kNumLayersStorageWO2dArray: + return R"(textureNumLayers(texture))"; case ValidTextureOverload::kDimensions2dLevel: case ValidTextureOverload::kDimensions2dArrayLevel: case ValidTextureOverload::kDimensions3dLevel: @@ -3181,6 +3191,8 @@ ty.vec3<i32>()->type_name()); break; } + } else if (std::string(param.function) == "textureNumLayers") { + EXPECT_EQ(call->result_type(), ty.i32); } else if (std::string(param.function) == "textureStore") { EXPECT_EQ(call->result_type(), ty.void_); } else {
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc index e1a5737..a750271 100644 --- a/src/writer/hlsl/generator_impl.cc +++ b/src/writer/hlsl/generator_impl.cc
@@ -695,49 +695,99 @@ auto* texture_type = texture->result_type()->UnwrapAll()->As<ast::type::Texture>(); - if (ident->intrinsic() == ast::Intrinsic::kTextureDimensions) { - // Declare a variable to hold the texture dimensions - auto dims = generate_name(kTempNamePrefix); - EmitType(pre, expr->result_type(), ""); - pre << " " << dims << ";" << std::endl; + switch (ident->intrinsic()) { + case ast::Intrinsic::kTextureDimensions: + case ast::Intrinsic::kTextureNumLayers: { + // Declare a variable to hold the queried texture info + auto dims = generate_name(kTempNamePrefix); - // Now call GetDimensions() on the texture object, populating the dims - // variable. - std::stringstream tex_out; - if (!EmitExpression(pre, tex_out, texture)) { - return false; - } - pre << tex_out.str() << ".GetDimensions("; - if (pidx.level != kNotUsed) { - pre << pidx.level << ", "; - } - switch (texture_type->dim()) { - case ast::type::TextureDimension::kNone: - error_ = "texture dimension is kNone"; + std::stringstream texture_name; + if (!EmitExpression(pre, texture_name, texture)) { return false; - case ast::type::TextureDimension::k1d: - case ast::type::TextureDimension::k1dArray: - pre << dims << ");"; - break; - case ast::type::TextureDimension::k2d: - case ast::type::TextureDimension::k2dArray: - pre << dims << "[0], " << dims << "[1]);"; - break; - case ast::type::TextureDimension::k3d: - pre << dims << "[0], " << dims << "[1], " << dims << "[2]);"; - break; - case ast::type::TextureDimension::kCube: - case ast::type::TextureDimension::kCubeArray: - // width == height == depth for cubes - // See https://github.com/gpuweb/gpuweb/issues/1345 - pre << dims << "[0], " << dims << "[1]);\n"; - pre << dims << "[2] = " << dims << "[1];"; // dims[2] = dims[1] - break; - } + } - // The result of the textureDimensions() call is now the temporary variable. - out << dims; - return true; + auto get_dimensions = [&](std::initializer_list<const char*>&& suffixes) { + pre << texture_name.str() << ".GetDimensions("; + if (pidx.level != kNotUsed) { + pre << pidx.level << ", "; + } + bool first = true; + for (auto* suffix : suffixes) { + if (!first) { + pre << ", "; + } + first = false; + pre << dims << suffix; + } + pre << ");"; + }; + + const char* dims_swizzle = ""; + const char* num_els_swizzle = ""; + + std::stringstream ss; + switch (texture_type->dim()) { + case ast::type::TextureDimension::kNone: + error_ = "texture dimension is kNone"; + return false; + case ast::type::TextureDimension::k1d: + pre << "int " << dims << ";\n"; + get_dimensions({""}); + break; + case ast::type::TextureDimension::k1dArray: + pre << "int2 " << dims << ";\n"; + get_dimensions({".x", ".y"}); + dims_swizzle = ".x"; + num_els_swizzle = ".y"; + break; + case ast::type::TextureDimension::k2d: + pre << "int2 " << dims << ";\n"; + get_dimensions({".x", ".y"}); + break; + case ast::type::TextureDimension::k2dArray: + pre << "int3 " << dims << ";\n"; + get_dimensions({".x", ".y", ".z"}); + dims_swizzle = ".xy"; + num_els_swizzle = ".z"; + break; + case ast::type::TextureDimension::k3d: + pre << "int3 " << dims << ";\n"; + get_dimensions({".x", ".y", ".z"}); + break; + case ast::type::TextureDimension::kCube: + // width == height == depth for cubes + // See https://github.com/gpuweb/gpuweb/issues/1345 + pre << "int2 " << dims << ";\n"; + get_dimensions({".x", ".y"}); + dims_swizzle = ".xyy"; // [width, height, height] + break; + case ast::type::TextureDimension::kCubeArray: + // width == height == depth for cubes + // See https://github.com/gpuweb/gpuweb/issues/1345 + pre << "int3 " << dims << ";\n"; + get_dimensions({".x", ".y", ".z"}); + dims_swizzle = ".xyy"; // [width, height, height] + num_els_swizzle = ".z"; + break; + } + + // The result of the textureDimensions() call is now in temporary + // variable. This may be packed with other data, so the final expression + // may require a swizzle. + switch (ident->intrinsic()) { + case ast::Intrinsic::kTextureDimensions: + out << dims << dims_swizzle; + return true; + case ast::Intrinsic::kTextureNumLayers: + out << dims << num_els_swizzle; + return true; + default: + error_ = "Unhandled intrinsic"; + return false; + } + } + default: + break; } if (!EmitExpression(pre, out, texture))
diff --git a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc index e5b5ee2..972283c 100644 --- a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc +++ b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
@@ -41,75 +41,121 @@ using ValidTextureOverload = ast::intrinsic::test::ValidTextureOverload; switch (overload) { case ValidTextureOverload::kDimensions1d: - case ValidTextureOverload::kDimensions1dArray: case ValidTextureOverload::kDimensionsStorageRO1d: - case ValidTextureOverload::kDimensionsStorageRO1dArray: case ValidTextureOverload::kDimensionsStorageWO1d: - case ValidTextureOverload::kDimensionsStorageWO1dArray: return { "int _tint_tmp;\n" "texture_tint_0.GetDimensions(_tint_tmp);", "_tint_tmp", }; - case ValidTextureOverload::kDimensions2d: - case ValidTextureOverload::kDimensions2dArray: - case ValidTextureOverload::kDimensionsMultisampled_2d: - case ValidTextureOverload::kDimensionsMultisampled_2dArray: - case ValidTextureOverload::kDimensionsDepth2d: - case ValidTextureOverload::kDimensionsDepth2dArray: - case ValidTextureOverload::kDimensionsStorageRO2d: - case ValidTextureOverload::kDimensionsStorageRO2dArray: - case ValidTextureOverload::kDimensionsStorageWO2d: - case ValidTextureOverload::kDimensionsStorageWO2dArray: + case ValidTextureOverload::kDimensions1dArray: + case ValidTextureOverload::kDimensionsStorageRO1dArray: + case ValidTextureOverload::kDimensionsStorageWO1dArray: return { "int2 _tint_tmp;\n" - "texture_tint_0.GetDimensions(_tint_tmp[0], _tint_tmp[1]);", + "texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);", + "_tint_tmp.x", + }; + case ValidTextureOverload::kDimensions2d: + case ValidTextureOverload::kDimensionsMultisampled_2d: + case ValidTextureOverload::kDimensionsDepth2d: + case ValidTextureOverload::kDimensionsStorageRO2d: + case ValidTextureOverload::kDimensionsStorageWO2d: + return { + "int2 _tint_tmp;\n" + "texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);", "_tint_tmp", }; + case ValidTextureOverload::kDimensions2dArray: + case ValidTextureOverload::kDimensionsMultisampled_2dArray: + case ValidTextureOverload::kDimensionsDepth2dArray: + case ValidTextureOverload::kDimensionsStorageRO2dArray: + case ValidTextureOverload::kDimensionsStorageWO2dArray: + return { + "int3 _tint_tmp;\n" + "texture_tint_0." + "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);", + "_tint_tmp.xy", + }; case ValidTextureOverload::kDimensions3d: case ValidTextureOverload::kDimensionsStorageRO3d: case ValidTextureOverload::kDimensionsStorageWO3d: return { "int3 _tint_tmp;\n" - "texture_tint_0.GetDimensions(_tint_tmp[0], _tint_tmp[1], " - "_tint_tmp[2]);", + "texture_tint_0." + "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);", "_tint_tmp", }; case ValidTextureOverload::kDimensionsCube: - case ValidTextureOverload::kDimensionsCubeArray: case ValidTextureOverload::kDimensionsDepthCube: + return { + "int2 _tint_tmp;\n" + "texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);", + "_tint_tmp.xyy", + }; + case ValidTextureOverload::kDimensionsCubeArray: case ValidTextureOverload::kDimensionsDepthCubeArray: return { "int3 _tint_tmp;\n" - "texture_tint_0.GetDimensions(_tint_tmp[0], _tint_tmp[1]);\n" - "_tint_tmp[2] = _tint_tmp[1];", - "_tint_tmp", + "texture_tint_0." + "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);", + "_tint_tmp.xyy", }; case ValidTextureOverload::kDimensions2dLevel: - case ValidTextureOverload::kDimensions2dArrayLevel: case ValidTextureOverload::kDimensionsDepth2dLevel: - case ValidTextureOverload::kDimensionsDepth2dArrayLevel: return { "int2 _tint_tmp;\n" - "texture_tint_0.GetDimensions(1, _tint_tmp[0], _tint_tmp[1]);", + "texture_tint_0.GetDimensions(1, _tint_tmp.x, _tint_tmp.y);", "_tint_tmp", }; + case ValidTextureOverload::kDimensions2dArrayLevel: + case ValidTextureOverload::kDimensionsDepth2dArrayLevel: + return { + "int3 _tint_tmp;\n" + "texture_tint_0." + "GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);", + "_tint_tmp.xy", + }; case ValidTextureOverload::kDimensions3dLevel: return { "int3 _tint_tmp;\n" - "texture_tint_0.GetDimensions(1, _tint_tmp[0], _tint_tmp[1], " - "_tint_tmp[2]);", + "texture_tint_0." + "GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);", "_tint_tmp", }; case ValidTextureOverload::kDimensionsCubeLevel: - case ValidTextureOverload::kDimensionsCubeArrayLevel: case ValidTextureOverload::kDimensionsDepthCubeLevel: + return { + "int2 _tint_tmp;\n" + "texture_tint_0.GetDimensions(1, _tint_tmp.x, _tint_tmp.y);", + "_tint_tmp.xyy", + }; + case ValidTextureOverload::kDimensionsCubeArrayLevel: case ValidTextureOverload::kDimensionsDepthCubeArrayLevel: return { "int3 _tint_tmp;\n" - "texture_tint_0.GetDimensions(1, _tint_tmp[0], _tint_tmp[1]);\n" - "_tint_tmp[2] = _tint_tmp[1];", - "_tint_tmp", + "texture_tint_0." + "GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);", + "_tint_tmp.xyy", + }; + case ValidTextureOverload::kNumLayers1dArray: + case ValidTextureOverload::kNumLayersStorageWO1dArray: + return { + "int2 _tint_tmp;\n" + "texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);", + "_tint_tmp.y", + }; + case ValidTextureOverload::kNumLayers2dArray: + case ValidTextureOverload::kNumLayersMultisampled_2dArray: + case ValidTextureOverload::kNumLayersDepth2dArray: + case ValidTextureOverload::kNumLayersCubeArray: + case ValidTextureOverload::kNumLayersDepthCubeArray: + case ValidTextureOverload::kNumLayersStorageWO2dArray: + return { + "int3 _tint_tmp;\n" + "texture_tint_0." + "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);", + "_tint_tmp.z", }; case ValidTextureOverload::kSample1dF32: return R"(texture_tint_0.Sample(sampler_tint_0, 1.0f))";
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc index 7efe837..30c1887 100644 --- a/src/writer/msl/generator_impl.cc +++ b/src/writer/msl/generator_impl.cc
@@ -616,57 +616,71 @@ ->UnwrapAll() ->As<ast::type::Texture>(); - if (ident->intrinsic() == ast::Intrinsic::kTextureDimensions) { - std::vector<const char*> dims; - switch (texture_type->dim()) { - case ast::type::TextureDimension::kNone: - error_ = "texture dimension is kNone"; - return false; - case ast::type::TextureDimension::k1d: - case ast::type::TextureDimension::k1dArray: - dims = {"width"}; - break; - case ast::type::TextureDimension::k2d: - case ast::type::TextureDimension::k2dArray: - dims = {"width", "height"}; - break; - case ast::type::TextureDimension::k3d: - dims = {"width", "height", "depth"}; - break; - case ast::type::TextureDimension::kCube: - case ast::type::TextureDimension::kCubeArray: - // width == height == depth for cubes - // See https://github.com/gpuweb/gpuweb/issues/1345 - dims = {"width", "height", "height"}; - break; - } + switch (ident->intrinsic()) { + case ast::Intrinsic::kTextureDimensions: { + std::vector<const char*> dims; + switch (texture_type->dim()) { + case ast::type::TextureDimension::kNone: + error_ = "texture dimension is kNone"; + return false; + case ast::type::TextureDimension::k1d: + case ast::type::TextureDimension::k1dArray: + dims = {"width"}; + break; + case ast::type::TextureDimension::k2d: + case ast::type::TextureDimension::k2dArray: + dims = {"width", "height"}; + break; + case ast::type::TextureDimension::k3d: + dims = {"width", "height", "depth"}; + break; + case ast::type::TextureDimension::kCube: + case ast::type::TextureDimension::kCubeArray: + // width == height == depth for cubes + // See https://github.com/gpuweb/gpuweb/issues/1345 + dims = {"width", "height", "height"}; + break; + } - auto get_dim = [&](const char* name) { + auto get_dim = [&](const char* name) { + if (!EmitExpression(params[pidx.texture])) { + return false; + } + out_ << ".get_" << name << "("; + if (pidx.level != kNotUsed) { + out_ << pidx.level; + } + out_ << ")"; + return true; + }; + + if (dims.size() == 1) { + out_ << "int("; + get_dim(dims[0]); + out_ << ")"; + } else { + EmitType(expr->result_type(), ""); + out_ << "("; + for (size_t i = 0; i < dims.size(); i++) { + if (i > 0) { + out_ << ", "; + } + get_dim(dims[i]); + } + out_ << ")"; + } + return true; + } + case ast::Intrinsic::kTextureNumLayers: { + out_ << "int("; if (!EmitExpression(params[pidx.texture])) { return false; } - out_ << ".get_" << name << "("; - if (pidx.level != kNotUsed) { - out_ << pidx.level; - } - out_ << ")"; + out_ << ".get_array_size())"; return true; - }; - - if (dims.size() == 1) { - get_dim(dims[0]); - } else { - EmitType(expr->result_type(), ""); - out_ << "("; - for (size_t i = 0; i < dims.size(); i++) { - if (i > 0) { - out_ << ", "; - } - get_dim(dims[i]); - } - out_ << ")"; } - return true; + default: + break; } if (!EmitExpression(params[pidx.texture]))
diff --git a/src/writer/msl/generator_impl_intrinsic_texture_test.cc b/src/writer/msl/generator_impl_intrinsic_texture_test.cc index 3955bed..67bbdc7 100644 --- a/src/writer/msl/generator_impl_intrinsic_texture_test.cc +++ b/src/writer/msl/generator_impl_intrinsic_texture_test.cc
@@ -38,7 +38,7 @@ case ValidTextureOverload::kDimensionsStorageRO1dArray: case ValidTextureOverload::kDimensionsStorageWO1d: case ValidTextureOverload::kDimensionsStorageWO1dArray: - return R"(texture_tint_0.get_width())"; + return R"(int(texture_tint_0.get_width()))"; case ValidTextureOverload::kDimensions2d: case ValidTextureOverload::kDimensions2dArray: case ValidTextureOverload::kDimensionsMultisampled_2d: @@ -71,6 +71,15 @@ case ValidTextureOverload::kDimensionsDepthCubeLevel: case ValidTextureOverload::kDimensionsDepthCubeArrayLevel: return R"(int3(texture_tint_0.get_width(1), texture_tint_0.get_height(1), texture_tint_0.get_height(1)))"; + case ValidTextureOverload::kNumLayers1dArray: + case ValidTextureOverload::kNumLayers2dArray: + case ValidTextureOverload::kNumLayersCubeArray: + case ValidTextureOverload::kNumLayersMultisampled_2dArray: + case ValidTextureOverload::kNumLayersDepth2dArray: + case ValidTextureOverload::kNumLayersDepthCubeArray: + case ValidTextureOverload::kNumLayersStorageWO1dArray: + case ValidTextureOverload::kNumLayersStorageWO2dArray: + return R"(int(texture_tint_0.get_array_size()))"; case ValidTextureOverload::kSample1dF32: return R"(texture_tint_0.sample(sampler_tint_0, 1.0f))"; case ValidTextureOverload::kSample1dArrayF32:
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index 0bc1565..8887d63 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc
@@ -2073,6 +2073,49 @@ return true; }; + // Appends a result type and id to `spirv_params`, by first swizzling the + // result of the op with `swizzle`. + auto append_result_type_and_id_to_spirv_params_swizzled = + [&](uint32_t spirv_result_width, std::vector<uint32_t> swizzle) { + if (swizzle.empty()) { + append_result_type_and_id_to_spirv_params(); + } else { + // Assign post_emission to swizzle the result of the call to + // OpImageQuerySize[Lod]. + auto* element_type = ElementTypeOf(call->result_type()); + auto spirv_result = result_op(); + auto* spirv_result_type = + mod_->create<ast::type::Vector>(element_type, spirv_result_width); + if (swizzle.size() > 1) { + post_emission = [=] { + OperandList operands{ + result_type, + result_id, + spirv_result, + spirv_result, + }; + for (auto idx : swizzle) { + operands.emplace_back(Operand::Int(idx)); + } + return push_function_inst(spv::Op::OpVectorShuffle, operands); + }; + } else { + post_emission = [=] { + return push_function_inst(spv::Op::OpCompositeExtract, + {result_type, result_id, spirv_result, + Operand::Int(swizzle[0])}); + }; + } + auto spirv_result_type_id = GenerateTypeIfNeeded(spirv_result_type); + if (spirv_result_type_id == 0) { + return false; + } + spirv_params.emplace_back(Operand::Int(spirv_result_type_id)); + spirv_params.emplace_back(spirv_result); + } + return true; + }; + auto append_coords_to_spirv_params = [&]() -> bool { if (pidx.array_index != kNotUsed) { // Array index needs to be appended to the coordinates. @@ -2147,41 +2190,9 @@ break; } - if (swizzle.empty()) { - append_result_type_and_id_to_spirv_params(); - } else { - // Assign post_emission to swizzle the result of the call to - // OpImageQuerySize[Lod]. - auto* element_type = ElementTypeOf(call->result_type()); - auto spirv_result = result_op(); - auto* spirv_result_type = - mod_->create<ast::type::Vector>(element_type, spirv_dims); - if (swizzle.size() > 1) { - post_emission = [=] { - OperandList operands{ - result_type, - result_id, - spirv_result, - spirv_result, - }; - for (auto idx : swizzle) { - operands.emplace_back(Operand::Int(idx)); - } - return push_function_inst(spv::Op::OpVectorShuffle, operands); - }; - } else { - post_emission = [=] { - return push_function_inst(spv::Op::OpCompositeExtract, - {result_type, result_id, spirv_result, - Operand::Int(swizzle[0])}); - }; - } - auto spirv_result_type_id = GenerateTypeIfNeeded(spirv_result_type); - if (spirv_result_type_id == 0) { - return false; - } - spirv_params.emplace_back(Operand::Int(spirv_result_type_id)); - spirv_params.emplace_back(spirv_result); + if (!append_result_type_and_id_to_spirv_params_swizzled(spirv_dims, + swizzle)) { + return false; } spirv_params.emplace_back(gen_param(pidx.texture)); @@ -2199,6 +2210,41 @@ } break; } + case ast::Intrinsic::kTextureNumLayers: { + uint32_t spirv_dims = 0; + switch (texture_type->dim()) { + default: + error_ = "texture is not arrayed"; + return false; + case ast::type::TextureDimension::k1dArray: + spirv_dims = 2; + break; + case ast::type::TextureDimension::k2dArray: + case ast::type::TextureDimension::kCubeArray: + spirv_dims = 3; + break; + } + + // OpImageQuerySize[Lod] packs the array count as the last element of the + // returned vector. Extract this. + if (!append_result_type_and_id_to_spirv_params_swizzled( + spirv_dims, {spirv_dims - 1})) { + return false; + } + + spirv_params.emplace_back(gen_param(pidx.texture)); + + if (texture_type->Is<ast::type::MultisampledTexture>() || + texture_type->Is<ast::type::StorageTexture>()) { + op = spv::Op::OpImageQuerySize; + } else { + ast::SintLiteral i32_0(Source{}, mod_->create<ast::type::I32>(), 0); + op = spv::Op::OpImageQuerySizeLod; + spirv_params.emplace_back( + Operand::Int(GenerateLiteralIfNeeded(nullptr, &i32_0))); + } + break; + } case ast::Intrinsic::kTextureLoad: { op = texture_type->Is<ast::type::StorageTexture>() ? spv::Op::OpImageRead
diff --git a/src/writer/spirv/builder_intrinsic_texture_test.cc b/src/writer/spirv/builder_intrinsic_texture_test.cc index c65fb96..abb588f 100644 --- a/src/writer/spirv/builder_intrinsic_texture_test.cc +++ b/src/writer/spirv/builder_intrinsic_texture_test.cc
@@ -740,6 +740,176 @@ R"( OpCapability ImageQuery )"}; + + case ValidTextureOverload::kNumLayers1dArray: + return {R"( +%4 = OpTypeFloat 32 +%3 = OpTypeImage %4 1D 0 1 0 1 Unknown +%2 = OpTypePointer UniformConstant %3 +%1 = OpVariable %2 UniformConstant +%7 = OpTypeSampler +%6 = OpTypePointer UniformConstant %7 +%5 = OpVariable %6 UniformConstant +%9 = OpTypeInt 32 1 +%11 = OpTypeVector %9 2 +%13 = OpConstant %9 0 +)", + R"( +%12 = OpLoad %3 %1 +%10 = OpImageQuerySizeLod %11 %12 %13 +%8 = OpCompositeExtract %9 %10 1 +)", + R"( +OpCapability Sampled1D +OpCapability ImageQuery +)"}; + case ValidTextureOverload::kNumLayers2dArray: + return {R"( +%4 = OpTypeFloat 32 +%3 = OpTypeImage %4 2D 0 1 0 1 Unknown +%2 = OpTypePointer UniformConstant %3 +%1 = OpVariable %2 UniformConstant +%7 = OpTypeSampler +%6 = OpTypePointer UniformConstant %7 +%5 = OpVariable %6 UniformConstant +%9 = OpTypeInt 32 1 +%11 = OpTypeVector %9 3 +%13 = OpConstant %9 0 +)", + R"( +%12 = OpLoad %3 %1 +%10 = OpImageQuerySizeLod %11 %12 %13 +%8 = OpCompositeExtract %9 %10 2 +)", + R"( +OpCapability ImageQuery +)"}; + case ValidTextureOverload::kNumLayersCubeArray: + return {R"( +%4 = OpTypeFloat 32 +%3 = OpTypeImage %4 Cube 0 1 0 1 Unknown +%2 = OpTypePointer UniformConstant %3 +%1 = OpVariable %2 UniformConstant +%7 = OpTypeSampler +%6 = OpTypePointer UniformConstant %7 +%5 = OpVariable %6 UniformConstant +%9 = OpTypeInt 32 1 +%11 = OpTypeVector %9 3 +%13 = OpConstant %9 0 +)", + R"( +%12 = OpLoad %3 %1 +%10 = OpImageQuerySizeLod %11 %12 %13 +%8 = OpCompositeExtract %9 %10 2 +)", + R"( +OpCapability SampledCubeArray +OpCapability ImageQuery +)"}; + case ValidTextureOverload::kNumLayersMultisampled_2dArray: + return {R"( +%4 = OpTypeFloat 32 +%3 = OpTypeImage %4 2D 0 1 1 1 Unknown +%2 = OpTypePointer UniformConstant %3 +%1 = OpVariable %2 UniformConstant +%7 = OpTypeSampler +%6 = OpTypePointer UniformConstant %7 +%5 = OpVariable %6 UniformConstant +%9 = OpTypeInt 32 1 +%11 = OpTypeVector %9 3 +)", + R"( +%12 = OpLoad %3 %1 +%10 = OpImageQuerySize %11 %12 +%8 = OpCompositeExtract %9 %10 2 +)", + R"( +OpCapability ImageQuery +)"}; + case ValidTextureOverload::kNumLayersDepth2dArray: + return {R"( +%4 = OpTypeFloat 32 +%3 = OpTypeImage %4 2D 1 1 0 1 Unknown +%2 = OpTypePointer UniformConstant %3 +%1 = OpVariable %2 UniformConstant +%7 = OpTypeSampler +%6 = OpTypePointer UniformConstant %7 +%5 = OpVariable %6 UniformConstant +%9 = OpTypeInt 32 1 +%11 = OpTypeVector %9 3 +%13 = OpConstant %9 0 +)", + R"( +%12 = OpLoad %3 %1 +%10 = OpImageQuerySizeLod %11 %12 %13 +%8 = OpCompositeExtract %9 %10 2 +)", + R"( +OpCapability ImageQuery +)"}; + case ValidTextureOverload::kNumLayersDepthCubeArray: + return {R"( +%4 = OpTypeFloat 32 +%3 = OpTypeImage %4 Cube 1 1 0 1 Unknown +%2 = OpTypePointer UniformConstant %3 +%1 = OpVariable %2 UniformConstant +%7 = OpTypeSampler +%6 = OpTypePointer UniformConstant %7 +%5 = OpVariable %6 UniformConstant +%9 = OpTypeInt 32 1 +%11 = OpTypeVector %9 3 +%13 = OpConstant %9 0 +)", + R"( +%12 = OpLoad %3 %1 +%10 = OpImageQuerySizeLod %11 %12 %13 +%8 = OpCompositeExtract %9 %10 2 +)", + R"( +OpCapability SampledCubeArray +OpCapability ImageQuery +)"}; + case ValidTextureOverload::kNumLayersStorageWO1dArray: + return {R"( +%4 = OpTypeFloat 32 +%3 = OpTypeImage %4 1D 0 1 0 2 Rgba32f +%2 = OpTypePointer UniformConstant %3 +%1 = OpVariable %2 UniformConstant +%7 = OpTypeSampler +%6 = OpTypePointer UniformConstant %7 +%5 = OpVariable %6 UniformConstant +%9 = OpTypeInt 32 1 +%11 = OpTypeVector %9 2 +)", + R"( +%12 = OpLoad %3 %1 +%10 = OpImageQuerySize %11 %12 +%8 = OpCompositeExtract %9 %10 1 +)", + R"( +OpCapability Image1D +OpCapability ImageQuery +)"}; + case ValidTextureOverload::kNumLayersStorageWO2dArray: + return {R"( +%4 = OpTypeFloat 32 +%3 = OpTypeImage %4 2D 0 1 0 2 Rgba32f +%2 = OpTypePointer UniformConstant %3 +%1 = OpVariable %2 UniformConstant +%7 = OpTypeSampler +%6 = OpTypePointer UniformConstant %7 +%5 = OpVariable %6 UniformConstant +%9 = OpTypeInt 32 1 +%11 = OpTypeVector %9 3 +)", + R"( +%12 = OpLoad %3 %1 +%10 = OpImageQuerySize %11 %12 +%8 = OpCompositeExtract %9 %10 2 +)", + R"( +OpCapability ImageQuery +)"}; case ValidTextureOverload::kSample1dF32: return { R"(