porting to the iphone

Member
Posts: 194
Joined: 2009.02
Post: #1
I'm totally new to iphone development and after fooling around for a few days and checking out sample code, I think I'm overlooking the optimal way to setup ogles because I'm getting some horrible frame rates with what I've tried. What is the best setup for ogl and what should I do for a timer?
Quote this message in a reply
Member
Posts: 50
Joined: 2008.06
Post: #2
Did you look at the samples on Apple's site?
http://developer.apple.com/iphone/librar...eCode.html

Such as GLPaint and GLTextureAtlas?
Quote this message in a reply
Member
Posts: 194
Joined: 2009.02
Post: #3
Yes I have, in fact what I did was basically copy and paste the basic cocoa opengl setup code from texture atlas to my program. With the animation interval set on 1/60, I'm getting around 37 fps(in both the simulator and the device) without even rendering anything. It strikes me as bizarre.
Quote this message in a reply
Member
Posts: 194
Joined: 2009.02
Post: #4
Here's some of the code I'm using for EAGLView and GLAppDelegate. At first I thought maybe I was just measuring the time intervals incorrectly, but it doesn't seem like it. Also I tried downloading the GLSprite example from apple and installing my update_fps() routine in it, and I got the same exact 37ish fps(while I'm running it on the sim and I click the desktop, deselecting the sim, the fps will go up but it is very, very erratic. I'm totally perplexed.

Code:
double get_current_time()
{
    static mach_timebase_info_data_t sTimebaseInfo;
    uint64_t time = mach_absolute_time();
    uint64_t nanos;
    
    // If this is the first time we've run, get the timebase.
    // We can use denom == 0 to indicate that sTimebaseInfo is
    // uninitialised because it makes no sense to have a zero
    // denominator is a fraction.
    if ( sTimebaseInfo.denom == 0 ) {
        (void) mach_timebase_info(&sTimebaseInfo);
    }
    
    // Do the maths.  We hope that the multiplication doesn't
    // overflow; the price you pay for working in fixed point.
    nanos = time * sTimebaseInfo.numer / sTimebaseInfo.denom;
    return ((double)nanos / 10000000.0);
}




void update_fps(void)
{
    if (get_current_time() > g_second_counter)
    {
        g_second_counter = get_current_time() + 60;
        
        NSLog(@"FPS = %d", g_fps);
        
        g_fps = 0;
        
        
    }
    
    g_fps++;
}
- (void)drawView
{
    [EAGLContext setCurrentContext:context];
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);

    update_fps();
    main_loop();
        glPushMatrix();
    glClear(GL_COLOR_BUFFER_BIT);
    draw_cube();
    glPopMatrix();    
    
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}


- (void)startAnimation
{
    animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
}


- (void)stopAnimation
{
    //[animationTimer invalidate];
    animationTimer = nil;
}


- (void)setAnimationInterval:(NSTimeInterval)interval
{
    animationInterval = interval;
    
    if(animationTimer) {
        [self stopAnimation];
        [self startAnimation];
    }
}


- (void)layoutSubviews
{
    [EAGLContext setCurrentContext:context];
    [self destroyFramebuffer];
    [self createFramebuffer];
    [self drawView];
}


- (BOOL)createFramebuffer
{
    glGenFramebuffersOES(1, &viewFramebuffer);
    glGenRenderbuffersOES(1, &viewRenderbuffer);
    
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
    
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
    
    if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
        NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
        return NO;
    }
    
    return YES;
}


- (id)initWithCoder:(NSCoder*)coder
{
    if((self = [super initWithCoder:coder])) {
        // Get the layer
        CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer;
        
        eaglLayer.opaque = YES;
        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                        [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
        
        context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
        
        if(!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer]) {
            [self release];
            return nil;
        }
        
        animationInterval = 1.0 / FPS;
        //animationInterval = 0.0;
        [self setupView];
        [self drawView];
    }
    
    return self;
}




and for app delegate I use:



// Sets up the frame rate and starts animating the sprite.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
    //application = application;
    // Look in the Info.plist file and you'll see the status bar is hidden
    // Set the style to black so it matches the background of the application
    [application setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO];
    // Now show the status bar, but animate to the style.
    [application setStatusBarHidden:NO animated:YES];
    glView.animationInterval = 1.0 / FPS;
    [glView startAnimation];
}


// Changes the frame rate when the application is about to be inactive.
- (void)applicationWillResignActive:(UIApplication *)application {
    NSLog(@"applicationWillResignActive:");
    glView.animationInterval = 1.0 / 5.0;
}

// Resumes the initial frame rate when the application becomes active.
- (void)applicationDidBecomeActive:(UIApplication *)application {
    NSLog(@"applicationDidBecomeActive:");
    glView.animationInterval = 1.0 / FPS;
}

// Stops the animation and then releases the window resource.
- (void)dealloc {
    [glView stopAnimation];
    [window release];
    [super dealloc];
}

