changeset 558:94725968dabb

Use vertex array objects, to be compatible with OpenGL 3.1+ core profile.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Thu, 12 Dec 2013 13:47:17 +0100
parents 0f2af7552462
children 1be60813f7cb
files pytouhou/lib/opengl.pxd pytouhou/ui/opengl/backend.pxd pytouhou/ui/opengl/backend.pyx pytouhou/ui/opengl/background.pxd pytouhou/ui/opengl/background.pyx pytouhou/ui/opengl/renderer.pxd pytouhou/ui/opengl/renderer.pyx
diffstat 7 files changed, 124 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/lib/opengl.pxd
+++ b/pytouhou/lib/opengl.pxd
@@ -155,3 +155,7 @@ cdef extern from 'epoxy/gl.h' nogil:
     void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
     void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
     GLenum glCheckFramebufferStatus(GLenum target)
+
+    void glGenVertexArrays(GLsizei n, GLuint *arrays)
+    void glDeleteVertexArrays(GLsizei n, const GLuint *arrays)
+    void glBindVertexArray(GLuint array)
--- a/pytouhou/ui/opengl/backend.pxd
+++ b/pytouhou/ui/opengl/backend.pxd
@@ -6,4 +6,5 @@ cdef int major
 cdef int minor
 cdef int double_buffer
 cdef bint is_legacy
+cdef bint use_vao
 cdef str shader_header
--- a/pytouhou/ui/opengl/backend.pyx
+++ b/pytouhou/ui/opengl/backend.pyx
@@ -11,7 +11,7 @@ GameRenderer = None
 
 
 def init(options):
-    global flavor, version, major, minor, double_buffer, is_legacy, shader_header, GameRenderer
+    global flavor, version, major, minor, double_buffer, is_legacy, use_vao, shader_header, GameRenderer
 
     flavor_name = options['flavor']
     assert flavor_name in ('core', 'es', 'compatibility', 'legacy')
@@ -26,6 +26,7 @@ def init(options):
 
     maybe_double_buffer = options['double-buffer']
     double_buffer = maybe_double_buffer if maybe_double_buffer is not None else -1
+    use_vao = (major == 3 and minor >= 1) or major > 3
 
     is_legacy = flavor_name == 'legacy'
 
--- a/pytouhou/ui/opengl/background.pxd
+++ b/pytouhou/ui/opengl/background.pxd
@@ -14,10 +14,12 @@ cdef class BackgroundRenderer:
 
     # For modern GL.
     cdef GLuint vbo, ibo
+    cdef GLuint vao
 
     # For fixed pipeline.
     cdef Vertex *vertex_buffer
     cdef GLushort *indices
 
+    cdef void set_state(self) nogil
     cdef void render_background(self) except *
     cdef void load(self, background, Renderer renderer) except *
--- a/pytouhou/ui/opengl/background.pyx
+++ b/pytouhou/ui/opengl/background.pyx
@@ -21,17 +21,26 @@ from pytouhou.lib.opengl cimport \
           GL_STATIC_DRAW, GL_UNSIGNED_BYTE, GL_FLOAT, GL_SRC_ALPHA,
           GL_ONE_MINUS_SRC_ALPHA, GL_TEXTURE_2D, glGenBuffers, glEnable,
           glDisable, GL_DEPTH_TEST, glDrawElements, GL_TRIANGLES,
-          GL_UNSIGNED_SHORT, GL_ELEMENT_ARRAY_BUFFER)
+          GL_UNSIGNED_SHORT, GL_ELEMENT_ARRAY_BUFFER, glDeleteBuffers,
+          glGenVertexArrays, glDeleteVertexArrays, glBindVertexArray)
 
 from .sprite cimport get_sprite_rendering_data
+from .backend cimport use_vao
 
 
 cdef class BackgroundRenderer:
     def __dealloc__(self):
-        if self.vertex_buffer != NULL:
-            free(self.vertex_buffer)
-        if self.indices != NULL:
-            free(self.indices)
+        if self.use_fixed_pipeline:
+            if self.vertex_buffer != NULL:
+                free(self.vertex_buffer)
+            if self.indices != NULL:
+                free(self.indices)
+        else:
+            glDeleteBuffers(1, &self.vbo)
+            glDeleteBuffers(1, &self.ibo)
+
+            if use_vao:
+                glDeleteVertexArrays(1, &self.vao)
 
 
     def __init__(self, use_fixed_pipeline):
@@ -41,6 +50,26 @@ cdef class BackgroundRenderer:
             glGenBuffers(1, &self.vbo)
             glGenBuffers(1, &self.ibo)
 
+            if use_vao:
+                glGenVertexArrays(1, &self.vao)
+
+                glBindVertexArray(self.vao)
+                self.set_state()
+                glBindVertexArray(0)
+
+
+    cdef void set_state(self) nogil:
+        glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.ibo)
+
+        #TODO: find a way to use offsetof() instead of those ugly hardcoded values.
+        glVertexAttribPointer(0, 3, GL_FLOAT, False, sizeof(Vertex), <void*>0)
+        glEnableVertexAttribArray(0)
+        glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), <void*>12)
+        glEnableVertexAttribArray(1)
+        glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), <void*>20)
+        glEnableVertexAttribArray(2)
+
 
     cdef void render_background(self):
         if self.use_fixed_pipeline:
