Jump to content

  • Log In with Google      Sign In   
  • Create Account

What's Your Ios Game Loop?


Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.


  • You cannot reply to this topic
12 replies to this topic

#1   GDNet+   

121
Like
1Likes
Like

Posted 30 July 2016 - 04:06 PM

Just looking at what other people have done, what's been successful, and what pitfalls to avoid.

 

Current Prototype:

  • Game update is variable update time
  • Game update and rendering done in CADisplayLink callback running on main thread.
  • Audio update occurs on separate thread controlled by AudioUnit.
  • (Game-specific context): Game update takes ~5ms to complete

 

Thoughts:

  • I feel like variable-time game update might be OK on mobile given we don't have to worry about being preempted as much.
  • Don't know if this is how CADisplayLink is designed to work - perhaps should run game logic on background thread and only render in CADisplayLink callback? Not sure what synchronization issues arise here. Game logic could be allowed to update as fast as possible - or could cap to screen refresh rate.
  • Similarly, could push rendering into same background thread as game update. Again, not sure what synchronization issues arise here.

Goals (The same as everyone else?):

  1. Minimize input -> display latency
  2. Every screen refresh, the device should have an new/updated frame buffer to display.

(Placed in Graphics Programming and Theory because of CPU/GPU synchronization issues - of which I am most uninformed)


Edited by zokeefe, 30 July 2016 - 04:28 PM.


#2   Members   

24827
Like
1Likes
Like

Posted 01 August 2016 - 02:28 AM

  • I feel like variable-time game update might be OK on mobile given we don't have to worry about being preempted as much.
It is never okay to use a variable-step rate. It is trivial to implement and failure to do so is only out of laziness, as it never enhances your game, only adds to its instability.


  • Don't know if this is how CADisplayLink is designed to work - perhaps should run game logic on background thread and only render in CADisplayLink callback? Not sure what synchronization issues arise here. Game logic could be allowed to update as fast as possible - or could cap to screen refresh rate.
  • Similarly, could push rendering into same background thread as game update. Again, not sure what synchronization issues arise here.

  • Minimize input -> display latency

Keep your game thread in a waiting state and trigger it from the display link. Spend as little time as possible in the display link or you will interfere with input timing and responsiveness.
For simplicity, there is no reason to render on a thread separately from your logic thread—just do the update and then render on the same thread.


(Placed in Graphics Programming and Theory because of CPU/GPU synchronization issues - of which I am most uninformed)

Making a separate render thread is non-trivial and requires some experience. Stick to single threads now and research multi-threaded rendering when you are ready.
It is unrelated to anything specific to iOS, and is its own subject large enough to deserve its own research.


L. Spiro

#3   Members   

666
Like
0Likes
Like

Posted 01 August 2016 - 02:51 AM

My loop is a little complicated, i work on PC and it should run on 60 or 30 fps dependent on hardware capibility.

 

I have multiple threads for each of the subsystems running( currently: network, audio, ki, physics and game logic, rendering)

 

User Input is collected in main thread at the beginning of the game loop, rendering draws always the scene calculated by the previous run of each subsystems;

 

Loop:

  1. Collect user input
  2. Trigger all subsystems
  3. Wait for finish
  4. Merge results and prepare next render frame
  5. Continue

This leads to the result that rendering is always on frame behind the user input.

Also various subsystems have their own copy of some parts of the scene to avoid race conditions. Which is a problem on huge scenes and low ram.



#4   GDNet+   

121
Like
0Likes
Like

Posted 01 August 2016 - 10:56 PM

@L.Spiro

 

Thanks for commenting :) I've read your blog - and as such am not surprised by

 

 

It is never okay to use a variable-step rate. It is trivial to implement and failure to do so is only out of laziness, as it never enhances your game, only adds to its instability.

I don't know if it's "trivial" (at least for me :P). Variable-step allows you to sim right up to start of frame easily, while to do this with fixed-step requires you to fudge all the renderable object transforms (at least just for rendering) No?

 

