Reputation: 942
I'm working on a shader manager architecture and I have several questions for more advanced people. My current choice oppose two designs which are:
You might notice that my current tendency is #1, but I wanted to know your opinion about it.
Thanks!
Upvotes: 41
Views: 9599
Reputation: 527
On mobile devices, branching in a shader greatly increases time to render. You should do some measuring on the time to switch programs vs the reduced draw rate associated with branching in a per vertex / per texel repeating operation. I'd recommend method #1 and take a look at how GPUImage is set up for a good oop friendly shader architecture.
https://github.com/BradLarson/GPUImage
Upvotes: 2
Reputation: 473447
Let's look at #1:
Considering every object might have its own material, it involves a lot of glUseProgram calls.
This isn't that big of a deal, really. Swapping programs is hard, but you'd be swapping textures too, so it's not like you're not already changing important state.
Implies the creation of a lot of shaderprogram objects.
This is going to hurt. Indeed, the main problem with #1 is the explosive combination of shaders. While ARB_separate_program_objects will help, it still means you have to write a lot of shaders, or come up with a way to not write a lot of shaders.
Or you can use deferred rendering, which helps to mitigate this. Among its many advantages is that it separates the generation of the material data from the computations that transform this material data into light reflectance (colors). Because of that, you have far fewer shaders to work with. You have a set of shaders that produces material data, and a set that uses the material data to do lighting computations.
So I would say to use #1 with deferred rendering.
Upvotes: 10
Reputation: 5470
It really depends on your hardware and the specific demands of your app.
Another con of #2 is that your shader usually ends up not being as efficient because it has to do some conditional branching based on the uniforms you pass in. So you're basically trading off between less time switching state versus decreased throughput in your shader. It depends on which one is worse.
You should definitely only call glLinkProgram once per shader. Compiling a shader takes much longer than switching out already-compiled shaders.
There aren't really any better solutions. Pretty much everyone writing a rendering engine has to make the decision you're faced with.
Upvotes: 9