# HG changeset patch # User Emmanuel Gil Peyrot # Date 1412786067 -7200 # Node ID 6c9d8a3d853f438d3baf2d9831698aae98dcde78 # Parent 4b0593da29d51df347c78a25c2613d4a797a8d0e Use ARB_framebuffer_blit instead of a second rendering pass for scaled rendering, if supported, and remove framebuffer stuff from the Renderer. diff --git a/pytouhou/lib/opengl.pxd b/pytouhou/lib/opengl.pxd --- a/pytouhou/lib/opengl.pxd +++ b/pytouhou/lib/opengl.pxd @@ -101,6 +101,7 @@ cdef extern from 'epoxy/gl.h' nogil: ctypedef enum GLenum_framebuffer 'GLenum': GL_FRAMEBUFFER + GL_DRAW_FRAMEBUFFER ctypedef enum GLenum_renderbuffer 'GLenum': GL_RENDERBUFFER @@ -198,6 +199,7 @@ cdef extern from 'epoxy/gl.h' nogil: void glRenderbufferStorage(GLenum_renderbuffer target, GLenum_renderbuffer_format internalformat, GLsizei width, GLsizei height) void glFramebufferRenderbuffer(GLenum_framebuffer target, GLenum_attachment attachment, GLenum_renderbuffer renderbuffertarget, GLuint renderbuffer) GLenum_framebuffer_status glCheckFramebufferStatus(GLenum_framebuffer target) + void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter_) void glGenVertexArrays(GLsizei n, GLuint *arrays) void glDeleteVertexArrays(GLsizei n, const GLuint *arrays) 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 @@ -7,5 +7,6 @@ cdef int double_buffer cdef bint is_legacy cdef bint use_debug_group cdef bint use_vao +cdef bint use_framebuffer_blit cdef bint use_primitive_restart 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 @@ -54,6 +54,7 @@ def discover_features(): use_debug_group = (is_desktop and version >= 43) or epoxy_has_gl_extension('GL_KHR_debug') use_vao = (is_desktop and version >= 30) or epoxy_has_gl_extension('GL_ARB_vertex_array_object') use_primitive_restart = (is_desktop and version >= 31) + use_framebuffer_blit = (is_desktop and version >= 30) if is_desktop: # gl_FragColor isn’t supported anymore starting with GLSL 4.2. diff --git a/pytouhou/ui/opengl/framebuffer.pxd b/pytouhou/ui/opengl/framebuffer.pxd --- a/pytouhou/ui/opengl/framebuffer.pxd +++ b/pytouhou/ui/opengl/framebuffer.pxd @@ -8,7 +8,8 @@ cdef struct PassthroughVertex: cdef class Framebuffer: cdef GLuint fbo, texture, rbo, vbo, vao cdef PassthroughVertex[4] buf + cdef int x, y, width, height cpdef bind(self) cdef void set_state(self) nogil - cdef void render(self) nogil + cdef void render(self, int x, int y, int width, int height) nogil diff --git a/pytouhou/ui/opengl/framebuffer.pyx b/pytouhou/ui/opengl/framebuffer.pyx --- a/pytouhou/ui/opengl/framebuffer.pyx +++ b/pytouhou/ui/opengl/framebuffer.pyx @@ -26,9 +26,11 @@ from pytouhou.lib.opengl cimport \ glDeleteBuffers, glBindBuffer, glBufferData, GL_ARRAY_BUFFER, GL_STATIC_DRAW, glGenVertexArrays, glDeleteVertexArrays, glBindVertexArray, glVertexAttribPointer, GL_SHORT, GL_FLOAT, - glEnableVertexAttribArray, glDrawArrays, GL_TRIANGLE_STRIP) + glEnableVertexAttribArray, glDrawArrays, GL_TRIANGLE_STRIP, + glBlitFramebuffer, GL_DRAW_FRAMEBUFFER, glClear, GL_COLOR_BUFFER_BIT, + GL_DEPTH_BUFFER_BIT, glViewport, glBlendFunc, GL_ONE, GL_ZERO) -from .backend cimport use_debug_group, use_vao +from .backend cimport use_debug_group, use_vao, use_framebuffer_blit cdef class Framebuffer: def __init__(self, int x, int y, int width, int height): @@ -62,36 +64,43 @@ cdef class Framebuffer: assert glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE glBindFramebuffer(GL_FRAMEBUFFER, 0) - # We’ll use only those vertices, everytime. - self.buf[0] = PassthroughVertex(x, y, 0, 1) - self.buf[1] = PassthroughVertex(x + width, y, 1, 1) - self.buf[2] = PassthroughVertex(x, y + height, 0, 0) - self.buf[3] = PassthroughVertex(x + width, y + height, 1, 0) + if not use_framebuffer_blit: + # We’ll use only those vertices, everytime. + self.buf[0] = PassthroughVertex(x, y, 0, 1) + self.buf[1] = PassthroughVertex(x + width, y, 1, 1) + self.buf[2] = PassthroughVertex(x, y + height, 0, 0) + self.buf[3] = PassthroughVertex(x + width, y + height, 1, 0) + + # Now we upload those vertices into a static vbo. + glGenBuffers(1, &self.vbo) + glBindBuffer(GL_ARRAY_BUFFER, self.vbo) + glBufferData(GL_ARRAY_BUFFER, sizeof(self.buf), self.buf, GL_STATIC_DRAW) - # Now we upload those vertices into a static vbo. - glGenBuffers(1, &self.vbo) - glBindBuffer(GL_ARRAY_BUFFER, self.vbo) - glBufferData(GL_ARRAY_BUFFER, sizeof(self.buf), self.buf, GL_STATIC_DRAW) + # As a performance optimisation, if supported, store the rendering state into a vao. + if use_vao and not use_framebuffer_blit: + glGenVertexArrays(1, &self.vao) + glBindVertexArray(self.vao) + self.set_state() + glBindVertexArray(0) - # As a performance optimisation, if supported, store the rendering state into a vao. - if use_vao: - glGenVertexArrays(1, &self.vao) - glBindVertexArray(self.vao) - self.set_state() - glBindVertexArray(0) - - glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindBuffer(GL_ARRAY_BUFFER, 0) + else: + self.x = x + self.y = y + self.width = width + self.height = height if use_debug_group: glPopDebugGroup() def __dealloc__(self): - if use_vao: - glDeleteVertexArrays(1, &self.vao) + if not use_framebuffer_blit: + glDeleteBuffers(1, &self.vbo) + if use_vao: + glDeleteVertexArrays(1, &self.vao) glDeleteTextures(1, &self.texture) glDeleteRenderbuffers(1, &self.rbo) glDeleteFramebuffers(1, &self.fbo) - glDeleteBuffers(1, &self.vbo) cpdef bind(self): glBindFramebuffer(GL_FRAMEBUFFER, self.fbo) @@ -105,17 +114,34 @@ cdef class Framebuffer: glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(PassthroughVertex), 4) glEnableVertexAttribArray(1) - cdef void render(self) nogil: - if use_vao: - glBindVertexArray(self.vao) + cdef void render(self, int x, int y, int width, int height) nogil: + if use_debug_group: + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Framebuffer drawing") + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + if use_framebuffer_blit: + glBlitFramebuffer(self.x, self.y, self.width, self.height, + x, y, x + width, y + height, + GL_COLOR_BUFFER_BIT, GL_LINEAR) else: - self.set_state() + glViewport(x, y, width, height) + glBlendFunc(GL_ONE, GL_ZERO) - glBindTexture(GL_TEXTURE_2D, self.texture) - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) - glBindTexture(GL_TEXTURE_2D, 0) + if use_vao: + glBindVertexArray(self.vao) + else: + self.set_state() - if use_vao: - glBindVertexArray(0) - else: - glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindTexture(GL_TEXTURE_2D, self.texture) + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) + glBindTexture(GL_TEXTURE_2D, 0) + + if use_vao: + glBindVertexArray(0) + else: + glBindBuffer(GL_ARRAY_BUFFER, 0) + + if use_debug_group: + glPopDebugGroup() diff --git a/pytouhou/ui/opengl/gamerenderer.pyx b/pytouhou/ui/opengl/gamerenderer.pyx --- a/pytouhou/ui/opengl/gamerenderer.pyx +++ b/pytouhou/ui/opengl/gamerenderer.pyx @@ -99,7 +99,7 @@ cdef class GameRenderer(Renderer): self.passthrough_shader.bind() self.passthrough_shader.uniform_matrix('mvp', self.interface_mvp) - self.render_framebuffer(self.framebuffer) + self.framebuffer.render(self.x, self.y, self.width, self.height) if use_debug_group: glPopDebugGroup() 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 @@ -37,4 +37,3 @@ cdef class Renderer: 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 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 @@ -22,12 +22,11 @@ from pytouhou.lib.opengl cimport \ glBindTexture, glDrawElements, glBindBuffer, glBufferData, GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_FLOAT, GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO, GL_TEXTURE_2D, GL_TRIANGLES, - GL_TRIANGLE_STRIP, glGenBuffers, glBindFramebuffer, glViewport, - glDeleteBuffers, GL_FRAMEBUFFER, glClear, GL_COLOR_BUFFER_BIT, - GL_DEPTH_BUFFER_BIT, GLuint, glDeleteTextures, glGenVertexArrays, - glDeleteVertexArrays, glBindVertexArray, glPushDebugGroup, - GL_DEBUG_SOURCE_APPLICATION, glPopDebugGroup) + GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_TEXTURE_2D, GL_TRIANGLES, + GL_TRIANGLE_STRIP, glGenBuffers, glDeleteBuffers, + GLuint, glDeleteTextures, glGenVertexArrays, glDeleteVertexArrays, + glBindVertexArray, glPushDebugGroup, GL_DEBUG_SOURCE_APPLICATION, + glPopDebugGroup) from pytouhou.lib.sdl import SDLError @@ -268,20 +267,3 @@ cdef class Renderer: if use_debug_group: glPopDebugGroup() - - - cdef void render_framebuffer(self, Framebuffer fb): - assert not is_legacy - - if use_debug_group: - glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Framebuffer drawing") - - glBindFramebuffer(GL_FRAMEBUFFER, 0) - glViewport(self.x, self.y, self.width, self.height) - glBlendFunc(GL_ONE, GL_ZERO) - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - - fb.render() - - if use_debug_group: - glPopDebugGroup()