| # SPIR-V Transpiler |
| |
| Note: This library is currently considered experimental until shader compilation is verified by engine unit tests, see the Testing section below for more details. |
| |
| A dart library for transpiling a subset of SPIR-V to the shader languages used by Flutter internally. |
| |
| - [SkSL](https://skia.org/docs/user/sksl/) |
| - [GLSL ES 100](https://www.khronos.org/files/opengles_shading_language.pdf) |
| - [GLSL ES 300](https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf) |
| |
| All exported symbols are documented in `lib/spirv.dart`. |
| |
| The supported subset of SPIR-V is specified in `lib/src/constants.dart`. |
| |
| If you're using GLSL to generate SPIR-V with `glslangValidator` or `shaderc`, |
| the code will need to adhere to the following rules. |
| |
| - There must be a single vec4 output at location 0. |
| - The output can only be written to from the main function. |
| - `gl_FragCoord` can only be read from the main function, and its z and w components |
| have no meaning. |
| - Control flow is prohibited aside from function calls and `return`. |
| `if`, `while`, `for`, `switch`, etc. |
| - No inputs from other shader stages. |
| - Only float, float-vector types, and square float-matrix types. |
| - Only square matrices are supported. |
| - Only built-in functions present in GLSL ES 100 are used. |
| - Debug symbols must be stripped, you can use the `spirv-opt` `--strip-debug` flag. |
| |
| These rules may become less strict in future versions. Confirmant SPIR-V should succesfully transpile from the current version onwards. In other words, a spir-v shader you use now that meets these rules should keep working, but the output of the transpiler may change for that shader. |
| |
| Support for textures, control flow, and structured types is planned, but not currently included. |
| |
| ## Testing |
| |
| ### Exception Tests |
| |
| These tests rely on the `.spvasm` (SPIR-V Assembly) and `.glsl` files contained under `test/exception_shaders` in this directory. They are compiled to binary SPIR-V using `spirv-asm`, from the SwiftShader dependency. They are tested by testing/dart/spirv_exception_test.dart as part of the normal suite of dart tests. The purpose of these tests is to exercise every explicit failure path for shader transpilation. Each `glsl` or `spvasm` file should include a comment describing the failure that it is testing. The given files should be valid apart from the single failure case they are testing. |
| |
| To test the exception tests directly: `./testing/run_tests.py --type dart --dart-filter spirv_exception_test.dart` |
| |
| ### Pixel Tests |
| |
| Pixel tests should run as part of unit-testing for each implementation of `dart:ui`. Currently, FragmentShader is only supported in C++. These tests aim to validate the correctness of transpilation to each target language. Each shader should render the color green for a correct transpilation, and any other color for failure. They will be a GLSL files that are compiled to SPIR-V via `shaderc`. Therefor, the `fragColor` should resolve to `vec4(0.0, 1.0, 0.0, 1.0)` |
| for all tests. |
| |
| In each test, the uniform `a` is initialized with the value of 1.0. |
| This is important so that expressions are not simplified during GLSL to SPIR-V compilation, which may result in the removal of the op being tested. |
| |
| To test the pixel tests directly: `./testing/run_tests.py --type dart --dart-filter fragment_shader_test.dart` |
| |
| #### A Note on Test Isolation |
| |
| Even the simplest GLSL program tests several instructions, so no test us completely isolated |
| to a single op. Also, some of the GLSL 450 op tests will use addition in subtraction, along with the |
| actual op being tested. However, the GLSL program for each test file is kept as simple as possible, |
| to satisfy these conditions: pass if the op works, and fail if the op does not work. In some tests, |
| it is sufficient to only call the GLSL op once, while other may need more calls to more completelty |
| test the op. Many ops support scalars, vectors, or a combination as parameters. Most tests default |
| to using scalars as params, but vec2, vec3, and vec4 parameters are also tested. |
| |
| - vec2 is tested as a paramter in glsl_op_normalize.glsl |
| - vec3 is tested as a parameter in glsl_op_cross.glsl |
| - vec4 is tested as a parameter in glsl_op_length.glsl |
| |
| ### Adding New Tests |
| |
| To add a new test, add a glsl (fragment shader tests) or spvasm (spirv exception tests) src file to a `lib/spirv/test/` subfolder, and add the file as a source to the corresponding `BUILD.gn`. |
| |
| - New files in `exception_shaders` are automatically tested in `testing/dart/spirv_exception_test`. |
| - New files in `supported_op_shaders` and `supported_glsl_op_shaders` are automatically tested in `testing/dart/fragment_shader_test`. |
| - New files in `general_shaders` are not automatically tested and must add a new manual test case in `testing/dart/fragment_shader_test`. |