I realized that these are two different things:
Drawing, and getting it on screen.
So while you may draw in every single call from CADisplayLink at a rate of 60 FPS, if your drawing operations take slightly longer than 1/60 seconds you end up with 30 FPS in theory, because you're missing out every other chance to get through the render pipeline.
OK; Knowing this, it seems nonsense to remember the start NSTimeInterval and incrementing a frame counter in the run loop, then checking at the end if a second has passed and calculate the FPS for the last passed second.
I want a way to actually get the true FPS value from OpenGL ES on screen. I looked into instruments in Xcode 3.2.6 but couldn't find one for this. But I remember there was a way to get that FPS value. The real one.
How?
Measuring OpenGL ES performance by framerate may not be the best approach. I've taken to recording frame time myself, which seems to provide a more accurate assessment of my overall rendering performance. It's trivial to encapsulate your rendering in something like
CFTimeInterval previousTimestamp = CFAbsoluteTimeGetCurrent();
// Do your OpenGL ES frame rendering here, as well as presenting the onscreen render buffer
CFTimeInterval frameDuration = CFAbsoluteTimeGetCurrent() - previousTimestamp;
NSLog(#"Frame duration: %f ms", frameDuration * 1000.0);
to obtain rendering time. If you want it, your instantaneous framerate is the inverse of frameDuration in the above code.
Be careful to time the entire frame rendering, because the tile-based deferred renderer in iOS and other mobile devices may hide the true cost of particular rendering operations by delaying them until just before the frame is drawn to the screen.
However, if you want to obtain a less precise framerate from Instruments, you can do that using the OpenGL ES Driver instrument, which reports Core Animation Frames Per Second as one of its logged statistics:
Related
I am developing a 2D Tile based game and currently struggling with performance issue as I am getting around 10 - 15 FPS even when running on iPad 3. OpenGL ES Frame capture reveals that I am making call to glDrawElements 689 times per frame! Is that a lot? Could it be the case of low performance?
Should I stack everything in one huge array and perform 1 draw call? will it make any difference?
At this point in time, you are currently limited by your command issue(assuming), if you run opengl performance detective ( it's under xcode (right click, open developer tools) you may have to download it through preferences ).
Your goal is to be limited by fill rate at the end of the day, here are some tips to help you get there
Sort all sprites by
Draw Depth
Blend Mode
Texture ID
Once sorted,
Pack all sprites into one vertex buffer object and an index buffer object.
When ever your draw depth, blend mode, or texture ID change, it's time to make a new draw call and bind those resources.
Also keep in mind that your sprites should have your vertices flatted on the cpu side (pos x mvp ) and you should not be sending over matrices and any other attributes such as color, should be part of the vertex.
Typical vertex
{
float pos[3]
int color
float uv[2]
}
I have, most of the time, 50+ FPS, but when I load resources(background tread) it drops to 30 FPS. I want to have constant FPS, 30 or even 20, it's not a problem for me. What is the best way to make FPS constant?
You should be using time-based redrawing, instead of frame based drawing. Michael Daley's book has some excellent info on this.
Also, try loading as many of your resources as possible in a spritesheet.
Not really sure if there is an established method, but frame rate in this case is the frequency at which you redraw. 20 FPS is a 50 millisecond redraw rate. One method would be to only redraw if the time between the last redraw and now is >=50 ms.
I'm working on an iPhone App that relies heavily on OpenGL. Right now it runs a bit slow on the iPhone 3G, but looks snappy on the new 32G iPod Touch. I assume this is hardware related. Anyway, I want to get the iPhone performance to resemble the iPod Touch performance. I believe I'm doing a lot of things sub-optimally in OpenGL and I'd like advice on what improvements will give me the most bang for the buck.
My scene rendering goes something like this:
Repeat 35 times
glPushMatrix
glLoadIdentity
glTranslate
Repeat 7 times
glBindTexture
glVertexPointer
glNormalPointer
glTexCoordPointer
glDrawArrays(GL_TRIANGLES, ...)
glPopMatrix
My Vertex, Normal and Texture Coords are already interleaved.
So, what steps should I take to speed this up? What step would you try first?
My first thought is to eliminate all those glBindTexture() calls by using a Texture Atlas.
What about some more efficient matrix operations? I understand the gl*() versions aren't too efficient.
What about VBOs?
Update
There are 8260 triangles.
Texture sizes are 64x64 pngs. There are 58 different textures.
I have not run instruments.
Update 2
After running the OpenGL ES Instrument on the iPhone 3G I found that my Tiler Utilization is in the 90-100% range, and my Render Utilization is in the 30% range.
Update 3
Texture Atlasing had no noticeable affect on the problem. Utilization ranges are still as noted above.
Update 4
Converting my Vertex and Normal pointers to GL_SHORT seemed to improve FPS, but the Tiler Utilization is still in the 90% range a lot of the time. I'm still using GL_FLOAT for my texture coordinates. I suppose I could knock those down to GL_SHORT and save four more bytes per vertex.
Update 5
Converting my texture coordinates to GL_SHORT yielded another performance increase. I'm now consistently getting >30 FPS. Tiler Utilization is still around 90%, but frequently drops down in the the 70-80% range. The Renderer Utilization is hovering around 50%. I suppose this might have something to do with scaling the texture coordinates from GL_TEXTURE Matrix Mode.
I'm still seeking additional improvements. I'd like to get closer to 40 FPS, as that's what my iPod Touch gets and it's silky smooth there. If anyone is still paying attention, what other low-hanging fruit can I pick?
With a tiler utilization still above 90%, you’re likely still vertex throughput-bound. Your renderer utilization is higher because the GPU is rendering more frames. If your primary focus is improving performance on older devices, then the key is still to cut down on the amount of vertex data needed per triangle. There are two sides to this:
Reducing the amount of data per vertex: Now that all of your vertex attributes are already GL_SHORTs, the next thing to pursue is finding a way to do what you want using fewer attributes or components. For example, if you can live without specular highlights, using DOT3 lighting instead of OpenGL ES fixed-function lighting would replace your 3 shorts (+ 1 short of padding) for normals with 2 shorts for an extra texture coordinate. As an additional bonus, you’d be able to light your models per-pixel.
Reducing the number of vertices needed per triangle: When drawing with indexed triangles, you should make sure that your indices are sorted for maximum reuse. Running your geometry through Imagination Technologies’ PVRTTriStrip tool would probably be your best bet here.
If you only have 58 different 64x64 textures, a texture atlas seems like a good idea, since they'd all fit in a single 512x512 texture... if you don't rely on texture wrap modes, I'd certainly at least try this.
What format are your textures in? You might try using a compressed PVRTC texture; I think that's less load on the Tiler, and I've been pleasantly surprised by the image quality even for 2-bit-per-pixel textures. (Good for natural images, not good if you're doing something that looks like an 8-bit video game)
The first thing I would do is run Instruments profiling on the hardware device that is slow. It should show you pretty quickly where the bottlenecks are for your particular case.
Update after instruments results:
This question has a similar result in Instruments to you, perhaps the advice is also applicable in your case (basically reducing number vertex data)
The biggest win in graphics programming comes down to this:
Batch, Batch, Batch
TextureAtlasing will make a bigger difference than most anything else you can do. Switching textures is like stopping a speeding train to let on new passengers every time.
Combine all those textures into an atlas and cut your draw calls down a lot.
This web-based tool may be helpful: http://zwoptex.zwopple.com/
Have you looked over the "OpenGL ES Programming Guide for iPhone OS" in the dev center? There are sections on Best Practices for Vertex Data and Texture Data.
Is your data formatted to be able to use triangle strips?
In terms of least effort, the modification sequence for you would probably be:
Reducing vertex attribute size
VBOs
Note that when you do these, you need to make sure that components are aligned on their native alignment, i.e. the floats or full ints are on 4-byte boundaries, the shorts are on 2-byte boundaries. If you don't do this it will tank your performance. It might be helpful to mentally map it by typing out your attribute ordering as a struct definition so you can sanity check your layout and alignment.
making sure your data is stripped to share vertices
using a texture atlas to reduce texture swaps
To try converting your textures to 16-bit RGB565 format, see this code in Apple's venerable Texture2D.m, search for kTexture2DPixelFormat_RGB565
http://code.google.com/p/cocos2d-iphone/source/browse/branches/branch-0.1/OpenGLSupport/Texture2D.m
(this code loads PNGs and converts them to RGB565 at texture creation time; I don't know if there's an RGB565 file format as such)
For more information on PVRTC compressed textures (which looked way better than I expected when I used them, even at 2 bits per pixel) see Apple's PVRTextureLoader sample:
http://developer.apple.com/iPhone/library/samplecode/PVRTextureLoader/index.html
it has both the code for loading PVRTC textures in your app and also instructions for using the texturetool to convert your .png files into .pvr files.
I am using an opengl es iphone application. What is the most accurate way to calculate the frames per second of my application for performance tuning?
I guess what you want is this:
// fps calculation
static int m_nFps; // current FPS
static CFTimeInterval lastFrameStartTime;
static int m_nAverageFps; // the average FPS over 15 frames
static int m_nAverageFpsCounter;
static int m_nAverageFpsSum;
static UInt8* m_pRGBimage;
static void calcFps()
{
CFTimeInterval thisFrameStartTime = CFAbsoluteTimeGetCurrent();
float deltaTimeInSeconds = thisFrameStartTime - lastFrameStartTime;
m_nFps = (deltaTimeInSeconds == 0) ? 0: 1 / (deltaTimeInSeconds);
m_nAverageFpsCounter++;
m_nAverageFpsSum+=m_nFps;
if (m_nAverageFpsCounter >= 15) // calculate average FPS over 15 frames
{
m_nAverageFps = m_nAverageFpsSum/m_nAverageFpsCounter;
m_nAverageFpsCounter = 0;
m_nAverageFpsSum = 0;
}
lastFrameStartTime = thisFrameStartTime;
}
Regards,
Asaf Pinhassi.
Try running:
Run -> Run With Performance Tool -> OpenGL ES.
You have to run that tool when connected to the device (which you'd obviously want to anyway for performance tuning...)
It gives you Core Animation FPS which may (probably) not be what you are looking for, but it can graph a number of other useful statistics for you which may also help you optimize.
Find something like a high resolution timer (more than 1000 ticks/seconds),
and measure the time between when you start rendering until it's on the screen.
Divide the ticks per second by the time you just measured, and you have the FPS.
When you reach the end of your drawing code, increase a counter.
Setup an NSTimer fire every second, display the counter, and reset it to zero.
Check this thread out. There are some very useful links on it. Good luck!
Measuring FPS during development is nearly meaningless.
Measure the rendering time you need!
This way you will have a much clearer understanding of how your changes affect performance.
Usually it's a very good idea to split your rendering time into meaningful slices, e.g. "render background", "render level", "render mobs", etc.
If you still want to do FPS my personal favourite is Johns NSTimer version, even if it doesn't show spikes.
Take CABasicAnimation for example. How do you lower the frame rate (overhead)? Animations run smooth, but my touchesMoved method skips a beat. Want to reduce the animation frame rate so touchesMoved is not skipping movements.
You don't have any inherent control over frame rate once you start your CABasicAnimation.
Probably the best way to achieve this would be to create multiple interpolations for a single animation (i.e. if you're moving 50 px down and 50px across, do 2 x 25px each) and induce an artificial sleep in your thread. Not a perfect solution, but will perhaps achieve slightly better results that you're seeing.
Be aware that this technique will have different framerates on different CPUs, and is therefore not generally recommended. Essentially, YMMV.