diff --git a/src/Nazara/Shader/Ast/DependencyCheckerVisitor.cpp b/src/Nazara/Shader/Ast/DependencyCheckerVisitor.cpp index 0d2175d8d..73f183e00 100644 --- a/src/Nazara/Shader/Ast/DependencyCheckerVisitor.cpp +++ b/src/Nazara/Shader/Ast/DependencyCheckerVisitor.cpp @@ -32,7 +32,7 @@ namespace Nz::ShaderAst void DependencyCheckerVisitor::Visit(CallFunctionExpression& node) { - const auto& targetFuncType = GetExpressionType(node); + const auto& targetFuncType = GetExpressionType(*node.targetFunction); assert(std::holds_alternative(targetFuncType)); const auto& funcType = std::get(targetFuncType); diff --git a/src/Nazara/Shader/LangWriter.cpp b/src/Nazara/Shader/LangWriter.cpp index a9143d467..e32dbf8a6 100644 --- a/src/Nazara/Shader/LangWriter.cpp +++ b/src/Nazara/Shader/LangWriter.cpp @@ -527,7 +527,10 @@ namespace Nz bool first = true; for (const ShaderAst::StatementPtr& statement : statements) { - if (!first && statement->GetType() != ShaderAst::NodeType::NoOpStatement) + if (statement->GetType() == ShaderAst::NodeType::NoOpStatement) + continue; + + if (!first) AppendLine(); statement->Visit(*this); diff --git a/tests/Engine/Shader/Optimizations.cpp b/tests/Engine/Shader/Optimizations.cpp index c47803b41..96d97f341 100644 --- a/tests/Engine/Shader/Optimizations.cpp +++ b/tests/Engine/Shader/Optimizations.cpp @@ -4,11 +4,12 @@ #include #include #include +#include #include #include #include -void ExpectOptimization(std::string_view sourceCode, std::string_view expectedOptimizedResult) +void PropagateConstantAndExpect(std::string_view sourceCode, std::string_view expectedOptimizedResult) { Nz::ShaderAst::StatementPtr shader; REQUIRE_NOTHROW(shader = Nz::ShaderLang::Parse(sourceCode)); @@ -18,11 +19,21 @@ void ExpectOptimization(std::string_view sourceCode, std::string_view expectedOp ExpectNZSL(*shader, expectedOptimizedResult); } +void EliminateUnusedAndExpect(std::string_view sourceCode, std::string_view expectedOptimizedResult) +{ + Nz::ShaderAst::StatementPtr shader; + REQUIRE_NOTHROW(shader = Nz::ShaderLang::Parse(sourceCode)); + REQUIRE_NOTHROW(shader = Nz::ShaderAst::Sanitize(*shader)); + REQUIRE_NOTHROW(shader = Nz::ShaderAst::EliminateUnusedPass(*shader)); + + ExpectNZSL(*shader, expectedOptimizedResult); +} + TEST_CASE("optimizations", "[Shader]") { WHEN("propagating constants") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -39,7 +50,7 @@ fn main() WHEN("propagating vector constants") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -55,7 +66,7 @@ fn main() WHEN("eliminating simple branch") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -73,7 +84,7 @@ fn main() WHEN("eliminating multiple branches") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -104,7 +115,7 @@ fn main() WHEN("eliminating multiple split branches") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -146,7 +157,7 @@ fn main() WHEN("optimizing out scalar swizzle") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -163,7 +174,7 @@ fn main() WHEN("optimizing out scalar swizzle to vector") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -180,7 +191,7 @@ fn main() WHEN("optimizing out vector swizzle") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -197,7 +208,7 @@ fn main() WHEN("optimizing out vector swizzle with repetition") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -214,7 +225,7 @@ fn main() WHEN("optimizing out complex swizzle") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( [entry(frag)] fn main() { @@ -231,7 +242,7 @@ fn main() WHEN("optimizing out complex swizzle on unknown value") { - ExpectOptimization(R"( + PropagateConstantAndExpect(R"( struct inputStruct { value: vec4[f32] @@ -255,4 +266,66 @@ fn main() } )"); } + + WHEN("eliminating unused code") + { + EliminateUnusedAndExpect(R"( +struct inputStruct +{ + value: vec4[f32] +} + +struct notUsed +{ + value: vec4[f32] +} + +external +{ + [set(0), binding(0)] unusedData: uniform[notUsed], + [set(0), binding(1)] data: uniform[inputStruct] +} + +fn unusedFunction() -> vec4[f32] +{ + return unusedData.value; +} + +struct Output +{ + value: vec4[f32] +} + +[entry(frag)] +fn main() -> Output +{ + let unusedvalue = unusedFunction(); + + let output: Output; + output.value = data.value; + return output; +})", R"( +struct inputStruct +{ + value: vec4[f32] +} + +external +{ + [set(0), binding(1)] data: uniform[inputStruct] +} + +struct Output +{ + value: vec4[f32] +} + +[entry(frag)] +fn main() -> Output +{ + let output: Output; + output.value = data.value; + return output; +})"); + } }