mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-10 05:57:51 +00:00
Require vertex shaders to return builtin(position)
Fixup many tests that were just returning void. Change-Id: Ic93db5b187c679dc1c24a356b48a64e41ba9a823 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48560 Commit-Queue: James Price <jrprice@google.com> Auto-Submit: James Price <jrprice@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
committed by
Commit Bot service account
parent
98c2cf0e91
commit
2dd393729c
@@ -94,7 +94,7 @@ TEST_P(FunctionReturnTypeDecorationTest, IsValid) {
|
||||
Func("main", ast::VariableList{}, ty.f32(),
|
||||
ast::StatementList{create<ast::ReturnStatement>(Expr(1.f))},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex)},
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kCompute)},
|
||||
ast::DecorationList{createDecoration({}, *this, params.kind)});
|
||||
|
||||
if (params.should_pass) {
|
||||
|
||||
@@ -32,7 +32,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Location) {
|
||||
// [[stage(vertex)]]
|
||||
// fn main() -> [[location(0)]] f32 { return 1.0; }
|
||||
Func(Source{{12, 34}}, "main", {}, ty.f32(), {Return(Expr(1.0f))},
|
||||
{Stage(ast::PipelineStage::kVertex)}, {Location(0)});
|
||||
{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
@@ -500,5 +500,17 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateLocation) {
|
||||
12:34 note: while analysing entry point main)");
|
||||
}
|
||||
|
||||
TEST_F(ResolverEntryPointValidationTest, VertexShaderMustReturnPosition) {
|
||||
// [[stage(vertex)]]
|
||||
// fn main() {}
|
||||
Func(Source{{12, 34}}, "main", {}, ty.void_(), {},
|
||||
{Stage(ast::PipelineStage::kVertex)});
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
"12:34 error: a vertex shader must include the 'position' builtin "
|
||||
"in its return type");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint
|
||||
|
||||
@@ -47,7 +47,6 @@ TEST_F(ResolverFunctionValidationTest, FunctionNamesMustBeUnique_fail) {
|
||||
|
||||
TEST_F(ResolverFunctionValidationTest,
|
||||
VoidFunctionEndWithoutReturnStatement_Pass) {
|
||||
// [[stage(vertex)]]
|
||||
// fn func { var a:i32 = 2; }
|
||||
auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
|
||||
|
||||
@@ -55,9 +54,6 @@ TEST_F(ResolverFunctionValidationTest,
|
||||
ty.void_(),
|
||||
ast::StatementList{
|
||||
create<ast::VariableDeclStatement>(var),
|
||||
},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
});
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
@@ -82,14 +78,10 @@ TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatement_Fail) {
|
||||
|
||||
TEST_F(ResolverFunctionValidationTest,
|
||||
VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
|
||||
// [[stage(vertex)]]
|
||||
// fn func {}
|
||||
|
||||
Func(Source{Source::Location{12, 34}}, "func", ast::VariableList{},
|
||||
ty.void_(), ast::StatementList{},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
});
|
||||
ty.void_(), ast::StatementList{});
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
@@ -109,15 +101,11 @@ TEST_F(ResolverFunctionValidationTest,
|
||||
|
||||
TEST_F(ResolverFunctionValidationTest,
|
||||
FunctionTypeMustMatchReturnStatementType_Pass) {
|
||||
// [[stage(vertex)]]
|
||||
// fn func { return; }
|
||||
|
||||
Func("func", ast::VariableList{}, ty.void_(),
|
||||
ast::StatementList{
|
||||
create<ast::ReturnStatement>(),
|
||||
},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
});
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
@@ -148,10 +136,6 @@ TEST_F(ResolverFunctionValidationTest,
|
||||
Expr(2.f)),
|
||||
},
|
||||
ast::DecorationList{});
|
||||
Func("main", ast::VariableList{}, ty.void_(), ast::StatementList{},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
});
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
@@ -183,10 +167,6 @@ TEST_F(ResolverFunctionValidationTest,
|
||||
Expr(2.f)),
|
||||
},
|
||||
ast::DecorationList{});
|
||||
Func("main", ast::VariableList{}, ty.void_(), ast::StatementList{},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
});
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
@@ -202,10 +182,6 @@ TEST_F(ResolverFunctionValidationTest,
|
||||
Expr(2u)),
|
||||
},
|
||||
ast::DecorationList{});
|
||||
Func("main", ast::VariableList{}, ty.void_(), ast::StatementList{},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
});
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
|
||||
@@ -521,7 +521,8 @@ bool Resolver::ValidateParameter(const ast::Variable* param) {
|
||||
return ValidateVariable(param);
|
||||
}
|
||||
|
||||
bool Resolver::ValidateFunction(const ast::Function* func) {
|
||||
bool Resolver::ValidateFunction(const ast::Function* func,
|
||||
const FunctionInfo* info) {
|
||||
if (symbol_to_function_.find(func->symbol()) != symbol_to_function_.end()) {
|
||||
diagnostics_.add_error("v-0016",
|
||||
"function names must be unique '" +
|
||||
@@ -564,7 +565,7 @@ bool Resolver::ValidateFunction(const ast::Function* func) {
|
||||
}
|
||||
|
||||
if (func->IsEntryPoint()) {
|
||||
if (!ValidateEntryPoint(func)) {
|
||||
if (!ValidateEntryPoint(func, info)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -572,7 +573,8 @@ bool Resolver::ValidateFunction(const ast::Function* func) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateEntryPoint(const ast::Function* func) {
|
||||
bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||
const FunctionInfo* info) {
|
||||
auto stage_deco_count = 0;
|
||||
for (auto* deco : func->decorations()) {
|
||||
if (deco->Is<ast::StageDecoration>()) {
|
||||
@@ -750,9 +752,13 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func) {
|
||||
}
|
||||
}
|
||||
|
||||
// Clear IO sets after parameter validation. Builtin and location attributes
|
||||
// in return types should be validated independently from those used in
|
||||
// parameters.
|
||||
builtins.clear();
|
||||
locations.clear();
|
||||
|
||||
if (!func->return_type()->Is<sem::Void>()) {
|
||||
builtins.clear();
|
||||
locations.clear();
|
||||
if (!validate_entry_point_decorations(func->return_type_decorations(),
|
||||
func->return_type(), func->source(),
|
||||
ParamOrRetType::kReturnType)) {
|
||||
@@ -760,6 +766,28 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func) {
|
||||
}
|
||||
}
|
||||
|
||||
if (func->pipeline_stage() == ast::PipelineStage::kVertex &&
|
||||
builtins.count(ast::Builtin::kPosition) == 0) {
|
||||
// Check module-scope variables, as the SPIR-V sanitizer generates these.
|
||||
bool found = false;
|
||||
for (auto* var : info->referenced_module_vars) {
|
||||
if (auto* builtin = ast::GetDecoration<ast::BuiltinDecoration>(
|
||||
var->declaration->decorations())) {
|
||||
if (builtin->value() == ast::Builtin::kPosition) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
diagnostics_.add_error(
|
||||
"a vertex shader must include the 'position' builtin in its return "
|
||||
"type",
|
||||
func->source());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -863,7 +891,7 @@ bool Resolver::Function(ast::Function* func) {
|
||||
Mark(deco);
|
||||
}
|
||||
|
||||
if (!ValidateFunction(func)) {
|
||||
if (!ValidateFunction(func, func_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -238,8 +238,8 @@ class Resolver {
|
||||
// Each return true on success, false on failure.
|
||||
bool ValidateAssignment(const ast::AssignmentStatement* a);
|
||||
bool ValidateBinary(ast::BinaryExpression* expr);
|
||||
bool ValidateEntryPoint(const ast::Function* func);
|
||||
bool ValidateFunction(const ast::Function* func);
|
||||
bool ValidateEntryPoint(const ast::Function* func, const FunctionInfo* info);
|
||||
bool ValidateFunction(const ast::Function* func, const FunctionInfo* info);
|
||||
bool ValidateGlobalVariable(const VariableInfo* var);
|
||||
bool ValidateMatrixConstructor(const sem::Matrix* matrix_type,
|
||||
const ast::ExpressionList& values);
|
||||
|
||||
@@ -1532,7 +1532,7 @@ TEST_F(ResolverTest, Function_EntryPoints_StageDecoration) {
|
||||
create<ast::AssignmentStatement>(Expr("call_b"), Call("b")),
|
||||
},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
|
||||
});
|
||||
|
||||
auto* ep_2 =
|
||||
@@ -1541,7 +1541,7 @@ TEST_F(ResolverTest, Function_EntryPoints_StageDecoration) {
|
||||
create<ast::AssignmentStatement>(Expr("call_c"), Call("c")),
|
||||
},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
@@ -1620,7 +1620,7 @@ TEST_F(ResolverTest, Function_EntryPoints_LinearTime) {
|
||||
create<ast::CallStatement>(Call(fn_b(0))),
|
||||
},
|
||||
{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
@@ -65,11 +65,12 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointReturnType) {
|
||||
}
|
||||
|
||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
|
||||
auto* s = Structure(
|
||||
"S", {Member("a", ty.f32(), {create<ast::LocationDecoration>(0)})});
|
||||
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
||||
|
||||
Func("main", {Param("param", s)}, ty.void_(), {},
|
||||
{create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
|
||||
Func("main", {Param("param", s)}, ty.vec4<f32>(),
|
||||
{Return(Construct(ty.vec4<f32>()))},
|
||||
{Stage(ast::PipelineStage::kVertex)},
|
||||
{Builtin(ast::Builtin::kPosition)});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
@@ -81,10 +82,10 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
|
||||
|
||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
|
||||
auto* s = Structure(
|
||||
"S", {Member("a", ty.f32(), {create<ast::LocationDecoration>(0)})});
|
||||
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
|
||||
|
||||
Func("main", {}, s, {Return(Construct(s, Expr(0.f)))},
|
||||
{create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
|
||||
{Stage(ast::PipelineStage::kVertex)});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
@@ -142,13 +143,13 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
|
||||
|
||||
TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
|
||||
auto* s = Structure(
|
||||
"S", {Member("a", ty.f32(), {create<ast::LocationDecoration>(0)})});
|
||||
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
|
||||
|
||||
Func("vert_main", {Param("param", s)}, s, {Return(Construct(s, Expr(0.f)))},
|
||||
{create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
|
||||
{Stage(ast::PipelineStage::kVertex)});
|
||||
|
||||
Func("frag_main", {Param("param", s)}, ty.void_(), {},
|
||||
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
|
||||
{Stage(ast::PipelineStage::kFragment)});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
|
||||
@@ -112,9 +112,7 @@ TEST_F(ResolverTypeValidationTest,
|
||||
|
||||
auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
|
||||
|
||||
Func("my_func", ast::VariableList{}, ty.void_(), {Decl(var)},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
|
||||
Func("my_func", ast::VariableList{}, ty.void_(), {Decl(var)});
|
||||
|
||||
Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
|
||||
|
||||
@@ -277,9 +275,6 @@ TEST_F(ResolverTypeValidationTest,
|
||||
ast::StatementList{
|
||||
create<ast::VariableDeclStatement>(Source{{13, 34}}, var1),
|
||||
create<ast::ReturnStatement>(),
|
||||
},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
});
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
@@ -280,9 +280,6 @@ TEST_F(ResolverValidationTest, UsingUndefinedVariableGlobalVariable_Pass) {
|
||||
create<ast::AssignmentStatement>(Source{Source::Location{12, 34}},
|
||||
Expr("global_var"), Expr(3.14f)),
|
||||
create<ast::ReturnStatement>(),
|
||||
},
|
||||
ast::DecorationList{
|
||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
|
||||
});
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
Reference in New Issue
Block a user