【问题标题】:Asynchronous texture loading iPhone OpenGL ES 2异步纹理加载 iPhone OpenGL ES 2
【发布时间】:2012-07-07 10:42:48
【问题描述】:

我正在创建和加载很多纹理(由字符串组成)。为了保持动画流畅运行,我将工作卸载到一个单独的工作线程。它似乎或多或少完全按照我想要的方式工作,但在旧设备(iPhone 3GS)上,我有时会注意到很长(1 秒)的延迟。它只是有时会发生。现在我想知道我是否正确执行此操作,或者是否存在任何概念问题。我把源代码贴在下面。

我还应该提到我不想使用 GLKit TextureLoader,因为我还想将纹理生成工作卸载到其他线程,而不仅仅是加载部分。

如果您想知道我需要这些纹理做什么,请观看此视频:http://youtu.be/U03p4ZhLjvY?hd=1

NSLock*                     _textureLock;
NSMutableDictionary*        _texturesWithString;
NSMutableArray*             _texturesWithStringLoading;

// This is called when I request a new texture from the drawing routine. 
// If this function returns 0, it means the texture is not ready and Im not displaying it.

-(unsigned int)getTextureWithString:(NSString*)string {
    Texture2D* _texture = [_texturesWithString objectForKey:string];
    if (_texture==nil){
        if (![_texturesWithStringLoading containsObject:string]){
            [_texturesWithStringLoading addObject:string];
            NSDictionary* dic = [[NSDictionary alloc] initWithObjectsAndKeys:string,@"string", nil];
            NSThread* thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadTextureWithDictionary:)object:dic];
            thread.threadPriority = 0.01;
            [thread start];
            [thread release];
        }
        return 0;
    }
    return _texture.name;
}

// This is executed on a separate worker thread.
// The lock makes sure that there are not hundreds of separate threads all creating a texture at the same time and therefore slowing everything down. 
// There must be a smarter way of doing that. Please let me know if you know how! ;-)
-(void)loadTextureWithOptions:(NSDictionary*)_dic{
    [_textureLock lock];
    EAGLContext* context = [[SharegroupManager defaultSharegroup] getNewContext];
    [EAGLContext setCurrentContext: context];

    NSString* string = [_dic objectForKey:@"string"];
    Texture2D* _texture = [[Texture2D alloc] initWithStringModified:string];

    if (_texture!=nil) {
        NSDictionary* _newdic = [[NSDictionary alloc] initWithObjectsAndKeys:_texture,@"texture",string,@"string", nil];
        [self performSelectorOnMainThread:@selector(doneLoadingTexture:) withObject:_newdic waitUntilDone:NO];
        [_newdic release];
        [_texture release];
    }
    [EAGLContext setCurrentContext: nil];
    [context release];
    [_textureLock unlock];
}

// This callback is executed on the main thread and marks adds the texture to the texture cache. 
-(void)doneLoadingTextureWithDictionary:(NSDictionary*)_dic{
    [_texturesWithString setValue:[_dic objectForKey:@"texture"] forKey:[_dic objectForKey:@"string"]];
    [_texturesWithStringLoading removeObject:[_dic objectForKey:@"string"]];
}

【问题讨论】:

  • 像往常一样,在这里发布问题后不久,我就开始工作了。我现在使用 NSOperationQueue 而不是创建太多 NSThreads。这使我可以设置似乎可以解决问题的“maxConcurrentOperationCount”。我仍然很想听听我是否在做其他在你看来很愚蠢的事情。
  • 如果是资源限制问题,您还可以查看调度信号量:mikeash.com/pyblog/friday-qa-2009-09-25-gcd-practicum.html。我通常将这些用于 I/O 速度可能比处理速度更受限制的项目。
  • 谢谢。还有一点:根据工具,从共享组获取和设置新上下文需要花费大量时间。我是否应该只创建一个额外的上下文并在线程之间重用它,同时确保我一次只能从一个线程访问它?我记得在某个地方读到了我不应该这样做的地方,因为我不记得为什么了。
  • 您只需要担心同时访问多个线程上的上下文。只要您将上下文设置为在给定线程上处于活动状态(使用 EAGLContext 的 -setCurrentContext:)并保证一次只能访问一次(例如,使用单宽调度队列),就可以非常安全地处理它在不同的线程之间关闭。
  • 如果您对您的问题有答案,请创建一个答案并接受它。否则,这个问题将留在“未回答”的堆中。干杯!

标签: iphone opengl-es asynchronous textures nsthread


【解决方案1】:

问题是同时启动了太多线程。现在我使用的是NSOperationQueue 而不是NSThreads。这允许我设置maxConcurrentOperationCount 并且只运行一个额外的后台线程来加载纹理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多