changeset 426:5d7bb2fd74f7

Never keep texture on the host when it has been uploaded, and prevent them from being decoded again.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 16 Jul 2013 21:11:35 +0200
parents 1104dc2553ee
children 0604f4fbbe3c
files pytouhou/lib/opengl.pxd pytouhou/ui/anmrenderer.pyx pytouhou/ui/background.pxd pytouhou/ui/background.pyx pytouhou/ui/gamerunner.pyx pytouhou/ui/renderer.pyx pytouhou/ui/texture.pxd pytouhou/ui/texture.pyx
diffstat 8 files changed, 76 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/lib/opengl.pxd
+++ b/pytouhou/lib/opengl.pxd
@@ -94,6 +94,7 @@ cdef extern from 'GL/gl.h':
     void glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
 
     void glGenTextures(GLsizei n, GLuint *textures)
+    void glDeleteTextures(GLsizei n, const GLuint *textures)
     void glBindTexture(GLenum target, GLuint texture)
     void glTexParameteri(GLenum target, GLenum pname, GLint param)
     void glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format_, GLenum type_, const GLvoid *data)
--- a/pytouhou/ui/anmrenderer.pyx
+++ b/pytouhou/ui/anmrenderer.pyx
@@ -37,7 +37,7 @@ class ANMRenderer(Renderer):
         Renderer.__init__(self, resource_loader)
 
         self.window = window
-        self.texture_manager.preload(resource_loader.instanced_anms.values())
+        self.texture_manager.load(resource_loader.instanced_anms.values())
 
         self._anm_wrapper = anm_wrapper
         self.sprites = sprites
--- a/pytouhou/ui/background.pxd
+++ b/pytouhou/ui/background.pxd
@@ -1,3 +1,5 @@
+from pytouhou.lib.opengl cimport GLuint
+
 cdef struct Vertex:
     float x, y, z
     float u, v
@@ -5,8 +7,7 @@ cdef struct Vertex:
 
 
 cdef class BackgroundRenderer:
-    cdef public texture_manager
-    cdef object texture_key
+    cdef GLuint texture
     cdef unsigned short blendfunc, nb_vertices
     cdef Vertex *vertex_buffer
     cdef unsigned int use_fixed_pipeline, vbo
--- a/pytouhou/ui/background.pyx
+++ b/pytouhou/ui/background.pyx
@@ -35,8 +35,7 @@ cdef class BackgroundRenderer:
         free(self.vertex_buffer)
 
 
-    def __init__(self, texture_manager, use_fixed_pipeline):
-        self.texture_manager = texture_manager
+    def __init__(self, use_fixed_pipeline):
         self.use_fixed_pipeline = use_fixed_pipeline
 
         if not use_fixed_pipeline:
@@ -61,7 +60,7 @@ cdef class BackgroundRenderer:
 
         glEnable(GL_DEPTH_TEST)
         glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[self.blendfunc])
-        glBindTexture(GL_TEXTURE_2D, self.texture_manager[self.texture_key])
+        glBindTexture(GL_TEXTURE_2D, self.texture)
         glDrawArrays(GL_QUADS, 0, self.nb_vertices)
         glDisable(GL_DEPTH_TEST)
 
@@ -91,7 +90,7 @@ cdef class BackgroundRenderer:
 
                 nb_vertices += 4
 
-        self.texture_key, self.blendfunc = key
+        self.texture, self.blendfunc = key
         self.nb_vertices = nb_vertices
         self.vertex_buffer = <Vertex*> realloc(vertex_buffer, nb_vertices * sizeof(Vertex))
 
--- a/pytouhou/ui/gamerunner.pyx
+++ b/pytouhou/ui/gamerunner.pyx
@@ -56,10 +56,10 @@ class GameRunner(GameRenderer):
         self.game = game
         self.background = background
 
-        self.texture_manager.preload(game.resource_loader.instanced_anms.values())
+        self.texture_manager.load(game.resource_loader.instanced_anms.values())
 
         if background:
