UnitTests: Use glslang to validate GLSL shaders
This commit is contained in:
parent
3e708cf5ed
commit
f798901c23
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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]")
|
||||||
|
|
|
||||||
|
|
@ -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,8 +130,29 @@ void ExpectingGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOu
|
||||||
{
|
{
|
||||||
std::string output = writer.Generate(shader);
|
std::string output = writer.Generate(shader);
|
||||||
|
|
||||||
INFO("full GLSL output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
WHEN("Validating expected code")
|
||||||
REQUIRE(output.find(expectedOutput) != std::string::npos);
|
{
|
||||||
|
INFO("full GLSL output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,11 +166,17 @@ void ExpectingNZSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOu
|
||||||
{
|
{
|
||||||
std::string output = writer.Generate(shader);
|
std::string output = writer.Generate(shader);
|
||||||
|
|
||||||
INFO("full NZSL output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
WHEN("Validating expected code")
|
||||||
REQUIRE(output.find(expectedOutput) != std::string::npos);
|
{
|
||||||
|
INFO("full NZSL output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
||||||
|
REQUIRE(output.find(expectedOutput) != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
// validate NZSL by recompiling it
|
WHEN("Validating full NZSL code (by recompiling it)")
|
||||||
REQUIRE_NOTHROW(Nz::ShaderLang::Parse(output));
|
{
|
||||||
|
// validate NZSL by recompiling it
|
||||||
|
REQUIRE_NOTHROW(Nz::ShaderLang::Parse(output));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,20 +196,26 @@ 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);
|
||||||
|
|
||||||
INFO("full SPIRV output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
WHEN("Validating expected code")
|
||||||
REQUIRE(output.find(expectedOutput) != std::string::npos);
|
|
||||||
|
|
||||||
// validate SPIRV with libspirv
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
std::string fullSpirv;
|
INFO("full SPIRV output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
||||||
if (!spirvTools.Disassemble(spirv, &fullSpirv))
|
REQUIRE(output.find(expectedOutput) != std::string::npos);
|
||||||
fullSpirv = "<failed to disassemble SPIRV>";
|
}
|
||||||
|
|
||||||
UNSCOPED_INFO(fullSpirv + "\n" + message);
|
WHEN("Validating full SPIRV code (using libspirv)")
|
||||||
});
|
{
|
||||||
|
// validate SPIRV with libspirv
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
std::string fullSpirv;
|
||||||
|
if (!spirvTools.Disassemble(spirv, &fullSpirv))
|
||||||
|
fullSpirv = "<failed to disassemble SPIRV>";
|
||||||
|
|
||||||
REQUIRE(spirvTools.Validate(spirv));
|
UNSCOPED_INFO(fullSpirv + "\n" + message);
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(spirvTools.Validate(spirv));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue