Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does PyOpenGL do it's magic with glGenBuffers?

Tags:

python

I'm trying to shy away from the slow and high-overhead latebind frontend of PyOpenGL and specifically use the raw backend implementation...

The problem I'm having is I can't seem to figure out how the frontend turns the backend function glGenBuffers( n, buffers ) into buffers = glGenBuffers( n ).

All I want to know is what do I pass to the buffers argument of the backend function??

like image 803
Tcll Avatar asked Dec 04 '16 01:12

Tcll


1 Answers

Here are some examples of creating one or multiple buffers using glGenBuffers. If you must use function calls like glGenBuffers(n, buffers), you can either use ctypes directly or use PyOpenGL's GLint, which wraps up a ctypes data type.

import ctypes
import numpy as np
from OpenGL.GL import *
import pygame

pygame.init()
screen = pygame.display.set_mode((800,600), pygame.OPENGL | pygame.DOUBLEBUF) #initialize OpenGL

py_id = glGenBuffers(1) #typical way to generate a single index
c_id = ctypes.c_int() #using ctypes to generate a second index
glGenBuffers(1, c_id)
gl_id = GLint() #using GL wrapper to generate a third index
glGenBuffers(1, gl_id)
print py_id, c_id.value, gl_id.value #should print 1 2 3

n = 10
py_list = glGenBuffers(n) #typical way to generate multiple indices
c_list = (ctypes.c_int * n)() #using ctypes to generate multiple indices
glGenBuffers(n, c_list)
gl_list = (GLint * n)() #using GL wrapper to generate multiple indices
glGenBuffers(n, gl_list)
print py_list, list(py_list) #note the default is a numpy array!
print np.array(c_list), list(c_list)
print np.array(gl_list), list(gl_list)

As a side note, I am not sure what the benefit of doing this is. I doubt that the convenient wrapper around glGenBuffers is really so slow that the typical approach like buffers = glGenBuffers(n) should be avoided. I am really curious to know if this is a performance bottleneck for you. Hope this helps!

Update: After your comment about the overhead of __call__, I figured I would test it out in timeit. Here is my code, with the results in seconds included next to each timed block:

import ctypes
import numpy as np
from OpenGL.GL import *
import pygame
import timeit

pygame.init()
screen = pygame.display.set_mode((800,600), pygame.OPENGL | pygame.DOUBLEBUF) #initialize OpenGL

def test(func, repeats):
    start_time = timeit.default_timer()
    for i in range(repeats):
        func()
    elapsed = timeit.default_timer() - start_time
    print elapsed

def func1():
    py_id = glGenBuffers(1)

def func2():
    c_id = ctypes.c_int()
    glGenBuffers(1, c_id)

def func3():
    gl_id = GLint()
    glGenBuffers(1, gl_id)

def func4():
    n = 1
    py_list = glGenBuffers(n)

def func5():
    n = 1
    c_list = (ctypes.c_int * n)()
    glGenBuffers(n, c_list)

def func6():
    n = 1
    gl_list = (GLint * n)()
    glGenBuffers(n, gl_list)

def func7():
    n = 100
    py_list = glGenBuffers(n)

def func8():
    n = 100
    c_list = (ctypes.c_int * n)()
    glGenBuffers(n, c_list)

def func9():
    n = 100
    gl_list = (GLint * n)()
    glGenBuffers(n, gl_list)

test(func1, 1000000)#4.12597930903
test(func2, 1000000)#5.2951610055
test(func3, 1000000)#5.17853478658
test(func4, 1000000)#4.06362866711
test(func5, 1000000)#3.45259988251
test(func6, 1000000)#3.43240155354
test(func7, 1000000)#4.128162421
test(func8, 1000000)#3.57384911559
test(func9, 1000000)#3.52125689729

From these results, it looks like the number of buffers you are generating does not make too much of an impact, so it should always be treated as a list, even when n=1. Not really sure why that is the case, perhaps some sort of conversion is going on behind the scenes in that case. Oddly enough, it looks like GLint() performs better than using ctypes directly which also makes no sense to me. Either way, the pure python version does perform the slowest, and I imagine that for other more complex OpenGL functions, the difference can be even greater!

like image 121
CodeSurgeon Avatar answered Oct 03 '22 00:10

CodeSurgeon