resolver: Validate uniform buffer types

Fixed: tint:210
Change-Id: I7763ca23a5dce09755a1ca71d35f24897a875ac0
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48604
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
Ben Clayton 2021-04-21 17:55:12 +00:00 committed by Commit Bot service account
parent 8db818840e
commit 42708348b7
10 changed files with 463 additions and 346 deletions

View File

@ -39,7 +39,7 @@ let c1 : bool = true;
type t0 = [[stride(16)]] array<vec4<f32>>;
type t1 = array<vec4<f32>>;
var<uniform> g0 : u32 = 20u;
var<private> g0 : u32 = 20u;
var<private> g1 : f32 = 123.0;
var g2 : texture_2d<f32>;
var g3 : [[access(read)]] texture_storage_2d<r32uint>;
@ -47,7 +47,7 @@ var g4 : [[access(write)]] texture_storage_2d<rg32float>;
var g5 : [[access(read)]] texture_storage_2d<r32uint>;
var g6 : [[access(write)]] texture_storage_2d<rg32float>;
[[builtin(position)]] var<uniform> g7 : vec3<f32>;
var<private> g7 : vec3<f32>;
[[group(10), binding(20)]] var<storage> g8 : [[access(write)]] S;
[[group(10), binding(20)]] var<storage> g9 : [[access(read)]] S;
[[group(10), binding(20)]] var<storage> g10 : [[access(read_write)]] S;

View File

