2012-01-03 14 views
11

Novità da sviluppare su iOS e in particolare le nuove funzionalità correlate a OpenGL su iOS 5, quindi mi scuso se alcune delle mie domande sono così basilari.Textures di rilascio (oggetti GLKTextureInfo) allocati da GLKTextureLoader

L'app su cui sto lavorando è progettata per ricevere i frame delle telecamere e visualizzarli sullo schermo tramite OpenGL ES (i grafici li prenderanno in carico e aggiungeranno l'attuale disegno OpenGL di cui conosco molto poco). L'applicazione è sviluppata XCode4, e l'obiettivo è iPhone4 con iOS 5. Per il momento, ho usato la funzionalità ARC e GLKit e tutto funziona bene, tranne che per la perdita di memoria nel caricare le immagini come texture. L'app riceve un "avviso memoria" molto presto.

In particolare, vorrei chiedere come rilasciare le texture assegnate dalla

@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); 
    } 
} 

L'image è un'immagine di quarzo costruita dal telaio macchina (codice di esempio da Apple). So che il problema non è in quella parte del codice poiché se disattivo l'assegnazione, l'app non riceve l'avviso.

risposta

22

Super soluzione hacky credo, ma sembra funzionare:

Aggiungere il seguente prima della cessione:

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

Se c'è un modo più ufficiale (o se questo è il modo ufficiale), Apprezzerei se qualcuno potesse farmelo sapere.

+1

Hmmm. Nessuna risposta fino ad ora, quindi questo è il più ufficiale che mi viene in mente al momento. :-) Il mio pensiero sarebbe che il 'GLKTextureInfo' gestisse questo (cioè maneggio rilasciando le trame a cui punta quando viene deallocato) ma a quanto pare non è così. – alokoko

+5

Credo che questo sia il modo corretto per farlo. Il problema è che dopo aver creato textureInfo quando si lega la texture a GL, GL possiede quindi la memoria, quindi è necessario utilizzare GL per cancellare la memoria. La spiegazione di –

+0

Anthoys ha senso per me. +1. – Soup

5

Non è una risposta diretta, ma qualcosa che ho notato e non si adatta veramente a un commento.

Se si utilizza GLKTextureLoader per caricare trame sullo sfondo per sostituire una trama esistente, è necessario eliminare la trama esistente sul thread principale. L'eliminazione di una trama nel gestore di completamento non funzionerà.

per quanto ne so questo è perché:

  1. filo Ogni iOS richiede una propria EAGLContext, così la coda di fondo ha il suo filo con il proprio contesto.
  2. Il gestore di completamento viene eseguito sulla coda passata, che molto probabilmente non è la coda principale. (Altrimenti non sarebbe fare il caricamento in background ...)

Cioè, questo perderà la 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; 
            }]; 

Per ovviare a questo problema è possibile:

  1. Eliminare la trama prima che il caricamento avviene. Potenzialmente abbozzato a seconda di come è progettato il tuo GL.
  2. Elimina la trama nella coda principale nel gestore di completamento.

Così, per riparare la perdita dovete fare questo:

// 
// 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

c'è un modo per sostituire semplicemente il contenuto della texture per lo stesso GLKTextureInfo. nome handle? Quando usi glgentextures puoi usare l'handle texture restituito per caricare nuovi dati di texuture usando glteximage2d. Ma con GLKTextureLoader sembra che si chiamino glgentextures ogni volta che vengono caricati nuovi dati di texture ...

Problemi correlati