OpenGL ES on loading iOS textures - how can I get RGB565 texture from RGBA8888.png file?

so I work with a buffet of 2048x2048 sprites that quickly fill up the memory. Like me, I use the following method (via Ray Wenderlich) to load the texture:

- (GLuint)setupTexture:(NSString *)fileName { CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage; if (!spriteImage) { NSLog(@"Failed to load image %@", fileName); exit(1); } size_t width = CGImageGetWidth(spriteImage); size_t height = CGImageGetHeight(spriteImage); GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte)); CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast); CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage); CGContextRelease(spriteContext); GLuint texName; glGenTextures(1, &texName); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 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, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData); GLenum err = glGetError(); if (err != GL_NO_ERROR) NSLog(@"Error uploading texture. glError: 0x%04X", err); free(spriteData); return texName; } 

so my question is: how do I discard alpha information from CGImage, then reduce the image to fewer bits per pixel, and finally tell OpenGL about it?

+4
source share
3 answers

I use this code to convert data recorded using CGContextDrawImage to RGB565. It uses the optimized NEON code to process 8 pixels at a time on devices with NEON support (each iOS device that runs the armv7 code has such a chip). The data pointer you see there matches your spriteData pointer, I'm just too lazy to rename it.

 void *temp = malloc(width * height * 2); uint32_t *inPixel32 = (uint32_t *)data; uint16_t *outPixel16 = (uint16_t *)temp; uint32_t pixelCount = width * height; #ifdef __ARM_NEON__ for(uint32_t i=0; i<pixelCount; i+=8, inPixel32+=8, outPixel16+=8) { uint8x8x4_t rgba = vld4_u8((const uint8_t *)inPixel32); uint8x8_t r = vshr_n_u8(rgba.val[0], 3); uint8x8_t g = vshr_n_u8(rgba.val[1], 2); uint8x8_t b = vshr_n_u8(rgba.val[2], 3); uint16x8_t r16 = vmovl_u8(r); uint16x8_t g16 = vmovl_u8(g); uint16x8_t b16 = vmovl_u8(b); r16 = vshlq_n_u16(r16, 11); g16 = vshlq_n_u16(g16, 5); uint16x8_t rg16 = vorrq_u16(r16, g16); uint16x8_t result = vorrq_u16(rg16, b16); vst1q_u16(outPixel16, result); } #else for(uint32_t i=0; i<pixelCount; i++, inPixel32++) { uint32_t r = (((*inPixel32 >> 0) & 0xFF) >> 3); uint32_t g = (((*inPixel32 >> 8) & 0xFF) >> 2); uint32_t b = (((*inPixel32 >> 16) & 0xFF) >> 3); *outPixel16++ = (r << 11) | (g << 5) | (b << 0); } #endif free(data); data = temp; 
+7
source

Instead of simply changing the color space, I could suggest using a texture compressed with PVRTC. This should use far less memory on the GPU than even the RGB565 version, because these textures remain compressed, rather than expanding into uncompressed bitmaps.

In the Texture Data Guidelines section of the OpenGL ES Programming Guide for iOS, Apple says

Texture compression usually provides the best balance of memory savings and quality. OpenGL ES for iOS supports PowerVR Compression Texture (PVRTC) by implementing the GL_IMG_texture_compression_pvrtc extension. There are two levels of PVRTC, 4 bits per channel and 2 bits per channel, which offer a compression ratio of 8: 1 and 16: 1 in an uncompressed 32-bit texture format, respectively. The compressed PVRTC texture still provides a decent level of quality, especially at the 4-bit level.

and

If your application cannot use compressed textures, consider using a lower pixel format.

which indicates that you will get smaller memory sizes for compressed textures than those used in smaller color space.

Apple has a good example of this in the PVRTextureLoader application, and I reused part of this code to load the PVRTC textures into the textured cube example application I hit together. You can see the assembly phase "Image Encoding" in PVRTextureLoader for a script for converting PNG textures to PVRTC at compile time.

+3
source

Look at the internalFormat parameter. Perhaps you could specify GL_R3_G3_B2 to use only 8 bits per pixel, or GL_RGB5 might be useful. There are several options that may be helpful.

See Texture internal formats for more details.

0
source

All Articles