Author Topic: Migration to FBO  (Read 28554 times)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1982
    • zapsolution
Re: Migration to FBO
« Reply #30 on: May 24, 2018, 02:30:39 pm »
Yes, my foot is going better, but causes extra troubles to my right leg (because of walk compensation).

See what Microsoft says about using TSC and/or QPC
https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx

Anyway i couldn't see why keeping using GetTickCount could cause any havoc for the purpose of animation, because on Windows 10, DWM always renders everything ultimatly onto the hidden DirectDraw surface, and that is the only way to work in composited mode. Remember, ObjReader64 has been designed to be a windowed cooperative application, and the use of a GDImage transparent window is something that alows us to mix easily 2D and 3D altogether.

I am slowly working on the REX FU's McLaren car, but i am getting lazy to complete the whole car, because of the huge amount of details.
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Migration to FBO
« Reply #31 on: May 24, 2018, 09:15:47 pm »
See what Microsoft says about using TSC and/or QPC

Alas, this is irrelevant to the problem in question, Patrice.

First, we need a self-calibrating clock (in fact, a stopwatch, not just a QPC counter!) that should trigger system events regardless of CPU clocks, based on Mother Nature's absolute time intervals (not CPU clocks per second!) at a rate slightly higher than the monitor refresh rate (144Hz, or 144 events per second, at the "worst" case). Believe me, that's a non-trivial task at all under any of Windows OS'es which in fact aren't realtime systems. Continuous rendering based on InvalidateRect() in every WM_PAINT message handler is too crude for this task because WM_PAINT has higher "priority" than WM_TIMER, and it overloads the CPU message pump even if it doesn't actually paint anything due to WM_PAINT's own low priority relative to other window messages.

The slightly extra frequency rate of such a clock will then be normalized by OpenGL VSYNC down to the monitor's actual frequency (144Hz) to avoid image tear -- with minimum overload on the window message pump, pretty much like ObjReader's current Windows timer-based "heart pacemaker" works.

Second, we will have to somehow mimic WM_TIMER's behavior in the message pump where it has a "synthetic priority" lower than any other window message except user-interactive "hardware interrupted" messages such as mouse moves and mouse/keyboard button clicks or wheel rotations. Our own custom message will then trigger OpenGL canvas renders in its own handler exactly like the original WM_TIMER did but at a considerably higher yet stabilized "turbo" rate/speed/pace.

Do you understand the nature of the problem better now, my friend?
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1982
    • zapsolution
Re: Migration to FBO
« Reply #32 on: May 25, 2018, 04:13:25 pm »
My friend

Many things have changed into Windows 10 compared to Seven, for the purpose of compositing.

Do you know the DwmGetCompositionTimingInfo.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa969503(v=vs.85).aspx

Note: in case of multiple monitors, DWM uses of course the lowest refresh rate, with the exception of running in full screen mode.

On Windows 10, trying to bypass the DWM compositing refresh rate is a NoNo.

To work around the low priority of the WM_TIMER message, the solution is to use a distinct thread to perform the sync, but this also means probably to change the ObjReader SetProcessorAffinity.
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Migration to FBO
« Reply #33 on: May 25, 2018, 06:46:41 pm »
Patrice,

I'm feeling somewhat nonplussed because we definitely seem to be speaking different languages. Thank you of course for the interesting info on Windows DWM but this isn't my point of discussion. Leave DWM alone to do its job: it will compose its frames as it sees fit accommodating them to the monitor's actual refresh rate (not vice versa!) that's independent of Windows own timers and performance counters. If the monitor refreshes occur at 144Hz rather than the current 60Hz, then DWM will adjust itself accordingly; that's what monitor drivers are for.

What I am talking about is as follows. As long as the monitor is running at 60Hz (my main monitor can switch between 60Hz and 75Hz), the Windows timer interval of 15.6 msec (= 64 Hz/FPS) is sufficient to clock our gP.hGL refreshes at 60FPS when VSYNC'ed to 1 ("turbo" mode). But when dealing with my 75Hz setting, ObjReader fails to turbo-VSYNC to 75FPS because the Windows timer events (WM_TIMER messages) are triggered too rarely and cannot occur any faster. As a result, the renderer rather continues to run un-VSYNC'ed at 64FPS as shown by the ObjReader FPS counter.

So, what we need is an analog to the Windows timer that can run at a pace of at least 144Hz + ca. 5Hz = ca. 150Hz to be able to VSYNC our redraws to the monitor actual refresh rate whatever it happens to be. And this analog should work as smooth and unstressful for the message pump as the current genuine Windows timer does. It will be a plus if that analog is also automatically switchable to run at the monitor exact refresh rate plus some 5 extra Hertz.

Do I sound clearer this time?
« Last Edit: May 26, 2018, 10:01:51 am by Michael Lobko-Lobanovsky »
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1982
    • zapsolution
Re: Migration to FBO
« Reply #34 on: May 26, 2018, 07:07:51 pm »
Quote
Do I sound clearer this time?
Yes, thank you :)

