Use re-spirv in the Vulkan driver to optimize shaders.#111452
Use re-spirv in the Vulkan driver to optimize shaders.#111452Repiteo merged 1 commit intogodotengine:masterfrom
Conversation
|
This makes a nice difference on AMD dGPUs too
Note: the values aren't comparable to the other devices since a different test project was used |
4cbfb2e to
c202ec7
Compare
|
There's a few pending items but this should be mostly ready for review. I replaced the old approach of printing the average time with a more detailed spreadsheet dumping, but perhaps we want to further analyze it and draw some more conclusions with it. CC @akien-mga I'd like a suggestion on how to properly handle the newer Vulkan SPIR-V header required. The PR updates the one on spirv-reflect, but perhaps we prefer to just move it to the common |
What are the pending items? Are the potential further optimizations in re-spirv, or are they things that will impact the integration code? At this point I am totally fine with the integration code. So I am happy to move forward with this PR unless you have any significant known issues |
We just need to sort out the bit I pinged Rémi about, as I'm not sure how we want to handle the SPIR-V header going forward. It's just a code organization issue. |
|
Looks like we use that header in SPIRV-Cross, SPIRV-reflect, and GLSLang. Usually it is only updated when we do an SDK update. IMO we should probably just update to a newer version of the SDK and leave the files in their current places instead of unifying them in one location. That being said, see #107773 |
Yeah I suggested doing that too in DMs with Darío. |
akien-mga
left a comment
There was a problem hiding this comment.
Buildsystem changes look good overall.
akien-mga
left a comment
There was a problem hiding this comment.
Approved for buildsystem changes.
f903f91 to
3b731ab
Compare
Includes contributions by Rémi to unify usage of SPIR-V Headers across the dependencies. Co-authored-by: Rémi Verschelde <rverschelde@gmail.com>
|
Thanks! |
|
Since this is now merged, for anyone that happens to track a particular regression to this PR, please search for the All in all, I expect to see some amazing loading time improvements on mobile platforms specially. |
Disclaimer
re-spirv is a project I started with another contributor on our own with the express purpose of doing shader optimization in SPIR-V in real time environments. The project uses the MIT License and should be compatible with Godot's licensing. This PR adds a new dependency to the third party folder.
Background
Since the ubershaders PR was merged, Godot has been making use of specialization constants to heavily eliminate parts of code that are unused by materials depending on the environment's configuration or proximity to nodes such as lights or reflection probes. This is specially important in the mobile renderer, which will generate specializations based on the amount of lights close to it and compile them on the fly on the background while relying on the ubershader to display it while it's getting ready.
Specialization constants are used as the main flags for eliminating unused code, but not all drivers will prioritize eliminating code based on them first. re-spirv was developed with the explicit goal of prioritizing DCE based on eliminating code branches that can be determined to be dead once the values for the constants are known. As measured in that project and in Godot itself, it is possible to get significant reductions in pipeline creation time by eliminating code from the SPIR-V instead on the application side at the cost of some very small extra processing time.
Why not apply spirv-opt instead?
We should eventually add shader optimization to Godot using spirv-opt. There's even a PR here which adds it and gives substantial benefits to shader sizes and pipeline creation times too. spirv-opt even features options to freeze specialization constants to certain values and run optimization passes.
However, the performance leaves a lot to be desired and is basically not applicable for real-time cases. While re-spirv is unlikely to ever feature the great size reductions that spirv-opt can achieve, the size reduction that is possible is very much worth it for the very little extra processing time it adds to the pipeline creation.
At the time being, I think spirv-opt will be best suited for optimizing shaders when using the new shader baker option, which can afford to take more processing time during a step where the user does not expect real-time performance.
For purposes of comparison to spirv-opt, re-spirv currently only features the following optimizations:
Procedure
We have multiple possible places to apply SPIR-V optimization, and for the purposes of this PR, it has been moved to live solely inside the Vulkan driver. Some benefits have been found by running re-spirv for non-specialized shaders because they're currently compiled without optimizations, but I believe it would be best suited to rely on spirv-opt at some point in the future to optimize these shaders and leave re-spirv solely for specialized shaders.
The implementation of re-spirv in the driver is very simple: a parsing step is performed during shader creation to generate the analysis DAG that will be used during optimization. The results of this step are reusable and the cost only has to be paid once per shader and isn't paid again for each specialization that is created.
Before a pipeline is created, the optimizer is called with the known values of the specialization constants. The resulting SPIR-V is passed to the driver to create the pipeline. This means a new unique SPIR-V is generated on the fly and there's no need for the driver to parse the specialization constants.
Results
In theory, we shouldn't be seeing substantial decreases in pipeline creation time, as drivers already apply several optimization steps to achieve optimal shader performance when converting the SPIR-V to actual GPU code. However, not all drivers are built the same, and not all of them may prioritize the passes featured by re-spirv which are known to be the most effective first given the nature of the shaders. These drivers may reach the optimal point by applying different passes first or may pay a higher price from converting SPIR-V as-is to their own intermediate format first.
Some of these measurements might be within a margin of error due to the highly parallelized nature of the workload depending on the system and the driver in question. However, there's hardware that shows significant improvements and it should make it clear as to why we pursued this path.
Not all of these were measured using the same project or renderer so the numerical values can't be compared between platforms. The main purpose of the chart is to show the reductions on each platform. For example, the NVIDIA measurement was done on a much larger project using Forward+ to better represent the improvements on a project that fits the platform's demands better.
Testing
PRINT_PIPELINE_COMPILATION_TIMESare provided on the source code itself, but my hope is to further polish the measuring and provide proper monitors and statistics as the PR progresses more.TODO
reflect-spirvto use a newer header. However, I think we should just stick these in thevulkandirectory and make both libraries use it instead.