Reputation: 547
I am using OpenGL to do my drawing on screen and want to draw a portion of the screen to a UIImage. This is code I've cobbled together looking at examples, which works, but produces a memory leak every time it's called. I've tested this on device and the leak still persists and eventually causes a crash. The returned UIImage is saved to an instance variable and is later definitely set to nil again. What is causing the memory leak here?
- (UIImage *)renderToImageWithContentFrame:(CGRect)contentFrame
exportFrame:(CGRect)exportFrame
scale:(float)scale {
float screenWidth = contentFrame.size.width * scale;
float screenHeight = contentFrame.size.height * scale;
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
GLuint renderTex;
glGenTextures(1, &renderTex);
glBindTexture(GL_TEXTURE_2D, renderTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenWidth, screenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTex, 0);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glViewport(0, 0, screenWidth, screenHeight);
[self _renderImageGL];
// grabbing image from FBO
NSInteger dataLength = screenWidth * screenHeight * 4;
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glReadPixels(0, 0, screenWidth, screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
glDeleteFramebuffers(1, &framebuffer);
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGImageRef iref = CGImageCreate(screenWidth, screenHeight, 8, 32, screenWidth * 4, colorspace,
kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
ref, NULL, true, kCGRenderingIntentDefault);
float x = (exportFrame.origin.x - contentFrame.origin.x) * scale;
float y = (exportFrame.origin.y - contentFrame.origin.y) * scale;
float width = exportFrame.size.width * scale;
float height = exportFrame.size.height * scale;
CGImageRef cropped = CGImageCreateWithImageInRect(iref, (CGRect){x, y, width, height});
UIGraphicsBeginImageContext((CGSize){width, height});
CGContextRef cgcontext = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
CGContextDrawImage(cgcontext, (CGRect){0, 0, width, height}, cropped);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
free(data);
CFRelease(ref);
CFRelease(colorspace);
CGImageRelease(iref);
CGImageRelease(cropped);
return image;
}
Upvotes: 0
Views: 753
Reputation: 26395
The variable renderTex
is not being freed (via a call to glDeleteTextures(1, &renderTex);
). My guess is that Instruments may not know about OpenGL-allocated memory because that memory may reside on a graphics card and may be harder (or impossible) to track. (Though that's mainly a guess.)
Upvotes: 3