Then perhaps we could use the EnumDisplaySettings API to get the smallest refresh rate, and a slave thread running a game loop and sending a private message to mimic the WM_TIMER, based on the real VSYNC frequency ?
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Migration to FBO
« Reply #35 on: May 27, 2018, 12:35:55 pm »
Fine! :)

Now Patrice, can you investigate the following tactics:
  • Disable setting process affinity (I don't understand what you're setting it now for, anyway? Are you measuring performances or profiling anything? Why would you stress your CPU so indiscriminately at all?)
  • On pressing the Show FPS, or Y Rotation Mode, or Turbo buttons, create a separate worker thread if it isn't already running.
  • Set up a loop in the worker thread with the following pseudo code:
    while (1) {
        SetMutexOrSemaphoreOrCriticalSection(); // avoid gP.doneRender access conflicts
        if (gP.doneRender) {
            gP.doneRender = FALSE;
            // experiment with Post/Send/BroadcastMessage whichever would work across threads
            PostMessage(gP.hMain, WM_TIMER, 0x1234, 0); // synthetic timer ID; use same in gP.hMain message loop
        }
        UnsetMutexOrSemaphoreOrCriticalSection();
        timeBeginPeriod(1); // set wait resolution to 1 msec, else Sleep() will be too rough!
        Sleep(12); // let loop run at ca. 83 FPS
        timeEndPeriod(1); // restore default resolution
        MaybeDoEventsHere(); // let gP.hMain message loop do its work if messages are pending
    }
  • gP.doneRender is a global flag to indicate if the renderer actually redraws our gP.hGL. At the end of gl_DrawScene(), use Set/UnsetMutex...(hehe) and assign gP.doneRender = TRUE. This flag should prevent sending/posting/broadcasting excessive synthetic WM_TIMER messages that can clog the gP.hMain message loop if they remain unprocessed and accrue there for whatever reason. I think this can help bring down our synthetic WM_TIMER's "priority" to an acceptable level comparable with the genuine one.
  • Do not activate our existing Windows timer but instead, use the existing code with these synthetic WM_TIMER messages. Check if the CPU usage stays as low (or low enough) as with the original Windows timer.
It would be great if the tactics works one way or another...
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1982
    • zapsolution
Re: Migration to FBO
« Reply #36 on: May 27, 2018, 07:08:05 pm »
Here is a quick change using thread (mobj.h + main.cpp).
New: StartSyncThread + Animate

Don't forget to link with Winmm.lib (for timeBeginPeriod/timeEndPeriod)

Tell me if it makes any difference by you ...
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Migration to FBO
« Reply #37 on: May 28, 2018, 09:34:41 am »
Thank you very much, Patrice, it looks very elegant! :)

IMO the initial results do seem very promising, usage-wise. I'll need a little time during the day to analyze the FPS counter behavior (wink-wink) and probably add a couple more touches but overall, I think we've nailed this whole issue on the head.

I will come back to you later to ask for some more creative work regarding your earlier EnumDisplaySettings/DwmGetCompositionTimingInfo input to add automatic detection of the monitor actual retrace rate and to fine-tune the Sleep(n) delay accordingly. This might help us bring down the CPU load yet some more.
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1982
    • zapsolution
Re: Migration to FBO
« Reply #38 on: May 28, 2018, 11:52:25 am »
The problem when dealing with DWM, is that many things have changed since Windows 8.1

See below how to get the correct refresh rate for Windows 10, and with older OS version…

On my ASUS main display the real refresh rate is 75.002
(pTimingInfo.rateRefresh.uiNumerator / (float)pTimingInfo.rateRefresh.uiDenominator)


void Animate (IN DWORD delay) {
    DWM_TIMING_INFO pTimingInfo;
    ClearMemory(&pTimingInfo, sizeof(pTimingInfo));
    pTimingInfo.cbSize = sizeof(pTimingInfo);

    // We must check the OS version, because many things have changed in DWM since Windows 8.1
    HWND hWnd = gP.hMain;
    OSVERSIONINFO osvi = { 0 };
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    if (GetVersionEx(&osvi)) { // Check for VISTA and above
        if ((osvi.dwPlatformId > 1) && (osvi.dwMajorVersion > 5)) {
            hWnd = NULL;
        }
    }
    HRESULT hr = DwmGetCompositionTimingInfo(hWnd, &pTimingInfo);

    float rate = pTimingInfo.rateRefresh.uiNumerator / (float)pTimingInfo.rateRefresh.uiDenominator;

    for (;;) {
        //SetMutexOrSemaphoreOrCriticalSection(); // avoid gP.doneRender access conflicts
        EnterCriticalSection(&gP.cs);
        if (gP.doneRender) {
            gP.doneRender = FALSE;
            // experiment with Post/Send/BroadcastMessage whichever would work across threads
            //PostMessage(gP.hMain, WM_TIMER, 0x1234, 0); // synthetic timer ID; use same in gP.hMain message loop
            WndProc(gP.hMain, WM_TIMER, 0x1234, 0);
        }
        LeaveCriticalSection(&gP.cs);
        //UnsetMutexOrSemaphoreOrCriticalSection();
        timeBeginPeriod(1); // set wait resolution to 1 msec, else Sleep() will be too rough!
        Sleep(12); // let loop run at ca. 83 FPS
        timeEndPeriod(1); // restore default resolution
        //MaybeDoEventsHere(); // let gP.hMain message loop do its work if messages are pending
        myDoEvents(gP.hMain);
    }
}
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Migration to FBO
« Reply #39 on: May 28, 2018, 04:35:27 pm »
Patrice,

