TIMING TIMING PLEASE HELP -- FRUSTRATING ME
encore

let me tell my code first ..

four pads will be moving independently , each moving 1 pixel per frame ... i have two players , each of them move 1 pixel per keyboard move.

now i want my limit my pads to move 100 pixels per second and my players move 100 pixels per second ...

when i run the program my pads and my players move extremely fast since i get nearly 7000 fps ....that is pads move 7000 pixels per second and players move the same ...

now i dont want to limit my game to run at 110 fps .. i want my game to run at the maximum possible fps ....

from the forums what i have learned is ... i can use delta timing to achieve this since i need not limit the fps for this purpose ...

let me tell u what i know about delta timing ....
1) set up timer
2) calculate the time it takes to render a single frame
3) now use this time to make your sprite / objects movements in the game using the formula .

all i want to know now is how do i acheive delta timing using allegro timer functions .... a working example will greatly help me ...

thanks
encore

:-/

Richard Phipps

First of all, it doesn't matter whether your fps is 200 or 2000 because you are limited by the speed your monitor can refresh.

Most monitors probably go between 60-120 fps, so fixing at around 100 fps should be fine. Your normal tv only refreshes at 50 or 60 fps.

Evert
Quote:

now i dont want to limit my game to run at 110 fps .. i want my game to run at the maximum possible fps ....

It is pointless to draw at a higher rate than the monitor refresh, you know that right? At that, it's also pointless to redraw more often than you update your logic.
Either way, limiting your logic to run at 100 cycles per second should not limit your framerate (except in the trivial sense that you should not redraw if nothing has changed).

Steve++

If it's pointless to draw at a higher framerate than that of the monitor (which I don't dispute) then we have to wonder why professional games do it.

These are my thoughts:
Games typically do this loop: get inputs, process logic, show results. This happens in one thread (which may use/spawn other threads). The more times the logic loop can execute per second, the less grainy the game logic becomes. We want game logic to be accurate, but we don't want it to be so accurate that it degrades graphical performance. So what does almost every game do? Interleave game logic with display code.

What are the alternatives? Back in the old days of C64 and 2D consoles, programmers could trap a signal that was triggered when a frame has finished on the monitor. For some stupid reason this capability was scrapped long ago on the PC. If we had access to such a signal, then we could write multithreaded games that maintain the visual framerate at the monitor's refresh rate and use all the left over CPU for gameplay. There may be some frame skipping occasionally (depends on PCs specs) because well written games will guarantee an input/logic framerate as well.

When I think about it though, I think by using flip-chains, the thread that flips will wait if the previous page is still being displayed. It's too early in the morning right now to think of how I could use this in a multithreaded alternative to the conventional game loop though.

Back on topic...

Quote:

all i want to know now is how do i acheive delta timing using allegro timer functions ....

Allegro's timers are too grainy in all OSs except DOS. You can use them, but not very accurately. If you're targeting windows only, you can use the high-resolution timers in the winapi. For that, have a look at these articles.

HoHo

An exellent thread about timing and threads.
http://www.allegro.cc/forums/thread/585140

I think there was something about delta-time and frame limiting too

Evert
Quote:

If it's pointless to draw at a higher framerate than that of the monitor (which I don't dispute) then we have to wonder why professional games do it.

It looks cool to the average person to see that game X runs with 10000 FPS instead of 5000 FPS on their new over-priced graphics card?
;)

Shawn Hargreaves
Quote:

If it's pointless to draw at a higher framerate than that of the monitor (which I don't dispute) then we have to wonder why professional games do it.

Most don't. At least not the sensible ones.

Some do if they want to have a double use as a performance benchmarking tool, because if they clamp to the screen refresh, that makes them less useful as a way of measuring GPU performance. But I think that's a crazy reason to design a game in a particular way!

Running faster than the monitor can actually hurt percieved smoothness. If your screen runs at 60hz, and your game runs at 60, all is well. But let's say you up the game to 100hz. That should look smoother, right? Not at all.

1: Render and present in 100hz cycle.
2: Notice that the monitor hasn't blanked yet, so start rendering the next frame.
3: Monitor finishes 60hz cycle. But rendering the next frame hasn't completed yet.
4: Wait for rendering to complete.
5: Now the monitor is in the middle of another 60hz cycle.
6: Finally both the game and monitor are back in sync, so you can present the next frame.

End result: far from upping a 60hz refresh to 100hz, the practical effect is you just dropped it to 30hz!

Much better to just stay exactly in sync with your output device.

Christopher Bludau

I wonder if this is true with disabled vsync, too?
Or maybe I´m getting this wrong.

Thomas Fjellstrom

Disabling vsync only makes it so the gfx api (X11, DirectX) doesnt FORCE a wait for vsync(). the monitor still has a vsync.

Shawn Hargreaves