-            self.background_renderer = BackgroundRenderer(self.texture_manager, self.use_fixed_pipeline)
+            self.background_renderer = BackgroundRenderer(self.use_fixed_pipeline)
             self.background_renderer.prerender(background)
 
         self.set_input(replay)
--- a/pytouhou/ui/renderer.pyx
+++ b/pytouhou/ui/renderer.pyx
@@ -27,7 +27,7 @@ from pytouhou.lib.opengl cimport \
           glGenBuffers)
 
 from .sprite cimport get_sprite_rendering_data
-from .texture cimport TextureManager
+from .texture import TextureManager
 
 
 MAX_ELEMENTS = 640*4*3
@@ -100,7 +100,7 @@ cdef class Renderer:
             glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), <void*>20)
             glEnableVertexAttribArray(2)
 
-        for (texture_key, blendfunc), indices in indices_by_texture.items():
+        for (texture, blendfunc), indices in indices_by_texture.items():
 
             #TODO: find a more elegent way.
             nb_indices = len(indices)
@@ -109,7 +109,7 @@ cdef class Renderer:
                 new_indices[i] = indices[i]
 
             glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc])
-            glBindTexture(GL_TEXTURE_2D, self.texture_manager[texture_key])
+            glBindTexture(GL_TEXTURE_2D, texture)
             glDrawElements(GL_TRIANGLES, nb_indices, GL_UNSIGNED_SHORT, new_indices)
             free(new_indices)
 
deleted file mode 100644
--- a/pytouhou/ui/texture.pxd
+++ /dev/null
@@ -1,3 +0,0 @@
-cdef class TextureManager:
-    cdef public object loader
-    cdef public dict textures
--- a/pytouhou/ui/texture.pyx
+++ b/pytouhou/ui/texture.pyx
@@ -16,7 +16,8 @@ from pytouhou.lib.opengl cimport \
          (glTexParameteri, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER,
           GL_LINEAR, GL_BGRA, GL_RGBA, GL_RGB, GL_LUMINANCE, GL_UNSIGNED_BYTE,
           GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4_REV,
-          glGenTextures, glBindTexture, glTexImage2D, GL_TEXTURE_2D, GLuint)
+          glGenTextures, glBindTexture, glTexImage2D, GL_TEXTURE_2D, GLuint,
+          glDeleteTextures)
 
 from pytouhou.lib.sdl import load_png, create_rgb_surface
 from pytouhou.formats.thtx import Texture #TODO: perhaps define that elsewhere?
@@ -24,85 +25,81 @@ from pytouhou.formats.thtx import Textur
 import os
 
 
-cdef class TextureManager:
-    def __init__(self, loader=None):
-        self.loader = loader
-        self.textures = {}
+class TextureId(int):
+    def __del__(self):
+        cdef GLuint texture = self
+        glDeleteTextures(1, &texture)
 
 
-    def __getitem__(self, key):
-        if not key in self.textures:
-            self.textures[key] = self.load_texture(key)
-        return self.textures[key]
+class TextureManager(object):
+    def __init__(self, loader=None):
+        self.loader = loader
 
 
-    def preload(self, anm_wrapper):
-        for anm in anm_wrapper:
-            anm.texture = self.load_png_texture(anm.first_name, anm.secondary_name)
+    def load(self, anm_list):
+        for anm in anm_list:
+            if not hasattr(anm, 'texture'):
+                texture = decode_png(self.loader, anm.first_name, anm.secondary_name)
+                anm.texture = load_texture(texture)
 
 
-    def load_png_texture(self, first_name, secondary_name):
-        image_file = load_png(self.loader.get_file(os.path.basename(first_name)))
-        width, height = image_file.width, image_file.height
+cdef decode_png(loader, first_name, secondary_name):
+    image_file = load_png(loader.get_file(os.path.basename(first_name)))
+    width, height = image_file.width, image_file.height
 
