1. Welcome to the new MacRumors forums. See our announcement and read our FAQ

Terrible 3D Performance.

Discussion in 'iPhone/iPad Programming' started by BananaDuffle, May 5, 2009.

  1. macrumors member

    At the moment i've got 114 triangles being rendered. I only have a 192kb texture being loaded. Also I'm running it in release mode on version 2.2.1

    And performance on the simulator is great but on my iPod touch is absolutely unusable.

    My drawView method is very simple(bellow)

    -(void)drawView {	
        [EAGLContext setCurrentContext:context];
        glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);   
    	glViewport(0, 0, backingWidth,backingHeight);
    	glRotatef(playerRot[0], -playerRot[1], -playerRot[2], -playerRot[3]);	
    	glTranslatef(-playerPos[0],-playerPos[1] , -playerPos[2]);		
    	for(int x = 0; x < 4; x++)
    		for(int y = 0; y < 4; y++)
    			if((1 & currentRoom[x][y]) != 0){				
    				[self drawTexturedQuad:northWallVerts texture:dungeonTexture textCoords:wallTextureCoords];
    			if((2 & currentRoom[x][y]) != 0){				
    				[self drawTexturedQuad:easthWallVerts texture:dungeonTexture textCoords:wallTextureCoords];
    			if((4 & currentRoom[x][y]) != 0){			
    				[self drawTexturedQuad:southWallVerts texture:dungeonTexture textCoords:wallTextureCoords];
    			if((8 & currentRoom[x][y]) != 0){				
    				[self drawTexturedQuad:westWallVerts texture:dungeonTexture textCoords:wallTextureCoords];
    			[self drawTexturedQuad:ceilVerts texture:dungeonTexture textCoords:wallTextureCoords];			
    			[self drawTexturedQuad:floorVerts texture:dungeonTexture textCoords:dungeonTextureCoords];			
    			glTranslatef(0, 0, -nsStride);
    		glTranslatef(ewStride, 0, (nsStride*4));
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
        [context presentRenderbuffer:GL_RENDERBUFFER_OES];	
    My drawTexturedQuad method (bellow)

    -(void) drawTexturedQuad:(GLfloat*) quad texture:(Texture2D*)texture textCoords:(GLfloat*)textCoords
    	glVertexPointer(3, GL_FLOAT, 0, quad);
    	glTexCoordPointer(2, GL_FLOAT, 0, textCoords);	
    	if(texture) {
    		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,texture.spriteData);				
    	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);	
    The update method being called on the player just increments his position for test purposes.

    I've also tried reducing the nested loop to run only 4x2 instead of 4x4 and the performance is still shocking on the iphone.

    I've also tried lowering the update speed from 1/60 to 1/30 and shrinking the viewport but still no major gains in performance. :(

    Am I being an utter Muppet? (this is my first iPhone app and my first OpenGL app) or is the performance that bad?

    I may have sussed this,

    I tried rendering the floor in sets of tiles with multiple draw calls then as one big triangle strip in a single draw call and got an immediate performance boost.

    Looks like I need a way to build my level, then render it in a single draw call.

    Though any other performance tips would be great.
  2. macrumors 6502a


    I think the root of your problems is you define a texture in every call to drawTexturedQuad(). What you need to do is pre generate textures, one for each sprite ideally, and then bind to the one you want to draw with. This will be faster.

    For example:-

    // Create a texture id and define its texture data.
    GLuint texture_1 ; 
    glGenTextures( 1, & texture_1 ) ;
    glBindTexture( GL_TEXTURE_2D, texture_1 ) ;
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data ) ;
    // Now draw using texture texture_1.
    glBindTexture( GL_TEXTURE_2D, texture_1 ) ;
    glEnable( GL_TEXTURE_2D ) ;etc
    ß e n


    A little more explanation: Every time you use glTexImage2D() OpenGL is reading your texture memory. So in your original code, every time you rendered a quad you were getting OpenGL to read your texture, all 192kb of it. By using texture ids and binding to them you only have to use glTextImage2D once.

    The other thing you can do, is define 1 big texture with everything in it (the way I mentioned above) and then use different UV coordinates to pick out the parts of the texture relevant to each sprite.

    ß e n
  3. macrumors member


    Wow, i had misunderstood some of the stuff i had read on texture loading. I had a texture class that did everything but glTexImage

    - (id) initWithFileName:(NSString*)fileName
    	if(self = [super init])
    		_spriteSheet = [UIImage imageNamed:fileName].CGImage;
    		_width = CGImageGetWidth(_spriteSheet);
    		_height = CGImageGetHeight(_spriteSheet);
    		_spriteData = (GLubyte *) malloc(_width * _height * 4);
    		_spriteContext = CGBitmapContextCreate(_spriteData, _width, _height, 8, _width * 4, CGImageGetColorSpace(_spriteSheet), kCGImageAlphaPremultipliedLast);
    		CGContextDrawImage(_spriteContext, CGRectMake(0.0, 0.0, (CGFloat)_width, (CGFloat)_height), _spriteSheet);
    		glGenTextures(1, &_name);
    		glBindTexture(GL_TEXTURE_2D, _name);	
    //This was missing---->		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE,_spriteData);			
    	return self;

    So all I had to do was add that line to my Texture2D class and then replace it in my drawing code with
    "glBindTexture( GL_TEXTURE_2D, texture.name);"

    That saved me a quite a few grey hairs. :)
  4. macrumors 6502a

    Great! I'd be interested to know how much faster it runs now.

    ß e n
  5. macrumors member

    Up from 12fps to, my current cap, 60fps.

    So it's LOTS faster!

    Thank's again :)

Share This Page