OpenGL ES 异步纹理加载

7
简单的问题,iOS和OpenGL ES是否可以异步加载纹理?
这是我的纹理加载方法,在一个单独的线程中被调用:
//Image size
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);

//Create context
void *imageData = malloc(height * width * 4);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);

//Prepare image
CGContextClearRect(context, CGRectMake(0, 0, width, height));
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.CGImage);

//Dispatch OpenGL stuff on main thread
dispatch_sync(dispatch_get_main_queue(), ^{
    //Bind texture
    glBindTexture(GL_TEXTURE_2D, name);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
});

//Release
CGContextRelease(context);
free(imageData);

如果我不在主线程上调用OpenGL函数,则我的纹理不会显示...
glDeleteTextures调用同样的问题...
有什么想法?
1个回答

4

你需要在后台线程上使用与主线程相同的上下文。为此,请使用 setCurrentContext:。 因此,在主线程上创建新线程(例如,最简单的方法),并传递主上下文。

[self performSelectorInBackground: @selector(loadTextureWithContext:) withObject: [EAGLContext currentContext]];

并且创建的代码:

-(void) loadTextureWithContext:(EAGLContext*) main_context {
    [EAGLContext setCurrentContext: main_context];

    //Image size
    GLuint width = CGImageGetWidth(image.CGImage);
    GLuint height = CGImageGetHeight(image.CGImage);

    //Create context
    void *imageData = malloc(height * width * 4);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);

    //Prepare image
    CGContextClearRect(context, CGRectMake(0, 0, width, height));
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.CGImage);

    //Bind texture
    glBindTexture(GL_TEXTURE_2D, name);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    //Release
    CGContextRelease(context);
    free(imageData);

    [EAGLContext setCurrentContext: nil];
}

作为一种选择,您还可以创建新的上下文,并与主要上下文共享相同的EAGLSharegroup

我在想,使用glBindTexture()创建纹理的调用是否会干扰您在主线程中执行的任何绘图操作?我猜共享组(=分离的gl上下文)是正确的方法? - Nicolas Miari
如果你正在销毁一个当前用于渲染的纹理,那么它可能会干扰绘图。 - Max
1
不,我的意思是:在纹理创建过程中的后台线程(负责加载纹理的线程)调用glBindTexture()时,你当前正在使用进行绘制的任何(之前创建的、完全加载的)纹理都会被取消绑定(因为在任何给定的上下文中只能绑定一个纹理,对吧?)。这是需要注意的。 - Nicolas Miari
@ranReloaded 取自此处:http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithOpenGLESContexts/WorkingwithOpenGLESContexts.html - Max
@ranReloaded,来自共享组的文档:当共享对象从多个上下文中访问时,管理状态更改是您的应用程序的责任。在另一个上下文中用于渲染时更改共享对象的状态的结果是未定义的。为了获得确定性结果,您的应用程序必须采取明确的步骤,以确保在修改共享对象时,该对象当前未用于渲染。 - Max
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接