UnitTests: Use glslang to validate GLSL shaders

This commit is contained in:
Jérôme Leclercq 2021-12-24 14:54:35 +01:00
parent 3e708cf5ed
commit f798901c23
5 changed files with 172 additions and 22 deletions

View File

@ -41,7 +41,7 @@ namespace Nz
ExtSupportCallback extCallback; ExtSupportCallback extCallback;
unsigned int glMajorVersion = 3; unsigned int glMajorVersion = 3;
unsigned int glMinorVersion = 0; unsigned int glMinorVersion = 0;
bool glES = false; bool glES = true;
bool flipYPosition = false; bool flipYPosition = false;
bool remapZPosition = false; bool remapZPosition = false;
}; };

View File

@ -4,7 +4,6 @@
#include <Nazara/Shader/ShaderBuilder.hpp> #include <Nazara/Shader/ShaderBuilder.hpp>
#include <Nazara/Shader/ShaderLangParser.hpp> #include <Nazara/Shader/ShaderLangParser.hpp>
#include <catch2/catch.hpp> #include <catch2/catch.hpp>
#include <spirv-tools/libspirv.hpp>
#include <cctype> #include <cctype>
SCENARIO("Shader generation", "[Shader]") SCENARIO("Shader generation", "[Shader]")

View File

