Tom94 / tev

High dynamic range (HDR) image viewer for graphics people
BSD 3-Clause "New" or "Revised" License
1.08k stars 86 forks source link

Window keeps repainting when idle #45

Open mackrol opened 6 years ago

mackrol commented 6 years ago

Thank You for such a great tool. This is currently my favorite exr viewer.

Crossposted in wjakob/nanogui#337 On Win10 tev window keeps constantly repainting itself eating GPU cycles. Task manager shows 1% GPU utilization on GTX 780 even when out of focus. To be a good desktop citizen, application should repaint its windows only when required. A quick investigation showed that repaint is configured in the main.cpp: nanogui::mainloop(250) I disabled continous refresh rate with: nonogui::mainloop(0) GPU utilization dropped to 0.5%, but surprisingly didn't disable repaints completely. Digging further I noticed that glfwWaitEvents in nanogui::mainloop keeps returning every second. This is caused by the constant stream of WM_GETICON messages (verified with Spy++). I couldn't resist to hack glfwWaitEvents to ignore this message:

void _glfwPlatformWaitEvents(void)
{
#define HACK_GETICON
#ifndef HACK_GETICON
    // Original implementation
    WaitMessage();
#else
    // Hack: Process WM_GETICON and keep waiting
    while (1)
    {
        MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE, QS_ALLEVENTS);
        MSG msg;
        if (PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE))
        {
            if (msg.message == WM_GETICON)
            {
                // Remove message from the queue
                GetMessageW(&msg, NULL, 0, 0);
                TranslateMessage(&msg);
                DispatchMessage(&msg);
                // Keep waiting
            }
            else // No more waiting
            {
                break;
            }
        }
    }
#endif
    _glfwPlatformPollEvents();
}

GPU utilization dropped to 0% after this hack. This is obviously more of a problem of nanogui rather than TEV itself. I'm reporting this just to keep You noted.

Tom94 commented 6 years ago

Hi mackrol, I'm glad you like tev. Thank you very much for the feedback!

Currently, nanogui::mainloop(250) is used intentionally since periodic tasks (such as listening for files opened from secondary instances of tev) are processed as part of the main loop. Through some such events tev needs to repaint while out of focus, and through others it needs to gain focus when minimized.

With your hack, I suspect if you open secondary instances of tev (e.g. by double-clicking an EXR file while an instance of tev is already open) nothing will happen until you manually re-focus the original instance. Could you confirm this?

I fully agree, that this situation is not optimal. Ideally, tev would request repaints only when such events occur, but I am not aware of a mechanism in nanogui that allows both

in a cross-platform manner. In-fact, I already tried getting this to work at some point using glfwPostEmptyEvent();, but this has not worked reliably for me on all platforms, causing tev to lock up in some cases (which is obviously unacceptable).

mackrol commented 6 years ago

Indeed, there is a problem when opening an image with a second instance of TEV with hack applied. New image is shown once I hover mouse over the window (new messages in the queue). I'm investigating this because I'm looking for a viable GUI library for small desktop applications like Yours. I use Qt professionally, but it's an overkill for hobby projects. All small GUI libraries that I know, fail my desktop citizenship test, that's the price of simplicity I guess.