changeset 587:6c9d8a3d853f

Use ARB_framebuffer_blit instead of a second rendering pass for scaled rendering, if supported, and remove framebuffer stuff from the Renderer.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 08 Oct 2014 18:34:27 +0200
parents 4b0593da29d5
children 7a82c4b52b16
files pytouhou/lib/opengl.pxd pytouhou/ui/opengl/backend.pxd pytouhou/ui/opengl/backend.pyx pytouhou/ui/opengl/framebuffer.pxd pytouhou/ui/opengl/framebuffer.pyx pytouhou/ui/opengl/gamerenderer.pyx pytouhou/ui/opengl/renderer.pxd pytouhou/ui/opengl/renderer.pyx
diffstat 8 files changed, 71 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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
--- 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.
--- 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
--- 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), <void*>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()
--- 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()
--- 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 *
--- 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()