On 4/24/19 12:51 AM, Henri Verbeet wrote:
On Tue, 23 Apr 2019 at 17:29, Zhiyi Zhang zzhang@codeweavers.com wrote:
+/* A correct occlusion detection method must consider following scenarios:
- On multiple monitors system. For example, the full-screen is on primary display, any window on
- on secondary monitor shouldn't be able to occlude the full-screen window, regardless being foreground or active.
- A non-Wine window, e.g., a X window occludes the full-screen window should be detected.
- Current method will incorrectly report occluded status where a window on a secondary monitor becomes foreground,
- which shouldn't be too harmful though. The actual implementation on Window probably has help from DWM.
- X11 VisibilityNotify is not useful here. The events doesn't work as expected.
- */
What is the actual issue with VisibilityNotify?
The feature that's needed here is determining whether a full-screen window is occluded, if it's then exit full-screen mode. The occlusion detection is implemented by DWM[1] and checked by IDXGISwapChain::Present[2]
The problem here is that to implement occlusion detection correctly 100%, we need something like VisibilityNotify events[3] on Linux. But for VisibilityNotify events to work reliably, we need to disable compositing. Modern window managers are compositing managers for those fancy visual effects, so they are using compositor by default, thus making VisibilityNotify events unreliable and even GTK stopped using them[4]. For some window managers, we could disable compositing when entering a full-screen app to get VisibilityNotify events working. But for GNOME Shell 3, I didn't find a method to disable its composition. And what's more, disabling compositing on DWM is per monitor while current Linux window managers are per screen. So if you disable compositing, you lose all the fancy effects on other monitors as well on Linux.
To test window manager compositing and VisibilityNotify events. You can see this commit[5] for commands to disable compositor. Then use `xev` to open a test window and try moving another window over it and see if VisibilityNotify events show up.
To pursue this window manager path, we need to adapt to different window managers to disable/enable compositor accordingly. If the window manager doesn't support disabling compositor, then we use a fallback method. The rationale behind why I am currently not touching the window manager side is that there are problems as stated above. Secondly, the fallback method works so well. So in the end, there is only the fallback method making this patch[6].
Feel free to let me know if there are better approaches.
[1]: D3DKMTCheckOcclusion (https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/d3dkmt...) [2]: IDXGISwapChain::Present (https://docs.microsoft.com/en-us/windows/desktop/api/dxgi/nf-dxgi-idxgiswapc...) [3]: VisibilityNotify (https://tronche.com/gui/x/xlib/events/window-state-change/visibility.html) [4]: gdk: Remove VisibilityNotify events (https://github.com/GNOME/gtk/commit/bd6b6ed93c075c2055dff5cdff6f85a886bc6571) [5]: disable the compositor for better performance (https://github.com/lutris/lutris/pull/881/commits/6dc34a53d7efa6f69c28029980...) [6]: dxgi: Implement fullscreen window occlusion detection. (https://source.winehq.org/patches/data/163529)
In any case, I imagine we should implement this on top of D3DKMTCheckOcclusion(). That would then still need to be implemented in gdi32, of course. It may also make more sense to check for swapchain occlusion in wined3d, since e.g. d3d9ex is also supposed to check for that.
Yes. I didn't notice there is a D3DKMTCheckOcclusion before. I will make the changes.
Thanks, Zhiyi