UnitTests: Add a lot of shader generation tests

This commit is contained in:
Jérôme Leclercq 2021-12-25 19:13:32 +01:00
parent f98ea6b0ca
commit b9642b0662
6 changed files with 483 additions and 24 deletions

View File

@ -6,7 +6,7 @@
#include <catch2/catch.hpp>
#include <cctype>
SCENARIO("Shader generation", "[Shader]")
TEST_CASE("structure member access", "[Shader]")
{
SECTION("Nested member loading")
{
@ -42,14 +42,14 @@ external
multiStatement.statements.push_back(Nz::ShaderBuilder::DeclareFunction(Nz::ShaderStageType::Vertex, "main", std::move(varDecl)));
ExpectingGLSL(*shader, R"(
ExpectGLSL(*shader, R"(
void main()
{
float result = ubo.s.field.z;
}
)");
ExpectingNZSL(*shader, R"(
ExpectNZSL(*shader, R"(
[entry(vert)]
fn main()
{
@ -57,7 +57,7 @@ fn main()
}
)");
ExpectingSpirV(*shader, R"(
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable
@ -79,14 +79,14 @@ OpFunctionEnd)");
multiStatement.statements.push_back(Nz::ShaderBuilder::DeclareFunction(Nz::ShaderStageType::Vertex, "main", std::move(varDecl)));
ExpectingGLSL(*shader, R"(
ExpectGLSL(*shader, R"(
void main()
{
float result = ubo.s.field.z;
}
)");
ExpectingNZSL(*shader, R"(
ExpectNZSL(*shader, R"(
[entry(vert)]
fn main()
{
@ -94,7 +94,7 @@ fn main()
}
)");
ExpectingSpirV(*shader, R"(
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable

View File

@ -0,0 +1,86 @@
#include <Engine/Shader/ShaderUtils.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/StringExt.hpp>
#include <Nazara/Shader/ShaderBuilder.hpp>
#include <Nazara/Shader/ShaderLangParser.hpp>
#include <catch2/catch.hpp>
#include <cctype>
TEST_CASE("branching", "[Shader]")
{
std::string_view nzslSource = R"(
struct inputStruct
{
value: f32
}
external
{
[set(0), binding(0)] data: uniform<inputStruct>
}
[entry(frag)]
fn main()
{
let value: f32;
if (data.value > 0.0)
value = 1.0;
else
value = 0.0;
}
)";
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
ExpectGLSL(*shader, R"(
void main()
{
float value;
if (data.value > (0.000000))
{
value = 1.000000;
}
else
{
value = 0.000000;
}
}
)");
ExpectNZSL(*shader, R"(
[entry(frag)]
fn main()
{
let value: f32;
if (data.value > (0.000000))
{
value = 1.000000;
}
else
{
value = 0.000000;
}
}
)");
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable
OpAccessChain
OpLoad
OpFOrdGreaterThanEqual
OpSelectionMerge
OpBranchConditional
OpLabel
OpStore
OpBranch
OpLabel
OpStore
OpBranch
OpLabel
OpReturn
OpFunctionEnd)");
}

View File

@ -0,0 +1,90 @@
#include <Engine/Shader/ShaderUtils.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/StringExt.hpp>
#include <Nazara/Shader/ShaderBuilder.hpp>
#include <Nazara/Shader/ShaderLangParser.hpp>
#include <catch2/catch.hpp>
#include <cctype>
TEST_CASE("loops", "[Shader]")
{
std::string_view nzslSource = R"(
struct inputStruct
{
value: f32
}
external
{
[set(0), binding(0)] data: uniform<inputStruct>
}
[entry(frag)]
fn main()
{
let value = 0.0;
let i = 0;
while (i < 10)
{
value += 0.1;
i += 1;
}
}
)";
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
ExpectGLSL(*shader, R"(
void main()
{
float value = 0.000000;
int i = 0;
while (i < (10))
{
value += 0.100000;
i += 1;
}
}
)");
ExpectNZSL(*shader, R"(
[entry(frag)]
fn main()
{
let value: f32 = 0.000000;
let i: i32 = 0;
while (i < (10))
{
value += 0.100000;
i += 1;
}
}
)");
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable
OpVariable
OpStore
OpStore
OpBranch
OpLabel
OpLoad
OpSLessThan
OpLoopMerge
OpBranchConditional
OpLabel
OpLoad
OpFAdd
OpStore
OpLoad
OpIAdd
OpStore
OpBranch
OpLabel
OpReturn
OpFunctionEnd)");
}

View File

@ -120,14 +120,13 @@ namespace
};
}
void ExpectingGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput)
void ExpectGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput)
{
expectedOutput = Nz::Trim(expectedOutput);
Nz::GlslWriter writer;
SECTION("Generating GLSL")
{
Nz::GlslWriter writer;
std::string output = writer.Generate(shader);
WHEN("Validating expected code")
@ -156,14 +155,13 @@ void ExpectingGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOu
}
}
void ExpectingNZSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput)
void ExpectNZSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput)
{
expectedOutput = Nz::Trim(expectedOutput);
Nz::LangWriter writer;
SECTION("Generating NZSL")
{
Nz::LangWriter writer;
std::string output = writer.Generate(shader);
WHEN("Validating expected code")
@ -180,19 +178,19 @@ void ExpectingNZSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOu
}
}
void ExpectingSpirV(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput)
void ExpectSpirV(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput, bool outputParameter)
{
expectedOutput = Nz::Trim(expectedOutput);
Nz::SpirvWriter writer;
Nz::SpirvPrinter printer;
Nz::SpirvPrinter::Settings settings;
settings.printHeader = false;
settings.printParameters = false;
SECTION("Generating SPIRV")
{
Nz::SpirvWriter writer;
Nz::SpirvPrinter printer;
Nz::SpirvPrinter::Settings settings;
settings.printHeader = false;
settings.printParameters = outputParameter;
auto spirv = writer.Generate(shader);
std::string output = printer.Print(spirv.data(), spirv.size(), settings);

View File

@ -6,8 +6,8 @@
#include <Nazara/Shader/Ast/Nodes.hpp>
#include <string>
void ExpectingGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput);
void ExpectingNZSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput);
void ExpectingSpirV(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput);
void ExpectGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput);
void ExpectNZSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput);
void ExpectSpirV(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput, bool outputParameter = false);
#endif

