I've noticed that many 3d programs normally do vector/matrix calculations as well as geometric transformations on the CPU. Has anyone found an advantage in moving these calculations into vertex shaders on the GPU?
Generally speaking: Mesh transformations are done on the GPU. You send in the transformation matrix to the GPU and the shader applies it to all verticies of the mesh.
Using the GPU to calculate the Matrix itself is a different matter & is actually slower on the GPU because there are so many stored values that change from frame to frame that are necessary to help determine the final transformation matrix. Sending this data to & from CPU - GPU is slow. Also, on the CPU, the calculations are done once, whereas on the GPU, they would be done for each vertex.
Many geometric transformations can be done on non-GPU processors, however one must consider the target platform. Your mileage will vary based on what platform you're targeting, and the bottlenecks of that platform.
One consideration is bus bandwidth between the device that is generating the geometry, and the device that is rendering the geometry.
In a typical modern PC system, the CPU is on one side of the PCIe bus (http://en.wikipedia.org/wiki/PCI_Express), and the GPU is on the other. The only way you can transfer per-frame generated data from CPU to GPU (and vice-versa) is via this bus. This means, you can be limited by the transfer speed of this bus. If your target platform has PCIe 2.x with 16 lanes, you have 8GB/s bandwidth. In practice, transfers across the PCIe are not 100% efficient, as some of the bandwidth is consumed for the protocol during your transfers. Depending on the size of your transfers, you could lose 5-10% of your bandwidth just on the per-packet overhead.
eg. Given a PC platform that is running PCIe 2.x with 16 lanes, how much data can you generate per frame for feeding to the GPU? Assuming you want the run at 60fps, this translates to 8GB/60 = 136MB per frame for PCIe 2.x. Multiplying by some (guestimated) 90% factor to account for driver communication overhead and PCIe transfer protocol overhead, you can generate around 120Mb data per frame without being limited by PCIe 2.x bandwidth.
Another question you have to answer: will the generation of this 120Mb of data be easily achievable in 1/60th of a second on your target CPU? Remembering that you have to perform a number of other game tasks on your CPU, you can run into a lack of time to generate the transformed data. In terms of just pure ALU throughput, this can limit you on CPU. In terms of CPU to sysmem buses, you can also be limited by the bandwidth (which varies, but is around ~8.5GB/s on recent CPUs).
Alright, so what factors makes it more viable to do on a GPU then? One factor is GPU memory bandwidth, which is the bandwidth between the GPU and it's local video memory. On contemporary mid-range GPUs this video memory bandwidth can be as high as 200GB/s (yes, that's 25x the PCIe 2.x bandwidth). Another factor is that the GPU is massively parallel, has hundreds of ALUs and is able to hide memory access latency by running thousands of threads at a time.
All of these factors can contribute to the obvious win of pushing more work onto the GPU, but again YMMV depending on your target platform.
What do you mean by "mesh transformations"? Transforming geometry by some set of matrices? Most games these days will let the GPU handle simple transformations, skinning, etc. And most of them will be using vertex shaders to do it. On some platforms you either don't have shaders, or there are other advantages to doing these things on the CPU. For example, on the PS3 you can take some load off the RSX by letting the SPUs handle skinning and transformation. If you're doing multi-pass lighting then skinning on the CPU can be advantageous, since you only have to do it once and submit the results to be drawn for each rendering pass. So there are exceptions, but in general most games are doing these things on the GPU and in shaders.
Or did you mean something fancier, like using the GPU for general vector math? These days we have general purpose GPUs that can run fairly generic C code via systems such as CUDA. It is possible to take advantage of this for heavy vector math, and I know there are programs out there that do this. I don't have any experience with it personally though.
There are situations where having everything on rendered on the GPU might make sense, but you can't set constants inside a shader and there is really no where else to set them up except on the CPU side before a draw call.
Even if you could compute your constants, like the bone transformation matrices, on the GPU with a custom initialization program, you probably wouldn't want to. the GPU is really good at parallel execution, but has a much slower clock speed.
Transforming a hierarchy is not trivially parallelizable, because the child nodes depend on the parents, but transforming all the vertices in a mesh is, because the vertices are computational independent from each other.
The general rule is:
- Serial processing : CPU
- Parallel processing : GPU