Large number of texture swaps causing big performance drop

I’m using a timer to loop through a large number of texture swaps. On each iteration it swaps to a different texture state to make it appear that it is blinking.

The problem is that I drop from 60fps down to 1fps.

Is there a better way to do this than using setTexture?

Perhaps a shader?

Layer the off state on top of the on state and just hide it / show it to create a blink?

# called from doMethodLater every .25 seconds

#loop through 96 textures:

if not textureBlink:
  t1 = textureOn
  if (defaultTS == None):
    defaultTS = dict[key]['node'].findTextureStage(textureStageDefault)    
  dict[key]['node'].setTexture(defaultTS,t1, 1)
  textureBlink = True

else:
  t1 = textureOff
  if (defaultTS == None):
    defaultTS = dict[key]['node'].findTextureStage(textureStageDefault)    
  dict[key]['node'].setTexture(defaultTS,t1, 1)
  textureBlink = False

#endloop

My guess is your performance hit is coming from the findTextureStage calls not the setTexture calls. In that case the solution would be to pre-store the result of your findTextureStage call in that dictionary you are using.

It could also cause problems if you have the auto-shader in effect on this node, since swapping the texture (or doing any other state change) will require the node to recompile a new shader.

David

I double checked, findTextureStage is only called once and saved to a global.

You’re right drwr, removing the auto-shader on render fixed the issue.

I lose my nice normal mapping and lighting on the model though.

So I guess I have to create my own shader for this node in order to get my model looking nice again. I ran a test with a simple shader and I didn’t run into the performance issue problem, but the shader also doesn’t do anything.

I looked through the forums / manual for a replacement shader, but haven’t found one that handles normals, gloss and lighting, but I also don’t fully understand them.

Can you point me in the direction of a shader that does this?

Or is there a way to export the auto generated shader that my program is using?

As always, thanks for your help drwr!

You can dump all of the shaders by (temporarily) putting “dump-generated-shaders 1” in your Config.prc file, then you can choose the appropriate shaders from the result and load them as shader files directly.

But you also can solve this problem by simply holding onto the RenderState that corresponds to the previous state, which will allow it to re-use the previous shader when you return to that state.

One way to do this is instead of calling setTexture() on the fly, walk through all of your textures at init time, and save the RenderState for each pair. Like this, at init time:

#loop through 96 textures:

  t1 = textureOn
  dict[key]['node'].setTexture(defaultTS,t1, 1)
  dict[key]['tex_on_state'] = dict[key]['node].getState()

  t1 = textureOff
  dict[key]['node'].setTexture(defaultTS,t1, 1)
  dict[key]['tex_off_state'] = dict[key]['node].getState()

And then do this at run time:

#loop through 96 textures:

if not textureBlink:
  state = dict[key]['tex_on_state']
  dict[key]['node'].setState(state)
  textureBlink = True

else:
  state = dict[key]['tex_off_state']
  dict[key]['node'].setState(state)
  textureBlink = False

#endloop 

David

Sorry drwr, but weren’t you who fixed this for Panda 1.8? Maybe he doesn’t mind using an unstable version for now.

Maybe it’s a stupid idea, but how about using a sequence node?
It’s a bit of copy-paste work with the eggs but then you just call loop() and it’s done.

Thanks David. Your solution was spot on.

I did try to save the state with the parent node (a lazier way!), but it only worked with the lower found nodes.

Either way, this is solved. Thanks!

If you’re changing state that doesn’t require a shader rebuild, then it’s not an issue in 1.8 any more. But changing the texture state still requires a shader rebuild.

This could probably be further optimized–certain changes to the shader state, for instance, swapping one texture out for a similar texture–don’t necessarily require a shader rebuild, but certain other changes to the texture state do (like adding or removing from the total number of textures), and right now it doesn’t make this distinction and just rebuilds the shader state in all cases.

David