2012-07-07 130 views
3

我創建並加載了很多紋理(由字符串組成)。爲了保持動畫順暢運行,我將工作卸載到單獨的工作線程。它似乎或多或少地按照我想要的方式工作,但在較舊的設備(iPhone 3GS)上,我有時會注意到很長時間(1秒)的延遲。它只是偶爾發生。現在我想知道我是否正確地做了這個或者是否有任何概念問題。我粘貼下面的源代碼。異步紋理加載iPhone OpenGL ES 2

我還應該提到我不想使用GLKit紋理加載器,因爲我也想將紋理生成工作卸載到另一個線程,而不僅僅是加載部分。

如果你想知道什麼,我需要這些紋理,看看這個視頻: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"]]; 
} 
+0

像往常一樣,在發佈問題後不久,我就開始工作。我現在使用NSOperationQueue而不是創建太多的NSThreads。這使我可以設置'maxConcurrentOperationCount'這似乎解決了這個問題。我仍然喜歡聽到我是否在做其他任何看起來很愚蠢的事情。 – hanno 2012-07-07 00:50:01

+1

如果是資源限制問題,您可能還會考慮調度信號量:http://www.mikeash.com/pyblog/friday-qa-2009-09-25-gcd-practicum.html。我通常將這些用於這樣的項目,其中I/O速度可能比處理速度更受限制。 – 2012-07-08 17:48:56

+0

謝謝。其他情況:根據儀器獲取和設置共享組的新環境需要很長時間。我應該只創建一個額外的上下文並在線程中重用它,同時確保我一次只能從一個線程訪問它?我記得在某個地方讀書時,我不應該記得原因。 – hanno 2012-07-08 19:01:25

回答

0

的問題是,過多的線程都在同一時間開始。現在我正在使用NSOperationQueue而不是NSThreads。這允許我設置maxConcurrentOperationCount並且只運行一個額外的後臺線程來完成紋理加載。