The other drawback of fixed-step is you don't know how many update steps you may take - which scares me since doing 1 game loop vs 2 game loops could blow my CPU budget for a frame out of the water and cause us to miss a rendered frame? (Included just for discussion :P).

 

 

 

Keep your game thread in a waiting state and trigger it from the display link.

OK :)


Edited by zokeefe, 01 August 2016 - 11:07 PM.


#5   GDNet+   

121
Like
0Likes
Like

Posted 01 August 2016 - 11:01 PM

@mgubisch

 

Thanks for commenting!

Interesting. Out of curiosity, how does one maintain separate threads for game logic & physics effectively? I would assume both want to be touching the same bits of data - to a large extent.



#6   Members   

24827
Like
1Likes
Like

Posted 02 August 2016 - 12:44 AM

The other drawback of fixed-step is you don't know how many update steps you may take - which scares me since doing 1 game loop vs 2 game loops could blow my CPU budget for a frame out of the water and cause us to miss a rendered frame?

If you need a cap, limit the number of updates you can do in a frame, but each update still needs to be of a fixed amount of time.
You have to be fine with having your game slow down and drop frames for this to work, which means online real-time multi-player games cannot do this, but generally iOS games can.


L. Spiro

#7   Members   

666
Like
0Likes
Like

Posted 03 August 2016 - 07:54 AM

@mgubisch

 

Thanks for commenting!

Interesting. Out of curiosity, how does one maintain separate threads for game logic & physics effectively? I would assume both want to be touching the same bits of data - to a large extent.

 

As a wrote up in my first post some parts of the scene are stored in each subsystem which uses it. This makes some unneccesary copies which isn't really beautyful and is on my list to optimize.

 

Also each entity has a common set of properties which may be influenced by various subsystems(e.g. positon, velocity, aso).

Each subsystem wich wants to modify such a proberty sets a change flag to that property.

 

The merge result step collects all that change requests and applies it to the properties, during next loop run the renderer works with this properties.

If only one subsystem wants a change this is easy, just take it. If more than one subsystems wants to update the same part there is some kind of hierachy which subsystem wins.

In my desing this don't happen to often so i works fine for me.

 

At the beginning a had user input also as a subsystem, but this was somehow problematic so a apply user input at first, bevor the subsytems start to work.

I tried to make the tasks as fixed to one subsystem as possible, Movement is for nearly everthing handled by physics. Some exceptions like setting a fixed position of velocity is done by gamelogic. But in that cases gamelogic wins and in the next frame physics works with the new values and everthing runs as expected againg.

 

The idea to this came from an intel paper describing the demo they wrote many years ago as the introduced TBB. In that time a adopted this idea and modified it over the years. But the basic idea having a one or more separate threads for each subsystem stayed the same.



#8   Moderators   

49397
Like
1Likes
Like

Posted 04 August 2016 - 06:24 AM

It is never okay to use a variable-step rate

Just to reduce the hardness of L.S.'s stance here; all the console games that I've ever worked on (up until my indie project) have used a variable time-step. If your simulation can tolerate a wide range of delta-time values, and gameplay isn't affected by the varying quality of integration, then variable time-step result in a far simpler codebase...
 
I'm currently doing game engine contracting for a console games company, and have tried to convince them that they should really be using fixed time-step plus game-state interpolation... but have been unable to provide an objective argument to sway them so far. Their variable-rate system is working perfectly fine for them, and as we say, if it ain't broke, don't fix it.

Making a separate render thread is non-trivial and requires some experience.

While this is true, switching from variable-time-step to fixed-time-step + interpolation lays a lot of the foundations. The game-state interpolation system basically requires that the renderer's input data is separated from the live game-state data, which is required for a good multi-thread implementation :)

If you need a cap, limit the number of updates you can do in a frame, but each update still needs to be of a fixed amount of time. You have to be fine with having your game slow down and drop frames for this to work

You should generally do this in a variable time-step system too -- cap the amount of time that a single frame is allowed to simulate -- as the quality of the integration will be pretty terrible if you try to simulate too much time in one go. As in the fixed-time-step case, this will cause your game to go into slow motion if the actual framerate is too low. 

