How to release a RenderTexture with antialiasing in Unity? - unity3d

I'm struggling with multisampling. I allocated a RenderTexture with the property 'antiAliasing' which could not be released totally and I don't know why.
I had found a way to allocate a RenderTexture which can be released as follows.
//allocate a temporary RenderTarget
multisampleRT = RenderTexture.GetTemporary(Camera.pixelWidth, Camera.pixelHeight, 32, RenderTextureFormat.Depth, RenderTextureReadWrite.Default, multisampleCount);
//release a temporary RenderTarget
RenderTexture.ReleaseTemporary(multisampleRT);
But this way is followed by a default resolve pass which will affect my later operation.
Then I tried another properties 'bindTextureMS'.
multisampleRT.bindTextureMS = true;
However, this causes the memory explosion again.
Above all, I'll appreciate a resolution that:
Allocate and release RenderTarget correctly.
Allocate RenderTarget with RenderTextureFromat not GraphicsFormat.(I must use this.)
Allocate RenderTarget without resloved by default.
Thanks a lot:)

Related

CFRelease on CMSampleBufferRef - Why do I need to call this?

CMSampleBufferRef sampleBuffer = [assetOutput copyNextSampleBuffer];
CMBlockBufferRef buffer = CMSampleBufferGetDataBuffer(sampleBuffer);
CMBlockBufferAppendBufferReference(_sem == 0 ? _buffer0 : _buffer1, buffer, 0, 0, 0);
//if(sampleBuffer)
// CFRelease(sampleBuffer);
Why does this cause a memory leak at the first line (at least that's where Leaks suggests)? I have my assetOutput.shouldAlwaysCopySampleOutput = NO. Here's my understanding of the situation:
CMSampleBufferRef sampleBuffer = [assetOutput copyNextSampleBuffer];
This line will create a reference to the sample buffer from the assetOutput.
CMBlockBufferRef buffer = CMSampleBufferGetDataBuffer(sampleBuffer);
This line will get the CMBlockBuffer from the CMSampleBuffer but will not allocate a new buffer, and the Get method in this case means it is a temporary (autoreleased) buffer
CMBlockBufferAppendBufferReference(_sem == 0 ? _buffer0 : _buffer1, buffer, 0, 0, 0);
This line will append the reference of the CMBlockBuffer created above, to the selected global-scope buffer. It will not copy any memory blocks.
So in none of these three lines do I allocate any memory nor do I copy any memory, it's all references. I don't understand where the leak is coming from. I tried adding the commented out lines and it still seems to leak (although fewer times)
alwaysCopiesSampleData is not about memory management. It is only about whether you are scribbling on the original sample buffer or a clone of the original. It is somewhat unfortunately named.
copyNextSampleBuffer follows the create rule and as such, should be released when you are done with it. It creates a reference with a retain count of at least 1.
The Create Rule:
https://developer.apple.com/library/ios/DOCUMENTATION/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-103029
Apple's doc links tend to change, but if the above link dies, just google "The Create Rule"
Core Foundation data structures follows the same ownership rules as Foundation objects.
The rules are pretty simple - whatewer you create (or get the ownership by some other way), you have to destroy. If some other method wants to work with the same structure/object, it has to ask for the ownership and thus preventing the destruction.
Taking ownership = "create" / "retain"
Releasing ownership ("destruction") = "release"
In your sample code, you have created a structure using copyNextSampleBuffer. That means, you have to also destroy it using CFRelease.
(Note that with ARC you don't actually see the retain and release calls but with Core Foundation, you have to use them explicitely).

Using CGDataProviderCreateWithData callback

I'm using CGDataProviderCreateWithData to (eventually) create a UIImage from a malloced array of bytes. I call CGDataProviderCreateWithData like this:
provider = CGDataProviderCreateWithData(NULL, dataPtr, dataLen, callbackFunc);
where
dataPtr is the previously malloced array of data bytes for the image,
dataLen is the number of bytes in the dataPtr array, and
callbackFunc is as described in the CGDataProviderCreateWithData documentation:
void callbackFunc(void *info, const void *data, size_t size);
The callback function is called when the data provider is released so I could free() dataPtr there, but I may want to continue using it (dataPtr) and at some later stage free it. This block of code will be called multiple times, and the flow will look something like:
malloc(dataPtr)
create image (call CGDataProviderCreateWithData etc)
display image
release image (and so release data provider created by CGDataProviderCreateWithData)
continue to use dataPtr
free(dataPtr)
so 1..6 may be executed multiple times. I don't want dataPtr hanging around for the entire execution of the program (and it may change in size anyway), so I want to malloc/free it as necessary.
The problem is that I can't free(dataPtr) in the callback from CGDataProviderCreateWithData because I still want to use it, so I want to free it some time later - and I can't free it until I know that the data provider no longer needs it (as far as I can tell CGDataProviderCreateWithData uses the array I pass, it doesn't take a copy).
I can't do (1) above until I know it is ok to free and re-malloc dataPtr, so what I really want to do is block waiting for the data provider to be freed (well, I want to know whether I should re-enter the 1..6 block of code, which I can't do until the data provider is freed). It will be - I create the data provider, create the image and immediately display it and release the data provider. The trouble is that the data provider isn't actually released until the UIImage is released and is finished with it.
I'm reasonably new to objective-c and iOS. Am I missing something obvious?
If you malloc the memory for the provider's data, you really want to to free it in the callback. Do not be tempted to try to circumvent this in any manner. It be too easy to leak and would be susceptible to simple memory issues.
Having said that, there are two simple solutions that address your question. Either:
Make your own copy of the data that you'll manage separately from the provider; or
Instead of using the void * renditions of the CGDataProvider methods, use the CFData rendition (e.g. CGDataProviderCreateWithCFData) and then you can maintain your own strong reference to this data object (or if in non-ARC code, do your own retain of the data object). The object will not be deallocated until all strong references are resolved (or, in non-ARC code, all of your manual retain calls are resolved with a corresponding release or autorelease call).
With either of these approaches, you can continue to let CGProviderRef manage the memory as it sees fit, but you can continue to use the data object for your own purposes, too.
I ran into a similar problem as well. I wanted to use CGImageCreateWithJPEGDataProvider, so used CGDataProviderRef with a malloc'd byte array. I was getting the same problem, when trying to free the byte array at some point after creating the Data Provider Reference.
It occurs because the data provider reference takes over the ownership of the byte array, so can only be freed by the reference, when it is done with it.
I agree with #TheBlack in that if you need the data elsewhere, make a copy of it.
What I'm doing is essentially the same to what you want to achieve, I just took different route.
This whole process is wrapped into NSOperation so you have control over scheduling memory usage.
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef);
NSUInteger bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
UInt8 *rawData = calloc((height * width * bitsPerComponent), sizeof(UInt8));
NSUInteger bytesPerRow = CGImageGetBytesPerRow(imageRef);
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
if (context)
{
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
// This is the place you get access to data trough rawData. Do whatever you want with it, when done, get image with
CGImageRef newImg = CGBitmapContextCreateImage(context);
}
OR
subclass CALayer, override drawInContext and use CGBitmapContextGetData to get raw data. Don't have much experience with this though, sorry, but if you want to see instant changes
on image based on user input, I'd do it this way:
Subclass UIView and CALayer which becomes layer for view and displays image. View gets input and image data (from CGBitmapContextGetData) in layer class is manipulated based on input.
Even CATiledLayer can be used for huge images in this way. When done with image, just release UIView and replace it with new one. I'll gladly provide help if you need any, just ping here.

Unable to release a CGContextRef (context is from a CGLayer)

When you create a CGLayer like so, and then get the context...it appears to be impossible to release the CGContextRef?
Releasing the CGLayerRef itself (apparently) works fine.
You'd think you could release the CGContextRef just before releasing the CGLayer - but no? Nor can you release the CGContextRef just after releasing the CGLayer.
If you release the CGContextRef, the app crashes.
CGLayerRef aether = CGLayerCreateWithContext(
UIGraphicsGetCurrentContext(), CGSizeMake(1024,768), NULL);
CGContextRef weird = CGLayerGetContext(aether);
// paths, strokes, filling etc
// paths, strokes, filling etc
// try releasing weird here
CGLayerRelease(aether);
// or, try releasing weird here
Does anyone know what is going on here? (Note further that CGContextRelease is indeed just the same as CFRelease, with some nil checking.)
In fact should you never manually release CGContextRef? Does anyone know? Cheers.
CGContextRelease(weird); // impossible, not necessary, doesn't work???
Regarding Joel's spectacular answer below:
Is releasing the CGLayerRef correct and proper? Joel has pointed out:
"Yes, since the function you're obtaining it from has 'Create' in its signature. See: documentation/CoreFoundation/"
You do not own the context returned from CGLayerGetContext, and so should not release it*. In particular, see http://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/writerid/cfGetRule for information regarding 'Get' functions in Core Foundation.
*: at least, you shouldn't release it given your example code. If you retained it first (CGContextRetain(weird)), then you should have a CGContextRelease to balance it.

IPHONE: memory still allocated after releasing object?

I have a method for drawing an object offscreen to a file, using quartz. The last lines of this method are:
CGRect LayerRect = CGRectMake(mX,mY, wLayer, hLayer);
CGContextDrawImage(objectContext, LayerRect, objectProxy.image.CGImage); // 1
CGRect superRect = CGRectMake(vX, vY, w,h);
CGContextDrawLayerInRect(context, superRect, objectLayer);
CGLayerRelease(objectLayer); // 2
UIImage * myImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext(); //3
return myImage;
as You see the layer drawn on //1 is released on //2, and the context is released on //3.
So, there's no leak right?
In fact, instruments reports this as having NO LEAKS, but after running this method and returning to the main loop, my application is using 1.38 MB of memory more than before.
Investigating on intruments, on memory allocation tab, I see an entry as
Malloc 1.38 MB
overall bytes = 1.38 MB
#Overall = 1
#alloc =
Live Bytes = 1.38 MB
#Living = 1
#Transitory = 0
and this entry points to this
CGContextDrawImage(objectContext, LayerRect, objectProxy.image.CGImage); // 1
So, apparently the memory allocated inside the method is still allocated but is not leaking?? How can that be?
How can I get rid of this memory allocation freeing the memory?
thanks in advance!
The image would certainly use some memory. I'm not totally proficient with iPhone programming but an image under OS X is always a copy of what you made the image from. The docs say that the image lives in an autoreleasepool, so depending on how you manage the pools, it could live there for quite some time. You could try putting an autoreleasepool around the call in the calling function (putting it into te function you're quoting above would return an invalid object).
Generally I can say that as soon as autoreleasepools are coming into play, trying to track the releasing of objects will become quite cumbersome (and impossible sometimes ... the idea behind autorelease objects is that the system knows best when to release them (which is something that drives a C++ programmer like me nuts ... but of course Objective C and Cocoa is not made to make me happy :-)))
However, assuming your function above is called drawOffline you should be able to get rid of the memory in image via
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *ret= [self drawOffline];
// do some work using ret (possibly copying it)
[pool release];
// memory should be released and the ret ptr is invalid from this point on.
going a bit further, if you intend to use the ret ptr a bit longer you should retain it to tell the system that it should not delete it even if the autorelease pool releases it.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *ret= [self drawOffline];
[ret retain]; // prevent ret from being deleted when the pool releases it
// do some work using ret (possibly copying it)
[pool release];
// ret ptr will continue to live until you release it.
// more stuff
[ret release]; // image behind ret being freed
As said, generally with autorelease objects you don`t worry about their lifetime, but if you intend to keep them longer (especially storing it in an object member for later use) you need to retain/release it yourself, because otherwise the system could pull it right under your feet.
This [link][1] describes memory management under OS X but also applies to the iphone.
[1]: http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html link
apparently there's no solution for that, until Apple fix this.

iPhone cocos2d sprites in array, memory problems

I'm trying to keep track of my sprites in an array, add and remove
them from layers, and then finally clear them out of the array.
I'm using the following code:
Sprite * Trees[50];
Layer * Forest;
Forest = [Layer node];
Forest.isTouchEnabled = YES;
[self addChild:Forest z:30];
// do this a bunch of times
Trees[0] = [[Sprite spriteWithFile:#"mytree.png"] retain];
[Trees[0] setPosition:cpv(240,160)];
[Forest addChild:Trees[0] z:5];
And then when I want to destroy a tree I use:
[Forest removeChild:Trees[0] cleanup:YES];
[Trees[0] release];
My problem is that when I look in Instruments, I'm never reclaiming
that memory, there is never a drop back down. I thought that by
releasing the sprite it would free up the memory. Am I doing this
completely wrong?
I know that when you are using the simulator with cocos2d, the memory doesn't look like it's being released, so you have to run it on the device to get an accurate picture of what's going on.
There is a good discussion here about cocos2d and memory.
What I've noticed is that everything that you create and retain must be released, but it isn't released from memory until I do this:
[[TextureMgr sharedTextureMgr] removeAllTextures];
That will release the memory.
Here's a bigger example:
Sprite * sPopup = [[Sprite spriteWithFile:#"popup.png"] retain];
sPopup.position = cpv(240,440);
[self addChild: sPopup z:2];
[sPopup release];
Then, when I'm done with sPopup in another function I have this:
[[TextureMgr sharedTextureMgr] removeAllTextures];
and the memory is freed.
My suspicion is that you are "over" retaining:
Trees[0] = [[Sprite spriteWithFile:#"mytree.png"] retain];
If Trees is a local variable in a function you do not have to retain in that case if spriteWithFile is returning a Sprite with an autorelease.
The section on delay release in the apple documentation discusses this further. The long and short of it is that the receiver of the autorelease is guaranteed to have the object be valid for the duration of its scope. If you need the object beyond the scope of the function (e.g. Trees is a property of a class) then yes, in that case you need a retain (or just synthesize a property configured to retain).
By issuing the extra retain, it is likely that your retain count is always too high (never reaches 0) and hence your object is not garbage collected.
For good measure, I'd suggest reviewing this paragraph as well that talks about the validity of objects.
Even though you call [Trees[x] release], I believe you still need to 'delete' the item from the array, like Trees[x] = nil or something, as the array itself is still containing the object.
The 'retain' in the Sprite creation is also not necessary, as [Forest addChild:z:] will place a retain on it as well (afaik).