[visionegg] Re: Dropping into C

Hi Simeon,

I've included my test app which I use to test things before I
incorporate them into the VisionEgg(it's kinda a mess ;) ). Since
the data is dynamically changing from frame to frame you do
have to call glVertexPointer() each frame. Curiously enough this
is the call that is hanging up things. glDrawarrays is quick. This
is from my own profiling. My develope machine here is a Mac.
Using the PythonIDE I made an applet out of glcube2.py but
I couldn't get the profiler to work with it. I may post to the Apple
OpenGl list to see if they have any hints.

My experiment with glVertexArray in C seemed to only show
a slight performance increase on NVidia harware over the draw_in_c
method. Best,

Doug


Simeon Fitch wrote:

Doug,

I think the reason you might have been getting *worse* performance was that you are (I'm inferring here) calling "glVertexPointer()" inside each call to draw(). This means that every time draw() is called you are copying all the data to the driver/hardware, which is exactly what you don't want to do.

In your __init__ method (or something called before you enter the draw() loop) you should call the glEnableClientState() and glVertexPointer(), and then in your draw() method call "glDrawArrays()". Don't call glDisableClientState() at all unless there is some specific reason you need to.

IMHO, you should be able to achieve the performance you desire without "dropping into C". If not, and you are running on MacOS X, and have the developer tools installed, try running the "OpenGL Profiler" tool to help identify OpenGL calls that are perhaps not necessary and slowing things down (remembering that OpenGL is a "state machine"). This tool is installed to "/Developer/Applications/Graphics Tools".

Best,

Simeon

On 1/27/06, Douglas Taylor <dtaylor@xxxxxxx <mailto:dtaylor@xxxxxxx>> wrote:

    Hi Andrew,

    I was trying to optimize the dot drawing routine
    using the Vertex Array method

                xy[:,0] = xstart      #where xy is an [npoints][2] array
                xy[:,1] = ystart
               # Pass a pointer to the start of the point-coordinate
    array:
                glVertexPointerd(xy);
               # glVertexPointer(2, GL_DOUBLE, 0, xy); Python did not
    like
    it this way
               # Enable fast rendering of arrays:
                glEnableClientState(GL_VERTEX_ARRAY);
               # Render all n points, starting at point 0, render them as
    POINTS:
                glDrawArrays(GL_POINTS, 0, len(xstart));
               # Disable fast rendering of arrays:
                glDisableClientState(GL_VERTEX_ARRAY);

    and on the Mac(10.3 and 10.4) I actually got worse performance
    than the
    GL_POINTS loop method. So I would like to drop into C and I found
    the _draw_in_c.c code which looks like a good place to start. I don't
    understand however how you generated the .so file. I couldn't find
    any examples on the Apple site either. I have XCODE and CodeWarrior.
    Could you point me in the right direction here. Thanks much,

    Doug


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




--
Simeon H.K. Fitch, Owner
Mustard Seed Software
1634 Brandywine Drive
Charlottesville, VA 22901
210.867.1616

#!/usr/bin/env python

"""Draw a cube on the screen. every frame we orbit
the camera around by a small amount and it appears
the object is spinning. note i've setup some simple
data structures here to represent a multicolored cube,
we then go through a semi-unopimized loop to draw
the cube points onto the screen. opengl does all the
hard work for us. :]
"""

import Numeric,time,sys,RandomArray,random,pygame
from pygame.locals import *

from random import *

print     sys.platform 

try:
    from OpenGL.GL import *
    from OpenGL.GLU import *
except:
    print 'The GLCUBE example requires PyOpenGL'
    raise SystemExit

if sys.platform == "darwin": 
    try:
        import _darwin_sync_swap
        #_darwin_sync_swap.sync_swap()
        success = 1
    except:
        print 'This GLCUBE example requires _darwin_sync_swap'
        raise SystemExit

import VisionEgg

try:
### C version of draw_dots() isn't (yet) as fast as Python version: 
    import VisionEgg._draw_in_c
    success = 1
##draw_dots = VisionEgg._draw_in_c.draw_dots # draw in C for speed
except:
    print 'The GLCUBE example requires _draw_in_c'
    raise SystemExit


#some simple data for a colored cube
#here we have the 3D point position and color
#for each corner. then we have a list of indices
#that describe each face, and a list of indieces
#that describes each edge

NUM_POINTS = 512
#use_vertex_array = True

CUBE_POINTS = (
    (0.5, -0.5, -0.5),  (0.5, 0.5, -0.5),
    (-0.5, 0.5, -0.5),  (-0.5, -0.5, -0.5),
    (0.5, -0.5, 0.5),   (0.5, 0.5, 0.5),
    (-0.5, -0.5, 0.5),  (-0.5, 0.5, 0.5)
)

#colors are 0-1 floating values
CUBE_COLORS = (
    (1, 0, 0), (1, 1, 0), (0, 1, 0), (0, 0, 0),
    (1, 0, 1), (1, 1, 1), (0, 0, 1), (0, 1, 1)
)

CUBE_QUAD_VERTS = (
    (0, 1, 2, 3), (3, 2, 7, 6), (6, 7, 5, 4),
    (4, 5, 1, 0), (1, 5, 7, 2), (4, 0, 3, 6)
)

CUBE_EDGES = (
    (0,1), (0,3), (0,4), (2,1), (2,3), (2,7),
    (6,3), (6,4), (6,7), (5,1), (5,4), (5,7),
)



def drawcube():
    "draw the cube"
    allpoints = zip(CUBE_POINTS, CUBE_COLORS)

    glBegin(GL_QUADS)
    for face in CUBE_QUAD_VERTS:
        for vert in face:
            pos, color = allpoints[vert]
            glColor3fv(color)
            glVertex3fv(pos)
    glEnd()

    glColor3f(1.0, 1.0, 1.0)
    glBegin(GL_LINES)
    for line in CUBE_EDGES:
        for vert in line:
            pos, color = allpoints[vert]
            glVertex3fv(pos)

    glEnd()


def main():
    "run the demo"
    use_vertex_array = input('Use vertex array method(1=yes)? ')
    #input('Use vertex arrayy method? ')
    #initialize pygame and setup an opengl display
    pygame.init()
    pygame.display.set_mode((1024,768), OPENGL|DOUBLEBUF|FULLSCREEN|HWSURFACE)

    #glEnable(GL_DEPTH_TEST)        #use our zbuffer
    #glClearColor(1.0,0.0,0.0,1.0)
    if sys.platform == "darwin":
        _darwin_sync_swap.sync_swap()

    #setup the camera
    glMatrixMode(GL_PROJECTION)
    #gluPerspective(45.0,640/480.0,0.1,100.0)    #setup lens
    #glTranslatef(0.0, 0.0, -3.0)                #move back
    #glRotatef(25, 1, 0, 0)                       #orbit higher
    gluOrtho2D(-1.33333, 1.33333, -1.0, 1.0)
    glEnable(GL_POINT_SMOOTH)
               # allow max_alpha value to control blending
    glEnable( GL_BLEND )
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )

    xstart = RandomArray.uniform(-1.0, 1.0, (NUM_POINTS,))
    ystart = RandomArray.uniform(-1.0,1.0, (NUM_POINTS,))
    zstart = RandomArray.uniform(0.0,1.0, (NUM_POINTS,))
    t1 = RandomArray.uniform(0.0,1.0, (NUM_POINTS,))
    xy = RandomArray.uniform(0.0,1.0, (2,NUM_POINTS))
    xyTrans = RandomArray.uniform(0.0,1.0, (NUM_POINTS,2))
    print xy[:,0]
    frame = 0
    t1[frame] = time.time()

    for i in range(NUM_POINTS):
        zstart[i] = 0.0
        while xstart[i]*xstart[i]+ystart[i]*ystart[i] > 1.0:
                xstart[i] = random()*2 - 1.0
                ystart[i] = random()*2 - 1.0
                
    xy[0,:] = xstart
    xy[1,:] = ystart
    #print len(xstart)

    while 1:
        #check for quit'n events
        event = pygame.event.poll()
        if event.type == QUIT or (event.type == KEYDOWN and event.key == 
K_ESCAPE) or frame==NUM_POINTS-1:
            break
 
        t1[frame] = time.time()

       #clear screen and move camera
        #glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        glClear(GL_COLOR_BUFFER_BIT)

        #orbit camera around by 1 degree
        #glRotatef(1, 0, 1, 0)                    

        drawcube()
        glPointSize(16)

        t1[frame] = time.time()
        if use_vertex_array == False:
            glColor4f(1.0, 0.0, 0.0,1.0);
            VisionEgg._draw_in_c.draw_dots(xstart,ystart,zstart)
            #glBegin(GL_POINTS);
            #for i in range(NUM_POINTS):
              #glVertex3f(random.random(),random.random(),1.0);
               #glVertex3f(xstart[i],ystart[i],zstart[i]);
               #glVertex2f(xstart[i],ystart[i]);
               #glVertex3f(xy[0,i],xy[1,i],zstart[i]);
            #glEnd()
        else:
        # Pass a pointer to the start of the point-coordinate array:
        #xyTrans = Numeric.transpose(xy)
         #glVertexPointer(2, GL_DOUBLE, 0, xyTrans);
            glColor4f(0.0, 1.0, 0.0,1.0);
            xyTrans[:,0] = xstart
            xyTrans[:,1] = ystart
            #VisionEgg._draw_in_c.draw_dots(xyTrans)
            glVertexPointerd(xyTrans);
           # glVertexPointer(2, GL_DOUBLE, 0, xyTrans);
           # Enable fast rendering of arrays:
            glEnableClientState(GL_VERTEX_ARRAY);
           # Render all n points, starting at point 0, render them as POINTS:
            glDrawArrays(GL_POINTS, 0, len(xstart));
           # Disable fast rendering of arrays:
            #glDisableClientState(GL_VERTEX_ARRAY);
        #glFlush()
        t1[frame] = time.time() - t1[frame]

        pygame.display.flip()
        #pygame.time.wait(10)
        xstart = xstart + 0.008
        #xy[0,:] = xy[0,:] + 0.008
        #t1[frame] = time.time()
        #xstart_mask = Numeric.where(xy[0,:] > 1.0, 1, 0)
        #Numeric.putmask(xy[0,:], xstart_mask, -xy[0,:])
        #t1[frame] = time.time()
        #xstart = xy[0,:]
        #ystart = xy[1,:]
        x = xstart*xstart
        y = ystart*ystart
        limit = x+y
        #xy[0,:] = Numeric.choose(Numeric.greater(limit,1.0), (xy[0,:], 
-xy[0,:]))
        xstart = Numeric.choose(Numeric.greater(limit,1.0), (xstart, -xstart))
        ystart = Numeric.choose(Numeric.greater(limit,1.0), (ystart, -ystart))
       #xstart = xy[0,:] 
        #t1[frame] = time.time() - t1[frame]

        frame += 1
      #To replace the values in the original data array T for which bigpts_mask 
is true (i.e. 1), use the Numeric.putmask command. For instance, to replace all 
the points where T is greater than 280 K with 5 K:

    #print zip([xstart,ystart]), xstart,ystart
    count = 0
    for i in range(NUM_POINTS):
        if t1[i]*1000 > 0.20:
           count += 1
           print count,t1[i]*1000 
#for i in range(10):
#        print "%d\t" % random.randint(0,NUM_POINTS)


if __name__ == '__main__': main()

Other related posts: