Source browser
scripts/validate_glsl.py
Read the complete file below or download its original bytes. Line numbers provide stable links to a declaration or processing step.
File fingerprint
1#!/usr/bin/env python3
2"""Export every dual shader and validate all supported GLSL language profiles."""
3
4import argparse # Read the exporter, compiler and source paths.
5from pathlib import Path # Build paths with pathlib.
6import subprocess # Run the exporter and GLSL compiler.
7import tempfile # Remove exported shader files after validation.
8
9
10def main(): # Validate every bundled compute shader for every supported profile.
11 parser = argparse.ArgumentParser(description=__doc__) # Provide command help.
12 parser.add_argument("--exporter", type=Path, required=True) # Locate the built shader exporter.
13 parser.add_argument("--validator", type=Path, required=True) # Locate glslangValidator.
14 parser.add_argument("--source-dir", type=Path, required=True) # Locate the shader examples.
15 options = parser.parse_args() # Read all required paths.
16 shaders = sorted( # Collect bundled shader filenames in reproducible order.
17 (options.source_dir / "examples" / "shaders").glob("*.cpp") # Read native compute sources in the example directory.
18 ) # Use a stable order.
19 if not shaders: # Validate the selected source directory.
20 parser.error("no shaders found") # Stop with a useful path-related error.
21 profiles = ("es31", "es32", "gl43", "gl45", "gl46") # Cover all runtime language choices.
22 with tempfile.TemporaryDirectory( # Remove all exported source files after the checks.
23 prefix="shdr-glsl-" # Identify temporary shader validation directories.
24 ) as directory: # Keep exports outside the source tree.
25 for shader in shaders: # Visit each registered shader factory.
26 for profile in profiles: # Export it using each version preamble.
27 command = [ # Build this factory's profile-specific export command.
28 str(options.exporter), # Use the built executable containing embedded shader text.
29 shader.stem + "_kernel", # Name the factory registered for this source file.
30 profile, # Select the exported shader language version.
31 ] # Select factory and profile.
32 result = subprocess.run( # Capture the exact text embedded in the executable.
33 command, # Pass each compiler argument directly.
34 check=True, # Propagate shader export failures.
35 stdout=subprocess.PIPE, # Read the exported source from standard output.
36 text=True, # Decode compiler output as text.
37 ) # The exporter result now contains the source.
38 path = Path(directory) / ( # Choose one temporary output path per source and profile.
39 shader.stem + "_" + profile + ".comp" # Keep compiler diagnostics easy to associate with their input.
40 ) # Give each check a separate file.
41 path.write_text( # Preserve the exact standalone source emitted by the runtime.
42 result.stdout, encoding="utf-8" # Write shader text with a deterministic encoding.
43 ) # Write standard GLSL for the compiler.
44 command = [ # Build the standard GLSL compiler command.
45 str(options.validator), # Use the configured standalone validator.
46 "-S", # Select a shader stage independently of the filename suffix.
47 "comp", # Require compute-shader grammar and built-ins.
48 str(path), # Compile this exported source/profile pair.
49 ] # Select the compute shader stage.
50 subprocess.run(command, check=True) # Stop on the first language error.
51 total = len(shaders) * len(profiles) # Count all successful source/profile pairs.
52 message = "Validated {} shaders for {} profiles ({} compilations)" # Keep the summary readable.
53 print(message.format(len(shaders), len(profiles), total)) # Report the completed checks.
54
55
56if __name__ == "__main__": # Run only when this file is used as a command.
57 main() # Read options and start validation.