@ -1822,31 +1822,6 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonEntryPointFunc) {
EXPECT_TRUE(error.find("not an entry point") != std::string::npos);
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, MissingBlockDeco) {
ast::DecorationList decos;
auto* str = create<ast::Struct>(
Sym("foo_type"),
ast::StructMemberList{Member(StructMemberName(0, ty.i32()), ty.i32())},
decos);
auto* foo_type = ty.struct_(str);
AddUniformBuffer("foo_ub", foo_type, 0, 0);
MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
MakeCallerBodyFunction(
"ep_func", {"ub_func"},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
});
Inspector& inspector = Build();
auto result = inspector.GetUniformBufferResourceBindings("ep_func");
ASSERT_FALSE(inspector.has_error()) << inspector.error();
EXPECT_EQ(0u, result.size());
}
TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple) {
sem::StructType* foo_struct_type =
MakeUniformBufferType("foo_type", {ty.i32()});

View File

@ -985,13 +985,42 @@ class ProgramBuilder {
decorations);
}
/// @param args the arguments to pass to Var()
/// @returns a `ast::Variable` constructed by calling Var() with the arguments
/// of `args`, which is automatically registered as a global variable with the
/// ast::Module.
template <typename... ARGS>
ast::Variable* Global(ARGS&&... args) {
auto* var = Var(std::forward<ARGS>(args)...);
/// @param name the variable name
/// @param type the variable type
/// @param storage the variable storage class
/// @param constructor constructor expression
/// @param decorations variable decorations
/// @returns a new `ast::Variable`, which is automatically registered as a
/// global variable with the ast::Module.
template <typename NAME>
ast::Variable* Global(NAME&& name,
sem::Type* type,
ast::StorageClass storage,
ast::Expression* constructor = nullptr,
ast::DecorationList decorations = {}) {
auto* var =
Var(std::forward<NAME>(name), type, storage, constructor, decorations);
AST().AddGlobalVariable(var);
return var;
}
/// @param source the variable source
/// @param name the variable name
/// @param type the variable type
/// @param storage the variable storage class
/// @param constructor constructor expression
/// @param decorations variable decorations
/// @returns a new `ast::Variable`, which is automatically registered as a
/// global variable with the ast::Module.
template <typename NAME>
ast::Variable* Global(const Source& source,
NAME&& name,
sem::Type* type,
ast::StorageClass storage,
ast::Expression* constructor = nullptr,
ast::DecorationList decorations = {}) {
auto* var = Var(source, std::forward<NAME>(name), type, storage,
constructor, decorations);
AST().AddGlobalVariable(var);
return var;
}

View File

@ -432,37 +432,69 @@ bool Resolver::GlobalVariable(ast::Variable* var) {
}
bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
if (info->storage_class == ast::StorageClass::kStorage) {
// https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
// Variables in the storage storage class and variables with a storage
// texture type must have an access attribute applied to the store type.
switch (info->storage_class) {
case ast::StorageClass::kStorage: {
// https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
// Variables in the storage storage class and variables with a storage
// texture type must have an access attribute applied to the store type.
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
// A variable in the storage storage class is a storage buffer variable. Its
// store type must be a host-shareable structure type with block attribute,
// satisfying the storage class constraints.
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
// A variable in the storage storage class is a storage buffer variable.
// Its store type must be a host-shareable structure type with block
// attribute, satisfying the storage class constraints.
auto* access = info->type->As<sem::AccessControl>();
auto* str = access ? access->type()->As<sem::StructType>() : nullptr;
if (!str) {
diagnostics_.add_error(
"variables declared in the <storage> storage class must be of an "
"[[access]] qualified structure type",
info->declaration->source());
return false;
}
if (!str->IsBlockDecorated()) {
diagnostics_.add_error(
"structure used as a storage buffer must be declared with the "
"[[block]] decoration",
str->impl()->source());
if (info->declaration->source().range.begin.line) {
diagnostics_.add_note("structure used as storage buffer here",
info->declaration->source());
auto* access = info->type->As<sem::AccessControl>();
auto* str = access ? access->type()->As<sem::StructType>() : nullptr;
if (!str) {
diagnostics_.add_error(
"variables declared in the <storage> storage class must be of an "
"[[access]] qualified structure type",
info->declaration->source());
return false;
}
return false;
if (!str->IsBlockDecorated()) {
diagnostics_.add_error(
"structure used as a storage buffer must be declared with the "
"[[block]] decoration",
str->impl()->source());
if (info->declaration->source().range.begin.line) {
diagnostics_.add_note("structure used as storage buffer here",
info->declaration->source());
}
return false;
}
break;
}
case ast::StorageClass::kUniform: {
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
// A variable in the uniform storage class is a uniform buffer variable.
// Its store type must be a host-shareable structure type with block
// attribute, satisfying the storage class constraints.
auto* str = info->type->As<sem::StructType>();
if (!str) {
diagnostics_.add_error(
"variables declared in the <uniform> storage class must be of a "
"structure type",
info->declaration->source());
return false;
}
if (!str->IsBlockDecorated()) {
diagnostics_.add_error(
"structure used as a uniform buffer must be declared with the "
"[[block]] decoration",
str->impl()->source());
if (info->declaration->source().range.begin.line) {
diagnostics_.add_note("structure used as uniform buffer here",
info->declaration->source());
}
return false;
}
break;
}
default:
break;
}
return ValidateVariable(info->declaration);

View File

@ -138,6 +138,94 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
ASSERT_TRUE(r()->Resolve());
}
///
TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {
// var<uniform> g : bool;
Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform);
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: variables declared in the <uniform> storage class must be of a structure type)");
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
// var<uniform> g : ptr<i32, input>;
Global(Source{{56, 78}}, "g", ty.pointer<i32>(ast::StorageClass::kInput),
ast::StorageClass::kUniform);
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: variables declared in the <uniform> storage class must be of a structure type)");
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
// var<uniform> g : [[access(read)]] array<S, 3>;
auto* s = Structure("S", {Member("a", ty.f32())});
auto* a = ty.array(s, 3);
auto* ac = ty.access(ast::AccessControl::kReadOnly, a);
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform);
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: variables declared in the <uniform> storage class must be of a structure type)");
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
// type a = bool;
// var<uniform> g : [[access(read)]] a;
auto* a = ty.alias("a", ty.bool_());
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform);
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(56:78 error: variables declared in the <uniform> storage class must be of a structure type)");
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) {
// struct S { x : i32 };
// var<uniform> g : S;
auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(12:34 error: structure used as a uniform buffer must be declared with the [[block]] decoration
56:78 note: structure used as uniform buffer here)");
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
// [[block]] struct S { x : i32 };
// var<uniform> g : S;
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
{create<ast::StructBlockDecoration>()});
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
ASSERT_TRUE(r()->Resolve());
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) {
// [[block]] struct S { x : i32 };
// type a1 = S;
// var<uniform> g : a1;
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
{create<ast::StructBlockDecoration>()});
auto* a1 = ty.alias("a1", s);
Global(Source{{56, 78}}, "g", a1, ast::StorageClass::kUniform);
ASSERT_TRUE(r()->Resolve());
}
} // namespace
} // namespace resolver
} // namespace tint

View File

