Release textures (GLKTextureInfo objects) allocated by GLKTextureLoader

后端 未结 3 957
北海茫月
北海茫月 2020-12-28 20:33

New to developing on iOS and in particular the new OpenGL related features on iOS 5, so I apologize if any of my questions are so basic.

The app I am working on is d

相关标签:
3条回答
  • 2020-12-28 20:50

    Super hacky solution I believe, but it seems to work:

    Add the following before the assignment:

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

    If there's a more official way (or if this is the official way), I would appreciate if someone could let me know.

    0 讨论(0)
  • 2020-12-28 21:00

    Is there a way to simply replace the contents of the texture to the same GLKTextureInfo.name handle? When using glgentextures you can use the returned texture handle to load new texuture data using glteximage2d. But with GLKTextureLoader it seems that glgentextures is being called every time new texture data is loaded...

    0 讨论(0)
  • 2020-12-28 21:09

    Not a direct answer, but something I noticed and it wont really fit in a comment.

    If you're using GLKTextureLoader to load textures in the background to replace an existing texture, you have to delete the existing texture on the main thread. Deleting a texture in the completion handler will not work.

    AFAIK this is because:

    1. Every iOS thread requires its own EAGLContext, so the background queue has its own thread with its own context.
    2. The completion handler is run on the queue you passed in, which is most likely not the main queue. (Else you wouldn't be doing the loading in the background...)

    That is, this will leak memory.

    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;
                                      }];
    

    To get around this issue you can either:

    1. Delete the texture before the upload happens. Potentially sketchy depending on how your GL is architected.
    2. Delete the texture on the main queue in the completion handler.

    So, to fix the leak you need to do this:

    //
    // 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;
                                      }];
    

    or

    //
    // 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 讨论(0)
提交回复
热议问题