View File

@ -0,0 +1,285 @@
#include <Engine/Shader/ShaderUtils.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/StringExt.hpp>
#include <Nazara/Shader/ShaderBuilder.hpp>
#include <Nazara/Shader/ShaderLangParser.hpp>
#include <catch2/catch.hpp>
#include <cctype>
TEST_CASE("swizzle", "[Shader]")
{
SECTION("Simple swizzle")
{
WHEN("reading")
{
std::string_view nzslSource = R"(
[entry(frag)]
fn main()
{
let vec = vec4<f32>(0.0, 1.0, 2.0, 3.0);
let value = vec.xyz;
}
)";
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
ExpectGLSL(*shader, R"(
void main()
{
vec4 vec = vec4(0.000000, 1.000000, 2.000000, 3.000000);
vec3 value = vec.xyz;
}
)");
ExpectNZSL(*shader, R"(
[entry(frag)]
fn main()
{
let vec: vec4<f32> = vec4<f32>(0.000000, 1.000000, 2.000000, 3.000000);
let value: vec3<f32> = vec.xyz;
}
)");
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable
OpVariable
OpCompositeConstruct
OpStore
OpLoad
OpVectorShuffle
OpStore
OpReturn
OpFunctionEnd)");
}
WHEN("writing")
{
std::string_view nzslSource = R"(
[entry(frag)]
fn main()
{
let vec = vec4<f32>(0.0, 0.0, 0.0, 0.0);
vec.yzw = vec3<f32>(1.0, 2.0, 3.0);
}
)";
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
ExpectGLSL(*shader, R"(
void main()
{
vec4 vec = vec4(0.000000, 0.000000, 0.000000, 0.000000);
vec.yzw = vec3(1.000000, 2.000000, 3.000000);
}
)");
ExpectNZSL(*shader, R"(
[entry(frag)]
fn main()
{
let vec: vec4<f32> = vec4<f32>(0.000000, 0.000000, 0.000000, 0.000000);
vec.yzw = vec3<f32>(1.000000, 2.000000, 3.000000);
}
)");
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable
OpCompositeConstruct
OpStore
OpCompositeConstruct
OpLoad
OpVectorShuffle
OpStore
OpReturn
OpFunctionEnd)");
}
}
SECTION("Scalar swizzle")
{
GIVEN("a variable")
{
std::string_view nzslSource = R"(
[entry(frag)]
fn main()
{
let value = 42.0;
let vec = value.xxx;
}
)";
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
ExpectGLSL(*shader, R"(
void main()
{
float value = 42.000000;
vec3 vec = vec3(value, value, value);
}
)");
ExpectNZSL(*shader, R"(
[entry(frag)]
fn main()
{
let value: f32 = 42.000000;
let vec: vec3<f32> = value.xxx;
}
)");
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable
OpVariable
OpStore
OpLoad
OpCompositeConstruct
OpStore
OpReturn
OpFunctionEnd)");
}
GIVEN("a function value")
{
std::string_view nzslSource = R"(
[entry(frag)]
fn main()
{
let vec = max(2.0, 1.0).xxx;
}
)";
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
ExpectGLSL(*shader, R"(
void main()
{
float cachedResult = max(2.000000, 1.000000);
vec3 vec = vec3(cachedResult, cachedResult, cachedResult);
}
)");
ExpectNZSL(*shader, R"(
[entry(frag)]
fn main()
{
let vec: vec3<f32> = (max(2.000000, 1.000000)).xxx;
}
)");
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable
OpExtInst
OpCompositeConstruct
OpStore
OpReturn
OpFunctionEnd)");
}
}
SECTION("Complex swizzle")
{
WHEN("reading")
{
std::string_view nzslSource = R"(
[entry(frag)]
fn main()
{
let vec = vec4<f32>(0.0, 1.0, 2.0, 3.0);
let value = vec.xyz.yz.y.x.xxxx;
}
)";
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
ExpectGLSL(*shader, R"(
void main()
{
vec4 vec = vec4(0.000000, 1.000000, 2.000000, 3.000000);
vec4 value = vec4(vec.xyz.yz.y, vec.xyz.yz.y, vec.xyz.yz.y, vec.xyz.yz.y);
}
)");
ExpectNZSL(*shader, R"(
[entry(frag)]
fn main()
{
let vec: vec4<f32> = vec4<f32>(0.000000, 1.000000, 2.000000, 3.000000);
let value: vec4<f32> = vec.xyz.yz.y.x.xxxx;
}
)");
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable
OpVariable
OpCompositeConstruct
OpStore
OpLoad
OpVectorShuffle
OpVectorShuffle
OpCompositeExtract
OpCompositeConstruct
OpStore
OpReturn
OpFunctionEnd)");
}
WHEN("writing")
{
std::string_view nzslSource = R"(
[entry(frag)]
fn main()
{
let vec = vec4<f32>(0.0, 1.0, 2.0, 3.0);
vec.wyxz.bra.ts.x = 0.0;
vec.zyxw.ar.xy.yx = vec2<f32>(1.0, 0.0);
}
)";
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
ExpectGLSL(*shader, R"(
void main()
{
vec4 vec = vec4(0.000000, 1.000000, 2.000000, 3.000000);
vec.wyxz.zxw.yx.x = 0.000000;
vec.zyxw.wx.xy.yx = vec2(1.000000, 0.000000);
}
)");
ExpectNZSL(*shader, R"(
[entry(frag)]
fn main()
{
let vec: vec4<f32> = vec4<f32>(0.000000, 1.000000, 2.000000, 3.000000);
vec.wyxz.zxw.yx.x = 0.000000;
vec.zyxw.wx.xy.yx = vec2<f32>(1.000000, 0.000000);
}
)");
ExpectSpirV(*shader, R"(
OpFunction
OpLabel
OpVariable
OpCompositeConstruct
OpStore
OpAccessChain
OpStore
OpCompositeConstruct
OpLoad
OpVectorShuffle
OpStore
OpReturn
OpFunctionEnd)");
}
}
}