Well, you don't have to, you could in theory do it all in one thread (the main process thread you always have) but it would not be that efficient.
Another benefit with the program spread over threads in that particular case (games esp.) is that certain threads can run at different speeds.
A graphics thread should only run at max the refresh rate, but could also throttle down to 0fps when appropriate. Timing threads would need very high fps like 1ms or 2ms (1000 or 500fps) to make sure timing is very consistent, an audio thread would need a "fps" that matches the audio playback and buffering etc. A Network thread would have to have a speed that fits the latency/speed of the network.
But in all cases those are max speeds, all threads should be able to throttle down if there is little or nothing to do.
Example: all threads (like the graphics thread) throttle down because the game scene is very quiet right now, all except the scene calculation or AI thread that are using all the extra free CPU because in just a few moments as the player rounds the corner all hell will break loose with hundreds of NPC's fighting each other in a huge battle.
So conserving CPU and GPU when possible is always wise as you never know when you need it, or in that particular case even planning ahead and taking advantage of it in the game design.
The end result is that for the player they get to have a smooth experience from being alone in a tiny corridor and exiting into a huge battle with hundreds of characters with barely a hiccup. (assuming the graphics card doesn't choke that is... *laughs*)
Take these two examples:
The first one there is no graphics updates when there is nothing to update.
And in the second it is the same, but in addition the entire flipping is avoided as well,
so in the 2nd source the graphics card isn't even "used" unless there is stuff to update.
The 2nd source is obviously more sensitive to timing issues. And I have no idea how much CPU is saved comparing the two sources.
But I assume that not having to flip buffers saves bandwidth (+CPU?) and some GPU as well.
Code: Select all
InitSprite()
InitMouse()
OpenWindow(0, 0, 0, 640, 480, "Crap Mouse Movement", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_BorderLess)
OpenWindowedScreen(WindowID(0), 0, 0, 640, 480, 0, 0, 0, #PB_Screen_SmartSynchronization)
CreateSprite(0, 32, 32)
StartDrawing(SpriteOutput(0))
Box(0, 0, 32, 32, #Blue)
StopDrawing()
Global mousex.i,mousey.i
Procedure mousethread(flag.i)
Static quit.i
If flag
Repeat
ExamineMouse()
mousex=MouseX()
mousey=MouseY()
Delay(1)
Until quit
quit=#False
Else
If Not flag
quit=#True
While quit
Delay(1)
Wend
EndIf
EndIF
EndProcedure
Define oldmousex.i,oldmousey.i
CreateThread(@mousethread(),#True)
Repeat
Repeat
Event = WindowEvent()
Select Event
Case #PB_Event_CloseWindow
Quit = 1
EndSelect
Until Event = 0
If mousex<>oldmousex Or mousey<>oldmousey ;only update graphics if something has changed.
oldmousex=mousex
oldmousey=mousey
ClearScreen(#Black)
DisplaySprite(0, mousex, mousey)
EndIf
FlipBuffers() ;Just to keep our loop synced to the refresh, could be improved to avoid the flip as well.
Until Quit Or (GetKeyState_(#VK_ESCAPE)&%10000000 And GetActiveWindow() = pWnd)
mousethread(#False)
CloseScreen()
End
Note that the source above is "slightly" flawed, it should be tweaked some more because currently you could end up with a slight shimmering as the buffer is flipped back and forth,
basically both buffers should be identical first.
Code: Select all
InitSprite()
InitMouse()
OpenWindow(0, 0, 0, 640, 480, "Crap Mouse Movement", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_BorderLess)
OpenWindowedScreen(WindowID(0), 0, 0, 640, 480, 0, 0, 0, #PB_Screen_SmartSynchronization)
CreateSprite(0, 32, 32)
StartDrawing(SpriteOutput(0))
Box(0, 0, 32, 32, #Blue)
StopDrawing()
Global mousex.i,mousey.i
Procedure mousethread(flag.i)
Static quit.i
If flag
Repeat
ExamineMouse()
mousex=MouseX()
mousey=MouseY()
Delay(1)
Until quit
quit=#False
Else
If Not flag
quit=#True
While quit
Delay(1)
Wend
EndIf
EndIF
EndProcedure
Define oldmousex.i,oldmousey.i
CreateThread(@mousethread(),#True)
Repeat
Repeat
Event = WindowEvent()
Select Event
Case #PB_Event_CloseWindow
Quit = 1
EndSelect
Until Event = 0
If mousex<>oldmousex Or mousey<>oldmousey ;only update graphics if something has changed.
oldmousex=mousex
oldmousey=mousey
ClearScreen(#Black)
DisplaySprite(0,mousex, mousey)
FlipBuffers()
Else
;Kinda tricky this one, we avoid the flip if nothing is updated but we could hae a small delay "waking" up again.
Delay(10) ;This is aprox 100fps delay (1000/10=100), so we asically check 100 times per second if there was any changes or not when there are no changes.
EndIf
Until Quit Or (GetKeyState_(#VK_ESCAPE)&%10000000 And GetActiveWindow() = pWnd)
mousethread(#False)
CloseScreen()
End