I'm not sure if it matters but the machine I'm testing on is a 1st gen ipod touch.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #5
What is the constant, FPS, set to?
Quote this message in a reply
Member
Posts: 194
Joined: 2009.02
Post: #6
The constant 'FPS' is set to 60, though I've tried it at just about everything, 0,1, 120, 240, 6000 and the results are all similar(around 37 fps).

What I find most troubling is that when I installed the above timer(update_fps()) in the GLSprite sample code from apple, I get around 37 fps. Am I crazy or does that program really run at 37 fps?

I'm almost to the point where I'd start to question whether or not my ipod's defective.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #7
I am certain it is not defective Wink

So if you comment out the line with update_fps() on it, it's back to 60 fps right?

How often is the NSLog getting called, because if it's really often, it'll bog everything down like a mo-fo.

It's getting late, so I'm likely missing something obvious here, but no, it should work just fine at 60 fps. We'll get to the bottom of it one way or another. Wink

BTW, just use 60 or 120 for your timer interval since there's no real purpose in going higher or lower in terms of efficiency on iPhone. I prefer 60 myself, but I've heard others doing 120, and I think id does 30 for Wolfenstein, but I think they do that specifically to fit with their antiquated tick in the game, which you shouldn't do in a modern game.
Quote this message in a reply
Member
Posts: 194
Joined: 2009.02
Post: #8
AnotherJake Wrote:So if you comment out the line with update_fps() on it, it's back to 60 fps right?

update_fps() is the only means that I have for measuring a program's fps. Is there a better way?

AnotherJake Wrote:How often is the NSLog getting called, because if it's really often, it'll bog everything down like a mo-fo.

Yeah I'm really aware of that. The NSLog is called once a second, not once a tick- doesn't impact performance(at least not tangibly).

AnotherJake Wrote:It's getting late, so I'm likely missing something obvious here, but no, it should work just fine at 60 fps. We'll get to the bottom of it one way or another. Wink

Thanks, and I feel the same way that I'm probably overlooking something real simple and I'll probably feel real dumb once I figure out what it is.


So I just ran shark on it(running on the sim), and I'm getting all kinds of weird feedback, I don't know if this is because it's an ipod program or what. Using bottom-up sorting, 6 of the first seven listings have the '!' warning symbol "shark was unable to find symbol info for this address range" then it tells me to check 'generate debug symbols' setting in xcode, which is already checked. I get a few of these warnings, but for less, running shark on downloaded sample code from apple.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #9
Okay, I think I got this figured out. Looks like your time function was off a bit, and I didn't understand your FPS calc so I used a different one and got 60 fps. Try these instead:

Code:
double get_current_time()
{
    static mach_timebase_info_data_t sTimebaseInfo;
    uint64_t time = mach_absolute_time();
    uint64_t nanos;
    
    // If this is the first time we've run, get the timebase.
    // We can use denom == 0 to indicate that sTimebaseInfo is
    // uninitialised because it makes no sense to have a zero
    // denominator is a fraction.
    if ( sTimebaseInfo.denom == 0 ) {
        (void) mach_timebase_info(&sTimebaseInfo);
    }
    
    // Do the maths.  We hope that the multiplication doesn't
    // overflow; the price you pay for working in fixed point.
    nanos = time * sTimebaseInfo.numer / sTimebaseInfo.denom;
    //return ((double)nanos / 1000000000.0); // <-- needed a couple extra zeroes
    return (double)nanos * 1.0e-9; // <-- multiply instead might be a whisker faster
}

void update_fps(void)
{
    static int    frameCount = 0;
    static double    lastFPSUpdateTime = 0.0;
    double    currTime = get_current_time();
    
    if (lastFPSUpdateTime == 0.0)
        lastFPSUpdateTime = currTime;
    
    double    timeSinceLastFPSUpdate = currTime - lastFPSUpdateTime;
    
    frameCount++;
    if (timeSinceLastFPSUpdate >= 0.5)
    {
        NSLog(@"FPS = %0.1f", (double)frameCount / timeSinceLastFPSUpdate);
        frameCount = 0;
        lastFPSUpdateTime = currTime;
    }
}
Quote this message in a reply
Member
Posts: 194
Joined: 2009.02
Post: #10
Thanks for the code AnnotherJake. I installed your code and I do get 60fps, but I get around 60 fps(it will spike up a bit if I set it the animationInterval above 60) no matter what animationInterval I use. Is this suppose to happen?

Also one other question. I wrote a small set of routines that draws 80(columns)x120(rows) of textured quads filling up the screen and I'm getting around 3.6 fps on average.

Initially quads are treated as 32x32 pixel tiles, each 32x32 tile quad is subdivided into 64 smaller tile quads(8 columns and 8 columns).

So am I doing something wrong or are my expectations just off in respect to the ipod's performance?