Below are my fixes. Everything works fine with the former WM_TIMER and FPS code except a few minor side effects:
  • Viewport doesn't get updated on app start.
  • CPU/GPU usages and FPS aren't updated when there's no model loaded yet.
  • When the model is rotated in the demo mode, the buttons on the lighting panel seem to respond to button-up, rather than button-down, events.
That's probably due to PeekMessage()/return 0 in case WM_TIMER. Can you suggest or figure out how we can fix those unwanted effects staying, at the same time, at the absolutely "lowest priority" in the message pump?

N.B. Make sure to add Dwmapi.lib to your linking stage.
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1982
    • zapsolution
Re: Migration to FBO
« Reply #40 on: May 28, 2018, 06:42:09 pm »
The latest code does not work well by me.

The previous WM_TIMER must be kept unchanged, and avoid the use of IDC_TIMER into the SYNC Animate.
We must keep InitMainTimer for the purpose of GDImage compositing into the lighting panel (and further enhancements) and to update correctly the viewport at startup.

Try using directly gl_Drawscene rather than postmessage.

FPS doesn't work (wink wink)

Investigating…

PS: Did you check with W10 ?
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Migration to FBO
« Reply #41 on: May 28, 2018, 08:34:21 pm »
The latest code does not work well by me.

This comes to me as quite a surprise.

Quote
The previous WM_TIMER must be kept unchanged, and avoid the use of IDC_TIMER into the SYNC Animate.
We must keep InitMainTimer for the purpose of GDImage compositing into the lighting panel (and further enhancements) and to update correctly the viewport at startup.

I seem to have all compositing in the lighting panel working correctly as-is except for no viewport update on app start. But we can split the timer's and "timer"'s IDs and handle them distinctly e.g. in case WM_TIMER.

Quote
Try using directly gl_Drawscene rather than postmessage.

Never! I need a CPU usage as low as possible. PostMessage+PeekMessage+return 0 is the smoothest way to lower the synthesized WM_TIMER priority to nil.

Quote
FPS doesn't work (wink wink)

No, it does for me in both Win 7 and 10! (wink-wink yourself :P )

Quote
PS: Did you check with W10 ?

Are you still having doubts on my account? ;) Have a look at my Windows 10 snapshot. It's a dual 1440x900 px monitor, Core 2 Duo setup with two 1MB VRAM nVidia geForces:
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1982
    • zapsolution
Re: Migration to FBO
« Reply #42 on: May 28, 2018, 09:19:21 pm »
I have a version that is now working better by me…

Added
On the main display, in non-turbo mode, i have the same FPS than the value reported by DWM, aka 75 FPS,
and between 90 to 100 in turbo mode …

When running on the secondary display (iiyama ProLite XUB2490HS vertical frequency 76 Khz)
60 FPS in non-turbo mode, and 118 to 120 in turbo mode …

BTW, now i can always see correctly the FPS...
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Migration to FBO
« Reply #43 on: May 28, 2018, 09:25:45 pm »
No problem Patrice,

Take your time. I am open for discussion, and I will accept any of your fixes if they work no worse than the genuine Windows timer but cover the entire range of possible monitor frequencies with correct FPS count (check against Fraps when in doubt) and low CPU usage. :)

On the main display, in non-turbo mode, i have the same FPS than the value reported by DWM, aka 75 FPS,
and between 90 to 100 in turbo mode …

When running on the secondary display (iiyama ProLite XUB2490HS vertical frequency 76 Khz)
60 FPS in non-turbo mode, and 118 to 120 in turbo mode …

THIS IS NOT CORRECT! You should see half the monitor rate at the normal default setting, and the exact monitor rate when in "turbo". In the test cases under Win 7 and 10 that I took the screenshots of, the FPS readings were 38FPS/75FPS and 30FPS/60FPS for the normal/"turbo" modes, respectively, using the code fixes I sent you -- with the existing FPS counter routines unchanged. If the same routines give you erroneous results, it means your "fixes" do not work, and OpenGL fails to VSYNC itself with the mash of your WM_TIMER messages (or redraws, to be more precise) coming indiscriminately from two interfering "timers".

Quote
... (iiyama ProLite XUB2490HS vertical frequency 76 Khz) ...

What's this? :o

See your system Advanced monitor settings to check what its permissible frame rates (a.k.a. vertical retrace signal frequency) are in Hertz, rather than Kilohertz...
« Last Edit: May 28, 2018, 10:00:00 pm by Michael Lobko-Lobanovsky »
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1982
    • zapsolution
Re: Migration to FBO
« Reply #44 on: May 28, 2018, 10:40:11 pm »
Send me your compiled version to let me check it here, thank you.
Patrice
(Always working with the latest Windows version available...)