2012-01-03 19 views
11

Nuevo para desarrollar en iOS y, en particular, las nuevas características relacionadas con OpenGL en iOS 5, así que me disculpo si alguna de mis preguntas es tan básica.Liberar texturas (objetos GLKTextureInfo) asignados por GLKTextureLoader

La aplicación en la que estoy trabajando está diseñada para recibir marcos de cámara y mostrarlos en pantalla a través de OpenGL ES (la gente de gráficos se hará cargo de esto y agregará el verdadero OpenGL del que sé muy poco). La aplicación está desarrollada XCode4, y el objetivo es iPhone4 con iOS 5. Por el momento, utilicé el ARC y la funcionalidad GLKit y todo funciona bien, excepto por la pérdida de memoria al cargar las imágenes como textura. La aplicación recibe una "advertencia de memoria" muy pronto.

En concreto, me gustaría preguntar cómo liberar las texturas asignados por

@property(retain) GLKTextureInfo *texture; 

-(void)setTextureCGImage:(CGImageRef)image 
{ 
    NSError *error; 

    self.texture = [GLKTextureLoader textureWithCGImage:image options:nil error:&error]; 

    if (error) 
    { 
     NSLog(@"Error loading texture from image: %@",error); 
    } 
} 

El image es una imagen de cuarzo construido a partir del marco de la cámara (código de ejemplo de manzana). Sé que el problema no está en esa parte del código, ya que si desactivo la asignación, la aplicación no recibe la advertencia.

Respuesta

22

Súper solución hacky creo, pero parece que funciona:

Añadir lo siguiente antes de la misión:

GLuint name = self.texture.name; 
glDeleteTextures(1, &name); 

Si hay una manera más oficial (o si esta es la forma oficial), Agradecería si alguien pudiera avisarme.

+1

Hmmm. No hay respuestas hasta ahora, así que esto es tan oficial como me parece en este momento. :-) Mi pensamiento sería que el 'GLKTextureInfo' manejaría esto (es decir, manejando la liberación de las texturas a las que apunta cuando se desasignara) pero aparentemente ese no es el caso. – alokoko

+5

Creo que esta es la forma correcta de hacerlo. El problema es que después de que tu textureInfo se crea cuando unes la textura a GL, GL entonces posee la memoria, por lo tanto, necesitas usar GL para eliminar la memoria –

+0

La explicación de Anthoys tiene sentido para mí. +1. – Soup

5

No es una respuesta directa, pero es algo que noté y que realmente no cabe en un comentario.

Si está utilizando GLKTextureLoader para cargar texturas en el fondo para reemplazar una textura existente, debe eliminar la textura existente en el hilo principal. Eliminar una textura en el controlador de finalización no funcionará.

Aparentemente, este es debido a que:

  1. Cada hilo iOS requiere su propio EAGLContext, por lo que la cola en segundo plano tiene su propio hilo con su propio contexto.
  2. El controlador de finalización se ejecuta en la cola que pasó, que probablemente no sea la cola principal. (De lo contrario no estaría haciendo la carga en el fondo ...)

Es decir, esto va a perder memoria.

NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES}; 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
[self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png" 
              options:options 
              queue:queue 
           completionHandler:^(GLKTextureInfo *texture, NSError *e){ 
            GLuint name = self.myTexture.name; 
            // 
            // This delete textures call has no effect!!! 
            // 
            glDeleteTextures(1, &name); 
            self.myTexture = texture; 
            }]; 

Para solucionar este problema, puede:

  1. Eliminar la textura antes de que ocurra la carga. Potencialmente incompleto dependiendo de cómo está diseñado su GL.
  2. Elimina la textura en la cola principal en el controlador de finalización.

Por lo tanto, para reparar la fuga que tiene que hacer esto:

// 
// Method #1, delete before upload happens. 
// Executed on the main thread so it works as expected. 
// Potentially leaves some GL content untextured if you're still drawing it 
// while the texture is being loaded in. 
// 

// Done on the main thread so it works as expected 
GLuint name = self.myTexture.name; 
glDeleteTextures(1, &name) 

NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES}; 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
[self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png" 
              options:options 
              queue:queue 
           completionHandler:^(GLKTextureInfo *texture, NSError *e){ 
            // no delete required, done previously. 
            self.myTexture = texture; 
            }]; 

o

// 
// Method #2, delete in completion handler but do it on the main thread. 
// 
NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES}; 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
[self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png" 
              options:options 
              queue:queue 
           completionHandler:^(GLKTextureInfo *texture, NSError *e){ 
            // you could potentially do non-gl related work here, still in the background 
            // ... 

            // Force the actual texture delete and re-assignment to happen on the main thread. 
            dispatch_sync(dispatch_get_main_queue(), ^{ 
             GLuint name = self.myTexture.name; 
             glDeleteTextures(1, &name); 
             self.myTexture = texture; 
            }); 
            }]; 
0

¿Hay una manera de reemplazar simplemente el contenido de la textura a la misma GLKTextureInfo. nombre manejar Al usar glgentextures, puede usar el identificador de textura devuelto para cargar nuevos datos de texuture usando glteximage2d. Pero con GLKTextureLoader parece que se está llamando glgentextures se carga cada vez que nuevos datos de la textura ...

Cuestiones relacionadas