blob: ba8e599e85358f845013c8c2635e27a448ddec2e [file] [log] [blame]
// 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/struct_block_decoration.h"
#include "src/sem/depth_texture_type.h"
#include "src/sem/multisampled_texture_type.h"
#include "src/sem/sampled_texture_type.h"
#include "src/writer/wgsl/test_helper.h"
namespace tint {
namespace writer {
namespace wgsl {
namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, EmitType_Alias) {
auto* alias = Alias("alias", ty.f32());
auto* alias_ty = ty.Of(alias);
WrapInFunction(Var("make_reachable", alias_ty));
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, alias_ty)) << gen.error();
EXPECT_EQ(out.str(), "alias");
}
TEST_F(WgslGeneratorImplTest, EmitType_Array) {
auto* arr = ty.array<bool, 4>();
Alias("make_type_reachable", arr);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, arr)) << gen.error();
EXPECT_EQ(out.str(), "array<bool, 4>");
}
TEST_F(WgslGeneratorImplTest, EmitType_Array_Decoration) {
auto* a = ty.array(ty.bool_(), 4, 16u);
Alias("make_type_reachable", a);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, a)) << gen.error();
EXPECT_EQ(out.str(), "[[stride(16)]] array<bool, 4>");
}
TEST_F(WgslGeneratorImplTest, EmitType_RuntimeArray) {
auto* a = ty.array(ty.bool_(), 0);
Alias("make_type_reachable", a);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, a)) << gen.error();
EXPECT_EQ(out.str(), "array<bool>");
}
TEST_F(WgslGeneratorImplTest, EmitType_Bool) {
auto* bool_ = ty.bool_();
Alias("make_type_reachable", bool_);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, bool_)) << gen.error();
EXPECT_EQ(out.str(), "bool");
}
TEST_F(WgslGeneratorImplTest, EmitType_F32) {
auto* f32 = ty.f32();
Alias("make_type_reachable", f32);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, f32)) << gen.error();
EXPECT_EQ(out.str(), "f32");
}
TEST_F(WgslGeneratorImplTest, EmitType_I32) {
auto* i32 = ty.i32();
Alias("make_type_reachable", i32);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, i32)) << gen.error();
EXPECT_EQ(out.str(), "i32");
}
TEST_F(WgslGeneratorImplTest, EmitType_Matrix) {
auto* mat2x3 = ty.mat2x3<f32>();
Alias("make_type_reachable", mat2x3);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, mat2x3)) << gen.error();
EXPECT_EQ(out.str(), "mat2x3<f32>");
}
TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
auto* p = ty.pointer<f32>(ast::StorageClass::kWorkgroup);
Alias("make_type_reachable", p);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, p)) << gen.error();
EXPECT_EQ(out.str(), "ptr<workgroup, f32>");
}
TEST_F(WgslGeneratorImplTest, EmitType_PointerAccessMode) {
auto* p =
ty.pointer<f32>(ast::StorageClass::kStorage, ast::Access::kReadWrite);
Alias("make_type_reachable", p);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, p)) << gen.error();
EXPECT_EQ(out.str(), "ptr<storage, f32, read_write>");
}
TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
auto* s = Structure("S", {
Member("a", ty.i32()),
Member("b", ty.f32()),
});
auto* s_ty = ty.Of(s);
WrapInFunction(Var("make_reachable", s_ty));
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, s_ty)) << gen.error();
EXPECT_EQ(out.str(), "S");
}
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
auto* s = Structure("S", {
Member("a", ty.i32(), {MemberOffset(8)}),
Member("b", ty.f32(), {MemberOffset(16)}),
});
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
EXPECT_EQ(gen.result(), R"(struct S {
[[size(8)]]
padding : u32;
a : i32;
[[size(4)]]
padding_1 : u32;
b : f32;
};
)");
}
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
auto* s =
Structure("S", {
Member("tint_0_padding", ty.i32(), {MemberOffset(8)}),
Member("tint_2_padding", ty.f32(), {MemberOffset(16)}),
});
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
EXPECT_EQ(gen.result(), R"(struct S {
[[size(8)]]
padding : u32;
tint_0_padding : i32;
[[size(4)]]
padding_1 : u32;
tint_2_padding : f32;
};
)");
}
TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
auto* s = Structure("S", {
Member("a", ty.i32(), {MemberAlign(8)}),
Member("b", ty.f32(), {MemberAlign(16)}),
});
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
EXPECT_EQ(gen.result(), R"(struct S {
[[align(8)]]
a : i32;
[[align(16)]]
b : f32;
};
)");
}
TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
auto* s = Structure("S", {
Member("a", ty.i32(), {MemberSize(16)}),
Member("b", ty.f32(), {MemberSize(32)}),
});
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
EXPECT_EQ(gen.result(), R"(struct S {
[[size(16)]]
a : i32;
[[size(32)]]
b : f32;
};
)");
}
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithDecoration) {
auto* s = Structure("S",
{
Member("a", ty.i32()),
Member("b", ty.f32(), {MemberAlign(8)}),
},
{create<ast::StructBlockDecoration>()});
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
EXPECT_EQ(gen.result(), R"([[block]]
struct S {
a : i32;
[[align(8)]]
b : f32;
};
)");
}
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithEntryPointDecorations) {
ast::DecorationList decos;
decos.push_back(create<ast::StructBlockDecoration>());
auto* s = Structure(
"S",
ast::StructMemberList{
Member("a", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)}),
Member("b", ty.f32(), {Location(2u)})},
decos);
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
EXPECT_EQ(gen.result(), R"([[block]]
struct S {
[[builtin(vertex_index)]]
a : u32;
[[location(2)]]
b : f32;
};
)");
}
TEST_F(WgslGeneratorImplTest, EmitType_U32) {
auto* u32 = ty.u32();
Alias("make_type_reachable", u32);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, u32)) << gen.error();
EXPECT_EQ(out.str(), "u32");
}
TEST_F(WgslGeneratorImplTest, EmitType_Vector) {
auto* vec3 = ty.vec3<f32>();
Alias("make_type_reachable", vec3);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, vec3)) << gen.error();
EXPECT_EQ(out.str(), "vec3<f32>");
}
struct TextureData {
ast::TextureDimension dim;
const char* name;
};
inline std::ostream& operator<<(std::ostream& out, TextureData data) {
out << data.name;
return out;
}
using WgslGenerator_DepthTextureTest = TestParamHelper<TextureData>;
TEST_P(WgslGenerator_DepthTextureTest, EmitType_DepthTexture) {
auto param = GetParam();
auto* d = ty.depth_texture(param.dim);
Alias("make_type_reachable", d);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, d)) << gen.error();
EXPECT_EQ(out.str(), param.name);
}
INSTANTIATE_TEST_SUITE_P(
WgslGeneratorImplTest,
WgslGenerator_DepthTextureTest,
testing::Values(
TextureData{ast::TextureDimension::k2d, "texture_depth_2d"},
TextureData{ast::TextureDimension::k2dArray, "texture_depth_2d_array"},
TextureData{ast::TextureDimension::kCube, "texture_depth_cube"},
TextureData{ast::TextureDimension::kCubeArray,
"texture_depth_cube_array"}));
using WgslGenerator_SampledTextureTest = TestParamHelper<TextureData>;
TEST_P(WgslGenerator_SampledTextureTest, EmitType_SampledTexture_F32) {
auto param = GetParam();
auto* t = ty.sampled_texture(param.dim, ty.f32());
Alias("make_type_reachable", t);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<f32>");
}
TEST_P(WgslGenerator_SampledTextureTest, EmitType_SampledTexture_I32) {
auto param = GetParam();
auto* t = ty.sampled_texture(param.dim, ty.i32());
Alias("make_type_reachable", t);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<i32>");
}
TEST_P(WgslGenerator_SampledTextureTest, EmitType_SampledTexture_U32) {
auto param = GetParam();
auto* t = ty.sampled_texture(param.dim, ty.u32());
Alias("make_type_reachable", t);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<u32>");
}
INSTANTIATE_TEST_SUITE_P(
WgslGeneratorImplTest,
WgslGenerator_SampledTextureTest,
testing::Values(
TextureData{ast::TextureDimension::k1d, "texture_1d"},
TextureData{ast::TextureDimension::k2d, "texture_2d"},
TextureData{ast::TextureDimension::k2dArray, "texture_2d_array"},
TextureData{ast::TextureDimension::k3d, "texture_3d"},
TextureData{ast::TextureDimension::kCube, "texture_cube"},
TextureData{ast::TextureDimension::kCubeArray, "texture_cube_array"}));
using WgslGenerator_MultiampledTextureTest = TestParamHelper<TextureData>;
TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_F32) {
auto param = GetParam();
auto* t = ty.multisampled_texture(param.dim, ty.f32());
Alias("make_type_reachable", t);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<f32>");
}
TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_I32) {
auto param = GetParam();
auto* t = ty.multisampled_texture(param.dim, ty.i32());
Alias("make_type_reachable", t);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<i32>");
}
TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_U32) {
auto param = GetParam();
auto* t = ty.multisampled_texture(param.dim, ty.u32());
Alias("make_type_reachable", t);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
EXPECT_EQ(out.str(), std::string(param.name) + "<u32>");
}
INSTANTIATE_TEST_SUITE_P(WgslGeneratorImplTest,
WgslGenerator_MultiampledTextureTest,
testing::Values(TextureData{
ast::TextureDimension::k2d,
"texture_multisampled_2d"}));
struct StorageTextureData {
ast::ImageFormat fmt;
ast::TextureDimension dim;
ast::Access access;
const char* name;
};
inline std::ostream& operator<<(std::ostream& out, StorageTextureData data) {
out << data.name;
return out;
}
using WgslGenerator_StorageTextureTest = TestParamHelper<StorageTextureData>;
TEST_P(WgslGenerator_StorageTextureTest, EmitType_StorageTexture) {
auto param = GetParam();
auto* t = ty.storage_texture(param.dim, param.fmt, param.access);
Global("g", t,
ast::DecorationList{
create<ast::BindingDecoration>(1),
create<ast::GroupDecoration>(2),
});
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
EXPECT_EQ(out.str(), param.name);
}
INSTANTIATE_TEST_SUITE_P(
WgslGeneratorImplTest,
WgslGenerator_StorageTextureTest,
testing::Values(
StorageTextureData{ast::ImageFormat::kRgba8Sint,
ast::TextureDimension::k1d, ast::Access::kRead,
"texture_storage_1d<rgba8sint, read>"},
StorageTextureData{ast::ImageFormat::kRgba8Sint,
ast::TextureDimension::k2d, ast::Access::kRead,
"texture_storage_2d<rgba8sint, read>"},
StorageTextureData{ast::ImageFormat::kRgba8Sint,
ast::TextureDimension::k2dArray, ast::Access::kRead,
"texture_storage_2d_array<rgba8sint, read>"},
StorageTextureData{ast::ImageFormat::kRgba8Sint,
ast::TextureDimension::k3d, ast::Access::kRead,
"texture_storage_3d<rgba8sint, read>"},
StorageTextureData{ast::ImageFormat::kRgba8Sint,
ast::TextureDimension::k1d, ast::Access::kWrite,
"texture_storage_1d<rgba8sint, write>"},
StorageTextureData{ast::ImageFormat::kRgba8Sint,
ast::TextureDimension::k2d, ast::Access::kWrite,
"texture_storage_2d<rgba8sint, write>"},
StorageTextureData{ast::ImageFormat::kRgba8Sint,
ast::TextureDimension::k2dArray, ast::Access::kWrite,
"texture_storage_2d_array<rgba8sint, write>"},
StorageTextureData{ast::ImageFormat::kRgba8Sint,
ast::TextureDimension::k3d, ast::Access::kWrite,
"texture_storage_3d<rgba8sint, write>"}));
struct ImageFormatData {
ast::ImageFormat fmt;
const char* name;
};
inline std::ostream& operator<<(std::ostream& out, ImageFormatData data) {
out << data.name;
return out;
}
using WgslGenerator_ImageFormatTest = TestParamHelper<ImageFormatData>;
TEST_P(WgslGenerator_ImageFormatTest, EmitType_StorageTexture_ImageFormat) {
auto param = GetParam();
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitImageFormat(out, param.fmt)) << gen.error();
EXPECT_EQ(out.str(), param.name);
}
INSTANTIATE_TEST_SUITE_P(
WgslGeneratorImplTest,
WgslGenerator_ImageFormatTest,
testing::Values(
ImageFormatData{ast::ImageFormat::kR8Unorm, "r8unorm"},
ImageFormatData{ast::ImageFormat::kR8Snorm, "r8snorm"},
ImageFormatData{ast::ImageFormat::kR8Uint, "r8uint"},
ImageFormatData{ast::ImageFormat::kR8Sint, "r8sint"},
ImageFormatData{ast::ImageFormat::kR16Uint, "r16uint"},
ImageFormatData{ast::ImageFormat::kR16Sint, "r16sint"},
ImageFormatData{ast::ImageFormat::kR16Float, "r16float"},
ImageFormatData{ast::ImageFormat::kRg8Unorm, "rg8unorm"},
ImageFormatData{ast::ImageFormat::kRg8Snorm, "rg8snorm"},
ImageFormatData{ast::ImageFormat::kRg8Uint, "rg8uint"},
ImageFormatData{ast::ImageFormat::kRg8Sint, "rg8sint"},
ImageFormatData{ast::ImageFormat::kR32Uint, "r32uint"},
ImageFormatData{ast::ImageFormat::kR32Sint, "r32sint"},
ImageFormatData{ast::ImageFormat::kR32Float, "r32float"},
ImageFormatData{ast::ImageFormat::kRg16Uint, "rg16uint"},
ImageFormatData{ast::ImageFormat::kRg16Sint, "rg16sint"},
ImageFormatData{ast::ImageFormat::kRg16Float, "rg16float"},
ImageFormatData{ast::ImageFormat::kRgba8Unorm, "rgba8unorm"},
ImageFormatData{ast::ImageFormat::kRgba8UnormSrgb, "rgba8unorm_srgb"},
ImageFormatData{ast::ImageFormat::kRgba8Snorm, "rgba8snorm"},
ImageFormatData{ast::ImageFormat::kRgba8Uint, "rgba8uint"},
ImageFormatData{ast::ImageFormat::kRgba8Sint, "rgba8sint"},
ImageFormatData{ast::ImageFormat::kBgra8Unorm, "bgra8unorm"},
ImageFormatData{ast::ImageFormat::kBgra8UnormSrgb, "bgra8unorm_srgb"},
ImageFormatData{ast::ImageFormat::kRgb10A2Unorm, "rgb10a2unorm"},
ImageFormatData{ast::ImageFormat::kRg11B10Float, "rg11b10float"},
ImageFormatData{ast::ImageFormat::kRg32Uint, "rg32uint"},
ImageFormatData{ast::ImageFormat::kRg32Sint, "rg32sint"},
ImageFormatData{ast::ImageFormat::kRg32Float, "rg32float"},
ImageFormatData{ast::ImageFormat::kRgba16Uint, "rgba16uint"},
ImageFormatData{ast::ImageFormat::kRgba16Sint, "rgba16sint"},
ImageFormatData{ast::ImageFormat::kRgba16Float, "rgba16float"},
ImageFormatData{ast::ImageFormat::kRgba32Uint, "rgba32uint"},
ImageFormatData{ast::ImageFormat::kRgba32Sint, "rgba32sint"},
ImageFormatData{ast::ImageFormat::kRgba32Float, "rgba32float"}));
TEST_F(WgslGeneratorImplTest, EmitType_Sampler) {
auto* sampler = ty.sampler(ast::SamplerKind::kSampler);
Alias("make_type_reachable", sampler);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, sampler)) << gen.error();
EXPECT_EQ(out.str(), "sampler");
}
TEST_F(WgslGeneratorImplTest, EmitType_SamplerComparison) {
auto* sampler = ty.sampler(ast::SamplerKind::kComparisonSampler);
Alias("make_type_reachable", sampler);
GeneratorImpl& gen = Build();
std::stringstream out;
ASSERT_TRUE(gen.EmitType(out, sampler)) << gen.error();
EXPECT_EQ(out.str(), "sampler_comparison");
}
} // namespace
} // namespace wgsl
} // namespace writer
} // namespace tint