@@ -49,17 +78,11 @@ cdef class BackgroundRenderer:
             glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &self.vertex_buffer[0].u)
             glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), &self.vertex_buffer[0].r)
         else:
-            glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
-            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.ibo)
             indices = NULL
-
-            #TODO: find a way to use offsetof() instead of those ugly hardcoded values.
-            glVertexAttribPointer(0, 3, GL_FLOAT, False, sizeof(Vertex), <void*>0)
-            glEnableVertexAttribArray(0)
-            glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), <void*>12)
-            glEnableVertexAttribArray(1)
-            glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), <void*>20)
-            glEnableVertexAttribArray(2)
+            if use_vao:
+                glBindVertexArray(self.vao)
+            else:
+                self.set_state()
 
         glEnable(GL_DEPTH_TEST)
         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
@@ -68,8 +91,11 @@ cdef class BackgroundRenderer:
         glDisable(GL_DEPTH_TEST)
 
         if not self.use_fixed_pipeline:
-            glBindBuffer(GL_ARRAY_BUFFER, 0)
-            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
+            if use_vao:
+                glBindVertexArray(0)
+            else:
+                glBindBuffer(GL_ARRAY_BUFFER, 0)
+                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
 
 
     cdef void load(self, background, Renderer renderer):
--- a/pytouhou/ui/opengl/renderer.pxd
+++ b/pytouhou/ui/opengl/renderer.pxd
@@ -31,6 +31,7 @@ cdef class Renderer:
 
     # For modern GL.
     cdef GLuint vbo, framebuffer_vbo, framebuffer_ibo
+    cdef GLuint vao, framebuffer_vao
 
     cdef bint use_fixed_pipeline #XXX
 
@@ -39,8 +40,11 @@ cdef class Renderer:
     cdef unsigned short last_indices[2 * MAX_TEXTURES]
     cdef PyObject *elements[640*3]
 
+    cdef void set_state(self) nogil
     cdef void render_elements(self, elements) except *
     cdef void render_quads(self, rects, colors, GLuint texture) except *
+
+    cdef void set_framebuffer_state(self) nogil
     cdef void render_framebuffer(self, Framebuffer fb) except *
 
 
--- a/pytouhou/ui/opengl/renderer.pyx
+++ b/pytouhou/ui/opengl/renderer.pyx
@@ -32,12 +32,14 @@ from pytouhou.lib.opengl cimport \
           GL_DEPTH_COMPONENT, GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT,
           GL_FRAMEBUFFER_COMPLETE, glClear, GL_COLOR_BUFFER_BIT,
           GL_DEPTH_BUFFER_BIT, GLuint, glDeleteTextures,
-          GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW)
+          GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, glGenVertexArrays,
+          glDeleteVertexArrays, glBindVertexArray)
 
 from pytouhou.lib.sdl import SDLError
 
 from pytouhou.game.element cimport Element
 from .sprite cimport get_sprite_rendering_data
+from .backend cimport use_vao
 
 from pytouhou.utils.helpers import get_logger
 
@@ -95,6 +97,10 @@ cdef class Renderer:
             glDeleteBuffers(1, &self.framebuffer_vbo)
             glDeleteBuffers(1, &self.vbo)
 
+            if use_vao:
+                glDeleteVertexArrays(1, &self.vao)
+                glDeleteVertexArrays(1, &self.framebuffer_vao)
+
 
     def __init__(self, resource_loader):
         # Only used in modern GL.
@@ -119,6 +125,43 @@ cdef class Renderer:
             glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(framebuffer_indices), framebuffer_indices, GL_STATIC_DRAW)
             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
 
+            if use_vao:
+                glGenVertexArrays(1, &self.vao)
+                glBindVertexArray(self.vao)
+                self.set_state()
+
+                glGenVertexArrays(1, &self.framebuffer_vao)
+                glBindVertexArray(self.framebuffer_vao)
+                self.set_framebuffer_state()
+                glBindVertexArray(0)
+
+
+    cdef void set_state(self) nogil:
+        glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
+
+        #TODO: find a way to use offsetof() instead of those ugly substractions.
+        glVertexAttribPointer(0, 3, GL_SHORT, False, sizeof(Vertex), <void*>0)
+        glEnableVertexAttribArray(0)
+        glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), <void*>8)
+        glEnableVertexAttribArray(1)
+        glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), <void*>16)
+        glEnableVertexAttribArray(2)
+
+        glBindBuffer(GL_ARRAY_BUFFER, 0)
+
+
+    cdef void set_framebuffer_state(self) nogil:
+        glBindBuffer(GL_ARRAY_BUFFER, self.framebuffer_vbo)
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.framebuffer_ibo)
+
+        #TODO: find a way to use offsetof() instead of those ugly hardcoded values.
+        glVertexAttribPointer(0, 2, GL_SHORT, False, sizeof(PassthroughVertex), <void*>0)
+        glEnableVertexAttribArray(0)
+        glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(PassthroughVertex), <void*>4)
+        glEnableVertexAttribArray(1)
+
+        glBindBuffer(GL_ARRAY_BUFFER, 0)
+
 
     cdef void render_elements(self, elements):
         cdef Element element
