Search code examples
c++timerdirectx-11

StepTimer.GetTotalSeconds() produces values that do not always increase


I'm using DirectX 11. For simplicity, and to reproduce the problem, I narrowed it down to the following steps:

  1. Create a new "DirectX and XAML App (UWP)" in Visual Studio (I'm using VS 2017).
  2. Replace the Sample3DSceneRenderer::Update method with the following code:

    void Sample3DSceneRenderer::Update(DX::StepTimer const& timer)
    {
        if (!m_tracking)
        {
            double total = timer.GetTotalSeconds();
    
            // Convert degrees to radians, then convert seconds to rotation angle
            float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond);
            double totalRotation = total * radiansPerSecond;
            float radians = static_cast<float>(fmod(totalRotation, XM_2PI));
    
            DX::DebugTrace(L"num = %4.2f\t%4.2f\n", radians, total);
    
            Rotate(radians);
        }
    }
    
  3. Add the following function to trace the values in the Output window:

    inline void DebugTrace(const wchar_t *format, ...)
    {
        // Generate the message string.
        va_list args;
        va_start(args, format); // initialize the argument list
        wchar_t buffer[1024];
        va_end(args);
    
        OutputDebugStringW(buffer); // this is a Windows function
    }
    

When I run the app, the Output window shows the following values:

    num = 0.01  0.01
    num = 0.02  0.02
    num = 0.00  0.00 // decreased
    num = 0.00  0.01 // decreased
    num = 0.03  0.04
    num = 0.05  0.06
    num = 0.02  0.02 // decreased
    num = 0.06  0.07
    num = 0.03  0.04 // decreased
    num = 0.07  0.09
    num = 0.04  0.06 // decreased
    num = 0.08  0.11
    num = 0.06  0.07 // decreased
    num = 0.10  0.12 
    num = 0.07  0.09 // decreased
    num = 0.11  0.14
    num = 0.08  0.11 // decreased
    num = 0.12  0.16
    num = 0.10  0.12 // decreased
    num = 0.11  0.14 
    num = 0.14  0.17
    num = 0.12  0.16 // decreased
    num = 0.15  0.19
    num = 0.16  0.21
    num = 0.14  0.17 // decreased
    num = 0.18  0.22
    num = 0.15  0.19 // decreased
    num = 0.16  0.21 
    num = 0.19  0.24
    num = 0.20  0.26
    num = 0.18  0.22 // decreased
    etc.

Question: Why does the TotalSeconds values increase and then decrease and then increase again etc.? For example: 0.01, 0.02, 0.00, 0.01. Shouldn't they always increase?


Solution

  • The bug is in App::OnLaunched. The version in the template is creating two DirectXPages:

    • Direct assignment: m_directXPage = ref new DirectXPage();
    • Navigation: rootFrame->Navigate(TypeName(DirectXPage::typeid), e->Arguments);

    I have a modified version that only creates a single version by taking a reference to the one created during navigation, but I haven't spent much time checking on error cases.

    void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e)
    {
    #if _DEBUG
           if (IsDebuggerPresent())
           {
                  DebugSettings->EnableFrameRateCounter = true;
           }
    #endif
    
           auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content);
    
           // Do not repeat app initialization when the Window already has content,
           // just ensure that the window is active
           if (rootFrame == nullptr)
           {
                  // Create a Frame to act as the navigation context and associate it with
                  // a SuspensionManager key
                  rootFrame = ref new Frame();
    
                  rootFrame->NavigationFailed += ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(this, &App::OnNavigationFailed);
    
                  // Place the frame in the current Window
                  Window::Current->Content = rootFrame;
           }
    
           if (rootFrame->Content == nullptr)
           {
                  // When the navigation stack isn't restored navigate to the first page,
                  // configuring the new page by passing required information as a navigation
                  // parameter
                  rootFrame->Navigate(TypeName(DirectXPage::typeid), e->Arguments);
           }
    
           if (m_directXPage == nullptr)
           {
                  m_directXPage = dynamic_cast<DirectXPage^>(rootFrame->Content);
           }
    
           if (e->PreviousExecutionState == ApplicationExecutionState::Terminated)
           {
                  m_directXPage->LoadInternalState(ApplicationData::Current->LocalSettings->Values);
           }
    
           // Ensure the current window is active
           Window::Current->Activate();
    }