From fe9939689d2af5dd9032301e5328b265d7c642cc Mon Sep 17 00:00:00 2001 From: Wunk Date: Mon, 11 Mar 2024 17:29:58 -0700 Subject: [PATCH] Add shader-jit unit-tests (#458) * Rename `dynapica` TU to `shader` These unit-tests in particular only actually test the shader-interpreter and not any of the JITs. * Conditionally test the shader-jit In the case that the host supports the shader-jit, the interpreter and the shader-jit will both be tested with the same unit-tests. Allowing for even more coverage. * Remove weird git submodule --- CMakeLists.txt | 2 +- tests/{dynapica.cpp => shader.cpp} | 84 ++++++++++++++++++++---------- 2 files changed, 58 insertions(+), 28 deletions(-) rename tests/{dynapica.cpp => shader.cpp} (75%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 629601ab..fe9a8584 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -534,7 +534,7 @@ if(ENABLE_TESTS) target_include_directories(nihstro-headers SYSTEM INTERFACE ./third_party/nihstro/include) add_executable(AlberTests - tests/dynapica.cpp + tests/shader.cpp ) target_link_libraries( AlberTests diff --git a/tests/dynapica.cpp b/tests/shader.cpp similarity index 75% rename from tests/dynapica.cpp rename to tests/shader.cpp index 32e7bdb0..2116549d 100644 --- a/tests/dynapica.cpp +++ b/tests/shader.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -27,12 +28,12 @@ static std::unique_ptr assembleVertexShader(std::initializer_list shader; + std::unique_ptr shader = {}; public: - explicit VertexShaderTest(std::initializer_list code) : shader(assembleVertexShader(code)) {} + explicit ShaderInterpreterTest(std::initializer_list code) : shader(assembleVertexShader(code)) {} // Multiple inputs, singular scalar output float runScalar(std::initializer_list inputs) { @@ -45,13 +46,42 @@ class VertexShaderTest { return shader->outputs[0][0]; } - static std::unique_ptr assembleTest(std::initializer_list code) { - return std::make_unique(code); + static std::unique_ptr assembleTest(std::initializer_list code) { + return std::make_unique(code); } }; -TEST_CASE("ADD", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +#if defined(PANDA3DS_SHADER_JIT_SUPPORTED) +class ShaderJITTest final { + private: + std::unique_ptr shader = {}; + ShaderJIT shaderJit = {}; + + public: + explicit ShaderJITTest(std::initializer_list code) : shader(assembleVertexShader(code)) { shaderJit.prepare(*shader.get()); } + + // Multiple inputs, singular scalar output + float runScalar(std::initializer_list inputs) { + usize inputIndex = 0; + for (const float& input : inputs) { + const std::array input_vec = std::array{f24::fromFloat32(input), f24::zero(), f24::zero(), f24::zero()}; + shader->inputs[inputIndex++] = input_vec; + } + shaderJit.run(*shader.get()); + return shader->outputs[0][0]; + } + + static std::unique_ptr assembleTest(std::initializer_list code) { + return std::make_unique(code); + } +}; +#define SHADER_TEST_CASE(NAME, TAG) TEMPLATE_TEST_CASE(NAME, TAG, ShaderInterpreterTest, ShaderJITTest) +#else +#define SHADER_TEST_CASE(NAME, TAG) TEMPLATE_TEST_CASE(NAME, TAG, ShaderInterpreterTest) +#endif + +SHADER_TEST_CASE("ADD", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::ADD, output0, input0, input1}, {nihstro::OpCode::Id::END}, }); @@ -63,8 +93,8 @@ TEST_CASE("ADD", "[shader][vertex]") { REQUIRE(std::isinf(shader->runScalar({INFINITY, -1.0f}))); } -TEST_CASE("MUL", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("MUL", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::MUL, output0, input0, input1}, {nihstro::OpCode::Id::END}, }); @@ -77,8 +107,8 @@ TEST_CASE("MUL", "[shader][vertex]") { REQUIRE(std::isnan(shader->runScalar({NAN, 0.0f}))); } -TEST_CASE("RCP", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("RCP", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::RCP, output0, input0}, {nihstro::OpCode::Id::END}, }); @@ -99,8 +129,8 @@ TEST_CASE("RCP", "[shader][vertex]") { REQUIRE(shader->runScalar({0.0625f}) == Catch::Approx(16.0f).margin(0.004f)); } -TEST_CASE("RSQ", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("RSQ", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::RSQ, output0, input0}, {nihstro::OpCode::Id::END}, }); @@ -121,8 +151,8 @@ TEST_CASE("RSQ", "[shader][vertex]") { REQUIRE(shader->runScalar({0.0625f}) == Catch::Approx(4.0f).margin(0.004f)); } -TEST_CASE("LG2", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("LG2", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::LG2, output0, input0}, {nihstro::OpCode::Id::END}, }); @@ -135,8 +165,8 @@ TEST_CASE("LG2", "[shader][vertex]") { REQUIRE(shader->runScalar({1.e24f}) == Catch::Approx(79.7262742773f)); } -TEST_CASE("EX2", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("EX2", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::EX2, output0, input0}, {nihstro::OpCode::Id::END}, }); @@ -150,8 +180,8 @@ TEST_CASE("EX2", "[shader][vertex]") { REQUIRE(std::isinf(shader->runScalar({800.f}))); } -TEST_CASE("MAX", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("MAX", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::MAX, output0, input0, input1}, {nihstro::OpCode::Id::END}, }); @@ -165,8 +195,8 @@ TEST_CASE("MAX", "[shader][vertex]") { REQUIRE(std::isnan(shader->runScalar({0.0f, NAN}))); } -TEST_CASE("MIN", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("MIN", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::MIN, output0, input0, input1}, {nihstro::OpCode::Id::END}, }); @@ -180,8 +210,8 @@ TEST_CASE("MIN", "[shader][vertex]") { REQUIRE(std::isnan(shader->runScalar({0.0f, NAN}))); } -TEST_CASE("SGE", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("SGE", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::SGE, output0, input0, input1}, {nihstro::OpCode::Id::END}, }); @@ -197,8 +227,8 @@ TEST_CASE("SGE", "[shader][vertex]") { REQUIRE(shader->runScalar({-1.0f, +1.0f}) == 0.0f); } -TEST_CASE("SLT", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("SLT", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::SLT, output0, input0, input1}, {nihstro::OpCode::Id::END}, }); @@ -214,8 +244,8 @@ TEST_CASE("SLT", "[shader][vertex]") { REQUIRE(shader->runScalar({-1.0f, +1.0f}) == 1.0f); } -TEST_CASE("FLR", "[shader][vertex]") { - const auto shader = VertexShaderTest::assembleTest({ +SHADER_TEST_CASE("FLR", "[shader][vertex]") { + const auto shader = TestType::assembleTest({ {nihstro::OpCode::Id::FLR, output0, input0}, {nihstro::OpCode::Id::END}, });