@@ -168,14 +211,12 @@ cdef class Renderer:
         else:
             glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
             glBufferData(GL_ARRAY_BUFFER, nb_vertices * sizeof(Vertex), &self.vertex_buffer[0], GL_DYNAMIC_DRAW)
+            glBindBuffer(GL_ARRAY_BUFFER, 0)
 
-            #TODO: find a way to use offsetof() instead of those ugly hardcoded values.
-            glVertexAttribPointer(0, 3, GL_SHORT, False, sizeof(Vertex), <void*>0)
-            glEnableVertexAttribArray(0)
-            glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), <void*>8)
-            glEnableVertexAttribArray(1)
-            glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), <void*>16)
-            glEnableVertexAttribArray(2)
+            if use_vao:
+                glBindVertexArray(self.vao)
+            else:
+                self.set_state()
 
         # Don’t change the state when it’s not needed.
         previous_blendfunc = -1
@@ -200,8 +241,8 @@ cdef class Renderer:
 
         glBindTexture(GL_TEXTURE_2D, 0)
 
-        if not self.use_fixed_pipeline:
-            glBindBuffer(GL_ARRAY_BUFFER, 0)
+        if not self.use_fixed_pipeline and use_vao:
+            glBindVertexArray(0)
 
 
     cdef void render_quads(self, rects, colors, GLuint texture):
@@ -228,22 +269,17 @@ cdef class Renderer:
         else:
             glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
             glBufferData(GL_ARRAY_BUFFER, 4 * length * sizeof(Vertex), buf, GL_DYNAMIC_DRAW)
+            glBindBuffer(GL_ARRAY_BUFFER, 0)
 
-            #TODO: find a way to use offsetof() instead of those ugly hardcoded values.
-            glVertexAttribPointer(0, 3, GL_SHORT, False, sizeof(Vertex), <void*>0)
-            glEnableVertexAttribArray(0)
-            glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), <void*>8)
-            glEnableVertexAttribArray(1)
-            glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), <void*>16)
-            glEnableVertexAttribArray(2)
+            if use_vao:
+                glBindVertexArray(self.vao)
+            else:
+                self.set_state()
 
         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
         glBindTexture(GL_TEXTURE_2D, texture)
         glDrawElements(GL_TRIANGLES, 6 * length, GL_UNSIGNED_SHORT, indices)
 
-        if not self.use_fixed_pipeline:
-            glBindBuffer(GL_ARRAY_BUFFER, 0)
-
 
     cdef void render_framebuffer(self, Framebuffer fb):
         cdef PassthroughVertex[4] buf
@@ -255,27 +291,28 @@ cdef class Renderer:
         glBlendFunc(GL_ONE, GL_ZERO)
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
 
-        glBindBuffer(GL_ARRAY_BUFFER, self.framebuffer_vbo)
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.framebuffer_ibo)
-
-        #TODO: find a way to use offsetof() instead of those ugly hardcoded values.
-        glVertexAttribPointer(0, 2, GL_SHORT, False, sizeof(PassthroughVertex), <void*>0)
-        glEnableVertexAttribArray(0)
-        glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(PassthroughVertex), <void*>4)
-        glEnableVertexAttribArray(1)
+        if use_vao:
+            glBindVertexArray(self.framebuffer_vao)
+        else:
+            self.set_framebuffer_state()
 
         buf[0] = PassthroughVertex(fb.x, fb.y, 0, 1)
         buf[1] = PassthroughVertex(fb.x + fb.width, fb.y, 1, 1)
         buf[2] = PassthroughVertex(fb.x + fb.width, fb.y + fb.height, 1, 0)
         buf[3] = PassthroughVertex(fb.x, fb.y + fb.height, 0, 0)
-        glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(PassthroughVertex), buf, GL_DYNAMIC_DRAW)
+
+        glBindBuffer(GL_ARRAY_BUFFER, self.framebuffer_vbo)
+        glBufferData(GL_ARRAY_BUFFER, sizeof(buf), buf, GL_DYNAMIC_DRAW)
+        glBindBuffer(GL_ARRAY_BUFFER, 0)
 
         glBindTexture(GL_TEXTURE_2D, fb.texture)
         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL)
         glBindTexture(GL_TEXTURE_2D, 0)
 
-        glBindBuffer(GL_ARRAY_BUFFER, 0)
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
+        if use_vao:
+            glBindVertexArray(0)
+        else:
+            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
 
 
 cdef class Framebuffer: