我試圖迴避PyOpenGL的緩慢和高開銷的後綁定前端,並專門使用原始後端實施...PyOpenGL如何用glGenBuffers實現它的魔力?
我遇到的問題是我似乎無法弄清楚如何前端將後端功能glGenBuffers(n, buffers)
變成buffers = glGenBuffers(n)
。
我想知道的是我通過後端函數的參數buffers
?
我試圖迴避PyOpenGL的緩慢和高開銷的後綁定前端,並專門使用原始後端實施...PyOpenGL如何用glGenBuffers實現它的魔力?
我遇到的問題是我似乎無法弄清楚如何前端將後端功能glGenBuffers(n, buffers)
變成buffers = glGenBuffers(n)
。
我想知道的是我通過後端函數的參數buffers
?
以下是使用glGenBuffers
創建一個或多個緩衝區的一些示例。如果你必須使用像glGenBuffers(n, buffers)
這樣的函數調用,你可以直接使用ctypes或者使用PyOpenGL的GLint
,它包裝一個ctypes數據類型。
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)
作爲一個方面說明,我不確定這樣做的好處是什麼。我懷疑圍繞glGenBuffers
的方便包裝真的太慢了,以至於應該避免使用像buffers = glGenBuffers(n)
這樣的典型方法。我很想知道這是否是您的性能瓶頸。希望這可以幫助!
更新: 您關於__call__
開銷評論後,我想我會測試它在timeit。這裏是我的代碼,與旁邊的每個計時塊包含秒的結果:
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
從這些結果,它看起來像你產生不作過多的影響緩衝區的數目,所以應該總是被視爲一個列表,即使當n = 1時也是如此。不太清楚爲什麼會出現這種情況,或許在這種情況下幕後發生了某種轉換。奇怪的是,它看起來像GLint()比直接使用ctypes更好,這對我也沒有意義。無論哪種方式,純Python版本的執行速度最慢,我想對於其他更復雜的OpenGL函數,差異會更大!
感謝您的詳細回答,是的,尤其是在我的單核4GB筆記本電腦上......但不是簡單地告訴我,我應該在後端和前端實施之間顯示時間結果...在分析極端大'__call__'包裝應用於這樣的功能,我已經可以告訴你,後端功能將會有明顯的速度提升。 – Tcll
好吧,所以我試圖用timeit來確定是否確實存在性能差異,而且看起來你是對的。我正在使用此信息更新我的帖子。總體而言,結果似乎是,您應該始終將緩衝區參數視爲列表,即使在n = 1的緩衝區中! – CodeSurgeon
我仍然沒有得到我的結果,因爲我仍然從iqm GPU演示中移植代碼,但是我從來不會猜到這一點......也是因爲GLint對你更好的原因是因爲點運算符很慢...嘗試導入c_int並直接調用它。 (它有助於知道點運算符只是對'__getattribute__'的調用) – Tcll