Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL ES Async texture loading

Simple question, is it possible to load texture asynchronously with iOS and OpenGL ES ?

Here is my loading method, called on a separate thread:

//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);

If I don't dispatch OpenGL calls on the main thread, my textures wont be displayed...

Same question for the glDeleteTextures call...

Any idea ?

like image 693
ingham Avatar asked Aug 01 '11 14:08

ingham


1 Answers

You need to use the same context on your background thread that you're using on the main one. For this use setCurrentContext:. So on main thread create new thread (as an example the simplest way) and pass main context

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

And the creation code:

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

As an option you can also create the new context and share the same EAGLSharegroup with the main one.

like image 140
Max Avatar answered Nov 09 '22 21:11

Max