shader validation checks
This commit is contained in:
@@ -59,7 +59,7 @@ jobs:
|
|||||||
shell: powershell
|
shell: powershell
|
||||||
run: cmake --build --preset build-debug
|
run: cmake --build --preset build-debug
|
||||||
|
|
||||||
- name: Run Native Tests
|
- name: Run Native Tests And Shader Validation
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: cmake --build --preset build-debug --target RUN_TESTS
|
run: cmake --build --preset build-debug --target RUN_TESTS
|
||||||
|
|
||||||
|
|||||||
@@ -235,6 +235,29 @@ endif()
|
|||||||
|
|
||||||
add_test(NAME ShaderPackageRegistryTests COMMAND ShaderPackageRegistryTests)
|
add_test(NAME ShaderPackageRegistryTests COMMAND ShaderPackageRegistryTests)
|
||||||
|
|
||||||
|
add_executable(ShaderSlangValidationTests
|
||||||
|
"${APP_DIR}/runtime/RuntimeJson.cpp"
|
||||||
|
"${APP_DIR}/shader/ShaderCompiler.cpp"
|
||||||
|
"${APP_DIR}/shader/ShaderPackageRegistry.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/tests/ShaderSlangValidationTests.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(ShaderSlangValidationTests PRIVATE
|
||||||
|
"${APP_DIR}"
|
||||||
|
"${APP_DIR}/platform"
|
||||||
|
"${APP_DIR}/runtime"
|
||||||
|
"${APP_DIR}/shader"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(ShaderSlangValidationTests PRIVATE /W3)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_test(NAME ShaderSlangValidationTests COMMAND ShaderSlangValidationTests)
|
||||||
|
set_tests_properties(ShaderSlangValidationTests PROPERTIES
|
||||||
|
ENVIRONMENT "SLANG_ROOT=${SLANG_ROOT}"
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(OscServerTests
|
add_executable(OscServerTests
|
||||||
"${APP_DIR}/control/OscServer.cpp"
|
"${APP_DIR}/control/OscServer.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/OscServerTests.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/tests/OscServerTests.cpp"
|
||||||
|
|||||||
@@ -190,6 +190,18 @@ bool ShaderCompiler::BuildWrapperSlangSource(const ShaderPackage& shaderPackage,
|
|||||||
|
|
||||||
bool ShaderCompiler::FindSlangCompiler(std::filesystem::path& compilerPath, std::string& error) const
|
bool ShaderCompiler::FindSlangCompiler(std::filesystem::path& compilerPath, std::string& error) const
|
||||||
{
|
{
|
||||||
|
char slangRootBuffer[MAX_PATH] = {};
|
||||||
|
const DWORD slangRootLength = GetEnvironmentVariableA("SLANG_ROOT", slangRootBuffer, static_cast<DWORD>(sizeof(slangRootBuffer)));
|
||||||
|
if (slangRootLength > 0 && slangRootLength < sizeof(slangRootBuffer))
|
||||||
|
{
|
||||||
|
std::filesystem::path candidate = std::filesystem::path(slangRootBuffer) / "bin" / "slangc.exe";
|
||||||
|
if (std::filesystem::exists(candidate))
|
||||||
|
{
|
||||||
|
compilerPath = candidate;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::filesystem::path thirdPartyRoot = mRepoRoot / "3rdParty";
|
std::filesystem::path thirdPartyRoot = mRepoRoot / "3rdParty";
|
||||||
if (!std::filesystem::exists(thirdPartyRoot))
|
if (!std::filesystem::exists(thirdPartyRoot))
|
||||||
{
|
{
|
||||||
|
|||||||
106
tests/ShaderSlangValidationTests.cpp
Normal file
106
tests/ShaderSlangValidationTests.cpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#include "ShaderCompiler.h"
|
||||||
|
#include "ShaderPackageRegistry.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
int gFailures = 0;
|
||||||
|
|
||||||
|
void Fail(const std::string& message)
|
||||||
|
{
|
||||||
|
std::cerr << "FAIL: " << message << "\n";
|
||||||
|
++gFailures;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path FindRepoRoot()
|
||||||
|
{
|
||||||
|
std::filesystem::path current = std::filesystem::current_path();
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (std::filesystem::exists(current / "shaders") &&
|
||||||
|
std::filesystem::exists(current / "runtime" / "templates" / "shader_wrapper.slang.in"))
|
||||||
|
{
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!current.has_parent_path() || current.parent_path() == current)
|
||||||
|
return std::filesystem::path();
|
||||||
|
current = current.parent_path();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsExpectedInvalidPackage(const ShaderPackageStatus& status)
|
||||||
|
{
|
||||||
|
return status.id.find("broken-shader-example") != std::string::npos &&
|
||||||
|
status.error.find("Unsupported parameter type") != std::string::npos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const std::filesystem::path repoRoot = FindRepoRoot();
|
||||||
|
if (repoRoot.empty())
|
||||||
|
{
|
||||||
|
Fail("Could not locate repository root from current working directory.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, ShaderPackage> packagesById;
|
||||||
|
std::vector<std::string> packageOrder;
|
||||||
|
std::vector<ShaderPackageStatus> packageStatuses;
|
||||||
|
std::string error;
|
||||||
|
|
||||||
|
ShaderPackageRegistry registry(12);
|
||||||
|
if (!registry.Scan(repoRoot / "shaders", packagesById, packageOrder, packageStatuses, error))
|
||||||
|
{
|
||||||
|
Fail("Shader package scan failed: " + error);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ShaderPackageStatus& status : packageStatuses)
|
||||||
|
{
|
||||||
|
if (status.available || IsExpectedInvalidPackage(status))
|
||||||
|
continue;
|
||||||
|
Fail("Unexpected invalid shader package '" + status.id + "': " + status.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::filesystem::path validationRoot = repoRoot / "runtime" / "shader_validation";
|
||||||
|
const std::filesystem::path wrapperPath = validationRoot / "validation_shader_wrapper.slang";
|
||||||
|
const std::filesystem::path generatedGlslPath = validationRoot / "validation_shader.raw.frag";
|
||||||
|
const std::filesystem::path patchedGlslPath = validationRoot / "validation_shader.frag";
|
||||||
|
|
||||||
|
ShaderCompiler compiler(repoRoot, wrapperPath, generatedGlslPath, patchedGlslPath, 12);
|
||||||
|
for (const std::string& packageId : packageOrder)
|
||||||
|
{
|
||||||
|
auto packageIt = packagesById.find(packageId);
|
||||||
|
if (packageIt == packagesById.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string fragmentShaderSource;
|
||||||
|
std::string compileError;
|
||||||
|
if (!compiler.BuildLayerFragmentShaderSource(packageIt->second, fragmentShaderSource, compileError))
|
||||||
|
{
|
||||||
|
Fail("Shader package '" + packageId + "' failed Slang validation: " + compileError);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fragmentShaderSource.find("#version 430 core") == std::string::npos)
|
||||||
|
Fail("Shader package '" + packageId + "' generated GLSL without the expected patched GLSL version header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code removeError;
|
||||||
|
std::filesystem::remove_all(validationRoot, removeError);
|
||||||
|
|
||||||
|
if (gFailures != 0)
|
||||||
|
{
|
||||||
|
std::cerr << gFailures << " shader Slang validation failure(s).\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Validated " << packagesById.size() << " shader package(s) through Slang.\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user