Calculations on uniform constants in shader

There seems to be conflicting advice from Apple and Imagination regarding calculations on uniform shader constants.

The PowerVR performance recommendations doc says:
"The PowerVR shader compiler is able to extract calculations based on uniforms from the shader and perform these calculations once per draw call."

Apple’s “Best Practices for Shaders” says:
"Whenever a value can be calculated outside the shader, pass it into the

shader as a uniform or a constant. Recalculating dynamic values can

potentially be very expensive in a shader."

So who is right?  Tests using PVRUniScoEditor suggest the compiler does indeed extract my constant calculations, however since we are targetting a wide range of apple devices and operating systems from the iphone 3gs / iOS3.1 upwards it’s plausible this optimisation isn’t implemented on all these devices.

Ideally I’d precompute any constants and pass them into the shader, however this is a lot of faff and CPU overhead when using Unity which would be nice to avoid.

Thanks in advance for any insight.






FTR, I mocked up a test and it appears that at least on iOS 5.01 constant extraction works as expected.

Hi Tim,

Whilst I don’t specifically know how iOS handles these cases, what they’re saying isn’t specifically at odds with what we say there. If you can do a calculation outside of a shader, you should as a general rule. All our document is saying is that if you do need/choose to do operations on uniforms within your shader, you should do it in a specific way to get the best performance.

Our performance recommendations could possibly stand to be a little clearer here - which is something I’ll flag up with our Documentation Lead.

Thanks,

Tobias





Hi Tobias.

Thanks for the reply.  As a general rule I usually go to some trouble to avoid computing constants in shaders.  In this case I can half the number of shader instructions I need by working in object space, however Unity doesn’t provide an easy way to localise constants per batch.  To do this I need to duplicate all the materials for each object and pass all the localised constants for each in manually using the C# UnityEngine.Material API.  According to XCode this stuff takes quite a bit of CPU time, and the game is already CPU bound on min spec.  My view is that if the driver does an efficient job of extracting the world space to object space transforms on constants then this is better all round, both from the code maintainability and performance point of view.

Tim



Hi Tim,

That seems like a good enough reason to rely on the drivers doing it, I see no problem with that methodology in this case. Of course this is assuming that iOS does handle these cases the same way we generally do, which seems likely.

One thing I would mention though is to make sure you follow our performance recommendations in terms of making sure the shader compiler actually catches these cases, as otherwise you might end up with extra cycles being wasted on an otherwise constant calculation.

Thanks,

Tobias



Tobias2012-05-08 12:48:02