1

I need to load large-ish (5 megapixel) jpeg images and create openGL texture from them. They are non-power-of-two, and cannot be pre-processed for this application. Loading is extremely slow, about one second per image on an iPad Air 2. I need to load a dozen or two such images and create a GL texture for each, as quickly as I can.

Profiling shows the bottleneck to be CGContextDrawImage. Previous answers suggest this is a common problem.

This previous answer seems most relevant and (unfortunately) does not leave me hopeful. I haven't tried lib-jpeg (suggested in another answer) yet - trying to keep third party code out for several reasons.

But - that answer was 2014 and things change. Does anybody know of a faster way to create textures from jpegs? Either by changing the arguments to CGContextDrawImage (as in this answer- I've tried the suggested changes with no noticeable speed change) or using a different approach entirely?

The current texture creation block (called asynchronously):

UIImage *image = [UIImage imageWithData:jpegImageData];
if (image) {

    GLuint textureID;
    glGenTextures(1, &textureID);
    glBindTexture( GL_TEXTURE_2D, textureID);
    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 );

    GLsizei width = (GLsizei)CGImageGetWidth(image.CGImage);
    GLsizei height = (GLsizei)CGImageGetHeight(image.CGImage);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    void *imageData = malloc( height * width * 4 );
    CGContextRef imgcontext = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big );
    CGColorSpaceRelease( colorSpace );
    CGContextDrawImage( imgcontext, CGRectMake( 0, 0, width, height ), image.CGImage );

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

    // ... store the textureID for use by the caller
    // ...
}

(edited to add)

I tried GLKTextureLoader. I kept getting a nil return value, with error theError NSError * domain: "GLKTextureLoaderErrorDomain" - code: 12.

I've realized that the JPEGs I need to load are JPEG 2000; and that may be the problem. I've played with the GLKTextureLoader approach; I can get it to work non-J2K jpegs, but not the J2K ones I need to load. (FWIW, the files I need to load are packed inside larger files, thus I extract a data subrange from within the file, as such:

NSData *jpegImageData = [data subdataWithRange:NSMakeRange(offset, dataLength)];
GLKTextureInfo *jpegTexture;
NSError *theError;
jpegTexture = [GLKTextureLoader textureWithContentsOfData:jpegImageData options:nil error:&theError];

but, as mentioned, jpegImageData comes back as nil with the aforementioned error. This works on small jpegs, even using the subdataWithRange approach.

Likewise,

UIImage *image = [UIImage imageWithData:jpegImageData];
jpegTexture = [GLKTextureLoader textureWithCGImage:image.CGImage options:nil error:&theError];

returns nil with the same "code 12" error.

This iOS Developer page (Table 1-1) suggests that JPEG-2000 is supported on OS X only, but when I try the

CFArrayRef mySourceTypes = CGImageSourceCopyTypeIdentifiers(); CFShow(mySourceTypes);

approach for showing supported formats, JPEG-2000 is among them (running on my iOS device):

33 : <CFString 0x19d721bf8 [0x1a1da0150]>{contents = "public.jpeg-

Any suggestions for using the faster GLKTextureLoader methods on JPEG-2000?

Community
  • 1
  • 1
bphi
  • 1,015
  • 6
  • 16

1 Answers1

1

Did you try the GLKit Framework method?

GLKTexGtureInfo *spriteTexture;    
NSError *theError;

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Sprite" ofType:@"jpg"]; // 1

spriteTexture = [GLKTextureLoader textureWithContentsOfFile:filePath options:nil error:&theError]; // 2

glBindTexture(spriteTexture.target, spriteTexture.name); // 3
Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200
246tNt
  • 2,122
  • 1
  • 16
  • 20
  • Good idea. Using Apple's frameworks is always the best approach. They can do things nobody else can (like using hardware to decompress jpeg). – Nikolai Ruhe Jun 03 '16 at 06:40
  • In `GLKTextureLoader`, there is also `textureWithCGImage`, worth trying also. – 246tNt Jun 03 '16 at 16:42
  • I tried GLKTextureLoader (see edits above) but it didn't work on my files. I will try `textureWithCGImage`. – bphi Jun 03 '16 at 16:57
  • @246tNt `textureWithCGImage` also not working - code 12 (DataPreprocessingFailure) as with `textureWithContentsofData`. This works on some small sample JPEGs I tried, but not on my large embedded JPEGs. – bphi Jun 03 '16 at 19:03
  • My guess is that there is something weird with your JPEG, but without knowing what it is, there is no way to propose any solution ... upload an example of the JPEG that's not loading somewhere. – 246tNt Jun 03 '16 at 20:59
  • JPEG2K has really nothing to do with JPEG, they're entirely different formats. You should try the GLKTextureLoader on a test project on OSX, if it works with J2K there, then that just means that what apple means by "OSX only" is that the j2k support on iOS is not feature complete and there is really nothing you can do but wait for them to add it completely. – 246tNt Jun 04 '16 at 13:09
  • For .jpg, GLKTextureLoader works great; accepting this for answer to question as originally posed (relating to regular jpegs, not jpeg 2000.) For .j2k (jpeg 2000) - it does't seem to work at all. I can only get nil returns using GLKTextureLoader, and available apple documentation indicates it's only supported for OS X. – bphi Jun 07 '16 at 13:35