[visionegg] Re: optimizing my code since timing is a catastrophe

  • From: Andrew Straw <andrew.straw@xxxxxxxxxxxxxxx>
  • To: visionegg@xxxxxxxxxxxxx
  • Date: Fri, 9 May 2003 08:49:59 -0400

Hi Christoph,

Here's your code shortened to relevant bits:

preloaded_texture_list = [] # empty list
for stim_index in range(num_images):
    texture = Texture(photoX[stim_index])
    preloaded_texture_list.append( texture )
stimulus = TextureStimulus(on = 1,
                           texture = preloaded_texture_list[0],
                           size = preloaded_texture_list[0].size,
                           lowerleft=(x,y))
viewport = Viewport( screen=screen, stimuli=[stimulus] )
    # draw the stimulus (during first loop: fixation)
    stimulus.parameters.texture = preloaded_texture_list[stim_index]
    screen.clear()
    viewport.draw()
    swap_buffers()

What your code does:


A) create an instance of the Texture class for each image you want to use. The Texture class merely gets the data ready to be sent to OpenGL, but does not actually send it unless the load() method is called. (If I remember correctly, you wrote this part of your code before I had re-written much of the Textures module to allow for the speedups detailed below.)

B) create a single TextureStimulus class called "stimulus". This method does call the load() method of the Texture you assign it and therefore actually sends the data to OpenGL. This loading is accomplished by creating a "texture object" (OpenGL terminology referring to an allocation of resources used to cache texture data). Creating a texture object can take some time.

C) when passing later images, they become the TextureSimulus's new texture parameter, and each one will have its load() call used, thus resulting in the problem when OpenGL needs a lot of time to (deallocate old resources and) allocate new resources for the new texture object. I'm 99% sure that this is your problem.

You have three options:

1) Use only one texture object. See the demo image_sequence_fast.py for an example. This uses the put_sub_image() method to avoid creating new texture objects. It recycles the old texture object instead.

2) Pre-allocate a texture object for each texture before you enter time-critical code. Create a list of TextureStimulus instances, one with each of your texture images. Change the viewport.parameters.stimuli list to include only the TextureStimulus you want to display on a particular frame. Note that you may have to draw each of the textures once to really convince OpenGL to cache it. (But you don't have to swap buffers, which means no one has to see that you drew those textures.) This will only help up to the number of textures you can put in video memory.

3) Wait for me to optimize Screen.put_pixels(), which is otherwise done. Screen.put_pixels() is called with the image data you want and will perform something very similar to #1 above. (Right now, put_pixels() goes the slow route and does what you're doing.) The advantage of using put_pixels() would be that you don't need to worry about the details of OpenGL texture memory management. (BTW, the approach is already described in the comments of put_pixels(), but just not implemented yet. Feel free to have a go. :)

I recommend #1 for now, although #2 is also easy to try.

Cheers!
Andrew

======================================
The Vision Egg mailing list
Archives: //www.freelists.org/archives/visionegg
Website: http://www.visionegg.org/mailinglist.html

Other related posts: