blob: b39566475ecf651448d20d576a65ae98e6dc2cfd [file] [log] [blame]
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/wgsl/helpers/flatten_bindings.h"
#include <utility>
#include "gtest/gtest.h"
#include "src/tint/lang/core/type/texture_dimension.h"
#include "src/tint/lang/wgsl/program/program_builder.h"
#include "src/tint/lang/wgsl/resolver/resolve.h"
#include "src/tint/lang/wgsl/sem/variable.h"
namespace tint::wgsl {
namespace {
using namespace tint::core::number_suffixes; // NOLINT
class FlattenBindingsTest : public ::testing::Test {};
TEST_F(FlattenBindingsTest, NoBindings) {
ProgramBuilder b;
Program program(resolver::Resolve(b));
ASSERT_TRUE(program.IsValid()) << program.Diagnostics();
auto flattened = FlattenBindings(program);
EXPECT_FALSE(flattened);
}
TEST_F(FlattenBindingsTest, AlreadyFlat) {
ProgramBuilder b;
b.GlobalVar("a", b.ty.i32(), core::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
b.GlobalVar("b", b.ty.i32(), core::AddressSpace::kUniform, b.Group(0_a), b.Binding(1_a));
b.GlobalVar("c", b.ty.i32(), core::AddressSpace::kUniform, b.Group(0_a), b.Binding(2_a));
Program program(resolver::Resolve(b));
ASSERT_TRUE(program.IsValid()) << program.Diagnostics();
auto flattened = FlattenBindings(program);
EXPECT_FALSE(flattened);
}
TEST_F(FlattenBindingsTest, NotFlat_SingleNamespace) {
ProgramBuilder b;
b.GlobalVar("a", b.ty.i32(), core::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
b.GlobalVar("b", b.ty.i32(), core::AddressSpace::kUniform, b.Group(1_a), b.Binding(1_a));
b.GlobalVar("c", b.ty.i32(), core::AddressSpace::kUniform, b.Group(2_a), b.Binding(2_a));
b.WrapInFunction(b.Expr("a"), b.Expr("b"), b.Expr("c"));
Program program(resolver::Resolve(b));
ASSERT_TRUE(program.IsValid()) << program.Diagnostics();
auto flattened = FlattenBindings(program);
EXPECT_TRUE(flattened);
auto& vars = flattened->AST().GlobalVariables();
auto* sem = flattened->Sem().Get<sem::GlobalVariable>(vars[0]);
ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->BindingPoint()->group, 0u);
EXPECT_EQ(sem->BindingPoint()->binding, 0u);
sem = flattened->Sem().Get<sem::GlobalVariable>(vars[1]);
ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->BindingPoint()->group, 0u);
EXPECT_EQ(sem->BindingPoint()->binding, 1u);
sem = flattened->Sem().Get<sem::GlobalVariable>(vars[2]);
ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->BindingPoint()->group, 0u);
EXPECT_EQ(sem->BindingPoint()->binding, 2u);
}
TEST_F(FlattenBindingsTest, NotFlat_MultipleNamespaces) {
ProgramBuilder b;
const size_t num_buffers = 3;
b.GlobalVar("buffer1", b.ty.i32(), core::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
b.GlobalVar("buffer2", b.ty.i32(), core::AddressSpace::kStorage, b.Group(1_a), b.Binding(1_a));
b.GlobalVar("buffer3", b.ty.i32(), core::AddressSpace::kStorage, core::Access::kRead,
b.Group(2_a), b.Binding(2_a));
const size_t num_samplers = 2;
b.GlobalVar("sampler1", b.ty.sampler(core::type::SamplerKind::kSampler), b.Group(3_a),
b.Binding(3_a));
b.GlobalVar("sampler2", b.ty.sampler(core::type::SamplerKind::kComparisonSampler), b.Group(4_a),
b.Binding(4_a));
const size_t num_textures = 6;
b.GlobalVar("texture1", b.ty.sampled_texture(core::type::TextureDimension::k2d, b.ty.f32()),
b.Group(5_a), b.Binding(5_a));
b.GlobalVar("texture2",
b.ty.multisampled_texture(core::type::TextureDimension::k2d, b.ty.f32()),
b.Group(6_a), b.Binding(6_a));
b.GlobalVar("texture3",
b.ty.storage_texture(core::type::TextureDimension::k2d,
core::TexelFormat::kR32Float, core::Access::kWrite),
b.Group(7_a), b.Binding(7_a));
b.GlobalVar("texture4", b.ty.depth_texture(core::type::TextureDimension::k2d), b.Group(8_a),
b.Binding(8_a));
b.GlobalVar("texture5", b.ty.depth_multisampled_texture(core::type::TextureDimension::k2d),
b.Group(9_a), b.Binding(9_a));
b.GlobalVar("texture6", b.ty.external_texture(), b.Group(10_a), b.Binding(10_a));
b.WrapInFunction(b.Assign(b.Phony(), "buffer1"), b.Assign(b.Phony(), "buffer2"),
b.Assign(b.Phony(), "buffer3"), b.Assign(b.Phony(), "sampler1"),
b.Assign(b.Phony(), "sampler2"), b.Assign(b.Phony(), "texture1"),
b.Assign(b.Phony(), "texture2"), b.Assign(b.Phony(), "texture3"),
b.Assign(b.Phony(), "texture4"), b.Assign(b.Phony(), "texture5"),
b.Assign(b.Phony(), "texture6"));
Program program(resolver::Resolve(b));
ASSERT_TRUE(program.IsValid()) << program.Diagnostics();
auto flattened = FlattenBindings(program);
EXPECT_TRUE(flattened);
auto& vars = flattened->AST().GlobalVariables();
for (size_t i = 0; i < num_buffers; ++i) {
auto* sem = flattened->Sem().Get<sem::GlobalVariable>(vars[i]);
ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->BindingPoint()->group, 0u);
EXPECT_EQ(sem->BindingPoint()->binding, i);
}
for (size_t i = 0; i < num_samplers; ++i) {
auto* sem = flattened->Sem().Get<sem::GlobalVariable>(vars[i + num_buffers]);
ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->BindingPoint()->group, 0u);
EXPECT_EQ(sem->BindingPoint()->binding, i);
}
for (size_t i = 0; i < num_textures; ++i) {
auto* sem = flattened->Sem().Get<sem::GlobalVariable>(vars[i + num_buffers + num_samplers]);
ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->BindingPoint()->group, 0u);
EXPECT_EQ(sem->BindingPoint()->binding, i);
}
}
} // namespace
} // namespace tint::wgsl