It's still true. Disabling vsync avoids the need for the CPU to wait on the graphics card, but you still can't actually get the new image out to the monitor until the electron beam is in the right place to do that.

If I waste a bunch of time rendering an image that the electron beam isn't in the right place to display, that can then hurt my ability to get it a new correct fresh image at the time when it is ready.

It leads to stuttery performance because the images you are rendering don't properly line up with the ones you are displaying.

Practical example:

At 60hz, you could move a sprite by 3cm each frame.

At 90hz, you move it by 2cm. Then you miss a frame (which you rendered but the monitor never actually displayed), the render another which is displayed. You think you moved it twice by 2cm each time, but the user just saw it jump by 4cm.

Alternating 2cm and 4cm jumps looks ugly: much better to just match the monitor and move it by 3cm every 60hz.

Christopher Bludau

Got it. Thanks.
Is it possible to check for the current refresh rate with allegro? Would be cool, so my game could run with the equivalent amount of fps.

Dustin Dettmer
Steve++ said:

...
When I think about it though, I think by using flip-chains, the thread that flips will wait if the previous page is still being displayed. It's too early in the morning right now to think of how I could use this in a multithreaded alternative to the conventional game loop though.
...

Doesn't triple buffering already solve this problem?

Shawn Hargreaves's Member Number said:

The Progenitor

Whats a progenitor?

Steve++

Use a dictionary :-* .

Quote:

Doesn't triple buffering already solve this problem?

Triple buffering works just like page-flipping, except there's one more page in the flip-chain. The advantage of three pages is that the time taken to render a frame is the running average of the last two frames (or something like that). In other words, if we get an occasional frame that takes longer to render than a standard refresh cycle, there won't be any jitter if the next frame takes less time to render such that the sum of those two times is not greater than two refresh cycles. The more pages we add to the flip chain, the more opportunity there is for smooth display when render times fluctuate all over the place. But the more pages we add, the more lag the player perceives - what they see happened n frames ago, where n is the number of frames in the chain.

Oops - I didn't answer the quote. No, triple buffering doesn't solve this problem. It just has the potential to make the current thread wait, just like I said. Solving the problem of capping the rendering and utilising the CPU for gameplay while waiting is something a little bit more complicated that is achieved with multithreading.

I was just thinking, perhaps another reason why games tend to use the conventional game loop is that if they use a multithreaded approach instead, what are they to do if they have to wait in the game loop? They must busy wait or sleep. If the thread sleeps and the render thread is also asleep, then the process will sleep and be placed on the back of the process queue. This could make a game really jittery, although on consoles that doesn't apply. But for PCs, I wonder if there's a way to make the process sleep only when it needs, yet keep the game responsive.

Edit: Shawn used to be member #2, but that hardly does justice to Allegro's progenitor.

Kitty Cat
Quote:

No, triple buffering doesn't solve this problem. It just has the potential to make the current thread wait, just like I said.

Only if you already have a whole frame rendered while another is still waiting to be shown (and another is being shown). You don't want to get too far ahead of what the player sees after all, so if you're too fast you're eventually going to have to wait. If you have a frame drawn and the system is waiting for another, when you go to show it, control will return to your code immediately while the card waits for the vsync.

Richard Phipps

On consoles and older computers such as the ST & Amiga you have the advantages that not only is the hardware pretty similar for each owner (meaning you can see where a program slows down for everyone), but that you had complete control over the CPU.

The problem with PC's is they all have different hardware specs and that the OS takes control and steals some of your game's cpu time. This makes 100% smooth animation/scrolling nearly impossible as you miss frames due to the OS taking over infrequently or frequently depending on what other programs are running.

It must be great to develop for a console! :)

A J

console games should be multithreaded as much as PC games, didn't one of those consoles have like a 9 core CPU ?

Richard Phipps

That's not the issue here. The problem is the OS stealing CPU time from the game and causing missed frames or slowdown.

Arthur Kalliokoski

If you only want something to move 100 pixels per second, no matter how much FPS exceeds 100, the objects should still be on the same pixels for 0.01 second right? So why does refreshing help? Make a little demo that fills tiles on the screen every 5 seconds and hit "Print Screen" every second, doesn't make sense does it?

Dustin Dettmer
Quote:

Triple buffering works just like page-flipping, except there's one more page in the flip-chain. The advantage of three pages is that the time taken to render a frame is the running average of the last two frames (or something like that). In other words, if we get an occasional frame that takes longer to render than a standard refresh cycle, there won't be any jitter if the next frame takes less time to render such that the sum of those two times is not greater than two refresh cycles. The more pages we add to the flip chain, the more opportunity there is for smooth display when render times fluctuate all over the place. But the more pages we add, the more lag the player perceives - what they see happened n frames ago, where n is the number of frames in the chain.

Hm, maybe I'm using the wrong term.

