I'm playing with RenderTexture and I've come to the conclusion that drawing, even very small sprites, on a RenderTexture is VERY slow (on iPhone 3G et least).
Is there a reason for this, am I doing something wrong, and is there a way to improve things ?
Why drawing on RenderTexture is so slow ?
(20 posts) (15 voices)-
Posted 2 years ago #
-
Hmm, mine seems slow too, but maybe it's just what I'm doing with it :)
Posted 2 years ago # -
Drawing to a render texture is the same speed as drawing to any other surface, since they are effectively the same thing under the hood. However, keep in mind, if you are then drawing the render texture over, say, the entire screen, then you are effectively adding a full screen worth of pixels to be drawn.
Perhaps with some more details we could figure out why what your doing is slow; but it shouldn't be that the drawing speed of drawing to a render texture is any slower than drawing to the screen.
Posted 2 years ago # -
I know with mine the main reason it's slow is because I have two 320x320 RenderTextures which are both drawn to the screen every frame, although I only draw to them every second(or so).
I really don't know a whole lot about OpenGL, but I've heard people talk about "clearing/resetting the pipeline" which causes huge slowdowns. I wonder if that's problem when switching FBOs?
Posted 2 years ago # -
Apple's recommendation is to have glBindFramebufferOES() at the start of a draw cycle, this command gets run when you call begin on your RenderTexture. So, for example, calling begin on a RenderTexture from the draw method of a CocosNode in your scene graph is not going to be good for performance. I've been getting good results by updating RenderTextures in a scheduled selector.
I had a play around today and found the results are highly device dependent. On a 1st gen iPod touch it seems that as soon as you call glBindFramebufferOES your frame rate will drop to around 20-30fps, this is consistent with what pabloruiz was telling me in another thread. However, the same code running on a 3GS runs at 60fps no problems. I don't have a 2nd gen device with me but would be interested on the results on such a device.
I've posted my test code below - it is a simple "scratch off" example. To build it just generate a project with the cocos2d template, replace the code in HelloWorldScene.m with the code below and make sure you add "fire.png" from the cocos2d source to your project.
#import "HelloWorldScene.h" @implementation HelloWorld Sprite * burnSprite; RenderTexture * darknessLayer; BOOL reset; +(id) scene { Scene *scene = [Scene node]; HelloWorld *layer = [HelloWorld node]; [scene addChild: layer]; return scene; } -(id) init { if( (self=[super init] )) { CGSize size = [[Director sharedDirector] winSize]; [self setIsTouchEnabled:YES]; Sprite *bg = [Sprite spriteWithFile:@"Default.png"]; bg.position = ccp( size.width /2 , size.height/2 ); bg.rotation = 90; [self addChild:bg]; //Set up the burn sprite that will "knock out" parts of the darkness layer depending on the //alpha value of the pixels in the image. burnSprite = [Sprite spriteWithFile:@"fire.png"]; [burnSprite setBlendFunc: (ccBlendFunc) { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }]; [burnSprite retain]; darknessLayer = [RenderTexture renderTextureWithWidth:size.width height:size.height]; darknessLayer.position = ccp( size.width /2 , size.height/2 ); reset = YES; [self addChild:darknessLayer]; [self schedule: @selector(tick:)]; } return self; } //Move the burn sprite unless user double taps - then we reset the darkness layer - (BOOL)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; if ([touch tapCount] >= 2) { reset = YES; } else { CGPoint location = [touch locationInView: [touch view]]; burnSprite.position = CGPointMake(location.y, location.x); } return kEventHandled; } //Move the burn sprite - (BOOL)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView: [touch view]]; burnSprite.position = CGPointMake(location.y, location.x); return kEventHandled; } -(void) tick: (ccTime) dt { //Update the render texture if (reset) { [darknessLayer clear:0.0f g:0.0f b:0.0f a:1.0f]; reset = NO; } [darknessLayer begin]; //Limit drawing to the alpha channel glColorMask(0.0f, 0.0f, 0.0f, 1.0f); [burnSprite visit]; glColorMask(1.0f, 1.0f, 1.0f, 1.0f); [darknessLayer end]; } - (void) dealloc { [burnSprite release]; [super dealloc]; } @endPosted 2 years ago # -
@Mat Rix, I think you are on the right way about the "clearing/reseting the pipeline". I had read something about the Way OpenGL ES is implemented on the iPhone, but I can't find it again.
Anyway here some more details about my slow down :
I have a RenderTexture 1024x1024, that is rendered to the screen. At first it is totally transparent.
Then I start to draw about 5 small sprites ([edit] AtlasSprites) on the RenderTexture every frame. >> FPS 10/15
When I stop drawing, the FPS is back to 40.[edit] @Steve, I just saw your post after posting mine. Thank you, I will try to change the order fo my drawings, but I don't think I'm drawing during a draw method. Will look deeper into this.
Posted 2 years ago # -
Nice example Steve.
On my regular 3G running 3.1 it seems to average around 25fps. Mainly flickering between 25-30 with the occasional drop to about 20.
Posted 2 years ago # -
hi! As steve mentioned i had the same problem, although i was using an iphone 3G.
i had the same problem as jptsetung, just having the rendertexture instance without drawing anything to it caused my fps to slowdown from 60 to 40 and every begin call to it caused my fps to drop to 15...
The weird thing is that the example that comes with cocos2d runs "fine" at least i don't have a 20 fps drop from 60 to 40 by just instatiating it. I copied the code exactly into my game and the problems remain...
Posted 2 years ago # -
@pabloruiz55 - it is the call to begin on the RenderTexture that causes the problem. In the RenderTextureTest example that only happens in touchesMoved. When I try that on my 1st gen iPod Touch the fps fluctuates wildly somewhere between 15-30fps whilst there are moving touches.
Posted 2 years ago # -
Hi all :)
I tested the implementation Steve posted on an 3GS and it keeps perfect 60FPS. Unfortunately an my iPhone 2G (first generation) there is a drop to about 20FPS (from about 30).
Wondering how to keep performance up. I will have to search for different approaches regarding visibility in a 2D world. :-/
Best,
MarkusPosted 2 years ago # -
How do I start with a transparent slate and knock in parts I want instead?
Also can I do this in the draw method so that the sprite positions can change frame by frame like an animation? (i.e. something being drawn into the screen by itself)Posted 1 year ago # -
Okay, I'm actually intending to use rendertexture to create some sort of masking with 2 sprites, one of which is the shape mask.
So I was thinking of first using visit of the content sprite and then removing unwanted portions using the mask sprite as a brush using
[burnSprite setBlendFunc: (ccBlendFunc) { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }];However, I also want to adjust the position of the content sprite during the game while the mask remains at the same position. (think of looking thru a binoculars but the "lens" remain at the same position while the content moves)
Does this mean I have overwrite the draw method and clear the rendertexture every frame?
Is that kind of processing intensive on the FPS?Posted 1 year ago # -
really cool,
do you think it is possible to simulate the effect of coloring an image starting with this example?I was thinking of putting a black-and-white image on the background, then add a colored image that will have to be rendered only where the user touches.
Posted 1 year ago # -
Use a blending function that affects the alpha channel only...
So, two layers.... the color image on the bottom and its black and white version on top of it (with blending set-up in such a way that alpha of the top layer controls which image is shown... RGB_TOP * ALPHA_TOP + RGB_BOTTOM*(1-ALPHA_TOP)... application set-up to use pre-multiplied alpha or not, you have to choose the right bending function to realize this equation). With the brush you should change the opacity of the top layer.
Posted 1 year ago # -
Hello,
I'm using this code and it's working well however I would like to use an image as the topmost layer not simply a black covering, any ideas how to adapt this code to work that way?
Nick
Posted 7 months ago # -
This may help fill in some of the detail http://www.raywenderlich.com/4421/how-to-mask-a-sprite-with-cocos2d-1-0
Posted 7 months ago # -
See my post : http://www.cocos2d-iphone.org/forum/topic/12557
Posted 4 months ago #
Reply
You must log in to post.