[visionegg] Re: GL state responsibility (warning: may contain theory)

Hi Tony,

This is an area where I've tried to be consistent, but there are
probably still occasional bugs.  (I discovered one last week.)

Basically, I've attempted to document this in the Core.Stimulus docstring:

>     OpenGL is a 'state machine', meaning that it has internal
>     parameters whose values vary and affect how it operates.  Because
>     of this inherent uncertainty, there are only limited assumptions
>     about the state of OpenGL that an instance of Stimulus should
>     expect when its draw() method is called.  Because the Vision Egg
>     loops through stimuli this also imposes some important behaviors:
> 
>     First, the framebuffer will contain the results of any drawing
>     operations performed since the last buffer swap by other instances
>     of (subclasses of) Stimulus. Therefore, the order in which stimuli
>     are present in the stimuli list of an instance of Viewport may be
>     important.  Additionally, if there are overlapping viewports, the
>     order in which viewports are added to an instance of Screen is
>     important.
> 
>     Second, previously established OpenGL display lists and OpenGL
>     texture objects will be available.  The __init__() method should
>     establish these things.
> 
>     Third, there are several OpenGL state variables which are
>     commonly set by subclasses of Stimulus, and which cannot be
>     assumed to have any particular value at the time draw() is called.
>     These state variables are: blending mode and function, texture
>     state and environment, the matrix mode (modelview or projection),
>     the modelview matrix, depth mode and settings. Therefore, if the
>     draw() method depends on specific values for any of these states,
>     it must specify its own values to OpenGL.
> 
>     Finally, a well-behaved Stimulus subclass resets any OpenGL state
>     values other than those listed above to their initial state before
>     draw() and init_gl() were called.  In other words, before your
>     stimulus changes the state of an OpenGL variable, use
>     glGetBoolean, glGetInteger, glGetFloat, or a similar function to
>     query its value and restore it later.  For example, upon calling
>     the draw() method, the projection matrix will be that which was
>     set by the viewport. If the draw() method alters the projection
>     matrix, it must be restored. The glPushMatrix() and glPopMatrix()
>     commands provide an easy way to do this.

So, the above should answer your specific question. In particular,
"before your stimulus changes the state of an OpenGL variable, use
glGetBoolean, glGetInteger, glGetFloat, or a similar function to query
its value and restore it later."  See above for the exceptions, but
texture coordinate generation is not one of them.

The bug I discovered last week was that changes to the modelview matrix
state would, against the above stated policy, cause other stimuli to
draw wrongly. So, I updated those builtin stimuli which modified it to
restore it after use.  If we want to live  by the documentation as
written, my approach is just a workaround, and I need to fix all stimuli
to be insensitive to the state of the modelview matrix when their draw()
method is called.

I should note that tracking of OpenGL state is one thing where the scene
graphs (e.g. OSG) are undoubtedly better.  The mechanisms in the Vision
Egg are enough to draw relatively simple stimuli, but sophisticated
state-tracking (like OSG has) would probably be needed for more complex
stuff.

Also, my best check of weather any particular stimulus adheres to the
above rules is to stick it as one of the first drawn objects in the
multi_stim.py. I'm sure a more rigorous state-testing machinery could be
built and stuck in the test/ directory.

Tony Arkles wrote:
> Hi!
> 
> I've stumbled onto a somewhat subtle bug, but I'm not sure if it's a
> VisionEgg responsibility or a Tony-Did-Something-Silly responsibility
> :).  From what I've read about OpenGL / game programming, it should be
> the responsibility of an object being drawn to ensure that GL is in a
> proper state.  This is where the bug popped up.
> 
> I made my own Viewport class that (will eventually) do the proper
> mapping from environment onto the rear-projection dome we have in the
> lab.  In this process, I did:
> 
> glEnable(GL_TEXTURE_GEN_S)
> glEnable(GL_TEXTURE_GEN_T)
> glEnable(GL_TEXTURE_GEN_R)
> 
> along with the associated calls to generate the texture coordinates from
> a normal map (more detail than necessary...).  Essentially, I turned on
> texture coordinate generation, and forgot to turn it off.
> Later on, I made a VisionEgg.Text.Text object, and put it in a standard
> viewport that was drawn much later on after my custom one had been
> drawn.  This refused to render at all because it provided its own
> texture coordinates while coordinate generation was still turned on.
> Now comes the question.  Is it my responsibility to make sure I turn off
> things I turn on, or is it the Text (or TextureStimulus?) object's
> responsibility to ensure that the system is in a state it cah properly
> use?  I think most objects do a pretty good effort in ensuring that the
> system is in a state it can use (e.g. calling glLoadIdentity() before
> trying to set position information), but I'm not sure how far that needs
> to / can be pushed.
> 
> Tony
> 
> ======================================
> The Vision Egg mailing list
> Archives: http://www.freelists.org/archives/visionegg
> Website: http://www.visionegg.org/mailinglist.html


-- 
Andrew D. Straw  Post-doctoral scholar
,-.              Dickinson Lab
\_/              California Institute of Technology
8||}             Mailcode 138-78
/ \              Pasadena CA 91125, USA
`-^
                 email:  astraw@xxxxxxxxxxx
                 office: +1 626 395 4396

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

Other related posts: