New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fullscreen window background visibility, and associated tearing glitch #1144

Open
jezhill opened this Issue Nov 22, 2017 · 16 comments

Comments

Projects
None yet
3 participants
@jezhill
Copy link

jezhill commented Nov 22, 2017

Congratulations on a beautifully designed and maintained toolbox.

My application uses a full-screen-sized undecorated window, and is mainly deployed on Windows. I've tried using the approach you call "windowed full screen" but that has a couple of drawbacks. The main one for me is what happens when the GLFW loses focus (e.g. when I alt-tab away to a console window): by default, it disappears completely; alternatively, I can set it so that it completely refuses to go behind other windows. But I want the intermediate behaviour: i.e. to ensure it is behind other windows, but still visible. I've enjoyed this capability with previous windowing toolboxes (freeglut, pyglet, and the SDL wrapper pygame) but for many other reasons I would like to switch to GLFW if I can. If there's a way to make fullscreen windows visible in the background, I'd be grateful if you could let me know.

Initially, windows with a non-NULL monitor pointer disappear when you switch away. Setting

glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE);

sounds like it should solve this in theory but it goes too far to the opposite extreme: now my fullscreen windows refuse to go to the background. If I alt-tab away, the GLFW window gives up keyboard-input focus but visually jumps back in front, as if floating. This is true regardless of whether I also explicitly ask for GLFW_FLOATING to be false.

My own attempts at a workaround led me to uncover a striking performance glitch in GLFW. I attempted to create a window with width, height and refreshRate matching the monitor mode info, but then leave the GLFWmonitor pointer itself NULL and, before window creation, hint that I want the window undecorated. That achieves my goal, but then I see a really huge focus-dependent tearing artefact.

Here are the details. In tests/tearing.c from the glfw-3.2.1 release, I added the following after line 158:

monitor = NULL;
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);

and then set the initial swap_interval to 1, on what used to be line 175:

set_swap_interval(window, 1);

(my system supports the appropriate extensions for a swap_interval of 1 or -1). I then built and executed a 64-bit Release-mode binary using Visual Studio 12 (2013) under Windows 10 on my Surface Pro 3, as follows:

cmake -G "Visual Studio 12 Win64" -DUSE_MSVC_RUNTIME_LIBRARY_DLL=OFF
call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat"
msbuild /p:Configuration=Release GLFW.sln
tests\Release\tearing.exe -f

When I alt-tab to my console, I see the fullscreen-sized undecorated window behind it and all looks fine, tearing-wise. Mission accomplished? No, because whenever the GLFW window is in the foreground, there is a single huge tear about 3cm down from the top of the screen. That's at 150% DPI scaling - if I turn DPI scaling off, the torn segment gets proportionally smaller. But the tear can be moved - for example, if I use the up-arrow to raise the swap_interval to 3, the tear moves to about 3/5 of the way down the screen. By contrast, in "windowed full screen" mode, I do not get any tearing except the usual vertically-distributed frizz at swap_interval=0.)

I have tried getting the best of both worlds by using a focus callback that switches between "windowed full screen" when focused and "undecorated and just coincidentally as big as the monitor it was recently filling" when unfocused. But the behaviour is just like full-screen (window disappears when I alt-tab away).

monitors.exe says:

Name: Generic PnP Monitor (primary)
Current mode: 2160 x 1440 x 24 (8 8 8) 59 Hz
Virtual position: 0 0
Physical size: 254 x 169 mm (216.00 dpi)
... [modes 0..173 omitted]

dxdiag.exe says (selectively pruned):

------------------
System Information
------------------
         Operating System: Windows 10 Pro 64-bit (10.0, Build 14393) (14393.rs1_release_inmarket.170906-1810)
                 Language: English (Regional Setting: English)
      System Manufacturer: Microsoft Corporation
             System Model: Surface Pro 3
                     BIOS: 3.11.2150
                Processor: Intel(R) Core(TM) i7-4650U CPU @ 1.70GHz (4 CPUs), ~2.3GHz
                   Memory: 8192MB RAM
      Available OS Memory: 8098MB RAM
                Page File: 9105MB used, 7613MB available
              Windows Dir: C:\WINDOWS
          DirectX Version: DirectX 12
      DX Setup Parameters: Not found
         User DPI Setting: Using System DPI
       System DPI Setting: 144 DPI (150 percent)
          DWM DPI Scaling: UnKnown
                 Miracast: Available, with HDCP
Microsoft Graphics Hybrid: Not Supported
           DxDiag Version: 10.00.14393.0000 64bit Unicode

------------
DxDiag Notes
------------
      Display Tab 1: No problems found.
        Sound Tab 1: No problems found.
          Input Tab: No problems found.

--------------------
DirectX Debug Levels
--------------------
Direct3D:    0/4 (retail)
DirectDraw:  0/4 (retail)
DirectInput: 0/5 (retail)
DirectMusic: 0/5 (retail)
DirectPlay:  0/9 (retail)
DirectSound: 0/5 (retail)
DirectShow:  0/6 (retail)

---------------
Display Devices
---------------
          Card name: Intel(R) HD Graphics 5000
       Manufacturer: Intel Corporation
          Chip type: Intel(R) HD Graphics Family
           DAC type: Internal
        Device Type: Full Device
         Device Key: Enum\PCI\VEN_8086&DEV_0A26&SUBSYS_00051414&REV_09
      Device Status: 0180200A [DN_DRIVER_LOADED|DN_STARTED|DN_DISABLEABLE|DN_NT_ENUMERATOR|DN_NT_DRIVER] 
Device Problem Code: No Problem
Driver Problem Code: Unknown
     Display Memory: 2160 MB
   Dedicated Memory: 112 MB
      Shared Memory: 2048 MB
       Current Mode: 2160 x 1440 (32 bit) (59Hz)
       Monitor Name: Generic PnP Monitor
      Monitor Model: unknown
         Monitor Id: SEC3542
        Native Mode: 2160 x 1440(p) (59.955Hz)
        Output Type: Internal
        Driver Name: igdumdim64.dll,igd10iumd64.dll,igd10iumd64.dll,igd12umd64.dll
Driver File Version: 20.19.0015.4568 (English)
     Driver Version: 20.19.15.4568
        DDI Version: 12
     Feature Levels: 11_1,11_0,10_1,10_0,9_3,9_2,9_1
       Driver Model: WDDM 2.0
Graphics Preemption: Primitive
 Compute Preemption: Thread group
           Miracast: Supported
Hybrid Graphics GPU: Integrated
     Power P-states: Not Supported
  Driver Attributes: Final Retail
   Driver Date/Size: 12/15/2016 7:00:00 PM, 39863872 bytes
        WHQL Logo'd: Yes
    WHQL Date Stamp: Unknown
  Device Identifier: {D7B78E66-4966-11CF-7C66-0A20B5C2D935}
          Vendor ID: 0x8086
          Device ID: 0x0A26
          SubSys ID: 0x00051414
        Revision ID: 0x0009
 Driver Strong Name: oem59.inf:5f63e5344b4d2c28:iHSWM_w10:20.19.15.4568:pci\ven_8086&dev_0a26&subsys_00051414
     Rank Of Driver: 00D10001
        Video Accel: ModeMPEG2_A ModeMPEG2_C ModeWMV9_C ModeVC1_C 
        DXVA2 Modes: DXVA2_ModeMPEG2_VLD  DXVA2_ModeMPEG2_IDCT  DXVA2_ModeVC1_D2010  DXVA2_ModeWMV9_IDCT  DXVA2_ModeVC1_IDCT  DXVA2_ModeH264_VLD_NoFGT  DXVA2_ModeH264_VLD_Stereo_Progressive_NoFGT  DXVA2_ModeH264_VLD_Stereo_NoFGT  DXVA2_ModeH264_VLD_Multiview_NoFGT  DXVA2_ModeHEVC_VLD_Main  
       D3D9 Overlay: Supported
            DXVA-HD: Supported
       DDraw Status: Enabled
         D3D Status: Enabled
         AGP Status: Enabled
           MPO Caps: Not Supported
        MPO Stretch: Not Supported
    MPO Media Hints: Not Supported
        MPO Formats: Not Supported
@ghuser404

This comment has been minimized.

Copy link

ghuser404 commented Nov 22, 2017

GLFW_AUTO_ICONIFY

@jezhill

This comment has been minimized.

Copy link

jezhill commented Nov 22, 2017

@ghuser404 Thanks for the pointer to GLFW_AUTO_ICONIFY. I had indeed overlooked it. However, it didn't solve my problem: setting it to false made the GLFW window float above others, regardless of whether it had focus or not (and I tried explicitly setting GLFW_FLOATING to false as well- didn't help). I have updated my initial report accordingly.

@ghuser404

This comment has been minimized.

Copy link

ghuser404 commented Nov 22, 2017

@jezhill, thanks for pointing this out to me. This suggestion about borderless windowed mode has always bothered me. I think the proper way to do it is to just create an undecorated window at 0,0 with the size of monitor.

Are your drivers up-to-date?

@ghuser404