By triple buffering I mean the technique where you render onto a video bitmap and use request_video_bitmap which returns immediately and swaps the monitor over to the new bitmap on the next vertical retrace. The result is that you're running effectively as fast as writting directly to the screen, don't have to wait for any vsyncs, and everythings completely buffered.

You need 3 buffers for each state the video bitmap can be in:

  1. Displayed on screen

  2. Will be displayed at any moment

  3. For drawing on

You mentioned something earlier about a trick you thought up using a secondary thread and signals to avoid wasting CPU ticks waiting for the GPU. This is a problem that triple buffering is supposed to solve.

Did i interpret your multithreaded rendering trick incorrectly?

Edit:

Quote:

Oops - I didn't answer the quote. No, triple buffering doesn't solve this problem. It just has the potential to make the current thread wait, just like I said. Solving the problem of capping the rendering and utilising the CPU for gameplay while waiting is something a little bit more complicated that is achieved with multithreading.

Hm, re-reading this quote I think I see something I missed. Are you talking about processing continuously instead of per-frame? Basically utilizing the extra CPU cycles of computers that get ahead of their monitor and are waiting for the monitor refresh rate to catch up with them? How do you propose to do that?

Steve++
Quote:

You mentioned something earlier about a trick you thought up using a secondary thread and signals to avoid wasting CPU ticks waiting for the GPU. This is a problem that triple buffering is supposed to solve.

Yes, this is one advantage triple buffering has - we can certainly take advantage of that when we're not multithreading. But if, on average, the frequency of the entire game loop (i.e. loop { gameplay, render }) exceeds the monitor refresh rate, then either the process will sleep (causing jitter) or the game will have to busy wait for the next available buffer (gets the CPU hot for no reason). If, on the other hand, we get a sequence of slow frames, the game will lose a frame and not even know, until of course it checks some external timer - which is not synchronised to the monitor - and makes an estimate that a frame or two has been dropped.

Quote:

That's not the issue here. The problem is the OS stealing CPU time from the game and causing missed frames or slowdown.

The OS won't steal more than it needs, which shouldn't be much if you haven't got other applications running. The issue isn't the OS stealing time, but the game yielding to the OS, which will use the CPU time on something else (or the system idle process) to maximise CPU throughput.

Quote:

Hm, re-reading this quote I think I see something I missed. Are you talking about processing continuously instead of per-frame? Basically utilizing the extra CPU cycles of computers that get ahead of their monitor and are waiting for the monitor refresh rate to catch up with them?

Exactly.

Quote:

How do you propose to do that?

This will happen naturally. By using a rendering thread and a game logic thread, if the rendering is struggling (not hitting the monitor refresh rate very often or at all), then the rendering and logic threads should both get around a 50-50 split of CPU time. Of course, this may vary because the game logic will need to have a critical section - perhaps where the game state is copied to a buffer or maybe the entire body of the loop if the game logic isn't that heavy (it is important to have the smallest possible critical section). If the rendering loop is, on average, running faster than the monitor refresh rate, its thread will sleep and automatically yield to the game logic thread. So the game logic thread must always have something to do. If we use a delta timing approach (i.e. find out how long it was since the last time the gameplay loop executed and move everything based on that), our gameplay loop will always have something to do.

Neil Walker
Quote:

Whats a progenitor?

Shawn's contribution to Allegro was the lovely 8-bit pallete based on the atari st ;)

Dustin Dettmer
Quote:

This will happen naturally. By using a rendering thread and a game logic thread, if the rendering is struggling (not hitting the monitor refresh rate very often or at all), then the rendering and logic threads should both get around a 50-50 split of CPU time. Of course, this may vary because the game logic will need to have a critical section - perhaps where the game state is copied to a buffer or maybe the entire body of the loop if the game logic isn't that heavy (it is important to have the smallest possible critical section). If the rendering loop is, on average, running faster than the monitor refresh rate, its thread will sleep and automatically yield to the game logic thread. So the game logic thread must always have something to do. If we use a delta timing approach (i.e. find out how long it was since the last time the gameplay loop executed and move everything based on that), our gameplay loop will always have something to do.

Hm, interesting. Sounds like it would have some unforseen weird update glitches though.

It does make sense though.

Steve++
Quote:

Hm, interesting. Sounds like it would have some unforseen weird update glitches though.

Yeah, that could happen. But let's bear in mind that the render logic should only read the game state. Also, if the game logic is interrupted mid-loop to render, any new input from the keyboard/mouse/etc could affect the loop adversely. The way around this is to copy the input state at the beginning of each game logic loop. Also, we would definitely not make the body of the rendering loop a critical section. This could make the gameplay logic deltas jump all over the place. It would have very little benefit, except increasing visual framerates.

Shawn Hargreaves

I'm not actually convinced that multithreading the game logic and rendering is a good idea in the majority of cases...

Threaded programming is really really hard! Something to be avoided except where absolutely neccessary.

