Can frequent texture and shader binding decrease rendering performance?

"Frequent" binding example:

for object
   for material in object
      render part of object using that material

"Low count" binding example:

for material
   for object in material
      render part of object using that material

I'm planning to use an octree later and with this "low count" method of rendering it can drastically increase memory consumption. So is it good idea?


State changes are, relatively speaking, an expensive operation and texture and shader state changes in particular can have the largest overhead. So yes, if you structure your render loop in such a way as to constantly change the shader and textures bound to the pipeline, that will have a negative impact on render performance. That impact may not be noticeable depending on the overall number of binds, however, it's still good to be aware of it.

Your second example will result in fewer state changes than your first example, and it is generally the way you want to go, especially for solid objects: essentially, sort what your going to render by shader and texture so that you can bind the appropriate combination and then render several objects using those resources. Transparent objects also need additional depth-based sorting or require you to use an order-independent transparency technique such as depth peeling.

An octree can be a useful optimization but it is intended as a means to cull out entire objects that are not visible or otherwise contributing to the scene. You should only have one octree, maintaining an octree-per-material is wasteful and doesn't provide you any real benefits.

  • \$\begingroup\$ Thanks. Examples were switched. If i have one octree, then i would need to check for each material pass every part/geometry if it belongs to the material. \$\endgroup\$ – kravemir Jun 27 '12 at 15:28
  • \$\begingroup\$ No; first you use a single octree to cull every object that does not contribute to the scene. That leaves you with a set of visible (or potentially visible) objects. For each potentially visible object, you insert that object into a list that corresponds to its material. "Object" in this case is a set of geometry with a unique shader/texture combination and not necessarily what a user might perceive as an object. You only need one pass over the potentially-visible set. \$\endgroup\$ – user1430 Jun 27 '12 at 15:32
  • \$\begingroup\$ However, this discussion about using an octree to optimize material state changes isn't really germane to your original question about the performance impact of frequent state changes. If you want to discuss it further, you should create a new question for it. \$\endgroup\$ – user1430 Jun 27 '12 at 15:33
  • \$\begingroup\$ Thanks for good idea in your first comment. You've answered my question with first sentence in answer :) \$\endgroup\$ – kravemir Jun 27 '12 at 15:38

Are your examples the right way round? If you sort by material, you bind once per material. If you sort by object, you might end up binding [numObjects * numMaterials] times.

To avoid those subloops, forget about the objects. You're not really rendering objects, you're rendering parts, so when you instantiate objects, add their parts to a render list. Then your two example loops would look like this:

for material
    bind material & render all parts


for part
    bind material & render

You would probably have more parts than materials, so you can see the first option would result in fewer bind calls.

  • \$\begingroup\$ Yes, but if i add octree, then i would be octree per material if i have cca 100 or more materials, wouldn't 100+ octrees consume a lot of memory? \$\endgroup\$ – kravemir Jun 27 '12 at 15:13
  • \$\begingroup\$ They would, but you should not need an octree per material. \$\endgroup\$ – user1430 Jun 27 '12 at 15:23

Your Answer

