Xbox LIVE Indie Games
Sort Discussions: Previous Discussion Next Discussion
Page 1 of 1 (5 posts)

Is it possible to Update and Draw in different threads?

Last post 5/27/2011 4:29 PM by Pete. 4 replies.
  • 5/20/2011 11:07 AM

    Is it possible to Update and Draw in different threads?

    Hi,

    My game is currently cpu bound on xbox, and I am trying to get 60fps, but seem to have come to an impasse. 

    In my Draw function there are some tasks that are taking cpu time that I don't believe I can reduce: one is uploading dynamic texture and vertex data (using the Discard option), the other I believe is that the graphics command buffer has filled as described by Shawn here http://blogs.msdn.com/b/shawnhar/archive/2008/04/02/lost-in-translation.aspx (I think this is the case because it is a large spike that happens within a loop making multiple effect changes and draw calls from static vertex buffers, i.e. lots of commands, but when I time individual parts of the loop and / or remove parts of it, the spike never leaves but moves between different commands, e.g. sometimes SetVertexBuffers, sometimes the draw call, sometimes applying the effects etc).

    I don't believe I can reduce my Update function either because it's already relatively optimised, and because the game isn't finished yet so I have more stuff to add :) Together the two functions take ~21ms, however if I could have them on different threads then they should fit comfortably within 16 with spare in the update function for extra features. I am inexperienced in threading so would be very grateful for any ideas / advice on whether this is possible.

    Ideally I'd like to still be able to use the Game Update/Draw system, with its nice timing handling when to drop Draw frames. Naively my approach would be:

     1) Double buffer output from Update function that is used by Draw e.g. world positions of moving objects
     2) Update function would then flip the buffers, then start a new thread that contains the actual update, then return while that executes
     3) Draw function would remain on main thread (to play nice with Present in EndDraw), and render from the buffer currently not in use

    Also my reference for threading is just the 'thread = new Thread (...) thread.Start ()' approach from the NetworkStateManagement sample, is this appropriate? Do I have to do anything to ensure the thread actually uses a separate processor or does that just happen?

    Thanks in advance!
  • 5/20/2011 12:55 PM In reply to

    Re: Is it possible to Update and Draw in different threads?

    Is this just once instance of one class taking this long or the entire draw/update of your game?  Something you might want to try is staggering your updates (ie: not update everything every frame).  An application of this is having the player update every frame, but then have enemies update every other frame.  You can even instance each of those to pull more performance.
    Multithreading in a game isn't always necessary and definitely complicates things more not to mention makes profiling a little more difficult.  If you do, however end up using multiple threads you may want to consider pooling them as well.
  • 5/20/2011 1:02 PM In reply to

    Re: Is it possible to Update and Draw in different threads?

    Pete47:
     1) Double buffer output from Update function that is used by Draw e.g. world positions of moving objects
     2) Update function would then flip the buffers, then start a new thread that contains the actual update, then return while that executes
     3) Draw function would remain on main thread (to play nice with Present in EndDraw), and render from the buffer currently not in use


    That's all correct in principle except for the "start a new thread" part.  Creating and starting new threads is expensive, and it'd be preferable to keep the existing thread around and just reuse it.

    Also, it depends a little bit on whether your total CPU time is weighted mostly towards Update or Draw.  If it's weighted towards Draw or roughly even, then the method you described is the best place to start.  If it's weighted towards update (e.g. 18ms in Update, then 3ms in Draw) then the threading method described above won't help you.  That scenario is common in heavy physics or AI simulations.  In those cases, it can be better to break up the update method into chunks and run them all in parallel across 2 or 3 threads.  Those methods can also be combined, but that's complex and should probably not be undertaken before you are a threading expert.
  • 5/20/2011 4:31 PM In reply to

    Re: Is it possible to Update and Draw in different threads?

    Sigil:
    That's all correct in principle except for the "start a new thread" part.  Creating and starting new threads is expensive, and it'd be preferable to keep the existing thread around and just reuse it.
    That makes sense. So I'll have to let the thread know when to start going again, but I can look into that, thanks

    Sigil:
    Also, it depends a little bit on whether your total CPU time is weighted mostly towards Update or Draw.  If it's weighted towards Draw or roughly even, then the method you described is the best place to start
    Yeah that's pretty much what I've got. Plus some of the Update tasks don't necessarily need to be deterministic so there's scope to move them to the Draw thread if need be

    BrokeDownGamesBman:
    Something you might want to try is staggering your updates (ie: not update everything every frame)
    When I said my Update was already relatively optimised, this was the kind of thing I meant. Thanks for the advice, but honestly I'm really only coming to threading as a last resort :) the numbers just didn't add up...

    BrokeDownGamesBman:
    If you do, however end up using multiple threads you may want to consider pooling them as well
    At the moment the update work is mostly looping through the entities to be updated that frame, but they reference each other a lot so I'm not sure I have many jobs I can batch off like that, the update and draw functions were the only obvious candidates. But I'll keep it in mind, thanks :)

    Cheers for the replies guys! 

    Incidentally for the processor question, I think Thread.SetProcessorAffinity is what I was after (http://msdn.microsoft.com/en-us/library/bb203911.aspx)
  • 5/27/2011 4:29 PM In reply to

    Re: Is it possible to Update and Draw in different threads?

    Finally got around to trying this, and it was suprisingly straightforward, and got me the performance gains I needed. For anyone else who wants to try it here's the gist of what I've done inside my Game class:


    AutoResetEvent WorkerBeginEvent = new AutoResetEvent(false); 
    ManualResetEvent WorkerCompletedEvent = new ManualResetEvent(true); 
    bool WorkerUpdateGameWorld = false
     
    public MyGame () 
        ... 
        WorkerThread = new Thread (new ThreadStart (Worker)); 
        WorkerThread.IsBackground = true
        WorkerThread.Start (); 
     
    protected override void Update (GameTime gameTime) 

    ...

        // wait for the worker to finish 
        WorkerCompletedEvent.WaitOne (); 
        WorkerCompletedEvent.Reset (); 
     
        WorkerUpdateGameWorld = true// or some test of whether it should or not        
     
        GameWorld.FlipDrawBuffers (); // game specific series of functions that swap various pointers 
     
        // allow the worker to begin again 
        WorkerBeginEvent.Set (); 
     
    private void Worker () 
    #if XBOX 
        Thread.CurrentThread.SetProcessorAffinity (4); 
    #endif 
     
        while (true
        { 
            WorkerBeginEvent.WaitOne (); 
     
            if (WorkerUpdateGameWorld) 
            { 
                GameWorld.Update (); 
            } 
     
            WorkerCompletedEvent.Set (); 
        } 

Page 1 of 1 (5 posts) Previous Discussion Next Discussion
var gDomain='m.webtrends.com'; var gDcsId='dcschd84w10000w4lw9hcqmsz_8n3x'; var gTrackEvents=1; var gFpc='WT_FPC'; /*<\/scr"+"ipt>");} /*]]>*/
DCSIMG