And to make it work right you have to synchronize all accesses to game state (perhaps by double buffering it). This adds a bunch of runtime overhead, in addition to the coding complexity.

Plus thread switches aren't fast. So you're wasting a bunch of time every time the OS has to jump from one to the other.

And finally, most OS thread schedulers run at a fairly coarse time granularity. 5ms is common. For a 60 fps game, that's a big chunk of the frame time potentially wasted before the OS even notices when it ought to switch.

Adding this all up, it seems to me that on a single processor machine, threading is going to hurt more than it helps!

On a dual core machine things are rather different, because you now have true parallelism and no switching overhead. There is still the overhead of synchronizing your data access, and still the huge increase in coding complexity, but this can be worth it if you can get the machine doing two things in parallel.

So I think it really depends what kind of hardware you are targetting. I certainly wouldn't recommend threading for beginners, though, even if they do have dual processor hardware!

Hyperthreaded processors are an interesting corner case. In theory they do have two truly independent simultaneous execution contexts with no switching overhead, so you'd think they'd be similar to dual core hardware, but in practice it can actually hurt more than it helps if you try to run two threads at once! That's because both threads share the same cache, and can easily end up stomping over each other and constantly flushing the working set. Generally hyperthreading seems to be a win if both threads are running the same code on adjacent pieces of data (eg. transforming a vertex buffer or decoding video), but isn't usually worth using for running totally unrelated computations in each thread.

Steve++
Quote:

Threaded programming is really really hard! Something to be avoided except where absolutely neccessary.

I haven't found it hard yet. Sometimes it's a challenge though. I learned to use semaphores and monitors in some simulator that uses C-- (or something like that). It was hard at first, as is anything new, but I got the hang of it quickly. I've played around extensively with java.nio using two threads to overlap the input and output. It was a challenge, but that had nothing to do with threads. Java makes threading easy though. I'll see what C# is like (probably similar).

Quote:

And to make it work right you have to synchronize all accesses to game state (perhaps by double buffering it). This adds a bunch of runtime overhead, in addition to the coding complexity.