Code:
#define TILE_WIDTH  32
#define TILE_HEIGHT  32
#define HALF_TILE_WIDTH  16
#define HALF_TILE_HEIGHT   16


void draw_map(void)
{
    int x, y;
    float_t pixel_x, pixel_y;
    
    
    for (x = 0; x < 10; x++)
    {
        for (y = 0; y < 15; y++)
        {
            pixel_x = (x*TILE_WIDTH);
            pixel_y = (y*TILE_HEIGHT);
            subdivide(pixel_x,pixel_y, 8, 8);
         }
    }    
}



void subdivide(   float_t pixel_x,           float_t pixel_y,
               int_t num_columns,   int_t num_rows  )
{

    int_t x, y;
    float_t w = TILE_WIDTH / num_columns;
    float_t h = TILE_HEIGHT / num_rows;
    float_t tex_w = (w/1024.0);
    float_t tex_h = (h/1024.0);
    
    float_t new_pixel_x, new_pixel_y;
    float_t new_texel_x, new_texel_y;
    
    for (x = 0; x < num_columns; x++)
    {
        for (y = 0; y < num_rows; y++)
        {
                
            new_pixel_x =  pixel_x + (x*w);
            new_pixel_y =  pixel_y + (y * h);
            new_texel_x = (new_pixel_x / 1024.0);
            new_texel_y = (new_pixel_y / 1024.0);
            
            render_quad(new_pixel_x,    new_pixel_y,
                        w,                  h,
                        new_texel_x, new_texel_y,
                        tex_w,            tex_h,
                        1.0 );
        
        }
    }
}



void render_quad(                    float_t x,        float_t y,
                        float_t w,        float_t h,
                        float_t tex_x,    float_t tex_y,
                        float_t tex_w,    float_t tex_h,
                        float_t atten )
{
    
    float_t v = AMB_LIGHT;

    
    glColor4f( v, v, v, 1.0);
    
    GLfloat verts[] = {
        x,        y,
        x + w,    y,
        x,        y + h,
        x + w,      y + h,
    };
    GLfloat color[] = {
        v, v, v, 1.0,
        v, v, v, 1.0,
        v, v, v, 1.0,
        v, v, v, 1.0,};
    
    GLfloat tex_coords[] = {
        tex_x,                tex_y,
        tex_x + tex_w,                tex_y,
        tex_x,                tex_y + tex_h,
        tex_x + tex_w,                tex_y + tex_h,
    };
    
    glBindTexture(GL_TEXTURE_2D, g_texture_list[1]);
    
    glColorPointer( 4, GL_FLOAT, 0, &color);
    glTexCoordPointer(2, GL_FLOAT, 0, &tex_coords);
    glVertexPointer(  2, GL_FLOAT, 0, &verts);
    
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #11
NelsonMandella Wrote:Thanks for the code AnnotherJake. I installed your code and I do get 60fps, but I get around 60 fps(it will spike up a bit if I set it the animationInterval above 60) no matter what animationInterval I use. Is this suppose to happen?
That's correct behavior. The iPhone is locked to the screen refresh of 60 Hz, so there's no way you can go higher than that. Lower, yes, but not higher.

NelsonMandella Wrote:Also one other question. I wrote a small set of routines that draws 80(columns)x120(rows) of textured quads filling up the screen and I'm getting around 3.6 fps on average.

Initially quads are treated as 32x32 pixel tiles, each 32x32 tile quad is subdivided into 64 smaller tile quads(8 columns and 8 columns).

So am I doing something wrong or are my expectations just off in respect to the ipod's performance?
The iPhone simply can't handle that. 80 x 120 quads would be 19200 triangles. The most you can reasonably expect to maybe use would be somewhere in the 10-12k range I think, but it depends on various factors like lighting, fill, blending, texture atlasing, how many calls to glDrawArrays/glDrawElements, etc. Shoot for a few thousand quads and you'll see much much better performance. Definitely have to get used to scaling things back dramatically on iPhone.
Quote this message in a reply
Member
Posts: 194
Joined: 2009.02
Post: #12
AnotherJake Wrote:The iPhone simply can't handle that. 80 x 120 quads would be 19200 triangles. The most you can reasonably expect to maybe use would be somewhere in the 10-12k range I think, but it depends on various factors like lighting, fill, blending, texture atlasing, how many calls to glDrawArrays/glDrawElements, etc. Shoot for a few thousand quads and you'll see much much better performance. Definitely have to get used to scaling things back dramatically on iPhone.

That really puts everything into perspective. Thanks so much for all the help.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #13
Your code is very inefficient-- 5 function calls per quad, dirtying GL state. Refactor so the entire array is calculated, then draw it all at once, and it will be faster.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  [Help] - Porting a game engine to iPhone iarwain 0 2,590 May 20, 2009 08:33 PM
Last Post: iarwain
  Porting a C++ game to iPhone Rasterman 12 9,732 Jun 12, 2008 09:48 PM
Last Post: AnotherJake