@ -6,8 +6,120 @@
#include <Nazara/Shader/SpirvPrinter.hpp> #include <Nazara/Shader/SpirvPrinter.hpp>
#include <Nazara/Shader/SpirvWriter.hpp> #include <Nazara/Shader/SpirvWriter.hpp>
#include <catch2/catch.hpp> #include <catch2/catch.hpp>
#include <glslang/Public/ShaderLang.h>
#include <spirv-tools/libspirv.hpp> #include <spirv-tools/libspirv.hpp>
namespace
{
// Use OpenGL default minimal values (from https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glGet.xhtml, https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGet.xhtml and https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/)
const TBuiltInResource s_minResources = {
8, //< maxLights
6, //< maxClipPlanes
32, //< maxTextureUnits
32, //< maxTextureCoords
16, //< maxVertexAttribs
1024, //< maxVertexUniformComponents
60, //< maxVaryingFloats
16, //< maxVertexTextureImageUnits
32, //< maxCombinedTextureImageUnits
16, //< maxTextureImageUnits
896, //< maxFragmentUniformComponents
4, //< maxDrawBuffers
256, //< maxVertexUniformVectors
15, //< maxVaryingVectors
224, //< maxFragmentUniformVectors
256, //< maxVertexOutputVectors
224, //< maxFragmentInputVectors
-8, //< minProgramTexelOffset
7, //< maxProgramTexelOffset
8, //< maxClipDistances
0xFFFF, //< maxComputeWorkGroupCountX
0xFFFF, //< maxComputeWorkGroupCountY
0xFFFF, //< maxComputeWorkGroupCountZ
1024, //< maxComputeWorkGroupSizeX
1024, //< maxComputeWorkGroupSizeY
64, //< maxComputeWorkGroupSizeZ
1024, //< maxComputeUniformComponents
16, //< maxComputeTextureImageUnits
8, //< maxComputeImageUniforms
8, //< maxComputeAtomicCounters
1, //< maxComputeAtomicCounterBuffers
60, //< maxVaryingComponents
64, //< maxVertexOutputComponents
64, //< maxGeometryInputComponents
128, //< maxGeometryOutputComponents
128, //< maxFragmentInputComponents
8, //< maxImageUnits
8, //< maxCombinedImageUnitsAndFragmentOutputs
8, //< maxCombinedShaderOutputResources
0, //< maxImageSamples
0, //< maxVertexImageUniforms
0, //< maxTessControlImageUniforms
0, //< maxTessEvaluationImageUniforms
0, //< maxGeometryImageUniforms
8, //< maxFragmentImageUniforms
8, //< maxCombinedImageUniforms
16, //< maxGeometryTextureImageUnits
256, //< maxGeometryOutputVertices
1024, //< maxGeometryTotalOutputComponents
1024, //< maxGeometryUniformComponents
64, //< maxGeometryVaryingComponents
128, //< maxTessControlInputComponents
128, //< maxTessControlOutputComponents
16, //< maxTessControlTextureImageUnits
1024, //< maxTessControlUniformComponents
4096, //< maxTessControlTotalOutputComponents
128, //< maxTessEvaluationInputComponents
128, //< maxTessEvaluationOutputComponents
16, //< maxTessEvaluationTextureImageUnits
1024, //< maxTessEvaluationUniformComponents
120, //< maxTessPatchComponents
32, //< maxPatchVertices
64, //< maxTessGenLevel
16, //< maxViewports
0, //< maxVertexAtomicCounters
0, //< maxTessControlAtomicCounters
0, //< maxTessEvaluationAtomicCounters
0, //< maxGeometryAtomicCounters
8, //< maxFragmentAtomicCounters
8, //< maxCombinedAtomicCounters
1, //< maxAtomicCounterBindings
0, //< maxVertexAtomicCounterBuffers
0, //< maxTessControlAtomicCounterBuffers
0, //< maxTessEvaluationAtomicCounterBuffers
0, //< maxGeometryAtomicCounterBuffers
1, //< maxFragmentAtomicCounterBuffers
1, //< maxCombinedAtomicCounterBuffers
16384, //< maxAtomicCounterBufferSize
4, //< maxTransformFeedbackBuffers
64, //< maxTransformFeedbackInterleavedComponents
8, //< maxCullDistances
8, //< maxCombinedClipAndCullDistances
4, //< maxSamples
256, //< maxMeshOutputVerticesNV
512, //< maxMeshOutputPrimitivesNV
32, //< maxMeshWorkGroupSizeX_NV
1, //< maxMeshWorkGroupSizeY_NV
1, //< maxMeshWorkGroupSizeZ_NV
32, //< maxTaskWorkGroupSizeX_NV
1, //< maxTaskWorkGroupSizeY_NV
1, //< maxTaskWorkGroupSizeZ_NV
4, //< maxMeshViewCountNV
1, //< maxDualSourceDrawBuffersEXT
{ //< limits
true, //< nonInductiveForLoops
true, //< whileLoops
true, //< doWhileLoops
true, //< generalUniformIndexing
true, //< generalAttributeMatrixVectorIndexing
true, //< generalVaryingIndexing
true, //< generalSamplerIndexing
true, //< generalVariableIndexing
true, //< generalConstantMatrixVectorIndexing
}
};
}
void ExpectingGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput) void ExpectingGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput)
{ {
expectedOutput = Nz::Trim(expectedOutput); expectedOutput = Nz::Trim(expectedOutput);
@ -18,9 +130,30 @@ void ExpectingGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOu
{ {
std::string output = writer.Generate(shader); std::string output = writer.Generate(shader);
WHEN("Validating expected code")
{
INFO("full GLSL output:\n" << output << "\nexcepted output:\n" << expectedOutput); INFO("full GLSL output:\n" << output << "\nexcepted output:\n" << expectedOutput);
REQUIRE(output.find(expectedOutput) != std::string::npos); REQUIRE(output.find(expectedOutput) != std::string::npos);
} }
WHEN("Validating full GLSL code (using glslang)")
{
glslang::TShader shader(EShLangVertex);
shader.setEnvInput(glslang::EShSourceGlsl, EShLangVertex, glslang::EShClientOpenGL, 300);
shader.setEnvClient(glslang::EShClientOpenGL, glslang::EShTargetOpenGL_450);
shader.setEnvTarget(glslang::EShTargetNone, static_cast<glslang::EShTargetLanguageVersion>(0));
shader.setEntryPoint("main");
const char* source = output.c_str();
shader.setStrings(&source, 1);
if (!shader.parse(&s_minResources, 100, false, static_cast<EShMessages>(EShMsgDefault | EShMsgKeepUncalled)))
{
INFO("full GLSL output:\n" << output << "\nerror:\n" << shader.getInfoLog());
REQUIRE(false);
}
}
}
} }
void ExpectingNZSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput) void ExpectingNZSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput)
@ -33,12 +166,18 @@ void ExpectingNZSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOu
{ {
std::string output = writer.Generate(shader); std::string output = writer.Generate(shader);
WHEN("Validating expected code")
{
INFO("full NZSL output:\n" << output << "\nexcepted output:\n" << expectedOutput); INFO("full NZSL output:\n" << output << "\nexcepted output:\n" << expectedOutput);
REQUIRE(output.find(expectedOutput) != std::string::npos); REQUIRE(output.find(expectedOutput) != std::string::npos);
}
WHEN("Validating full NZSL code (by recompiling it)")
{
// validate NZSL by recompiling it // validate NZSL by recompiling it
REQUIRE_NOTHROW(Nz::ShaderLang::Parse(output)); REQUIRE_NOTHROW(Nz::ShaderLang::Parse(output));
} }
}
} }
void ExpectingSpirV(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput) void ExpectingSpirV(Nz::ShaderAst::Statement& shader, std::string_view expectedOutput)
@ -57,9 +196,14 @@ void ExpectingSpirV(Nz::ShaderAst::Statement& shader, std::string_view expectedO
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);
WHEN("Validating expected code")
{
INFO("full SPIRV output:\n" << output << "\nexcepted output:\n" << expectedOutput); INFO("full SPIRV output:\n" << output << "\nexcepted output:\n" << expectedOutput);
REQUIRE(output.find(expectedOutput) != std::string::npos); REQUIRE(output.find(expectedOutput) != std::string::npos);
}
WHEN("Validating full SPIRV code (using libspirv)")
{
// validate SPIRV with libspirv // validate SPIRV with libspirv
spvtools::SpirvTools spirvTools(spv_target_env::SPV_ENV_VULKAN_1_0); spvtools::SpirvTools spirvTools(spv_target_env::SPV_ENV_VULKAN_1_0);
spirvTools.SetMessageConsumer([&](spv_message_level_t /*level*/, const char* /*source*/, const spv_position_t& /*position*/, const char* message) spirvTools.SetMessageConsumer([&](spv_message_level_t /*level*/, const char* /*source*/, const spv_position_t& /*position*/, const char* message)
@ -73,4 +217,5 @@ void ExpectingSpirV(Nz::ShaderAst::Statement& shader, std::string_view expectedO
REQUIRE(spirvTools.Validate(spirv)); REQUIRE(spirvTools.Validate(spirv));
} }
}
} }