This will add either runtime overhead or complexity - not both (the other will have a negligable increase). By that I mean if the gamestate has to be buffered in a critical section, then this adds runtime overhead, but it does not increase complexity (because this is contained in one small critical section; If, on the other hand, gamestate isn't buffered then we potentially need critical sections all over the place, and this certainly will add to complexity, but will save us the copying overhead.

Quote:

Plus thread switches aren't fast. So you're wasting a bunch of time every time the OS has to jump from one to the other.

They're fast enough! It's not like I'll be creating and destroying threads all over the place. These threads will persist throughout the life of the game. I'll do some benchmarks when I get around to it.

Quote:

And finally, most OS thread schedulers run at a fairly coarse time granularity. 5ms is common. For a 60 fps game, that's a big chunk of the frame time potentially wasted before the OS even notices when it ought to switch.

5ms fits nicely inside 16.7ms, but it still is a problem somewhat. This could be countered by the end of the gameplay loop body yielding to the rendering thread depending on an estimate of the need to do so (i.e. a frame skip could result otherwise). This would involve a combination of dynamic benchmarking and possible a user-controlled variable (some sort of slider that controls a bias between gameplay and rendering processing).

Quote:

Adding this all up, it seems to me that on a single processor machine, threading is going to hurt more than it helps!

On a dual core machine things are rather different, because you now have true parallelism and no switching overhead. There is still the overhead of synchronizing your data access, and still the huge increase in coding complexity, but this can be worth it if you can get the machine doing two things in parallel.

Agreed. The ratio of multi-core to single core machines is only going to increase, so I may as well start this multithreaded approach and hopefully I will have it nailed by the time most people have multiple cores. I still don't think single core machines present much of a problem.

Quote:

I certainly wouldn't recommend threading for beginners, though, even if they do have dual processor hardware!

Yeah - I blame RP and Evert (both posted at the same time) for hijacking this thread after the first post.

Richard Phipps

That's not fair. We pointed an 'issue' in his assumptions.

Shawn Hargreaves
Quote:

If, on the other hand, gamestate isn't buffered then we potentially need critical sections all over the place, and this certainly will add to complexity, but will save us the copying overhead.

But then you're paying the cost of acquiring and releasing all those critical sections, which is far from free. It's actually surprisingly hard to write multithreaded game code that is both correct (ie. not just ignoring a few rare race conditions) and also ends up faster than the simple singlethreaded version! Not impossible, but just a warning to make sure you're aware of this stuff. I've often managed to get a nice speed boost from threading, and then find I'm now spending more time than I saved just executing the synchronization code!

Quote:

Quote:

Plus thread switches aren't fast. So you're wasting a bunch of time every time the OS has to jump from one to the other.

They're fast enough! It's not like I'll be creating and destroying threads all over the place.

I didn't mean creating and destroying (which is REALLY slow), just the switch operation when the OS decides to suspend one thread and start running another. This is a pretty heavyweight task: it has to save all the CPU state (including FPU registers), reset a load of MMU information (and segment registers if you are on x86), and do a ton of internal OS bookkeeping. You're easily talking 0.01ms per switch, which is enough to quickly add up if you're using threads in places where you don't strictly need them.

Quote:

This would involve a combination of dynamic benchmarking and possible a user-controlled variable (some sort of slider that controls a bias between gameplay and rendering processing).

But what user is going to have a clue how to set that slider? Strikes me as a bad interface to ask questions that nobody is going to know how to answer...

Steve++

It should be faster than single-threading when the frame rate would otherwise exceed the refresh rate. When this isn't the case, I could have the game drop back to a more traditional game loop. Best of both worlds.

The good thing about the slider is that it's just one slider and the user has just half a clue what it does, he can fiddle around with it until it seems right (usually the masses will go for frame rate). Anyway, it's just something optional that may or may not make it in a game. There may be the odd user that prefers gameplay accuracy :o.

EDIT: I have a question regarding multiple CPU cores and multitasking:
Suppose the rendering thread is limited to rendering at the refresh rate. Then suppose that thread has nothing to do so it waits. Will that thread wakeup at the moment it has something to do, or will it be woken up when it has something to do and the OS scheduler runs? Because if it's the latter, then this isn't a good thing at all. The rendering thread would need to busy wait for an available buffer to avoid being displaced in that core by another thread (which could belong to another process).

Shawn Hargreaves
Quote:

It should be faster than single-threading when the frame rate would otherwise exceed the refresh rate. When this isn't the case, I could have the game drop back to a more traditional game loop. Best of both worlds.

But why?

I guess I don't understand, if you're falling back on a more traditional loop when failing to hit the refresh rate, what's the point in trying to do anything clever when you're above it?

Seems like this is adding a ton of code complexity, potential bugs, making it harder to read and maintain, to speed up something that is by definition already fast enough?

Quote:

Suppose the rendering thread is limited to rendering at the refresh rate. Then suppose that thread has nothing to do so it waits. Will that thread wakeup at the moment it has something to do, or will it be woken up when it has something to do and the OS scheduler runs? Because if it's the latter, then this isn't a good thing at all. The rendering thread would need to busy wait for an available buffer to avoid being displaced in that core by another thread (which could belong to another process).

"it depends" (tm)

If you are careful about how you use your synchronization primitives, that can kick the thread into waking up at the right time. This still requires an OS schedule, which imposes a fairly large amount of fixed overhead, but raising an event will force that to happen when you want. And you can use thread affinity APIs to control which core each thread runs on. But it's incredibly easy to destroy performance by making mistakes setting the affinity (hard to know what the right thing to do is on different machines).

Steve++
Quote:

I guess I don't understand, if you're falling back on a more traditional loop when failing to hit the refresh rate, what's the point in trying to do anything clever when you're above it?

On a single core machine, when the game limits rendering to the refresh rate and the rendering loop is waiting for the next buffer, it will automatically switch to the gameplay thread, giving it more CPU time and therefore more precision.

Thomas Fjellstrom
Quote:

it will automatically switch

and that switch, along with the switch back to the other thread will eat up more time than you may have to spare.

Its hardly more CPU time.. a proper timing loop will use less CPU than two threads trying to compete for the same resources. All the locks, waiting and context switches will quickly erode any possible benefit.

_Dante
Quote:

On a single core machine, when the game limits rendering to the refresh rate and the rendering loop is waiting for the next buffer, it will automatically switch to the gameplay thread, giving it more CPU time and therefore more precision.

It most certainly will not switch to the gameplay thread. Once your thread goes to sleep, you have zero control over it. The OS will swap it back in according to normal scheduling rules. The only way around that is of course to use synchonization methods to make sure that the gameplay thread runs at that point and the rendering thread doesn't, but then you're back to a single-threaded model essentially.

Using multiple threads only makes sense if you have operations you can parallelize (and you can't really do that with logic/rendering), or if you're doing I/O and don't need the result of that to continue doing whatever it is that the other thread's doing. In pretty much any other case, you're just thrashing.

Steve++
Quote:

All the locks, waiting and context switches will quickly erode any possible benefit.

Silly me. I was thinking there was a reason for threads existing.

Quote:

Its hardly more CPU time.. a proper timing loop will use less CPU than two threads trying to compete for the same resources. All the locks, waiting and context switches will quickly erode any possible benefit.

It's not about using less CPU. Games will always use 100%-overhead CPU. It's what we do with the CPU that counts. And redundant rendering certainly doesn't count.

Quote:

It most certainly will not switch to the gameplay thread. Once your thread goes to sleep, you have zero control over it. The OS will swap it back in according to normal scheduling rules. The only way around that is of course to use synchonization methods to make sure that the gameplay thread runs at that point and the rendering thread doesn't, but then you're back to a single-threaded model essentially.

It will automatically switch to the next thread on the queue that isn't waiting for a resource, which will usually be the game logic. Anyway, as far as I know, if a thread waits for a resource, preference is given to threads in the same process, because a timeslice hasn't been reached yet and it wouldn't make sense to switch processes when the current process still has something to do.

Quote:

Using multiple threads only makes sense if you have operations you can parallelize (and you can't really do that with logic/rendering), or if you're doing I/O and don't need the result of that to continue doing whatever it is that the other thread's doing. In pretty much any other case, you're just thrashing.

You most certainly can parallelise logic and rendering. Let's remember that rendering and refreshing the monitor are parallelised and they are much more related than logic and rendering. This can be achieved by buffering the gamestate. Earlier I mentioned copying the gamestate, but in fact, we can just have two or three buffers and write to the next available gamestate buffer while processing game logic. At the end of the logic loop, it is flipped so that it can be made available to the rendering loop.

Anyway, this all very conceptual at the moment, and there are probably a lot of things that need changing. I just know I'm on the right track with multithreading though.

I even saw something on gamedev.net about three threads - gameplay, physics and rendering.

_Dante

Fair enough. 60Hz seems like enough to me, but I suppose for some realtime physics stuff, the extra logic frames would smooth things out.

Shawn Hargreaves
Quote:

Silly me. I was thinking there was a reason for threads existing.

Of course there are. Two in fact:

- For separating processing that should take place on an independent timeline. Playing background music, for instance, or keeping the UI responsive while encoding an MP3.

- For taking advantage of multiprocessor hardware.

The first reason is not a good one for separating game logic and rendering, because these do not logically belong on independent timelines. The second reason is very relevant, but only if you have multiprocessor hardware!

Quote:

It's not about using less CPU. Games will always use 100%-overhead CPU. It's what we do with the CPU that counts. And redundant rendering certainly doesn't count.

Of course not. But neither does redundant logic computation!

Beware of trying to make your game logic hugely flexible and adaptable to differing CPU resources. Down that route lies madness, and a pile of crazy gameplay bugs that will be almost impossible to resolve. Do you really want to end up with the game being easier to complete on machines with different clock speeds? Or unable to do accurate network prediction because the client and server have a different CPU? Keep it simple and make your logic deterministic.

Also, it seems backward to spend all this effort further optimizing the case where you are already running fast enough, especially when this adds overhead that will hurt performance on slower machines. Surely you should be trying to improve the worst case rather than the best?

Quote:

You most certainly can parallelise logic and rendering.

Absolutely you can. But this is very hard, requires a lot of discipline across the entire codebase, increases complexity, slows development, adds overhead, makes the code harder to read, etc etc.

It only makes sense to pay those costs if you have a good reason for needing to be threaded.

Quote:

I just know I'm on the right track with multithreading though.

Actually I think you could be, but for entirely the wrong reasons.

On a single core processor, multithreading is just crazy. It will make your game slower, every single time.

But not all machines have single processors. If you are targetting dual core hardware, then threading is indeed a good idea.

Steve++
Quote:

Also, it seems backward to spend all this effort further optimizing the case where you are already running fast enough, especially when this adds overhead that will hurt performance on slower machines. Surely you should be trying to improve the worst case rather than the best?

Yeah, that completely makes sense.

Quote:

Beware of trying to make your game logic hugely flexible and adaptable to differing CPU resources. Down that route lies madness, and a pile of crazy gameplay bugs that will be almost impossible to resolve. Do you really want to end up with the game being easier to complete on machines with different clock speeds?

Isn't this the case with the traditional game loop anyway? Doesn't gameplay logic get executed at more frames per second on machines that can render the graphics at more frames per second?

OK, I'm convinced now that multithreading gameplay and rendering isn't such a good idea on a single-core CPU. It has merit for two cores though. Perhaps gameplay+physics in one thread and rendering in another. When four+ core CPUs become common, then we can have gameplay + physics + rendering + one spare for the OS to play with.

Kitty Cat
Quote:

Isn't this the case with the traditional game loop anyway? Doesn't gameplay logic get executed at more frames per second on machines that can render the graphics at more frames per second?

Not if you use a fixed logic rate.

Quote:

But not all machines have single processors. If you are targetting dual core hardware, then threading is indeed a good idea.

But isn't it also true that just because you have a dual-core system doesn't mean that your two threads will run on those two cores? eg. the OS could decide to put both your threads on the same core.

Lucid Nightmare

Howcome encore hasn't even posted one message after startin off with the thread while everyone else is debating over his topic...

HoHo
Quote:

eg. the OS could decide to put both your threads on the same core.

I don't think any OS would be that stupid, not even the one that is used by majority of people.

Only place where OS could mess up threading is on multi-cpu machine with SMT, a'la dualcore P4 with HT. When OS decides tu run two recource hungry threads on one core's two virtual CPU's then the other core will just sit idle.

Simon Parzer

This thread somehow confuses me... so one should run the logic at the refresh rate of the monitor to ensure fluent graphics? I usually lock my logic to 50 Hz, measure the time needed for drawing and wait the rest of it.
Example: MeasureTime() Logic+Drawing() MeasureTime() Wait(20-TimeDiff) --> Logic is locked to 50Hz, drawing is locked to 50Hz and the game leaves plenty of CPU for other applications. Is this a good way? And how would one go about determining the monitor refresh rate on different platforms?

As for the multithreading, I would only use it for sound, networking and such tasks, not for the internal logic/drawing things.

Kitty Cat
Quote:

I don't think any OS would be that stupid, not even the one that is used by majority of people.

How would it know what threads to put where, though? Even if you turn off as many programs as possible, the system will still have several of its own processes/threads running (even if mostly idle). How would it know your two threads would need to go onto two seperate cores, and not put them onto the same core?

HoHo
Quote:

How would it know what threads to put where, though?

You should know that not all threads/processes run at the same time. Usually they run for a couple of milliseconds and then get replaced with a thread that has something to do.

It is the exactly the same with dualcore CPU but scheduler has two cores to divide threads to and usually it takes first one that does nothing.

Audric
Shawn Hargreaves said:

Beware of trying to make your game logic hugely flexible and adaptable to differing CPU resources. Down that route lies madness (...)

sayeth Shawn, A.cc 586057/594632 ;D
sorry, I couldn't resist

Quote:

(...) and a pile of crazy gameplay bugs that will be almost impossible to resolve. Do you really want to end up with the game being easier to complete on machines with different clock speeds?

ooooh, is it why a Quake 3 character runs faster and jumps higher when the renderer is set to ultra-low detail ? Indeed, it's evil.

HoHo

There is one more interesting thing about Q3A.
it has SMP support under Linux and probably under windows too. When I run it without SMP support I get ~350FPS at max quality. When I run the SMP version it drops down to "only" ~300FPS. I wonder why is that. Might it be that with slower SMP CPU's it makes sense to multithread it and my super-fast dualcore P4 just spends most of its time switching between threads?

IIRC in some version of Q3A you could run faster and jump higher at some specific FPS. I think it was around 80-something.

Shawn Hargreaves
Quote:

Isn't this the case with the traditional game loop anyway? Doesn't gameplay logic get executed at more frames per second on machines that can render the graphics at more frames per second?

"it depends" (tm)

This is holy war territory among game developers.

One school of thought (mostly PC programmers) believes your logic update should be parameterized on the time since the last update, so you can call it as fast as possible for any given machine.

Pros:

- Can easily lock to any arbitrary refresh rate.
- Can efficiently drop updates if running below refresh rate.

Cons:

- Makes game logic code more complicated.
- Unless you are a math genius, makes game logic give different results depending on effectively random performance details. This may or may not actually be noticable to the player, but even the smallest deviations are pain when implementing things like replays and networking.

The other school of thought (mostly console programmers) believes you should just pick an update rate and stick to it.

Pros:

- Keeps code nice and simple.
- Everything is 100% deterministic.

Cons:

- If the rate you picked is different to the monitor refresh, won't be perfectly smooth. Of course this isn't a problem on consoles where you know the TV goes at 60. You could always just set the PC monitor to that known rate, though.

Personally I prefer the fixed rate approach, because I'm a big fan of keeping things as simple as possible, but game devs will argue for ever about this.

Even if you're going for a variable rate update, though, I still wouldn't ever run multiple updates in between render cycles. Just wait until the next refresh, then run a singe update passing it the appropriate time delta.

Quote:

OK, I'm convinced now that multithreading gameplay and rendering isn't such a good idea on a single-core CPU. It has merit for two cores though. Perhaps gameplay+physics in one thread and rendering in another. When four+ core CPUs become common, then we can have gameplay + physics + rendering + one spare for the OS to play with.

This is one of the biggest issues commercial game devs are struggling with at the moment, as they figure out how to work with the 3-core Xbox. Splitting gameplay and rendering pretty consistently seems to give good results, although depending on the engine architecture the amount of pain involved ranges from a fair amount to an incredible amount :-) Splitting gameplay and physics generally seems to be less successful: a handful of people are managing to get ok results there, but it really depends on the game if this is feasible. Pathfinding is an obvious candidate for doing in the background perhaps even over multiple frames, and people are also getting good results moving CPU graphics effect computations (fluid simulation, cloth, hair, particles) onto the third core.

Quote:

But isn't it also true that just because you have a dual-core system doesn't mean that your two threads will run on those two cores? eg. the OS could decide to put both your threads on the same core.

That's where it gets fun. You could just trust the OS, and you might be lucky, but who knows. Setting an explicit thread affinity makes things a lot more robust, but then you have to know what kind of processor you are running on, and that's currently quite a pain (not easy to tell the difference between dual core and some hyperthreading configurations, for instance). I have a feeling Vista is adding some new API's to make this easier though.

Quote:

This thread somehow confuses me... so one should run the logic at the refresh rate of the monitor to ensure fluent graphics? I usually lock my logic to 50 Hz, measure the time needed for drawing and wait the rest of it.

That's what I tend to do to, although I usually go for 60. Not perfect if the monitor happens to be set to something other than your chosen rate, but hey. Opinions differ as to whether the extra smoothness of being able to adapt to different refresh rates is worth the extra complexity and unpredictableness that this introduces into your code.

Quote:

There is one more interesting thing about Q3A.
it has SMP support under Linux and probably under windows too. When I run it without SMP support I get ~350FPS at max quality. When I run the SMP version it drops down to "only" ~300FPS. I wonder why is that. Might it be that with slower SMP CPU's it makes sense to multithread it and my super-fast dualcore P4 just spends most of its time switching between threads?

Interesting fact, but hard to say why without a detailed investigation.

It's very possible that the threading overhead is just bigger than the gains they are getting from the parallelism, but there are other possible explanations. For instance maybe on your machine the CPU is so fast that the game ends up totally bottlenecked by GPU performance, and the use of multithreading might be forcing the driver to disable some potentially unsafe GPU level optimisations?

No idea really, but it does confirm that even on a dual core machine, it can be surprisingly hard to actually gain that much of a benefit from threading. It's certainly nowhere near the 2x speed that you might naively expect.

Quote:

IIRC in some version of Q3A you could run faster and jump higher at some specific FPS. I think it was around 80-something.

That sucks. But it is hard to avoid such quirks in variable time update games.

Steve++
Quote:

One school of thought (mostly PC programmers) believes your logic update should be parameterized on the time since the last update, so you can call it as fast as possible for any given machine.

I thought this had become the industry standard.

Quote:

The other school of thought (mostly console programmers) believes you should just pick an update rate and stick to it.

It's good to know this is still acceptable, given the fashionable trend towards variable rate updating. Seriously though, I think this trend is caused by variations between PCs. Not only are CPUs, GPUs and RAM different, we've also got bus speeds, HDD seek times, different soundcard speeds due to different cards having different drivers, etc. On consoles, everything is the same, but on PCs you have to be dynamic.

Now I just have to figure out how to mesh deterministic game logic with nondeterministic render times. I'm sure there must be some way on the PC to synchronise on the refresh rate. Here I go with threads again... perhaps there could be a thread that just vsyncs (somehow) and updates a counter, all in a loop. It would be nice if windows just used the monitor refresh rate as its timer. Then PCs would be serious gaming machines.

Shawn Hargreaves
Quote:

I thought this had become the industry standard.

If anything I think the trend is the other way: more and more PC games are sharing a codebase with Xbox and PS3, and starting to be influenced by console approaches.

Quote:

Seriously though, I think this trend is caused by variations between PCs. Not only are CPUs, GPUs and RAM different, we've also got bus speeds, HDD seek times, different soundcard speeds due to different cards having different drivers, etc.

I think the monitor is the biggest difference.

When it comes to raw computing horsepower, 60 or 70 fps is 'good enough' for anything but the most rabid Quake geeks, so there's no problem just locking a game to that.

But the monitor could easily be set anything from 50 to 120, so your game won't look perfectly smooth unless you happen to match.

Consoles used to have this problem too, with 60 in the US and 50 in Europe. Some ignored it and just always ran at 60, causing jerky updates in their European versions, while others changed their update frequency and tweaked the logic to match, causing inconsistent gameplay across continents.

These days, though, modern European TVs can do 60, so everyone just locks to 60 without any problems.

And things are changing in the PC world, too. LCD monitors don't have the same refresh characteristics as a CRT, and increasing numbers of gamers have their PC connected to an HDTV movie display. I can see those factors making it a lot more appealing to just lock PC titles to 60, too...

Steve++
Quote:

Consoles used to have this problem too, with 60 in the US and 50 in Europe. Some ignored it and just always ran at 60, causing jerky updates in their European versions, while others changed their update frequency and tweaked the logic to match, causing inconsistent gameplay across continents.

I know what you mean about inconsistency across continents... A friend of mine was a huge Wonder Boy fan in the 80s/early 90s. We have PAL over here, so he played these games in 50Hz. Then one day recently he played the first Wonder Boy (the action oriented one where you have to keep moving or die) in 60Hz and realised that the 50Hz version feels rather pedestrian now. There's a big difference.

Thread #586057. Printed from Allegro.cc