@ -66,53 +66,53 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) {
TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) {
auto* s = Structure("S", {Member("a", ty.f32())});
Global("g", s, ast::StorageClass::kUniform);
Global("g", s, ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s);
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kUniform));
UnorderedElementsAre(ast::StorageClass::kPrivate));
}
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) {
auto* s = Structure("S", {Member("a", ty.f32())});
auto* a = ty.alias("A", s);
Global("g", a, ast::StorageClass::kUniform);
Global("g", a, ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s);
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kUniform));
UnorderedElementsAre(ast::StorageClass::kPrivate));
}
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) {
auto* s = Structure("S", {Member("a", ty.f32())});
auto* o = Structure("O", {Member("a", s)});
Global("g", o, ast::StorageClass::kUniform);
Global("g", o, ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s);
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kUniform));
UnorderedElementsAre(ast::StorageClass::kPrivate));
}
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) {
auto* s = Structure("S", {Member("a", ty.f32())});
auto* a = ty.array(s, 3);
Global("g", a, ast::StorageClass::kUniform);
Global("g", a, ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s);
ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kUniform));
UnorderedElementsAre(ast::StorageClass::kPrivate));
}
TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {

View File

@ -31,10 +31,9 @@ using HlslGeneratorImplTest_Function = TestHelper;
TEST_F(HlslGeneratorImplTest_Function, Emit_Function) {
Func("my_func", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::ReturnStatement>(),
},
ast::DecorationList{});
{
Return(),
});
GeneratorImpl& gen = Build();
@ -50,10 +49,9 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function) {
TEST_F(HlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
Func("GeometryShader", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::ReturnStatement>(),
},
ast::DecorationList{});
{
Return(),
});
GeneratorImpl& gen = SanitizeAndBuild();
@ -68,10 +66,9 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithParams) {
Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())},
ty.void_(),
ast::StatementList{
create<ast::ReturnStatement>(),
},
ast::DecorationList{});
{
Return(),
});
GeneratorImpl& gen = Build();
@ -87,10 +84,9 @@ TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithParams) {
TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_NoReturn_Void) {
Func("main", ast::VariableList{}, ty.void_(),
ast::StatementList{/* no explicit return */},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
Func("main", ast::VariableList{}, ty.void_(), {/* no explicit return */},
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -111,9 +107,8 @@ TEST_F(HlslGeneratorImplTest_Function,
// return foo;
// }
auto* foo_in = Param("foo", ty.f32(), {create<ast::LocationDecoration>(0)});
Func("frag_main", ast::VariableList{foo_in}, ty.f32(),
{create<ast::ReturnStatement>(Expr("foo"))},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)},
Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return(Expr("foo"))},
{Stage(ast::PipelineStage::kFragment)},
{create<ast::LocationDecoration>(1)});
GeneratorImpl& gen = SanitizeAndBuild();
@ -146,8 +141,8 @@ TEST_F(HlslGeneratorImplTest_Function,
Param("coord", ty.vec4<f32>(),
{create<ast::BuiltinDecoration>(ast::Builtin::kPosition)});
Func("frag_main", ast::VariableList{coord_in}, ty.f32(),
{create<ast::ReturnStatement>(MemberAccessor("coord", "x"))},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)},
{Return(MemberAccessor("coord", "x"))},
{Stage(ast::PipelineStage::kFragment)},
{create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth)});
GeneratorImpl& gen = SanitizeAndBuild();
@ -201,14 +196,12 @@ TEST_F(HlslGeneratorImplTest_Function,
Func("frag_main", {Param("inputs", interface_struct)}, ty.void_(),
{
WrapInStatement(
Const("r", ty.f32(), MemberAccessor(Expr("inputs"), "col1"))),
WrapInStatement(
Const("g", ty.f32(), MemberAccessor(Expr("inputs"), "col2"))),
WrapInStatement(Const("p", ty.vec4<f32>(),
MemberAccessor(Expr("inputs"), "pos"))),
Decl(Const("r", ty.f32(), MemberAccessor(Expr("inputs"), "col1"))),
Decl(Const("g", ty.f32(), MemberAccessor(Expr("inputs"), "col2"))),
Decl(Const("p", ty.vec4<f32>(),
MemberAccessor(Expr("inputs"), "pos"))),
},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = SanitizeAndBuild();
@ -268,20 +261,19 @@ TEST_F(HlslGeneratorImplTest_Function,
{create<ast::BuiltinDecoration>(ast::Builtin::kPosition)})});
Func("foo", {Param("x", ty.f32())}, vertex_output_struct,
{create<ast::ReturnStatement>(Construct(
vertex_output_struct, Construct(ty.vec4<f32>(), Expr("x"), Expr("x"),
Expr("x"), Expr(1.f))))},
{Return(Construct(vertex_output_struct,
Construct(ty.vec4<f32>(), Expr("x"), Expr("x"),
Expr("x"), Expr(1.f))))},
{});
Func("vert_main1", {}, vertex_output_struct,
{create<ast::ReturnStatement>(
Construct(vertex_output_struct, Expr(Call("foo", Expr(0.5f)))))},
{create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
{Return(Construct(vertex_output_struct, Expr(Call("foo", Expr(0.5f)))))},
{Stage(ast::PipelineStage::kVertex)});
Func("vert_main2", {}, vertex_output_struct,
{create<ast::ReturnStatement>(
Construct(vertex_output_struct, Expr(Call("foo", Expr(0.25f)))))},
{create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
Func(
"vert_main2", {}, vertex_output_struct,
{Return(Construct(vertex_output_struct, Expr(Call("foo", Expr(0.25f)))))},
{Stage(ast::PipelineStage::kVertex)});
GeneratorImpl& gen = SanitizeAndBuild();
@ -320,33 +312,48 @@ tint_symbol_2 vert_main2() {
TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_With_Uniform) {
Global("coord", ty.vec4<f32>(), ast::StorageClass::kUniform, nullptr,
ast::DecorationList{
create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1),
});
auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
{create<ast::StructBlockDecoration>()});
auto* ubo = Global(
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction,
MemberAccessor("coord", "x"));
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Func("sub_func",
{
Param("param", ty.f32()),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
ty.f32(),
{
Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
});
auto* var =
Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f));
Func("frag_main", {}, ty.void_(),
{
Decl(var),
Return(),
},
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.Generate(out)) << gen.error();
EXPECT_EQ(result(), R"(cbuffer cbuffer_coord : register(b0, space1) {
EXPECT_EQ(result(), R"(struct UBO {
float4 coord;
};
ConstantBuffer<UBO> ubo : register(b0, space1);
float sub_func(float param) {
return ubo.coord.x;
}
void frag_main() {
float v = coord.x;
float v = sub_func(1.0f);
return;
}
@ -357,10 +364,11 @@ void frag_main() {
TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_With_UniformStruct) {
auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())});
auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())},
{create<ast::StructBlockDecoration>()});
Global("uniforms", s, ast::StorageClass::kUniform, nullptr,
ast::DecorationList{
{
create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1),
});
@ -370,12 +378,12 @@ TEST_F(HlslGeneratorImplTest_Function,
MemberAccessor("uniforms", "coord"), Expr("x")));
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -409,7 +417,7 @@ TEST_F(HlslGeneratorImplTest_Function,
sem::AccessControl ac(ast::AccessControl::kReadWrite, s);
Global("coord", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{
{
create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1),
});
@ -418,12 +426,12 @@ TEST_F(HlslGeneratorImplTest_Function,
MemberAccessor("coord", "b"));
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = SanitizeAndBuild();
@ -455,7 +463,7 @@ TEST_F(HlslGeneratorImplTest_Function,
sem::AccessControl ac(ast::AccessControl::kReadOnly, s);
Global("coord", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{
{
create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1),
});
@ -464,12 +472,12 @@ TEST_F(HlslGeneratorImplTest_Function,
MemberAccessor("coord", "b"));
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = SanitizeAndBuild();
@ -501,19 +509,19 @@ TEST_F(HlslGeneratorImplTest_Function,
sem::AccessControl ac(ast::AccessControl::kWriteOnly, s);
Global("coord", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{
{
create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1),
});
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::AssignmentStatement>(MemberAccessor("coord", "b"),
Expr(2.0f)),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = SanitizeAndBuild();
@ -545,19 +553,19 @@ TEST_F(HlslGeneratorImplTest_Function,
sem::AccessControl ac(ast::AccessControl::kReadWrite, s);
Global("coord", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{
{
create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1),
});
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::AssignmentStatement>(MemberAccessor("coord", "b"),
Expr(2.0f)),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = SanitizeAndBuild();
@ -582,36 +590,35 @@ TEST_F(
HlslGeneratorImplTest_Function,
Emit_Decoration_Called_By_EntryPoints_WithLocationGlobals_And_Params) { // NOLINT
Global("foo", ty.f32(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{
{
create<ast::LocationDecoration>(0),
});
Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
{
create<ast::LocationDecoration>(1),
});
Global("val", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
{
create<ast::LocationDecoration>(0),
});
Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
ast::StatementList{
{
create<ast::AssignmentStatement>(Expr("bar"), Expr("foo")),
create<ast::AssignmentStatement>(Expr("val"), Expr("param")),
create<ast::ReturnStatement>(Expr("foo")),
},
ast::DecorationList{});
Return(Expr("foo")),
});
Func(
"ep_1", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::AssignmentStatement>(Expr("bar"), Call("sub_func", 1.0f)),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -646,24 +653,23 @@ ep_1_out ep_1(ep_1_in tint_in) {
TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_Called_By_EntryPoints_NoUsedGlobals) {
Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
{
create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth),
});
Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
ast::StatementList{
create<ast::ReturnStatement>(Expr("param")),
},
ast::DecorationList{});
{
Return(Expr("param")),
});
Func("ep_1", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::AssignmentStatement>(Expr("depth"),
Call("sub_func", 1.0f)),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -693,31 +699,30 @@ TEST_F(
HlslGeneratorImplTest_Function,
Emit_Decoration_Called_By_EntryPoints_WithBuiltinGlobals_And_Params) { // NOLINT
Global("coord", ty.vec4<f32>(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{
{
create<ast::BuiltinDecoration>(ast::Builtin::kPosition),
});
Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
{
create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth),
});
Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
ast::StatementList{
{
create<ast::AssignmentStatement>(Expr("depth"),
MemberAccessor("coord", "x")),
create<ast::ReturnStatement>(Expr("param")),
},
ast::DecorationList{});
Return(Expr("param")),
});
Func("ep_1", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::AssignmentStatement>(Expr("depth"),
Call("sub_func", 1.0f)),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = SanitizeAndBuild();
@ -749,37 +754,40 @@ ep_1_out ep_1(ep_1_in tint_in) {
TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
Global("coord", ty.vec4<f32>(), ast::StorageClass::kUniform, nullptr,
ast::DecorationList{
auto* s = Structure("S", {Member("x", ty.f32())},
{create<ast::StructBlockDecoration>()});
Global("coord", s, ast::StorageClass::kUniform, nullptr,
{
create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1),
});
Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
ast::StatementList{
create<ast::ReturnStatement>(MemberAccessor("coord", "x")),
},
ast::DecorationList{});
{
Return(MemberAccessor("coord", "x")),
});
auto* var =
Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f));
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.Generate(out)) << gen.error();
EXPECT_EQ(result(), R"(cbuffer cbuffer_coord : register(b0, space1) {
float4 coord;
EXPECT_EQ(result(), R"(struct S {
float x;
};
ConstantBuffer<S> coord : register(b0, space1);
float sub_func(float param) {
return coord.x;
}
@ -800,27 +808,26 @@ TEST_F(HlslGeneratorImplTest_Function,
{create<ast::StructBlockDecoration>()});
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{
{
create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1),
});
Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
ast::StatementList{
create<ast::ReturnStatement>(MemberAccessor("coord", "x")),
},
ast::DecorationList{});
{
Return(MemberAccessor("coord", "x")),
});
auto* var =
Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f));
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = SanitizeAndBuild();
@ -847,25 +854,21 @@ void frag_main() {
TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoints_WithGlobal_Nested_Return) {
Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
{
create<ast::LocationDecoration>(1),
});
auto* list = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(),
});
Func(
"ep_1", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::AssignmentStatement>(Expr("bar"), Expr(1.0f)),
create<ast::IfStatement>(create<ast::BinaryExpression>(
ast::BinaryOp::kEqual, Expr(1), Expr(1)),
list, ast::ElseStatementList{}),
create<ast::ReturnStatement>(),
Block(Return()), ast::ElseStatementList{}),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -891,9 +894,9 @@ ep_1_out ep_1() {
TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_WithNameCollision) {
Func("GeometryShader", ast::VariableList{}, ty.void_(), ast::StatementList{},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
Func("GeometryShader", ast::VariableList{}, ty.void_(), {},
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = SanitizeAndBuild();
@ -908,11 +911,11 @@ TEST_F(HlslGeneratorImplTest_Function,
TEST_F(HlslGeneratorImplTest_Function, Emit_Decoration_EntryPoint_Compute) {
Func("main", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::ReturnStatement>(),
{
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
{
Stage(ast::PipelineStage::kCompute),
});
GeneratorImpl& gen = Build();
@ -931,11 +934,11 @@ void main() {
TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_Compute_WithWorkgroup) {
Func("main", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::ReturnStatement>(),
{
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
{
Stage(ast::PipelineStage::kCompute),
create<ast::WorkgroupDecoration>(2u, 4u, 6u),
});
@ -954,8 +957,8 @@ void main() {
TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithArrayParams) {
Func("my_func", ast::VariableList{Param("a", ty.array<f32, 5>())}, ty.void_(),
ast::StatementList{
create<ast::ReturnStatement>(),
{
Return(),
});
GeneratorImpl& gen = Build();
@ -990,14 +993,13 @@ TEST_F(HlslGeneratorImplTest_Function,
// return;
// }
auto* s =
Structure("Data", {Member("d", ty.f32())},
ast::DecorationList{create<ast::StructBlockDecoration>()});
auto* s = Structure("Data", {Member("d", ty.f32())},
{create<ast::StructBlockDecoration>()});
sem::AccessControl ac(ast::AccessControl::kReadWrite, s);
Global("data", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{
{
create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(0),
});
@ -1007,12 +1009,12 @@ TEST_F(HlslGeneratorImplTest_Function,
MemberAccessor("data", "d"));
Func("a", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
{
Stage(ast::PipelineStage::kCompute),
});
}
@ -1021,12 +1023,12 @@ TEST_F(HlslGeneratorImplTest_Function,
MemberAccessor("data", "d"));
Func("b", ast::VariableList{}, ty.void_(),
ast::StatementList{
{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
{
Stage(ast::PipelineStage::kCompute),
});
}

View File

@ -28,9 +28,9 @@ using MslGeneratorImplTest = TestHelper;
TEST_F(MslGeneratorImplTest, Emit_Function) {
Func("my_func", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{});
{});
GeneratorImpl& gen = Build();
@ -54,9 +54,9 @@ TEST_F(MslGeneratorImplTest, Emit_Function_WithParams) {
Func("my_func", params, ty.void_(),
ast::StatementList{
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{});
{});
GeneratorImpl& gen = Build();
@ -76,8 +76,7 @@ using namespace metal;
TEST_F(MslGeneratorImplTest, Emit_Decoration_EntryPoint_NoReturn_Void) {
Func("main", ast::VariableList{}, ty.void_(),
ast::StatementList{/* no explicit return */},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build();
@ -97,9 +96,8 @@ TEST_F(MslGeneratorImplTest, Emit_Decoration_EntryPoint_WithInOutVars) {
// return foo;
// }
auto* foo_in = Param("foo", ty.f32(), {create<ast::LocationDecoration>(0)});
Func("frag_main", ast::VariableList{foo_in}, ty.f32(),
{create<ast::ReturnStatement>(Expr("foo"))},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)},
Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return(Expr("foo"))},
{Stage(ast::PipelineStage::kFragment)},
{create<ast::LocationDecoration>(1)});
GeneratorImpl& gen = SanitizeAndBuild();
@ -133,8 +131,8 @@ TEST_F(MslGeneratorImplTest, Emit_Decoration_EntryPoint_WithInOut_Builtins) {
Param("coord", ty.vec4<f32>(),
{create<ast::BuiltinDecoration>(ast::Builtin::kPosition)});
Func("frag_main", ast::VariableList{coord_in}, ty.f32(),
{create<ast::ReturnStatement>(MemberAccessor("coord", "x"))},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)},
{Return(MemberAccessor("coord", "x"))},
{Stage(ast::PipelineStage::kFragment)},
{create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth)});
GeneratorImpl& gen = SanitizeAndBuild();
@ -194,7 +192,7 @@ TEST_F(MslGeneratorImplTest,
WrapInStatement(
Const("g", ty.f32(), MemberAccessor(Expr("colors"), "col2"))),
},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
{Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = SanitizeAndBuild();
@ -255,20 +253,19 @@ TEST_F(MslGeneratorImplTest,
{create<ast::BuiltinDecoration>(ast::Builtin::kPosition)})});
Func("foo", {Param("x", ty.f32())}, vertex_output_struct,
{create<ast::ReturnStatement>(Construct(
vertex_output_struct, Construct(ty.vec4<f32>(), Expr("x"), Expr("x"),
Expr("x"), Expr(1.f))))},
{Return(Construct(vertex_output_struct,
Construct(ty.vec4<f32>(), Expr("x"), Expr("x"),
Expr("x"), Expr(1.f))))},
{});
Func("vert_main1", {}, vertex_output_struct,
{create<ast::ReturnStatement>(
Construct(vertex_output_struct, Expr(Call("foo", Expr(0.5f)))))},
{create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
{Return(Construct(vertex_output_struct, Expr(Call("foo", Expr(0.5f)))))},
{Stage(ast::PipelineStage::kVertex)});
Func("vert_main2", {}, vertex_output_struct,
{create<ast::ReturnStatement>(
Construct(vertex_output_struct, Expr(Call("foo", Expr(0.25f)))))},
{create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
Func(
"vert_main2", {}, vertex_output_struct,
{Return(Construct(vertex_output_struct, Expr(Call("foo", Expr(0.25f)))))},
{Stage(ast::PipelineStage::kVertex)});
GeneratorImpl& gen = SanitizeAndBuild();
@ -317,8 +314,7 @@ TEST_F(MslGeneratorImplTest,
sem::AccessControl ac(ast::AccessControl::kReadWrite, s);
Global("coord", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1)});
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction,
MemberAccessor("coord", "b"));
@ -326,10 +322,10 @@ TEST_F(MslGeneratorImplTest,
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -363,8 +359,7 @@ TEST_F(MslGeneratorImplTest,
sem::AccessControl ac(ast::AccessControl::kReadOnly, s);
Global("coord", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1)});
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction,
MemberAccessor("coord", "b"));
@ -372,10 +367,10 @@ TEST_F(MslGeneratorImplTest,
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -402,13 +397,13 @@ TEST_F(
MslGeneratorImplTest,
Emit_Decoration_Called_By_EntryPoints_WithLocationGlobals_And_Params) { // NOLINT
Global("foo", ty.f32(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{create<ast::LocationDecoration>(0)});
{create<ast::LocationDecoration>(0)});
Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{create<ast::LocationDecoration>(1)});
{create<ast::LocationDecoration>(1)});
Global("val", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{create<ast::LocationDecoration>(0)});
{create<ast::LocationDecoration>(0)});
ast::VariableList params;
params.push_back(Param("param", ty.f32()));
@ -416,18 +411,18 @@ TEST_F(
auto body = ast::StatementList{
create<ast::AssignmentStatement>(Expr("bar"), Expr("foo")),
create<ast::AssignmentStatement>(Expr("val"), Expr("param")),
create<ast::ReturnStatement>(Expr("foo"))};
Return(Expr("foo"))};
Func("sub_func", params, ty.f32(), body, ast::DecorationList{});
Func("sub_func", params, ty.f32(), body, {});
body = ast::StatementList{
create<ast::AssignmentStatement>(Expr("bar"), Call("sub_func", 1.0f)),
create<ast::ReturnStatement>(),
Return(),
};
Func("ep_1", ast::VariableList{}, ty.void_(), body,
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -464,26 +459,25 @@ fragment ep_1_out ep_1(ep_1_in _tint_in [[stage_in]]) {
TEST_F(MslGeneratorImplTest,
Emit_Decoration_Called_By_EntryPoints_NoUsedGlobals) {
Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth)});
{create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth)});
ast::VariableList params;
params.push_back(Param("param", ty.f32()));
Func("sub_func", params, ty.f32(),
ast::StatementList{
create<ast::ReturnStatement>(Expr("param")),
Return(Expr("param")),
},
ast::DecorationList{});
{});
auto body = ast::StatementList{
create<ast::AssignmentStatement>(Expr("depth"), Call("sub_func", 1.0f)),
create<ast::ReturnStatement>(),
Return(),
};
Func("ep_1", ast::VariableList{}, ty.void_(), body,
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -514,12 +508,10 @@ TEST_F(
MslGeneratorImplTest,
Emit_Decoration_Called_By_EntryPoints_WithBuiltinGlobals_And_Params) { // NOLINT
Global("coord", ty.vec4<f32>(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{
create<ast::BuiltinDecoration>(ast::Builtin::kPosition)});
{create<ast::BuiltinDecoration>(ast::Builtin::kPosition)});
Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth)});
{create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth)});
ast::VariableList params;
params.push_back(Param("param", ty.f32()));
@ -527,19 +519,19 @@ TEST_F(
auto body = ast::StatementList{
create<ast::AssignmentStatement>(Expr("depth"),
MemberAccessor("coord", "x")),
create<ast::ReturnStatement>(Expr("param")),
Return(Expr("param")),
};
Func("sub_func", params, ty.f32(), body, ast::DecorationList{});
Func("sub_func", params, ty.f32(), body, {});
body = ast::StatementList{
create<ast::AssignmentStatement>(Expr("depth"), Call("sub_func", 1.0f)),
create<ast::ReturnStatement>(),
Return(),
};
Func("ep_1", ast::VariableList{}, ty.void_(), body,
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -568,29 +560,31 @@ fragment ep_1_out ep_1(float4 coord [[position]]) {
TEST_F(MslGeneratorImplTest,
Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
Global("coord", ty.vec4<f32>(), ast::StorageClass::kUniform, nullptr,
ast::DecorationList{create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1)});
auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
{create<ast::StructBlockDecoration>()});
auto* ubo = Global(
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
ast::VariableList params;
params.push_back(Param("param", ty.f32()));
auto body = ast::StatementList{
create<ast::ReturnStatement>(MemberAccessor("coord", "x")),
};
Func("sub_func", params, ty.f32(), body, ast::DecorationList{});
Func("sub_func",
{
Param("param", ty.f32()),
},
ty.f32(),
{
Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
});
auto* var =
Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f));
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Func("frag_main", {}, ty.void_(),
{
Decl(var),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -599,12 +593,16 @@ TEST_F(MslGeneratorImplTest,
EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
using namespace metal;
float sub_func(constant float4& coord, float param) {
return coord.x;
struct UBO {
/* 0x0000 */ packed_float4 coord;
};
float sub_func(constant UBO& ubo, float param) {
return ubo.coord.x;
}
fragment void frag_main(constant float4& coord [[buffer(0)]]) {
float v = sub_func(coord, 1.0f);
fragment void frag_main(constant UBO& ubo [[buffer(0)]]) {
float v = sub_func(ubo, 1.0f);
return;
}
@ -623,16 +621,14 @@ TEST_F(MslGeneratorImplTest,
sem::AccessControl ac(ast::AccessControl::kReadWrite, s);
Global("coord", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1)});
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
ast::VariableList params;
params.push_back(Param("param", ty.f32()));
auto body = ast::StatementList{
create<ast::ReturnStatement>(MemberAccessor("coord", "b"))};
auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))};
Func("sub_func", params, ty.f32(), body, ast::DecorationList{});
Func("sub_func", params, ty.f32(), body, {});
auto* var =
Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f));
@ -640,10 +636,10 @@ TEST_F(MslGeneratorImplTest,
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -681,16 +677,14 @@ TEST_F(MslGeneratorImplTest,
sem::AccessControl ac(ast::AccessControl::kReadOnly, s);
Global("coord", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(1)});
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
ast::VariableList params;
params.push_back(Param("param", ty.f32()));
auto body = ast::StatementList{
create<ast::ReturnStatement>(MemberAccessor("coord", "b"))};
auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))};
Func("sub_func", params, ty.f32(), body, ast::DecorationList{});
Func("sub_func", params, ty.f32(), body, {});
auto* var =
Var("v", ty.f32(), ast::StorageClass::kFunction, Call("sub_func", 1.0f));
@ -698,10 +692,10 @@ TEST_F(MslGeneratorImplTest,
Func("frag_main", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -731,10 +725,10 @@ fragment void frag_main(const device Data& coord [[buffer(0)]]) {
TEST_F(MslGeneratorImplTest,
Emit_Decoration_EntryPoints_WithGlobal_Nested_Return) {
Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{create<ast::LocationDecoration>(1)});
{create<ast::LocationDecoration>(1)});
auto* list = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(),
Return(),
});
auto body = ast::StatementList{
@ -742,12 +736,12 @@ TEST_F(MslGeneratorImplTest,
create<ast::IfStatement>(create<ast::BinaryExpression>(
ast::BinaryOp::kEqual, Expr(1), Expr(1)),
list, ast::ElseStatementList{}),
create<ast::ReturnStatement>(),
Return(),
};
Func("ep_1", ast::VariableList{}, ty.void_(), body,
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
{
Stage(ast::PipelineStage::kFragment),
});
GeneratorImpl& gen = Build();
@ -778,9 +772,9 @@ TEST_F(MslGeneratorImplTest, Emit_Function_WithArrayParams) {
Func("my_func", params, ty.void_(),
ast::StatementList{
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{});
{});
GeneratorImpl& gen = Build();
@ -821,8 +815,7 @@ TEST_F(MslGeneratorImplTest,
sem::AccessControl ac(ast::AccessControl::kReadWrite, s);
Global("data", &ac, ast::StorageClass::kStorage, nullptr,
ast::DecorationList{create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(0)});
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(0)});
{
auto* var = Var("v", ty.f32(), ast::StorageClass::kFunction,
@ -831,10 +824,10 @@ TEST_F(MslGeneratorImplTest,
Func("a", ast::VariableList{}, ty.void_(),
ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(),
Return(),
},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
{
Stage(ast::PipelineStage::kCompute),
});
}
@ -843,10 +836,8 @@ TEST_F(MslGeneratorImplTest,
MemberAccessor("data", "d"));
Func("b", ast::VariableList{}, ty.void_(),
ast::StatementList{create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>()},
ast::DecorationList{
create<ast::StageDecoration>(ast::PipelineStage::kCompute)});
ast::StatementList{create<ast::VariableDeclStatement>(var), Return()},
{Stage(ast::PipelineStage::kCompute)});
}
GeneratorImpl& gen = Build();

View File

@ -53,7 +53,7 @@ struct Particle {
particles : array<Particle, 5>;
};
[[binding(0), group(0)]] var<uniform> params : [[access(read)]] SimParams;
[[binding(0), group(0)]] var<uniform> params : SimParams;
[[binding(1), group(0)]] var<storage> particlesA : [[access(read_write)]] Particles;
[[binding(2), group(0)]] var<storage> particlesB : [[access(read_write)]] Particles;

View File

@ -17,7 +17,7 @@
modelViewProjectionMatrix : mat4x4<f32>;
};
[[binding(0), group(0)]] var<uniform> uniforms : [[access(read)]] Uniforms;
[[binding(0), group(0)]] var<uniform> uniforms : Uniforms;
struct VertexInput {
[[location(0)]] cur_position : vec4<f32>;