Out of curiosity, how does one maintain separate threads for game logic & physics effectively? I would assume both want to be touching the same bits of data - to a large extent.

The key to any good multithreading system is ensuring that no two threads ever need to share the same mutable data :)
For update/render, this means forming a pipeline where each frame, the update task generates a fresh blob of immutable data which is consumed by the render task.

The other drawback of fixed-step is you don't know how many update steps you may take

It's the same as in a variable-step architecture. You measure how long the previous frame took, and then advance the simulation by that amount of time next frame.



#9   GDNet+   

121
Like
0Likes
Like

Posted 06 August 2016 - 10:56 PM

@mgubisch

 

Interesting. Do you know what the original paper was called?



#10   GDNet+   

121
Like
0Likes
Like

Posted 06 August 2016 - 11:14 PM

@Hodgman

 

Thanks for the reply!

 

I'm currently doing game engine contracting for a console games company, and have tried to convince them that they should really be using fixed time-step plus game-state interpolation... but have been unable to provide an objective argument to sway them so far.

 

What argument are you using? :)

 

Their variable-rate system is working perfectly fine for them, and as we say, if it ain't broke, don't fix it.
 

 

This is where I am at now :) It's a 2D engine, my game update loop is very tight. The physics is entirely continuous. The only vulnerable aspect are objects undergoing acceleration dependent on velocity & position (using Verlet).

 

I wish I could find that object argument you were looking for - then I could stop worrying about this :)



#11   GDNet+   

121
Like
0Likes
Like

Posted 06 August 2016 - 11:31 PM

@L. Spiro

 

Thanks again for the reply!

 

You have to be fine with having your game slow down and drop frames for this to work

 

 

Ya - don't know how I feel about slowmo - seems almost as "physics-breaking" as object behaving unpredictably in variable-step under large dt.

 

 

You'll have to forgive me - first time writing such a system from this level! Just trying to get it "right".

 

If (part) of the objective of using fixed-time is to have your game-update rate be independent of display refresh rate - why not go all the way and not have your game update thread wait for CADisplayLink? I.e. Just setup a normal system timer to wake up your game update thread at your desired rate? You could still do interpolation of game object states when you go to render in your CADisplayLink callback.



#12   Moderators   

49397
Like
1Likes
Like

Posted 07 August 2016 - 08:40 AM

What argument are you using?

For starters: that your gameplay logic will always behave correctly :)
e.g. they had an issue in the past where we had a game that ran at 30Hz on consoles, but 60Hz on our development PC's. Gameplay programmers and designers mostly played the PC build as it was easier, and tuned the gameplay until they were happy with it... but then when they finally tested it on a console (running at half the frame-rate, double the delta time), the AI were... stupid! A lot of the AI code just so happened to be responsive and challenging with a 17ms delta, but was unresponsive and easily defeated when it operated with a 33ms delta!
They fixed this at the time by adding an option on PC to cap the frame-rate to 30FPS, and then re-tuning the entire game when this option was enabled...
However, that doesn't fix the underlying problem, it just swept it under the rug -- if a user's PC can only muster 20FPS, is the AI going to be "stupid" for them? If a user runs the game at 120Hz, will the AI be too "smart"??
If they'd be using a fixed-time-step, this would've never been a problem as every one would always experience the same AI.
 
Another example is Call of Duty :) The physics of jumping is approximating a curved arc via lots of little linear steps. The higher your framerate, the closer it matches that perfect arc, and the lower your framerate, the more approximate it is. COD4 had an issue where in a multiplayer match (which is crazy, as the server should be authoritative over this!) it was possible to jump over certain "impassable" walls, but only if your PC was running the game at about 600 FPS so that your jumping motions were just that tiny fraction smoother than everyone else's...
 
 Another reason can be performance. For some games, fixed-time-step may increase your CPU time per frame, because you may end up with >1 update's per rendered frame, and you have the overhead of game-state interpolation... e.g. my racing game simulates vehicles at 600Hz (and tires at 1200Hz) for accuracy, but costs me a lot of CPU time!

