Add a shader generation unit test

This commit is contained in:
Jérôme Leclercq 2020-08-27 19:26:59 +02:00
parent 4df7d0b4e2
commit 8fb7bb78a5
2 changed files with 146 additions and 0 deletions

View File

@ -46,5 +46,6 @@ TOOL.Libraries = {
"NazaraNetwork", "NazaraNetwork",
"NazaraPhysics2D", "NazaraPhysics2D",
"NazaraPhysics3D", "NazaraPhysics3D",
"NazaraShader",
"NazaraUtility" "NazaraUtility"
} }

View File

@ -0,0 +1,145 @@
#include <Nazara/Core/File.hpp>
#include <Nazara/Shader/GlslWriter.hpp>
#include <Nazara/Shader/ShaderAst.hpp>
#include <Nazara/Shader/ShaderBuilder.hpp>
#include <Nazara/Shader/SpirvPrinter.hpp>
#include <Nazara/Shader/SpirvWriter.hpp>
#include <Catch/catch.hpp>
#include <cctype>
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<std::size_t>{ 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)");
}
}
}
}