4
\$\begingroup\$

I am making a real-time game in XNA and I would like to reduce the Update() call frequency while getting as many Draw() calls as possible. This would enable the program to finish long calculations in the Update() method while Draw() is still regularly called to perform interpolation and rendering to have the game appear running smoothly.

But, it seems like Draw() is never invoked before Update() has finished. This creates stuttering.

Is it possible to achieve concurrent calls to Draw() before Update() has finished?

\$\endgroup\$
  • \$\begingroup\$ This is not a good idea usually... But if you ever want to, you'd have to synchronize all your resources so that they don't create race conditions or concurrent modifications. \$\endgroup\$ – Alexandre Desbiens Jul 1 '15 at 15:28
  • \$\begingroup\$ Is my only option to timeslice all calculations perfectly to fit within a regular Update duration? If I get it wrong, the stuttering will appear... \$\endgroup\$ – Rye bread Jul 1 '15 at 15:33
  • 2
    \$\begingroup\$ I think a solution would be to put your long calculations in a thread, so that it doesn't interfere with neither Update() nor Draw(). Because of the way the XNA engine works, I don't think it is possible to do what you want in another way... \$\endgroup\$ – Alexandre Desbiens Jul 1 '15 at 15:36
  • \$\begingroup\$ Then I would have to synchronize all the data involved. \$\endgroup\$ – Rye bread Jul 1 '15 at 15:47
  • \$\begingroup\$ You'll have to synchronize one way of the other. What you're asking is to do concurrent Update and Draw calls, so you will need synchonization, no mather how you solve your problem. \$\endgroup\$ – Alexandre Desbiens Jul 1 '15 at 15:49
1
\$\begingroup\$

XNA's update and draw methods do in fact happen in a single thread. In order to utilize other threads on the machine, or do long running calculations across multiple frames you can utilize C#'s asynchronous function calls. The basic idea is, you start a calculation by invoking an asynchronous function, this function will execute in a new context on the machine and won't block your main update thread. The trouble now is getting the result of the calculation back. Here's a quick example that I think is free of race conditions:

private volatile object Result = null;
private volatile bool CalculationInProgress = false;
private void AsyncCalculation() {
    Result = DoSomeStuffThatTakesAWhile();
    CalculationInProgress = false
}
public override Update(GameTime time) {
    if(Result == null) {
        if(!CalculationInProgress) {
            CalculationInProgress = true;
            ((Action)AsyncCalculation).BeginInvoke(null, this);
        }
    else {
        UseResult(Result);
        Result = null;
    }
}

I hope this gives a general idea of how .BeginInvoke could be used in your case. You're basically polling your result in each update call until it is completed.You don't need to use Action either, Action is a delegate that takes no parameters and returns void, if you need to pass parameters and have an output take a look at Func<>.

There may be a more simple way, I would very much enjoy seeing a simpler solution in C#. Hope this gives you a bit of a starting point though.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.