View File

@ -7,12 +7,18 @@
#include <Nazara/Network/Network.hpp> #include <Nazara/Network/Network.hpp>
#include <Nazara/Physics2D/Physics2D.hpp> #include <Nazara/Physics2D/Physics2D.hpp>
#include <Nazara/Shader/Shader.hpp> #include <Nazara/Shader/Shader.hpp>
#include <glslang/Public/ShaderLang.h>
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
Nz::Modules<Nz::Network, Nz::Physics2D, Nz::Shader> nazaza; Nz::Modules<Nz::Network, Nz::Physics2D, Nz::Shader> nazaza;
if (!glslang::InitializeProcess())
return EXIT_FAILURE;
int result = Catch::Session().run(argc, argv); int result = Catch::Session().run(argc, argv);
glslang::FinalizeProcess();
return result; return result;
} }

View File

@ -3,14 +3,14 @@ if is_mode("asan") then
add_defines("CATCH_CONFIG_NO_POSIX_SIGNALS") add_defines("CATCH_CONFIG_NO_POSIX_SIGNALS")
end end
add_requires("catch2", "spirv-tools") add_requires("catch2", "glslang", "spirv-tools")
-- Common config -- Common config
set_group("Tests") set_group("Tests")
set_kind("binary") set_kind("binary")
add_deps("NazaraCore", "NazaraNetwork", "NazaraPhysics2D", "NazaraShader") add_deps("NazaraCore", "NazaraNetwork", "NazaraPhysics2D", "NazaraShader")
add_packages("catch2", "spirv-tools") add_packages("catch2", "glslang", "spirv-tools")
add_headerfiles("Engine/**.hpp") add_headerfiles("Engine/**.hpp")
add_files("resources.cpp") add_files("resources.cpp")
add_files("Engine/**.cpp") add_files("Engine/**.cpp")