-        # Support only 32 bits RGBA. Paletted surfaces are awful to work with.
-        #TODO: verify it doesn’t blow up on big-endian systems.
-        new_image = create_rgb_surface(width, height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000)
-        new_image.blit(image_file)
+    # Support only 32 bits RGBA. Paletted surfaces are awful to work with.
+    #TODO: verify it doesn’t blow up on big-endian systems.
+    new_image = create_rgb_surface(width, height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000)
+    new_image.blit(image_file)
 
-        if secondary_name:
-            alpha_file = load_png(self.loader.get_file(os.path.basename(secondary_name)))
-            assert (width == alpha_file.width and
-                    height == alpha_file.height)
+    if secondary_name:
+        alpha_file = load_png(loader.get_file(os.path.basename(secondary_name)))
+        assert (width == alpha_file.width and height == alpha_file.height)
 
-            new_alpha_file = create_rgb_surface(width, height, 24)
-            new_alpha_file.blit(alpha_file)
+        new_alpha_file = create_rgb_surface(width, height, 24)
+        new_alpha_file.blit(alpha_file)
 
-            new_image.set_alpha(new_alpha_file)
+        new_image.set_alpha(new_alpha_file)
 
-        return Texture(width, height, -4, new_image.pixels)
+    return Texture(width, height, -4, new_image.pixels)
 
 
-    def load_texture(self, key):
-        cdef GLuint id_
-
-        if not isinstance(key, Texture):
-            first_name, secondary_name = key
-            key = self.load_png_texture(first_name, secondary_name)
+cdef load_texture(thtx):
+    cdef GLuint texture
 
-        if key.fmt == 1:
-            format_ = GL_BGRA
-            type_ = GL_UNSIGNED_BYTE
-            composants = GL_RGBA
-        elif key.fmt == 3:
-            format_ = GL_RGB
-            type_ = GL_UNSIGNED_SHORT_5_6_5
-            composants = GL_RGB
-        elif key.fmt == 5:
-            format_ = GL_BGRA
-            type_ = GL_UNSIGNED_SHORT_4_4_4_4_REV
-            composants = GL_RGBA
-        elif key.fmt == 7:
-            format_ = GL_LUMINANCE
-            type_ = GL_UNSIGNED_BYTE
-            composants = GL_LUMINANCE
-        elif key.fmt == -4: #XXX: non-standard
-            format_ = GL_RGBA
-            type_ = GL_UNSIGNED_BYTE
-            composants = GL_RGBA
-        else:
-            raise Exception('Unknown texture type')
+    if thtx.fmt == 1:
+        format_ = GL_BGRA
+        type_ = GL_UNSIGNED_BYTE
+        composants = GL_RGBA
+    elif thtx.fmt == 3:
+        format_ = GL_RGB
+        type_ = GL_UNSIGNED_SHORT_5_6_5
+        composants = GL_RGB
+    elif thtx.fmt == 5:
+        format_ = GL_BGRA
+        type_ = GL_UNSIGNED_SHORT_4_4_4_4_REV
+        composants = GL_RGBA
+    elif thtx.fmt == 7:
+        format_ = GL_LUMINANCE
+        type_ = GL_UNSIGNED_BYTE
+        composants = GL_LUMINANCE
+    elif thtx.fmt == -4: #XXX: non-standard
+        format_ = GL_RGBA
+        type_ = GL_UNSIGNED_BYTE
+        composants = GL_RGBA
+    else:
+        raise Exception('Unknown texture type')
 
-        glGenTextures(1, &id_)
-        glBindTexture(GL_TEXTURE_2D, id_)
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
+    glGenTextures(1, &texture)
+    glBindTexture(GL_TEXTURE_2D, texture)
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
 
-        glTexImage2D(GL_TEXTURE_2D, 0,
-                     composants,
-                     key.width, key.height,
-                     0,
-                     format_, type_,
-                     <char*>key.data)
+    glTexImage2D(GL_TEXTURE_2D, 0,
+                 composants,
+                 thtx.width, thtx.height,
+                 0,
+                 format_, type_,
+                 <char*>thtx.data)
 
-        return id_
+    return TextureId(texture)