UnitTests: Use glslang to validate GLSL shaders
This commit is contained in:
parent
3e708cf5ed
commit
f798901c23
|
|
@ -41,7 +41,7 @@ namespace Nz
|
|||
ExtSupportCallback extCallback;
|
||||
unsigned int glMajorVersion = 3;
|
||||
unsigned int glMinorVersion = 0;
|
||||
bool glES = false;
|
||||
bool glES = true;
|
||||
bool flipYPosition = false;
|
||||
bool remapZPosition = false;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include <Nazara/Shader/ShaderBuilder.hpp>
|
||||
#include <Nazara/Shader/ShaderLangParser.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
#include <spirv-tools/libspirv.hpp>
|
||||
#include <cctype>
|
||||
|
||||
SCENARIO("Shader generation", "[Shader]")
|
||||
|
|
|
|||
|
|
@ -6,8 +6,120 @@
|
|||
#include <Nazara/Shader/SpirvPrinter.hpp>
|
||||
#include <Nazara/Shader/SpirvWriter.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
#include <glslang/Public/ShaderLang.h>
|
||||
#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)
|
||||
{
|
||||
expectedOutput = Nz::Trim(expectedOutput);
|
||||
|
|
@ -18,8 +130,29 @@ void ExpectingGLSL(Nz::ShaderAst::Statement& shader, std::string_view expectedOu
|
|||
{
|
||||
std::string output = writer.Generate(shader);
|
||||
|
||||
INFO("full GLSL output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
||||
REQUIRE(output.find(expectedOutput) != std::string::npos);
|
||||
WHEN("Validating expected code")
|
||||
{
|
||||
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);
|
||||
|
||||
INFO("full NZSL output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
||||
REQUIRE(output.find(expectedOutput) != std::string::npos);
|
||||
WHEN("Validating expected code")
|
||||
{
|
||||
INFO("full NZSL output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
||||
REQUIRE(output.find(expectedOutput) != std::string::npos);
|
||||
}
|
||||
|
||||
// validate NZSL by recompiling it
|
||||
REQUIRE_NOTHROW(Nz::ShaderLang::Parse(output));
|
||||
WHEN("Validating full NZSL code (by recompiling it)")
|
||||
{
|
||||
// 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);
|
||||
std::string output = printer.Print(spirv.data(), spirv.size(), settings);
|
||||
|
||||
INFO("full SPIRV output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
||||
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)
|
||||
WHEN("Validating expected code")
|
||||
{
|
||||
std::string fullSpirv;
|
||||
if (!spirvTools.Disassemble(spirv, &fullSpirv))
|
||||
fullSpirv = "<failed to disassemble SPIRV>";
|
||||
INFO("full SPIRV output:\n" << output << "\nexcepted output:\n" << expectedOutput);
|
||||
REQUIRE(output.find(expectedOutput) != std::string::npos);
|
||||
}
|
||||
|
||||
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/Physics2D/Physics2D.hpp>
|
||||
#include <Nazara/Shader/Shader.hpp>
|
||||
#include <glslang/Public/ShaderLang.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Nz::Modules<Nz::Network, Nz::Physics2D, Nz::Shader> nazaza;
|
||||
|
||||
if (!glslang::InitializeProcess())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
int result = Catch::Session().run(argc, argv);
|
||||
|
||||
glslang::FinalizeProcess();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ if is_mode("asan") then
|
|||
add_defines("CATCH_CONFIG_NO_POSIX_SIGNALS")
|
||||
end
|
||||
|
||||
add_requires("catch2", "spirv-tools")
|
||||
add_requires("catch2", "glslang", "spirv-tools")
|
||||
|
||||
-- Common config
|
||||
set_group("Tests")
|
||||
set_kind("binary")
|
||||
|
||||
add_deps("NazaraCore", "NazaraNetwork", "NazaraPhysics2D", "NazaraShader")
|
||||
add_packages("catch2", "spirv-tools")
|
||||
add_packages("catch2", "glslang", "spirv-tools")
|
||||
add_headerfiles("Engine/**.hpp")
|
||||
add_files("resources.cpp")
|
||||
add_files("Engine/**.cpp")
|
||||
|
|
|
|||
Loading…
Reference in New Issue