7.1 KiB
Mega-Strict Shader Pipeline Validation
Overview
This system provides comprehensive validation of shader pipelines BEFORE they reach the GPU driver, preventing system crashes from malformed shader state.
Architecture
1. Runtime C++ Validator (shader_pipeline_validator.hpp/cpp)
Location: src/services/impl/shader_pipeline_validator.*
Purpose: Validates shader pipelines at runtime before compilation
Checks Performed:
- ✅ Vertex layout matches shader input expectations
- ✅ Vertex struct size matches layout stride
- ✅ Vertex shader outputs match fragment shader inputs
- ✅ SPIR-V requirements (all inputs/outputs have
layout(location=N)) - ✅ Type compatibility between GLSL and vertex attributes
- ✅ Location continuity and gaps
Integration Point: MaterialXShaderGenerator::Generate() - validates every MaterialX shader before returning
Failure Mode: Throws exception if validation fails, preventing GPU submission
2. Static Clang-Tidy Configuration (.clang-tidy)
Location: ./.clang-tidy
Purpose: Static analysis during development
Enabled Checks:
bugprone-*- Bug-prone code patternscert-*- CERT secure coding guidelinesclang-analyzer-*- Deep static analysiscppcoreguidelines-*- C++ Core Guidelinesperformance-*- Performance issuesmisc-*,modernize-*,portability-*,readability-*
Critical Errors: Bug-prone and CERT violations are treated as errors
3. Multi-Layer Linting Script (scripts/lint.sh)
Layers:
- Clang-Tidy - Static analysis with compile_commands.json
- Cppcheck - Independent static analyzer
- Compiler Warnings - Maximum strictness build (
-Wall -Wextra -Wpedantic -Werror) - Sanitizer Build - AddressSanitizer + UndefinedBehaviorSanitizer
Usage:
./scripts/lint.sh [build-dir]
4. Python Shader Validator (scripts/validate_shaders.py)
Purpose: Standalone shader validation tool
Features:
- Extracts shader attributes from GLSL source
- Validates vertex layout compatibility
- Checks SPIR-V requirements
- Validates inter-stage matching
- Naming convention validation
Usage:
python3 scripts/validate_shaders.py [--verbose]
Validation Rules
Vertex Attribute Mapping
bgfx Vertex Layout Order (MUST MATCH):
location 0: Position (vec3, 12 bytes)
location 1: Normal (vec3, 12 bytes)
location 2: Tangent (vec3, 12 bytes)
location 3: TexCoord0 (vec2, 8 bytes)
location 4: Color0 (vec3, 12 bytes)
Total: 56 bytes
Vertex Struct (core::Vertex):
struct Vertex {
std::array<float, 3> position; // offset 0, 12 bytes
std::array<float, 3> normal; // offset 12, 12 bytes
std::array<float, 3> tangent; // offset 24, 12 bytes
std::array<float, 2> texcoord; // offset 36, 8 bytes
std::array<float, 3> color; // offset 44, 12 bytes
}; // Total: 56 bytes
GLSL Shader Inputs (MaterialX):
layout (location = 0) in vec3 i_position;
layout (location = 1) in vec3 i_normal;
layout (location = 2) in vec3 i_tangent;
layout (location = 3) in vec2 i_texcoord_0;
// location 4 (color) optional - not used by MaterialX
Critical Validations
-
Location Match
- Every shader input MUST have corresponding vertex layout attribute at same location
- Violation = CRASH
-
Type Compatibility
- GLSL
vec3↔ C++std::array<float, 3> - GLSL
vec2↔ C++std::array<float, 2> - Violation = CRASH or garbage data
- GLSL
-
Stride Match
sizeof(core::Vertex)MUST equal sum of layout attribute sizes- Violation = Memory corruption, reading wrong vertices
-
Interface Matching
- Vertex shader outputs MUST match fragment shader inputs (by location & type)
- Violation = Undefined behavior, may crash
-
SPIR-V Requirements
- All
in/outvariables MUST havelayout(location=N) - Violation = Compilation failure
- All
How It Prevented System Crash
The Bug
Before Validation:
- MaterialX generated shaders with locations:
[0, 1, 2, 3] - But actual order was
[position=0, texcoord=1, normal=2, tangent=3] - bgfx vertex layout expected:
[position=0, normal=1, tangent=2, texcoord=3] - Mismatch → Vulkan driver received malformed pipeline state
- AMD Radeon driver bug → System crash (not just app crash!)
After Validation:
- Validator detects location mismatch
- Throws exception with detailed error message
- Prevents submission to GPU → No driver crash
Fix Applied
// MaterialX shader generator now remaps locations to match bgfx:
std::map<std::string, int> bgfxLocationMap;
bgfxLocationMap["i_position"] = 0; // MUST be 0
bgfxLocationMap["i_normal"] = 1; // MUST be 1
bgfxLocationMap["i_tangent"] = 2; // MUST be 2
bgfxLocationMap["i_texcoord_0"] = 3; // MUST be 3
Integration Points
MaterialX Pipeline
// In MaterialXShaderGenerator::Generate()
ShaderPipelineValidator validator(logger_);
// Define expected layout
std::vector<AttributeInfo> expectedLayout = { /* ... */ };
// Validate BEFORE returning shaders
auto result = validator.ValidatePipeline(
vertexSource, fragmentSource, expectedLayout,
sizeof(core::Vertex), pipelineName
);
if (!result.passed) {
throw std::runtime_error("Validation failed"); // PREVENTS CRASH
}
Pre-Commit Hook (Recommended)
# .git/hooks/pre-commit
#!/bin/bash
./scripts/lint.sh build-ninja || {
echo "❌ Linting failed! Fix errors before committing."
exit 1
}
Future Enhancements
-
Compile-Time Validation
- Use
static_assertto validate vertex struct layout at compile time - Template metaprogramming for layout/struct correspondence
- Use
-
Shader Hot-Reload Validation
- Re-validate on shader modification
- Runtime checks in debug builds
-
GPU Capability Checks
- Validate against actual GPU limits
- Query max vertex attributes, texture units, etc.
-
Vulkan Validation Layers
- Enable comprehensive Vulkan validation in debug builds
- Parse validation layer output for early warnings
Debugging
Enable Verbose Validation
// In shader_pipeline_validator.cpp, re-enable trace logging
logger_->Info("Attribute at location " + std::to_string(loc) + ": " + name);
Manual Validation
# Run standalone validator
python3 scripts/validate_shaders.py --verbose
# Check specific shader
grep -A20 "RAW_VERTEX_SHADER" sdl3_app.log
Sanitizer Run
# Build with sanitizers
cmake -B build-asan -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined"
# Run and check for issues
./build-asan/sdl3_app -j config/seed_runtime.json
Summary
The mega-strict validation system prevents GPU driver crashes by:
- ✅ Validating shader/vertex layout compatibility BEFORE GPU submission
- ✅ Enforcing strict type and location matching
- ✅ Catching SPIR-V requirement violations early
- ✅ Providing detailed error messages for debugging
- ✅ THROWING EXCEPTIONS on validation failure (fail-safe)
Result: No more system crashes from shader pipeline bugs! 🎉