However, for other games, fixed-time-step may actually decrease your CPU time per frame, because you may end up with <1 updates per rendered frame!!

 

e.g. in the first example, their minimum spec hardware could only run it at 30Hz, so they could have chosen a 30Hz fixed simulation rate. On high-spec PC's, the simulation would continue to run at 30Hz, but the renderer would be free to run at 60Hz, or 144Hz, etc, and it would do so more efficiently due to the simulation rate being fixed...

 

Say that updating is 20ms and rendering is 7ms:

* with variable timestep, one rendered frame takes 27ms, two frames takes 54ms, three takes 81ms, four takes 108ms -- four frames in 108ms is 37 FPS.

* with fixed update of 30Hz, first frame will take 27ms, but then it will skip an update (because 33ms/a 30Hz step hasn't elapsed yet) and render again, bringing us up to 33ms. The third frame then updates+renders (in 27ms) bringing us to 60ms, and the 4th frame just renders, bringing us to 66ms. Four frames in 66ms is 60FPS.

 

It's common for RTS games (with thousands of units to simulate) to use a very low fixed simulation rate -- as low as 10Hz -- while rendering at a variable rate, such as 30-60Hz.

 

Ya - don't know how I feel about slowmo - seems almost as "physics-breaking" as object behaving unpredictably in variable-step under large dt.

You should implement the same slowmo effect in a variable time-step system as there surely will be a limit to how large a time-step can be without being completely full of garbage errors!
e.g. if a player's jump takes one second, and your physics engine is integrating via "small" linear steps, then jumping at 1FPS will be equivalent to... not jumping at all... 
At this limit, you can either choose between letting the simulation continue on in this ridiculously approximate state, or you can slow down the game to a point where the user's PC is able to keep up with the simulation...
 
Fixed-time step is exactly the same, but as well as choosing a "minimum acceptable framerate", you've also set the "maximum simulation rate" to that same number :)
 
In any case, this slow-mo effect should only ever occur if the user's PC isn't actually capable of running your simulation at the minimum frame rate. It's your job to specify the game's minimum hardware requirement and then make sure that it does run at an acceptable framerate on that hardware.


Edited by Hodgman, 07 August 2016 - 08:59 AM.


#13   GDNet+   

121
Like
0Likes
Like

Posted 07 August 2016 - 06:21 PM

@Hodgeman

 

Say that updating is 20ms and rendering is 7ms: * with variable timestep, one rendered frame takes 27ms, two frames takes 54ms, three takes 81ms, four takes 108ms -- four frames in 108ms is 37 FPS. * with fixed update of 30Hz, first frame will take 27ms, but then it will skip an update (because 33ms/a 30Hz step hasn't elapsed yet) and render again, bringing us up to 33ms. The third frame then updates+renders (in 27ms) bringing us to 60ms, and the 4th frame just renders, bringing us to 66ms. Four frames in 66ms is 60FPS.
 

 

I have a hard time following this. Don't know how realistic it is without VSYNC. And sure, you can get extra "render frames" from just doing the interpolation with different interpolation factors. I think this is the only way to be able to handle these new 144fps displays. But, I mean, there's nothing stopping us from doing the same thing with variable time step...

 

You should implement the same slowmo effect in a variable time-step system as there surely will be a limit to how large a time-step can be without being completely full of garbage errors!

 

I'm scared of this. I'm scared of missing a frame, having to do 2 updates, which cause me to miss another frame, which causes me to do 2 updates, ...

 

Also, it totally depends on your physics whether or not that is true. If you have forces that depend on object's velocity or position (like drag, springs), then yes. If you only use constant forces (like gravity), and impulses, with continuous collision detection and a global collision-stepped physics solver - then any amount of time can pass and you're fine :) (Though that physics simulation step may take a long time... which will arguably cause you to miss your next frame, ect). No good solution!






Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.