I want to send quite a bit of data to the GPU, the data will never change (or will change very rarely) after it has been created. Is there a performance impact to using global shader variables or should I pack the data into a texture to perform look ups?
-
\$\begingroup\$ Can you clarify what you mean by 'external arrays?' Constant buffers? \$\endgroup\$– user1430Commented Jul 11, 2013 at 17:41
-
\$\begingroup\$ @JoshPetrie I haven't looked into constant buffers much, would they perhaps be better? Perhaps external variables is not the best word, but 'global' variables which can be set from outside the shader. \$\endgroup\$– Levi HCommented Jul 11, 2013 at 17:50
2 Answers
Sometimes. Maybe. Maybe not. It depends.
Early shader models had a very limited count of constant registers (I'm assuming pixel shader registers here since you're comparing to texture lookups) - 8 in SM1.x, 32 in SM2.0, and scaling the giddy heights of 224 in SM3.0. What's worse, some hardware didn't even support any pixel shader constants natively, and needed to patch the raw shader binary in order to emulate them (some GPU manufacturers would even recompile shaders, with - IIRC - NVIDIA for example advising that values of 0.0, 0.5 and 1.0 would trigger a recompile).
Common tricks included using textures to encode trig functions, normalization, etc (which also helped with overcoming the pathetic instruction limits that these shader models had).
If you want to support this class of hardware you need to bear all of this in mind.
More recently, it's the case that ALU operations are vastly faster than texture lookups, so straightaway you have a bottleneck if you use textures for storing your data. See the accepted answer to this question for more info.
Nowadays a constant buffer would be the optimal solution, and GPUs and drivers can be expected to be optimized for that kind of usage, but since you mention "global shader variables" that indicates to me that you're using D3D9 (also looking at your "HLSL" tag here which rules out OpenGL).
If that's the case then it depends on your definition of "quite a bit of data". Note the register limits I gave above, note that you're going to want to keep some spare for other usage, and you could very quickly find yourself bumping into those limits. So a texture would be your only real option, and available register space would be a more important determining factor than performance.
For older shader models, "global" variables are just mapped to GPU registers. They may be faster at a micro-timing level than texture lookups, but you probably won't have enough of them to sufficiently represent the data you want. Updating each constant variable would also have some overhead, but since you said updates will be quite rare, that may not be a problem. Textures are probably want you want if you are using an old model.
On newer shader models (4 and up) "global" variables (shader constants) are stored in constant buffers or texture buffers. You'd want to use whichever is more appropriate for your data and update/access patterns.
-
1\$\begingroup\$ On DX11 a structured buffer is also a possibility. They can be bigger than constant buffers, and have tighter packing (no need to pad things to 16-byte boundaries). \$\endgroup\$ Commented Jul 11, 2013 at 19:54
-
\$\begingroup\$ How many can I use? I remember using arrays of floats up to 2^16 in XNA. \$\endgroup\$– Levi HCommented Jul 11, 2013 at 20:51