This comment has been minimized.

Copy link

ghuser404 commented Nov 23, 2017

Although, I'm wondering if it will hide task bar on all platforms (it does on Windows). If not, then might have to enable floating mode on focus and disable it on losing focus. Or maybe potentially introduce API to remove taskbar.

I'd be interested to see what @elmindreda thinks about all this.

@jezhill

This comment has been minimized.

Copy link

jezhill commented Nov 23, 2017

I agree, creating an undecorated window at 0,0 should be the way to go but that's the case in which I get the strange tearing artefact (see this movie). Yes, my graphics drivers are up-to-date (at least, Windows claims that they are when I ask it to update via the device manager).

@elmindreda

This comment has been minimized.

Copy link
Member

elmindreda commented Nov 23, 2017

@jezhill Awesome, you have a GLFW source tree already set up. Let's experiment!

Does anything change if you remove everything except the call to SwapBuffers from the function swapBuffersWGL in wgl_context.c?

@ghuser404

This comment has been minimized.

Copy link

ghuser404 commented Nov 23, 2017

@elmindreda, don't mean to hijack this thread, but I think @jezhill will appreciate this question too:
do you suggest making borderless window at 0,0 - to create real borderless windowed experience, where you can drag other windows on top of that one - or do you think there should be a better API for this?

Current suggestion (to set fullscreen with desktop dimensions) has its own advantages, like having GLFW track linked monitor - but sadly, it doesn't let you have other windows on top of it.

@jezhill

This comment has been minimized.

Copy link

jezhill commented Nov 23, 2017

@jezhill

This comment has been minimized.

Copy link

jezhill commented Nov 23, 2017

Oh, hey, but if I remove the _glfw_DwmFlush call and then do the obvious thing of removing

if (isCompositionEnabled() && !window->monitor)
    interval = 0;

from swapIntervalWGL a few lines further down, then all is good (foreground and background both 60Hz, no tearing).

What was DwmFlush buying us in the first place?

@elmindreda

This comment has been minimized.

Copy link
Member

elmindreda commented Nov 24, 2017

@ghuser404 I think this is a good place for that question! My initial feeling is that the approach here is better than further complicating the full screen window model, especially considering things like macOS Spaces.

@elmindreda

This comment has been minimized.

Copy link
Member

elmindreda commented Nov 24, 2017

@jezhill It's a workaround for Nvidia OpenGL swap interval issues under DWM. Will have to revisit it. Thank you for all the data!

@ghuser404

This comment has been minimized.

Copy link

ghuser404 commented Nov 24, 2017

@elmindreda, alright, but then the window is not guaranteed to cover the taskbar (or is it?) - should we use the floating mode then? It seems like a coincidence that it covers the taskbar on Windows.

@jezhill

This comment has been minimized.

Copy link

jezhill commented Nov 24, 2017

If you never have, I recommend digging into the way pyglet does things. I can't claim to know the details but it seems a lot of work has been done to cover all the same bases.

@ghuser404

This comment has been minimized.

Copy link

ghuser404 commented Nov 24, 2017

@jezhill, if you were referring to me, I'm not sure how this would help me, as I'm using GLFW - not native API.

@elmindreda, not a fan of SDL, but just checked, they do HWND_NOTOPMOST when fullscreen window loses focus. It seems there is really no benefit leaving it TOPMOST after it loses focus - I have never seen a single app do this.

@ghuser404

This comment has been minimized.

Copy link

ghuser404 commented Nov 25, 2017

Just tried adding these lines into _glfwInputWindowFocus after it calls window->callbacks.focus:

if (window->monitor)
    _glfwPlatformSetWindowFloating(window, focused);

Seems to work fine, of course the function name may seem unrelated.

Edit: Won't work if you want 2 windows in fullscreen. I really think this should be controllable - maybe floating hint extended for fullscreen windows.

@ghuser404

This comment has been minimized.

Copy link

ghuser404 commented Nov 27, 2017

OK, I've played around a little bit with this and here is my verdict (sorry for a small spam here):

  1. Changing TOPMOST on the fly doesn't work smoothly, there is a case where a secondary window would still appear under your fullscreen window, i.e. when you focus fullscreen window, then start dragging the secondary window (without clicking on it beforehand), it seems Windows waits for you to click on it to process the message properly.

  2. I've inspected several games with inspect.exe, and while they set TOPMOST in fullscreen mode, the do not set TOPMOST in fullscreen borderless mode.

I wouldn't recommend anyone changing TOPMOST on the fly, at least on Windows. I need to get around testing this on other platforms. Again, sorry for spam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment