サイズの大きいテクスチャを読み込む画面がある場合に、全てのテクスチャの準備が出来てから画面を表示するとレスポンスが遅くなる。
このような場合に別スレッドでテクスチャをロードしつつ、用意のできた部分から使うことにより画面のレスポンスを改善する方法がある。
ただし、各スレッドはデフォルトで異なる OpenGL ES レンダリングコンテキストを持つため、
異なるスレッドで確保したテクスチャを使う場合は、各スレッドで使用する EAGLContext から EAGLShareGroup を共有する必要がある。
これを行うには EAGLContext 生成時に initWithAPI:sharegroup: で元スレッドの sharedGroup を渡す。
AsyncSample.m
- (id)init
{
// ... (略)
// 非同期読み込み. EAGLContext を渡す.
[self performSelectorInBackground:@selector(loadTexture:) withObject:[EAGLContext currentContext]];
// ... (略)
}
// バックグラウンドスレッドで呼ばれるメソッド.
- (void)loadTexture:(EAGLContext *)ctx;
{
// sharegroup を指定して異なるコンテクストのリソースを共有する.
EAGLContext* myContext = [[EAGLContext alloc] initWithAPI:[ctx API]
sharegroup:[ctx sharegroup]];
// EAGLContext を設定
[EAGLContext setCurrentContext:myContext];
NSArray *imageNames = @[@"image1.png", @"image2.png", @"image3.png"];
glFlush(); // glFlush を呼び出してコマンドを反映させる.
for (NSString *imageName in imageNames) {
GLuint tex = [self createTextureFromUIImage:[UIImage imageNamed:imageName]];
dispatch_async(dispatch_get_main_queue(), ^{
// スレッド間共有変数への書き込みは競合を起こさないよう main スレッドで実行.
self.textures[i] = tex;
});
}
}
// UIImage からテクスチャの作成.
- (GLuint)createTextureFromUIImage:(UIImage *)teximage
{
CGImageRef textureImage = teximage.CGImage;
NSInteger texWidth = CGImageGetWidth(textureImage);
NSInteger texHeight = CGImageGetHeight(textureImage);
GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4);
CGContextRef textureContext = CGBitmapContextCreate(textureData,
texWidth,
texHeight,
8, texWidth * 4,
CGImageGetColorSpace(textureImage),
kCGImageAlphaPremultipliedLast);
CGContextDrawImage(textureContext, CGRectMake(0.0, 0.0, (float)texWidth, (float)texHeight), textureImage);
CGContextRelease(textureContext);
GLuint texid;
glGenTextures(1, &texid);
glBindTexture(GL_TEXTURE_2D, texid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA,GL_UNSIGNED_BYTE, textureData);
free(textureData);
return texid;
}