From 8fb7bb78a5eb4bdbc766931084c2f0a819c9a2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 27 Aug 2020 19:26:59 +0200 Subject: [PATCH] Add a shader generation unit test --- build/scripts/tools/ndk_server.lua | 1 + tests/Engine/Shader/AccessMember.cpp | 145 +++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 tests/Engine/Shader/AccessMember.cpp diff --git a/build/scripts/tools/ndk_server.lua b/build/scripts/tools/ndk_server.lua index 96ef7a0ab..e50d8c802 100644 --- a/build/scripts/tools/ndk_server.lua +++ b/build/scripts/tools/ndk_server.lua @@ -46,5 +46,6 @@ TOOL.Libraries = { "NazaraNetwork", "NazaraPhysics2D", "NazaraPhysics3D", + "NazaraShader", "NazaraUtility" } diff --git a/tests/Engine/Shader/AccessMember.cpp b/tests/Engine/Shader/AccessMember.cpp new file mode 100644 index 000000000..7ed92bd9c --- /dev/null +++ b/tests/Engine/Shader/AccessMember.cpp @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +std::string_view Trim(std::string_view str) +{ + while (!str.empty() && std::isspace(str.front())) + str.remove_prefix(1); + + while (!str.empty() && std::isspace(str.back())) + str.remove_suffix(1); + + return str; +} + +void ExpectingGLSL(const Nz::ShaderAst& shader, std::string_view expectedOutput) +{ + Nz::GlslWriter writer; + + std::string output = writer.Generate(shader); + std::size_t funcOffset = output.find("void main()"); + std::string_view subset = Trim(output).substr(funcOffset); + expectedOutput = Trim(expectedOutput); + + REQUIRE(subset == expectedOutput); +} + +void ExpectingSpirV(const Nz::ShaderAst& shader, std::string_view expectedOutput) +{ + Nz::SpirvWriter writer; + auto spirv = writer.Generate(shader); + + Nz::SpirvPrinter printer; + + Nz::SpirvPrinter::Settings settings; + settings.printHeader = false; + settings.printParameters = false; + + std::string output = printer.Print(spirv.data(), spirv.size(), settings); + std::size_t funcOffset = output.find("OpFunction"); + std::string_view subset = Trim(output).substr(funcOffset); + expectedOutput = Trim(expectedOutput); + + REQUIRE(subset == expectedOutput); +} + +SCENARIO("Shader generation", "[Shader]") +{ + SECTION("Nested member loading") + { + Nz::ShaderAst baseShader(Nz::ShaderStageType::Vertex); + baseShader.AddStruct("innerStruct", { + { + "field", + Nz::ShaderNodes::BasicType::Float3 + } + }); + + baseShader.AddStruct("outerStruct", { + { + "s", + "innerStruct" + } + }); + + baseShader.AddUniform("ubo", "outerStruct"); + baseShader.AddOutput("result", Nz::ShaderNodes::BasicType::Float1); + + SECTION("Nested AccessMember") + { + Nz::ShaderAst shader = baseShader; + + auto uniform = Nz::ShaderBuilder::Uniform("ubo", "outerStruct"); + auto output = Nz::ShaderBuilder::Output("result", Nz::ShaderNodes::BasicType::Float1); + + auto access = Nz::ShaderBuilder::Swizzle(Nz::ShaderBuilder::AccessMember(Nz::ShaderBuilder::AccessMember(Nz::ShaderBuilder::Identifier(uniform), 0, "innerStruct"), 0, Nz::ShaderNodes::BasicType::Float3), Nz::ShaderNodes::SwizzleComponent::Third); + auto assign = Nz::ShaderBuilder::Assign(Nz::ShaderBuilder::Identifier(output), access); + + shader.AddFunction("main", Nz::ShaderBuilder::ExprStatement(assign)); + + SECTION("Generating GLSL") + { + ExpectingGLSL(shader, R"( +void main() +{ + result = ubo.s.field.z; +} +)"); + } + SECTION("Generating Spir-V") + { + ExpectingSpirV(shader, R"( +OpFunction +OpLabel +OpAccessChain +OpAccessChain +OpLoad +OpCompositeExtract +OpStore +OpReturn +OpFunctionEnd)"); + } + } + + SECTION("AccessMember with multiples fields") + { + Nz::ShaderAst shader = baseShader; + + auto uniform = Nz::ShaderBuilder::Uniform("ubo", "outerStruct"); + auto output = Nz::ShaderBuilder::Output("result", Nz::ShaderNodes::BasicType::Float1); + + auto access = Nz::ShaderBuilder::Swizzle(Nz::ShaderBuilder::AccessMember(Nz::ShaderBuilder::Identifier(uniform), std::vector{ 0, 0 }, Nz::ShaderNodes::BasicType::Float3), Nz::ShaderNodes::SwizzleComponent::Third); + auto assign = Nz::ShaderBuilder::Assign(Nz::ShaderBuilder::Identifier(output), access); + + shader.AddFunction("main", Nz::ShaderBuilder::ExprStatement(assign)); + + SECTION("Generating GLSL") + { + ExpectingGLSL(shader, R"( +void main() +{ + result = ubo.s.field.z; +} +)"); + } + SECTION("Generating Spir-V") + { + ExpectingSpirV(shader, R"( +OpFunction +OpLabel +OpAccessChain +OpLoad +OpCompositeExtract +OpStore +OpReturn +OpFunctionEnd)"); + } + } + } +}