# HG changeset patch # User Emmanuel Gil Peyrot # Date 1386852437 -3600 # Node ID 94725968dabbc70048fe8171b80f763e2a1982e9 # Parent 0f2af75524626506552a4a8bae4b17e28086faff Use vertex array objects, to be compatible with OpenGL 3.1+ core profile. diff --git a/pytouhou/lib/opengl.pxd b/pytouhou/lib/opengl.pxd --- 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) diff --git a/pytouhou/ui/opengl/backend.pxd b/pytouhou/ui/opengl/backend.pxd --- 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 diff --git a/pytouhou/ui/opengl/backend.pyx b/pytouhou/ui/opengl/backend.pyx --- 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' diff --git a/pytouhou/ui/opengl/background.pxd b/pytouhou/ui/opengl/background.pxd --- 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 * diff --git a/pytouhou/ui/opengl/background.pyx b/pytouhou/ui/opengl/background.pyx --- 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), 0) + glEnableVertexAttribArray(0) + glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), 12) + glEnableVertexAttribArray(1) + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), 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), 0) - glEnableVertexAttribArray(0) - glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), 12) - glEnableVertexAttribArray(1) - glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), 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): diff --git a/pytouhou/ui/opengl/renderer.pxd b/pytouhou/ui/opengl/renderer.pxd --- 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 * diff --git a/pytouhou/ui/opengl/renderer.pyx b/pytouhou/ui/opengl/renderer.pyx --- 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), 0) + glEnableVertexAttribArray(0) + glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), 8) + glEnableVertexAttribArray(1) + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), 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), 0) + glEnableVertexAttribArray(0) + glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(PassthroughVertex), 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), 0) - glEnableVertexAttribArray(0) - glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), 8) - glEnableVertexAttribArray(1) - glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), 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), 0) - glEnableVertexAttribArray(0) - glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), 8) - glEnableVertexAttribArray(1) - glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), 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), 0) - glEnableVertexAttribArray(0) - glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(PassthroughVertex), 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: