Add support for multisampled textures. This Cl adds the AST, WGSL-Reader and SPIRV-Writer support for the `texture_multisampled_2d` type. Bug: tint:237 Change-Id: Ib3eb831227b49f32162801f1e1b4e474774c78b3 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/28480 Commit-Queue: dan sinclair <dsinclair@chromium.org> Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc5fc11..33cd006 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt
@@ -154,6 +154,8 @@ ast/type/i32_type.h ast/type/matrix_type.cc ast/type/matrix_type.h + ast/type/multisampled_texture_type.cc + ast/type/multisampled_texture_type.h ast/type/pointer_type.cc ast/type/pointer_type.h ast/type/sampled_texture_type.cc @@ -337,6 +339,7 @@ ast/type/f32_type_test.cc ast/type/i32_type_test.cc ast/type/matrix_type_test.cc + ast/type/multisampled_texture_type_test.cc ast/type/pointer_type_test.cc ast/type/sampled_texture_type_test.cc ast/type/sampler_type_test.cc
diff --git a/src/ast/type/multisampled_texture_type.cc b/src/ast/type/multisampled_texture_type.cc new file mode 100644 index 0000000..7bfc885 --- /dev/null +++ b/src/ast/type/multisampled_texture_type.cc
@@ -0,0 +1,47 @@ +// Copyright 2020 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/ast/type/multisampled_texture_type.h" + +#include <cassert> +#include <sstream> + +namespace tint { +namespace ast { +namespace type { + +MultisampledTextureType::MultisampledTextureType(TextureDimension dim, + Type* type) + : TextureType(dim), type_(type) { + assert(type_); +} + +MultisampledTextureType::MultisampledTextureType(MultisampledTextureType&&) = + default; + +MultisampledTextureType::~MultisampledTextureType() = default; + +bool MultisampledTextureType::IsMultisampled() const { + return true; +} + +std::string MultisampledTextureType::type_name() const { + std::ostringstream out; + out << "__multisampled_texture_" << dim() << type_->type_name(); + return out.str(); +} + +} // namespace type +} // namespace ast +} // namespace tint
diff --git a/src/ast/type/multisampled_texture_type.h b/src/ast/type/multisampled_texture_type.h new file mode 100644 index 0000000..ae8f38e --- /dev/null +++ b/src/ast/type/multisampled_texture_type.h
@@ -0,0 +1,54 @@ +// Copyright 2020 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_AST_TYPE_MULTISAMPLED_TEXTURE_TYPE_H_ +#define SRC_AST_TYPE_MULTISAMPLED_TEXTURE_TYPE_H_ + +#include <string> + +#include "src/ast/type/texture_type.h" + +namespace tint { +namespace ast { +namespace type { + +/// A multisampled texture type. +class MultisampledTextureType : public TextureType { + public: + /// Constructor + /// @param dim the dimensionality of the texture + /// @param type the data type of the multisampled texture + MultisampledTextureType(TextureDimension dim, Type* type); + /// Move constructor + MultisampledTextureType(MultisampledTextureType&&); + ~MultisampledTextureType() override; + + /// @returns true if the type is a sampled texture type + bool IsMultisampled() const override; + + /// @returns the subtype of the sampled texture + Type* type() const { return type_; } + + /// @returns the name for this type + std::string type_name() const override; + + private: + Type* type_ = nullptr; +}; + +} // namespace type +} // namespace ast +} // namespace tint + +#endif // SRC_AST_TYPE_MULTISAMPLED_TEXTURE_TYPE_H_
diff --git a/src/ast/type/multisampled_texture_type_test.cc b/src/ast/type/multisampled_texture_type_test.cc new file mode 100644 index 0000000..c50cef9 --- /dev/null +++ b/src/ast/type/multisampled_texture_type_test.cc
@@ -0,0 +1,74 @@ +// Copyright 2020 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/ast/type/multisampled_texture_type.h" + +#include "gtest/gtest.h" +#include "src/ast/type/f32_type.h" + +namespace tint { +namespace ast { +namespace type { +namespace { + +using MultisampledTextureTypeTest = testing::Test; + +TEST_F(MultisampledTextureTypeTest, Is) { + F32Type f32; + MultisampledTextureType s(TextureDimension::kCube, &f32); + EXPECT_FALSE(s.IsAlias()); + EXPECT_FALSE(s.IsArray()); + EXPECT_FALSE(s.IsBool()); + EXPECT_FALSE(s.IsF32()); + EXPECT_FALSE(s.IsI32()); + EXPECT_FALSE(s.IsMatrix()); + EXPECT_FALSE(s.IsPointer()); + EXPECT_FALSE(s.IsSampler()); + EXPECT_FALSE(s.IsStruct()); + EXPECT_TRUE(s.IsTexture()); + EXPECT_FALSE(s.IsU32()); + EXPECT_FALSE(s.IsVector()); +} + +TEST_F(MultisampledTextureTypeTest, IsTextureType) { + F32Type f32; + MultisampledTextureType s(TextureDimension::kCube, &f32); + EXPECT_FALSE(s.IsDepth()); + EXPECT_TRUE(s.IsMultisampled()); + EXPECT_FALSE(s.IsSampled()); + EXPECT_FALSE(s.IsStorage()); +} + +TEST_F(MultisampledTextureTypeTest, Dim) { + F32Type f32; + MultisampledTextureType s(TextureDimension::k3d, &f32); + EXPECT_EQ(s.dim(), TextureDimension::k3d); +} + +TEST_F(MultisampledTextureTypeTest, Type) { + F32Type f32; + MultisampledTextureType s(TextureDimension::k3d, &f32); + EXPECT_EQ(s.type(), &f32); +} + +TEST_F(MultisampledTextureTypeTest, TypeName) { + F32Type f32; + MultisampledTextureType s(TextureDimension::k3d, &f32); + EXPECT_EQ(s.type_name(), "__multisampled_texture_3d__f32"); +} + +} // namespace +} // namespace type +} // namespace ast +} // namespace tint
diff --git a/src/ast/type/texture_type.cc b/src/ast/type/texture_type.cc index 690a514..ab4e54f 100644 --- a/src/ast/type/texture_type.cc +++ b/src/ast/type/texture_type.cc
@@ -17,6 +17,7 @@ #include <cassert> #include "src/ast/type/depth_texture_type.h" +#include "src/ast/type/multisampled_texture_type.h" #include "src/ast/type/sampled_texture_type.h" #include "src/ast/type/storage_texture_type.h" @@ -41,12 +42,6 @@ case TextureDimension::k2dArray: out << "2d_array"; break; - case TextureDimension::k2dMs: - out << "2d_ms"; - break; - case TextureDimension::k2dMsArray: - out << "2d_ms_array"; - break; case TextureDimension::k3d: out << "3d"; break; @@ -73,6 +68,9 @@ bool TextureType::IsDepth() const { return false; } +bool TextureType::IsMultisampled() const { + return false; +} bool TextureType::IsStorage() const { return false; } @@ -85,6 +83,11 @@ return static_cast<const DepthTextureType*>(this); } +const MultisampledTextureType* TextureType::AsMultisampled() const { + assert(IsMultisampled()); + return static_cast<const MultisampledTextureType*>(this); +} + const SampledTextureType* TextureType::AsSampled() const { assert(IsSampled()); return static_cast<const SampledTextureType*>(this); @@ -100,6 +103,11 @@ return static_cast<DepthTextureType*>(this); } +MultisampledTextureType* TextureType::AsMultisampled() { + assert(IsMultisampled()); + return static_cast<MultisampledTextureType*>(this); +} + SampledTextureType* TextureType::AsSampled() { assert(IsSampled()); return static_cast<SampledTextureType*>(this);
diff --git a/src/ast/type/texture_type.h b/src/ast/type/texture_type.h index e0f44fa..14cac19 100644 --- a/src/ast/type/texture_type.h +++ b/src/ast/type/texture_type.h
@@ -25,6 +25,7 @@ namespace type { class DepthTextureType; +class MultisampledTextureType; class SampledTextureType; class StorageTextureType; @@ -40,10 +41,6 @@ k2d, /// 2 dimensional array texture k2dArray, - /// 2 dimensional multi-sampled texture - k2dMs, - /// 2 dimensional multi-sampled array texture - k2dMsArray, /// 3 dimensional texture k3d, /// cube texture @@ -71,6 +68,8 @@ /// @returns true if this is a depth texture virtual bool IsDepth() const; + /// @returns ture if this is a multisampled texture + virtual bool IsMultisampled() const; /// @returns true if this is a storage texture virtual bool IsStorage() const; /// @returns true if this is a sampled texture @@ -78,6 +77,8 @@ /// @returns the texture as a depth texture const DepthTextureType* AsDepth() const; + /// @returns the texture as a multisampled texture + const MultisampledTextureType* AsMultisampled() const; /// @returns the texture as a sampled texture const SampledTextureType* AsSampled() const; /// @returns the texture as a storage texture @@ -85,6 +86,8 @@ /// @returns the texture as a depth texture DepthTextureType* AsDepth(); + /// @returns the texture as a multisampled texture + MultisampledTextureType* AsMultisampled(); /// @returns the texture as a sampled texture SampledTextureType* AsSampled(); /// @returns the texture as a storage texture
diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc index 66a2dc2..37bfeb5 100644 --- a/src/reader/wgsl/lexer.cc +++ b/src/reader/wgsl/lexer.cc
@@ -657,6 +657,10 @@ return {Token::Type::kTextureDepthCubeArray, source, "texture_depth_cube_array"}; } + if (str == "texture_multisampled_2d") { + return {Token::Type::kTextureMultisampled2d, source, + "texture_multisampled_2d"}; + } if (str == "texture_ro_1d") return {Token::Type::kTextureStorageReadonly1d, source, "texture_ro_1d"}; if (str == "texture_ro_1d_array") @@ -681,12 +685,6 @@ return {Token::Type::kTextureSampled2dArray, source, "texture_sampled_2d_array"}; } - if (str == "texture_sampled_2d_ms") - return {Token::Type::kTextureSampled2dMs, source, "texture_sampled_2d_ms"}; - if (str == "texture_sampled_2d_ms_array") { - return {Token::Type::kTextureSampled2dMsArray, source, - "texture_sampled_2d_ms_array"}; - } if (str == "texture_sampled_3d") return {Token::Type::kTextureSampled3d, source, "texture_sampled_3d"}; if (str == "texture_sampled_cube")
diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc index 4806cb6..d21f3b6 100644 --- a/src/reader/wgsl/lexer_test.cc +++ b/src/reader/wgsl/lexer_test.cc
@@ -401,7 +401,7 @@ Lexer l(params.input); auto t = l.next(); - EXPECT_TRUE(t.Is(params.type)); + EXPECT_TRUE(t.Is(params.type)) << params.input; EXPECT_EQ(1u, t.line()); EXPECT_EQ(1u, t.column()); @@ -505,6 +505,8 @@ TokenData{"texture_depth_cube", Token::Type::kTextureDepthCube}, TokenData{"texture_depth_cube_array", Token::Type::kTextureDepthCubeArray}, + TokenData{"texture_multisampled_2d", + Token::Type::kTextureMultisampled2d}, TokenData{"texture_ro_1d", Token::Type::kTextureStorageReadonly1d}, TokenData{"texture_ro_1d_array", Token::Type::kTextureStorageReadonly1dArray}, @@ -518,9 +520,6 @@ TokenData{"texture_sampled_2d", Token::Type::kTextureSampled2d}, TokenData{"texture_sampled_2d_array", Token::Type::kTextureSampled2dArray}, - TokenData{"texture_sampled_2d_ms", Token::Type::kTextureSampled2dMs}, - TokenData{"texture_sampled_2d_ms_array", - Token::Type::kTextureSampled2dMsArray}, TokenData{"texture_sampled_3d", Token::Type::kTextureSampled3d}, TokenData{"texture_sampled_cube", Token::Type::kTextureSampledCube}, TokenData{"texture_sampled_cube_array",
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 82af4cc..a85f7c7 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc
@@ -50,6 +50,7 @@ #include "src/ast/type/f32_type.h" #include "src/ast/type/i32_type.h" #include "src/ast/type/matrix_type.h" +#include "src/ast/type/multisampled_texture_type.h" #include "src/ast/type/pointer_type.h" #include "src/ast/type/sampled_texture_type.h" #include "src/ast/type/sampler_type.h" @@ -582,7 +583,7 @@ // : sampler_type // | depth_texture_type // | sampled_texture_type LESS_THAN type_decl GREATER_THAN -// | TODO: multisampled_texture_type LESS_THAN type_decl GREATER_THAN +// | multisampled_texture_type LESS_THAN type_decl GREATER_THAN // | storage_texture_type LESS_THAN image_storage_type GREATER_THAN ast::type::Type* ParserImpl::texture_sampler_types() { auto* type = sampler_type(); @@ -595,8 +596,8 @@ return type; } - auto sampled_dim = sampled_texture_type(); - if (sampled_dim != ast::type::TextureDimension::kNone) { + auto dim = sampled_texture_type(); + if (dim != ast::type::TextureDimension::kNone) { auto t = next(); if (!t.IsLessThan()) { set_error(peek(), "missing '<' for sampled texture type"); @@ -618,7 +619,33 @@ } return ctx_.type_mgr().Get( - std::make_unique<ast::type::SampledTextureType>(sampled_dim, subtype)); + std::make_unique<ast::type::SampledTextureType>(dim, subtype)); + } + + dim = multisampled_texture_type(); + if (dim != ast::type::TextureDimension::kNone) { + auto t = next(); + if (!t.IsLessThan()) { + set_error(peek(), "missing '<' for multisampled texture type"); + return nullptr; + } + + auto* subtype = type_decl(); + if (has_error()) + return nullptr; + if (subtype == nullptr) { + set_error(peek(), "invalid subtype for multisampled texture type"); + return nullptr; + } + + t = next(); + if (!t.IsGreaterThan()) { + set_error(peek(), "missing '>' for multisampled texture type"); + return nullptr; + } + + return ctx_.type_mgr().Get( + std::make_unique<ast::type::MultisampledTextureType>(dim, subtype)); } ast::type::TextureDimension storage_dim; @@ -675,8 +702,6 @@ // | TEXTURE_SAMPLED_1D_ARRAY // | TEXTURE_SAMPLED_2D // | TEXTURE_SAMPLED_2D_ARRAY -// | TEXTURE_SAMPLED_2D_MS -// | TEXTURE_SAMPLED_2D_MS_ARRAY // | TEXTURE_SAMPLED_3D // | TEXTURE_SAMPLED_CUBE // | TEXTURE_SAMPLED_CUBE_ARRAY @@ -698,14 +723,6 @@ next(); // Consume the peek return ast::type::TextureDimension::k2dArray; } - if (t.IsTextureSampled2dMs()) { - next(); // Consume the peek - return ast::type::TextureDimension::k2dMs; - } - if (t.IsTextureSampled2dMsArray()) { - next(); // Consume the peek - return ast::type::TextureDimension::k2dMsArray; - } if (t.IsTextureSampled3d()) { next(); // Consume the peek return ast::type::TextureDimension::k3d; @@ -721,6 +738,17 @@ return ast::type::TextureDimension::kNone; } +// multisampled_texture_type +// : TEXTURE_MULTISAMPLED_2D +ast::type::TextureDimension ParserImpl::multisampled_texture_type() { + auto t = peek(); + if (t.IsTextureMultisampled2d()) { + next(); // Consume the peek + return ast::type::TextureDimension::k2d; + } + return ast::type::TextureDimension::kNone; +} + // storage_texture_type // : TEXTURE_RO_1D // | TEXTURE_RO_1D_ARRAY
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h index eb35b3d..6da84df 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h
@@ -188,6 +188,10 @@ /// Parses a `sampler_type` grammar element /// @returns the parsed Type or nullptr if none matched. ast::type::Type* sampler_type(); + /// Parses a `multisampled_texture_type` grammar element + /// @returns returns the multisample texture dimension or kNone if none + /// matched. + ast::type::TextureDimension multisampled_texture_type(); /// Parses a `sampled_texture_type` grammar element /// @returns returns the sample texture dimension or kNone if none matched. ast::type::TextureDimension sampled_texture_type();
diff --git a/src/reader/wgsl/parser_impl_sampled_texture_type_test.cc b/src/reader/wgsl/parser_impl_sampled_texture_type_test.cc index da9a461..6e838a2 100644 --- a/src/reader/wgsl/parser_impl_sampled_texture_type_test.cc +++ b/src/reader/wgsl/parser_impl_sampled_texture_type_test.cc
@@ -57,20 +57,6 @@ EXPECT_FALSE(p->has_error()); } -TEST_F(ParserImplTest, SampledTextureType_2dMs) { - auto* p = parser("texture_sampled_2d_ms"); - auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k2dMs); - EXPECT_FALSE(p->has_error()); -} - -TEST_F(ParserImplTest, SampledTextureType_2dMsArray) { - auto* p = parser("texture_sampled_2d_ms_array"); - auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k2dMsArray); - EXPECT_FALSE(p->has_error()); -} - TEST_F(ParserImplTest, SampledTextureType_3d) { auto* p = parser("texture_sampled_3d"); auto t = p->sampled_texture_type();
diff --git a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc index 3174004..649920f 100644 --- a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc +++ b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
@@ -13,6 +13,7 @@ // limitations under the License. #include "gtest/gtest.h" +#include "src/ast/type/multisampled_texture_type.h" #include "src/ast/type/sampled_texture_type.h" #include "src/ast/type/sampler_type.h" #include "src/reader/wgsl/parser_impl.h" @@ -33,67 +34,68 @@ TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) { auto* p = parser("sampler"); auto* t = p->texture_sampler_types(); + ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(t, nullptr); ASSERT_TRUE(t->IsSampler()); ASSERT_FALSE(t->AsSampler()->IsComparison()); - EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) { auto* p = parser("sampler_comparison"); auto* t = p->texture_sampler_types(); + ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(t, nullptr); ASSERT_TRUE(t->IsSampler()); ASSERT_TRUE(t->AsSampler()->IsComparison()); - EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) { auto* p = parser("texture_depth_2d"); auto* t = p->texture_sampler_types(); + ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(t, nullptr); ASSERT_TRUE(t->IsTexture()); ASSERT_TRUE(t->AsTexture()->IsDepth()); EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); - EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) { auto* p = parser("texture_sampled_1d<f32>"); auto* t = p->texture_sampler_types(); + ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(t, nullptr); ASSERT_TRUE(t->IsTexture()); ASSERT_TRUE(t->AsTexture()->IsSampled()); ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32()); EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); - EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) { auto* p = parser("texture_sampled_2d<i32>"); auto* t = p->texture_sampler_types(); + ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(t, nullptr); ASSERT_TRUE(t->IsTexture()); ASSERT_TRUE(t->AsTexture()->IsSampled()); ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsI32()); EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); - EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) { auto* p = parser("texture_sampled_3d<u32>"); auto* t = p->texture_sampler_types(); + ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(t, nullptr); ASSERT_TRUE(t->IsTexture()); ASSERT_TRUE(t->AsTexture()->IsSampled()); ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsU32()); EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k3d); - EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid) { auto* p = parser("texture_sampled_1d<abc>"); auto* t = p->texture_sampler_types(); + ASSERT_TRUE(p->has_error()); EXPECT_EQ(t, nullptr); EXPECT_EQ(p->error(), "1:20: unknown type alias 'abc'"); } @@ -101,6 +103,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) { auto* p = parser("texture_sampled_1d<>"); auto* t = p->texture_sampler_types(); + ASSERT_TRUE(p->has_error()); EXPECT_EQ(t, nullptr); EXPECT_EQ(p->error(), "1:20: invalid subtype for sampled texture type"); } @@ -108,6 +111,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan) { auto* p = parser("texture_sampled_1d"); auto* t = p->texture_sampler_types(); + ASSERT_TRUE(p->has_error()); EXPECT_EQ(t, nullptr); EXPECT_EQ(p->error(), "1:19: missing '<' for sampled texture type"); } @@ -115,13 +119,58 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan) { auto* p = parser("texture_sampled_1d<u32"); auto* t = p->texture_sampler_types(); + ASSERT_TRUE(p->has_error()); EXPECT_EQ(t, nullptr); EXPECT_EQ(p->error(), "1:23: missing '>' for sampled texture type"); } +TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) { + auto* p = parser("texture_multisampled_2d<i32>"); + auto* t = p->texture_sampler_types(); + ASSERT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(t, nullptr); + ASSERT_TRUE(t->IsTexture()); + ASSERT_TRUE(t->AsTexture()->IsMultisampled()); + ASSERT_TRUE(t->AsTexture()->AsMultisampled()->type()->IsI32()); + EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); +} + +TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_Invalid) { + auto* p = parser("texture_multisampled_2d<abc>"); + auto* t = p->texture_sampler_types(); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(t, nullptr); + EXPECT_EQ(p->error(), "1:25: unknown type alias 'abc'"); +} + +TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) { + auto* p = parser("texture_multisampled_2d<>"); + auto* t = p->texture_sampler_types(); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(t, nullptr); + EXPECT_EQ(p->error(), "1:25: invalid subtype for multisampled texture type"); +} + +TEST_F(ParserImplTest, + TextureSamplerTypes_MultisampledTexture_MissingLessThan) { + auto* p = parser("texture_multisampled_2d"); + auto* t = p->texture_sampler_types(); + EXPECT_EQ(t, nullptr); + EXPECT_EQ(p->error(), "1:24: missing '<' for multisampled texture type"); +} + +TEST_F(ParserImplTest, + TextureSamplerTypes_MultisampledTexture_MissingGreaterThan) { + auto* p = parser("texture_multisampled_2d<u32"); + auto* t = p->texture_sampler_types(); + EXPECT_EQ(t, nullptr); + EXPECT_EQ(p->error(), "1:28: missing '>' for multisampled texture type"); +} + TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm) { auto* p = parser("texture_ro_1d<r8unorm>"); auto* t = p->texture_sampler_types(); + ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(t, nullptr); ASSERT_TRUE(t->IsTexture()); ASSERT_TRUE(t->AsTexture()->IsStorage()); @@ -130,12 +179,12 @@ EXPECT_EQ(t->AsTexture()->AsStorage()->access(), ast::type::StorageAccess::kRead); EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); - EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float) { auto* p = parser("texture_wo_2d<r16float>"); auto* t = p->texture_sampler_types(); + ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(t, nullptr); ASSERT_TRUE(t->IsTexture()); ASSERT_TRUE(t->AsTexture()->IsStorage()); @@ -144,7 +193,6 @@ EXPECT_EQ(t->AsTexture()->AsStorage()->access(), ast::type::StorageAccess::kWrite); EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); - EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
diff --git a/src/reader/wgsl/token.cc b/src/reader/wgsl/token.cc index 58d60f4..dd1ad3e 100644 --- a/src/reader/wgsl/token.cc +++ b/src/reader/wgsl/token.cc
@@ -289,6 +289,8 @@ return "texture_depth_cube"; case Token::Type::kTextureDepthCubeArray: return "texture_depth_cube_array"; + case Token::Type::kTextureMultisampled2d: + return "texture_multisampled_2d"; case Token::Type::kTextureStorageReadonly1d: return "texture_ro_1d"; case Token::Type::kTextureStorageReadonly1dArray: @@ -307,10 +309,6 @@ return "texture_sampled_2d"; case Token::Type::kTextureSampled2dArray: return "texture_sampled_2d_array"; - case Token::Type::kTextureSampled2dMs: - return "texture_sampled_2d_ms"; - case Token::Type::kTextureSampled2dMsArray: - return "texture_sampled_2d_ms_array"; case Token::Type::kTextureSampled3d: return "texture_sampled_3d"; case Token::Type::kTextureSampledCube:
diff --git a/src/reader/wgsl/token.h b/src/reader/wgsl/token.h index 2e9f2da..da18df3 100644 --- a/src/reader/wgsl/token.h +++ b/src/reader/wgsl/token.h
@@ -300,6 +300,8 @@ kTextureDepthCube, /// A 'texture_depth_cube_array' kTextureDepthCubeArray, + /// A 'texture_multisampled_2d' + kTextureMultisampled2d, /// A 'texture_ro_1d' kTextureStorageReadonly1d, /// A 'texture_ro_2d_array' @@ -318,10 +320,6 @@ kTextureSampled2d, /// A 'texture_sampled_2d_array' kTextureSampled2dArray, - /// A 'texture_sampled_2d_ms' - kTextureSampled2dMs, - /// A 'texture_sampled_2d_ms_array' - kTextureSampled2dMsArray, /// A 'texture_sampled_3d' kTextureSampled3d, /// A 'texture_sampled_cube' @@ -689,6 +687,10 @@ bool IsTextureDepthCubeArray() const { return type_ == Type::kTextureDepthCubeArray; } + /// @returns true if the token is a 'texture_multisample_2d' + bool IsTextureMultisampled2d() const { + return type_ == Type::kTextureMultisampled2d; + } /// @returns true if token is a 'texture_ro_1d' bool IsTextureStorageReadonly1d() const { return type_ == Type::kTextureStorageReadonly1d; @@ -721,14 +723,6 @@ bool IsTextureSampled2dArray() const { return type_ == Type::kTextureSampled2dArray; } - /// @returns true if token is a 'texture_sampled_2d_ms' - bool IsTextureSampled2dMs() const { - return type_ == Type::kTextureSampled2dMs; - } - /// @returns true if token is a 'texture_sampled_2d_ms_array' - bool IsTextureSampled2dMsArray() const { - return type_ == Type::kTextureSampled2dMsArray; - } /// @returns true if token is a 'texture_sampled_3d' bool IsTextureSampled3d() const { return type_ == Type::kTextureSampled3d; } /// @returns true if token is a 'texture_sampled_cube'
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc index 926fbde..512e0b2 100644 --- a/src/type_determiner_test.cc +++ b/src/type_determiner_test.cc
@@ -1870,8 +1870,7 @@ return std::make_unique<ast::type::F32Type>(); } } else if (dim == ast::type::TextureDimension::k1dArray || - dim == ast::type::TextureDimension::k2d || - dim == ast::type::TextureDimension::k2dMs) { + dim == ast::type::TextureDimension::k2d) { return std::make_unique<ast::type::VectorType>(type, 2); } else if (dim == ast::type::TextureDimension::kCubeArray) { return std::make_unique<ast::type::VectorType>(type, 4); @@ -2144,18 +2143,6 @@ TextureType::kI32}, TextureTestParams{ast::type::TextureDimension::k2dArray, TextureType::kU32}, - TextureTestParams{ast::type::TextureDimension::k2dMs, - TextureType::kF32}, - TextureTestParams{ast::type::TextureDimension::k2dMs, - TextureType::kI32}, - TextureTestParams{ast::type::TextureDimension::k2dMs, - TextureType::kU32}, - TextureTestParams{ast::type::TextureDimension::k2dMsArray, - TextureType::kF32}, - TextureTestParams{ast::type::TextureDimension::k2dMsArray, - TextureType::kI32}, - TextureTestParams{ast::type::TextureDimension::k2dMsArray, - TextureType::kU32}, TextureTestParams{ast::type::TextureDimension::k3d, TextureType::kF32}, TextureTestParams{ast::type::TextureDimension::k3d, TextureType::kI32}, TextureTestParams{ast::type::TextureDimension::k3d, TextureType::kU32},
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index bce9333..9754fb2 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc
@@ -54,6 +54,7 @@ #include "src/ast/type/f32_type.h" #include "src/ast/type/i32_type.h" #include "src/ast/type/matrix_type.h" +#include "src/ast/type/multisampled_texture_type.h" #include "src/ast/type/pointer_type.h" #include "src/ast/type/sampled_texture_type.h" #include "src/ast/type/storage_texture_type.h" @@ -2039,7 +2040,6 @@ auto dim = texture->dim(); if (dim == ast::type::TextureDimension::k1dArray || dim == ast::type::TextureDimension::k2dArray || - dim == ast::type::TextureDimension::k2dMsArray || dim == ast::type::TextureDimension::kCubeArray) { array_literal = 1u; } @@ -2058,8 +2058,7 @@ } uint32_t ms_literal = 0u; - if (dim == ast::type::TextureDimension::k2dMs || - dim == ast::type::TextureDimension::k2dMsArray) { + if (texture->IsMultisampled()) { ms_literal = 1u; } @@ -2069,7 +2068,7 @@ } uint32_t sampled_literal = 2u; - if (texture->IsSampled() || texture->IsDepth()) { + if (texture->IsMultisampled() || texture->IsSampled() || texture->IsDepth()) { sampled_literal = 1u; } @@ -2079,6 +2078,8 @@ type_id = GenerateTypeIfNeeded(&f32); } else if (texture->IsSampled()) { type_id = GenerateTypeIfNeeded(texture->AsSampled()->type()); + } else if (texture->IsMultisampled()) { + type_id = GenerateTypeIfNeeded(texture->AsMultisampled()->type()); } else if (texture->IsStorage()) { if (texture->AsStorage()->access() == ast::type::StorageAccess::kWrite) { ast::type::VoidType void_type;
diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc index 1adfbb1..e950da4 100644 --- a/src/writer/spirv/builder_intrinsic_test.cc +++ b/src/writer/spirv/builder_intrinsic_test.cc
@@ -458,8 +458,7 @@ return std::make_unique<ast::type::F32Type>(); } } else if (dim == ast::type::TextureDimension::k1dArray || - dim == ast::type::TextureDimension::k2d || - dim == ast::type::TextureDimension::k2dMs) { + dim == ast::type::TextureDimension::k2d) { return std::make_unique<ast::type::VectorType>(type, 2); } else if (dim == ast::type::TextureDimension::kCubeArray) { return std::make_unique<ast::type::VectorType>(type, 4); @@ -523,20 +522,13 @@ if (dim == ast::type::TextureDimension::k1dArray || dim == ast::type::TextureDimension::k2dArray || - dim == ast::type::TextureDimension::k2dMsArray || dim == ast::type::TextureDimension::kCubeArray) { res += "1 "; } else { res += "0 "; } - if (dim == ast::type::TextureDimension::k2dMs || - dim == ast::type::TextureDimension::k2dMsArray) { - res += "1 "; - } else { - res += "0 "; - } - + res += "0 "; res += std::to_string(sampled_literal) + " "; if (unknown_format) {
diff --git a/src/writer/spirv/builder_type_test.cc b/src/writer/spirv/builder_type_test.cc index 48a5652..351b1cf 100644 --- a/src/writer/spirv/builder_type_test.cc +++ b/src/writer/spirv/builder_type_test.cc
@@ -26,6 +26,7 @@ #include "src/ast/type/f32_type.h" #include "src/ast/type/i32_type.h" #include "src/ast/type/matrix_type.h" +#include "src/ast/type/multisampled_texture_type.h" #include "src/ast/type/pointer_type.h" #include "src/ast/type/sampled_texture_type.h" #include "src/ast/type/sampler_type.h" @@ -771,6 +772,53 @@ return out; } +class MultisampledTextureTypeTest : public testing::TestWithParam<TextureType> { + public: + std::unique_ptr<ast::type::Type> get_type(TextureType param) { + if (param == TextureType::kF32) { + return std::make_unique<ast::type::F32Type>(); + } + if (param == TextureType::kI32) { + return std::make_unique<ast::type::I32Type>(); + } + return std::make_unique<ast::type::U32Type>(); + } + + std::string get_type_line(TextureType param) { + if (param == TextureType::kI32) { + return "%2 = OpTypeInt 32 1\n"; + } + if (param == TextureType::kU32) { + return "%2 = OpTypeInt 32 0\n"; + } + return "%2 = OpTypeFloat 32\n"; + } +}; + +TEST_P(MultisampledTextureTypeTest, Generate_2d) { + auto param = GetParam(); + auto type = get_type(param); + + ast::type::MultisampledTextureType two_d(ast::type::TextureDimension::k2d, + type.get()); + + ast::Module mod; + Builder b(&mod); + + auto id_two_d = b.GenerateTypeIfNeeded(&two_d); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(1u, id_two_d); + + EXPECT_EQ(DumpInstructions(b.types()), + get_type_line(param) + "%1 = OpTypeImage %2 2D 0 0 1 1 Unknown\n"); +} + +INSTANTIATE_TEST_SUITE_P(BuilderTest_Type, + MultisampledTextureTypeTest, + testing::Values(TextureType::kU32, + TextureType::kI32, + TextureType::kF32)); + class SampledTextureTypeTest : public testing::TestWithParam<TextureType> { public: std::unique_ptr<ast::type::Type> get_type(TextureType param) {
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc index ec38eb9..c64a1b3 100644 --- a/src/writer/wgsl/generator_impl.cc +++ b/src/writer/wgsl/generator_impl.cc
@@ -52,6 +52,7 @@ #include "src/ast/type/array_type.h" #include "src/ast/type/depth_texture_type.h" #include "src/ast/type/matrix_type.h" +#include "src/ast/type/multisampled_texture_type.h" #include "src/ast/type/pointer_type.h" #include "src/ast/type/sampled_texture_type.h" #include "src/ast/type/sampler_type.h" @@ -655,6 +656,8 @@ out_ << "depth_"; } else if (texture->IsSampled()) { out_ << "sampled_"; + } else if (texture->IsMultisampled()) { + out_ << "multisampled_"; } else if (texture->IsStorage()) { auto* storage = texture->AsStorage(); @@ -684,12 +687,6 @@ case ast::type::TextureDimension::k2dArray: out_ << "2d_array"; break; - case ast::type::TextureDimension::k2dMs: - out_ << "2d_ms"; - break; - case ast::type::TextureDimension::k2dMsArray: - out_ << "2d_ms_array"; - break; case ast::type::TextureDimension::k3d: out_ << "3d"; break; @@ -712,6 +709,14 @@ return false; } out_ << ">"; + } else if (texture->IsMultisampled()) { + auto* sampled = texture->AsMultisampled(); + + out_ << "<"; + if (!EmitType(sampled->type())) { + return false; + } + out_ << ">"; } else if (texture->IsStorage()) { auto* storage = texture->AsStorage();
diff --git a/src/writer/wgsl/generator_impl_type_test.cc b/src/writer/wgsl/generator_impl_type_test.cc index 46e06fc..fe09925 100644 --- a/src/writer/wgsl/generator_impl_type_test.cc +++ b/src/writer/wgsl/generator_impl_type_test.cc
@@ -24,6 +24,7 @@ #include "src/ast/type/f32_type.h" #include "src/ast/type/i32_type.h" #include "src/ast/type/matrix_type.h" +#include "src/ast/type/multisampled_texture_type.h" #include "src/ast/type/pointer_type.h" #include "src/ast/type/sampled_texture_type.h" #include "src/ast/type/sampler_type.h" @@ -276,6 +277,46 @@ TextureData{ast::type::TextureDimension::kCubeArray, "texture_sampled_cube_array"})); +using WgslGenerator_MultiampledTextureTest = + testing::TestWithParam<TextureData>; +TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_F32) { + auto param = GetParam(); + + ast::type::F32Type f32; + ast::type::MultisampledTextureType t(param.dim, &f32); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&t)) << g.error(); + EXPECT_EQ(g.result(), std::string(param.name) + "<f32>"); +} + +TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_I32) { + auto param = GetParam(); + + ast::type::I32Type i32; + ast::type::MultisampledTextureType t(param.dim, &i32); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&t)) << g.error(); + EXPECT_EQ(g.result(), std::string(param.name) + "<i32>"); +} + +TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_U32) { + auto param = GetParam(); + + ast::type::U32Type u32; + ast::type::MultisampledTextureType t(param.dim, &u32); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitType(&t)) << g.error(); + EXPECT_EQ(g.result(), std::string(param.name) + "<u32>"); +} +INSTANTIATE_TEST_SUITE_P(WgslGeneratorImplTest, + WgslGenerator_MultiampledTextureTest, + testing::Values(TextureData{ + ast::type::TextureDimension::k2d, + "texture_multisampled_2d"})); + struct StorageTextureData { ast::type::ImageFormat fmt; ast::type::TextureDimension dim;