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 <catch2/catch.hpp>
#include <cctype> #include <cctype>
SCENARIO("Shader generation", "[Shader]") TEST_CASE("structure member access", "[Shader]")
{ {
SECTION("Nested member loading") SECTION("Nested member loading")
{ {
@ -42,14 +42,14 @@ external
multiStatement.statements.push_back(Nz::ShaderBuilder::DeclareFunction(Nz::ShaderStageType::Vertex, "main", std::move(varDecl))); multiStatement.statements.push_back(Nz::ShaderBuilder::DeclareFunction(Nz::ShaderStageType::Vertex, "main", std::move(varDecl)));
ExpectingGLSL(*shader, R"( ExpectGLSL(*shader, R"(
void main() void main()
{ {
float result = ubo.s.field.z; float result = ubo.s.field.z;
} }
)"); )");
ExpectingNZSL(*shader, R"( ExpectNZSL(*shader, R"(
[entry(vert)] [entry(vert)]
fn main() fn main()
{ {
@ -57,7 +57,7 @@ fn main()
} }
)"); )");
ExpectingSpirV(*shader, R"( ExpectSpirV(*shader, R"(
OpFunction OpFunction
OpLabel OpLabel
OpVariable OpVariable
@ -79,14 +79,14 @@ OpFunctionEnd)");
multiStatement.statements.push_back(Nz::ShaderBuilder::DeclareFunction(Nz::ShaderStageType::Vertex, "main", std::move(varDecl))); multiStatement.statements.push_back(Nz::ShaderBuilder::DeclareFunction(Nz::ShaderStageType::Vertex, "main", std::move(varDecl)));
ExpectingGLSL(*shader, R"( ExpectGLSL(*shader, R"(
void main() void main()
{ {
float result = ubo.s.field.z; float result = ubo.s.field.z;
} }
)"); )");
ExpectingNZSL(*shader, R"( ExpectNZSL(*shader, R"(
[entry(vert)] [entry(vert)]
fn main() fn main()
{ {
@ -94,7 +94,7 @@ fn main()
} }
)"); )");
ExpectingSpirV(*shader, R"( ExpectSpirV(*shader, R"(
OpFunction OpFunction
OpLabel OpLabel
OpVariable 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); expectedOutput = Nz::Trim(expectedOutput);
Nz::GlslWriter writer;
SECTION("Generating GLSL") SECTION("Generating GLSL")
{ {
Nz::GlslWriter writer;
std::string output = writer.Generate(shader); std::string output = writer.Generate(shader);
WHEN("Validating expected code") 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); expectedOutput = Nz::Trim(expectedOutput);
Nz::LangWriter writer;
SECTION("Generating NZSL") SECTION("Generating NZSL")
{ {
Nz::LangWriter writer;
std::string output = writer.Generate(shader); std::string output = writer.Generate(shader);
WHEN("Validating expected code") 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); expectedOutput = Nz::Trim(expectedOutput);
Nz::SpirvWriter writer;
Nz::SpirvPrinter printer;
Nz::SpirvPrinter::Settings settings;
settings.printHeader = false;
settings.printParameters = false;
SECTION("Generating SPIRV") SECTION("Generating SPIRV")
{ {
Nz::SpirvWriter writer;
Nz::SpirvPrinter printer;
Nz::SpirvPrinter::Settings settings;
settings.printHeader = false;
settings.printParameters = outputParameter;
auto spirv = writer.Generate(shader); auto spirv = writer.Generate(shader);
std::string output = printer.Print(spirv.data(), spirv.size(), settings); std::string output = printer.Print(spirv.data(), spirv.size(), settings);

View File

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