Hi, "is_used_once" within an inexact transformation in nir_opt_algebraic can lead to geometry differences with multi-pass rendering, causing incorrect output. Here's an example to proof this:
Let's assume there is a pass that writes out some intermediate value from the position calculation as a varying. Let's assume there is another pass that does the same thing, but only draws to the depth buffer, so varyings are eliminated. The second pass would get "is_used_once" because there is just the position, and let's assume there is an inexact transformation with "is_used_once" that matches that. On the other hand, the first pass wouldn't get "is_used_once" because there is the varying. Now the same position calculation is different for each pass, causing depth test functions commonly used in multi-pass rendering such as EQUAL to fail. The application might even use the exact same shader for both passes, and the driver might just look for depth-only rendering and remove the varyings based on that. Or it can introduce more "is_used_once" cases via uniform inlining. From the app's point of view, the positions should be identical between both passes if it's the exact same shader. The workaround we have for this issue is called "vs_position_always_invariant", which was added for inexact FMA fusing, but it works with all inexact transformations containing "is_used_once". This issue could be exacerbated by future optimizations. Some of the solutions are: - Remove "is_used_once" (safe) - Enable vs_position_always_invariant by default (not helpful if the data flow is shader->texture->shader->position) - Always suppress inexact transformations containing "is_used_once" for all instructions contributing to the final position value (less aggressive than vs_position_always_invariant; it needs a proof that it's equivalent to vs_position_always_invariant in terms of invariance, not behavior) - Continue using app workarounds. Just some food for thought. Marek