locked
Concurrency and updating DirectXPage::m_renderNeeded

    Question

  • Let me preface this post with a note that this is my first time working with the concurrency stuff so I'm probably making a stupid mistake somewhere.

    I'm having difficulty getting consistent results when I use create_task in my UI thread. This is in an app derived from the XAML Direct2D template, so it has a SwapChainBackgroundPanel and the m_renderNeeded member in the DirectXPage class. m_renderNeeded is checked in DirectXPage::OnRendering to see if the SCBP needs to be updated. OnRendering is called constantly and, usually, all I have to do to force an update of the SCBP is set m_renderNeeded to true. However, when I set m_renderNeeded in the thread of a create_task lambda, it doesn't appear to work properly. Here's a code snippet:

    // // this is inside a DirectXPage function //

    void DirectXPage::Button_Clicked( stuff )

    {

    SynchronousWork(); // generate some graphics quickly

    create_task([this]() // defer slow stuff to thread { FastFunction(); // generate some more D3D elements quickly m_renderNeeded = true; SlowFunction(); // generate some more D3D elements slowly

    m_renderNeeded = true; }) .then([this]() { m_renderNeeded = true; });

    m_renderNeeded = true;

    }

    When I click on the button, the SynchronousWork stuff is displayed instantly, as expected. The problem is with FastFunction and SlowFunction. It looks like their output is typically displayed simultaneously after SlowFunction completes rather than one after the other. It's almost as if DirectXPage::m_renderNeeded isn't being set properly in the task.

    I thought that using [this] in the create_task would make DirectXPage::m_renderNeeded available to the background thread and that would make the results of FastFunction be displayed long before SlowFunction was completed. FastFunction is executing quickly as expected and I can see its results if I manually pan or zoom the display to force a redraw (which just updates the viewpoint and sets m_renderNeeded synchronously). It's just that setting m_renderNeeded in the task itself doesn't appear to work properly.

    What am I doing wrong? Thanks.

    Friday, September 21, 2012 4:25 PM

Answers

  • This was my error. The concurrency stuff is working fine, the problem is that signaling a refresh is needed via m_renderNeeded is, of course, not thread-safe. It was made worse because OnRender set m_renderNeeded to false *after* ->Present, which opened up a long time interval where another thread could set it to true and be overwritten.

    I switched to a thread safe method of signaling a render was needed (InterlockedBitTestAndSet/Reset) and the inconsistency went away.

    Note: the XAML+Direct2D template should be changed to, at a minimum, set m_renderNeeded to false right after the if( m_renderNeeded ) line. That's still not 100% safe but comes close.

    • Marked as answer by henador Friday, September 21, 2012 8:02 PM
    Friday, September 21, 2012 8:01 PM

All replies

  • This was my error. The concurrency stuff is working fine, the problem is that signaling a refresh is needed via m_renderNeeded is, of course, not thread-safe. It was made worse because OnRender set m_renderNeeded to false *after* ->Present, which opened up a long time interval where another thread could set it to true and be overwritten.

    I switched to a thread safe method of signaling a render was needed (InterlockedBitTestAndSet/Reset) and the inconsistency went away.

    Note: the XAML+Direct2D template should be changed to, at a minimum, set m_renderNeeded to false right after the if( m_renderNeeded ) line. That's still not 100% safe but comes close.

    • Marked as answer by henador Friday, September 21, 2012 8:02 PM
    Friday, September 21, 2012 8:01 PM
  • Thanks for sharing the solution.

    Best regards,
    Jesse

     


    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us

    Monday, September 24, 2012 5:32 AM