fabiangreffrath / woof

Woof! is a continuation of the Boom/MBF bloodline of Doom source ports.
GNU General Public License v2.0
209 stars 35 forks source link

Video fixes #1754

Closed ceski-1 closed 3 months ago

ceski-1 commented 3 months ago

The alt+tab fix works for all Windows render drivers. It doesn't seem necessary for Linux and just makes switching back and forth slower there (OpenGL + Arch tested). Fixes https://github.com/fabiangreffrath/woof/issues/1752

OpenGL exclusive fullscreen didn't work right in Windows. It would just start minimized. Looking at the SDL behavior on launch, it fires off a bunch of window events during window/render creation that confuses the logic we have in Woof. There's no point in parsing those initial window events, so they're now flushed, which fixes the issue.

Since the initial events are flushed, the priority is just raised explicitly on launch. Some of the other calls were redundant, so they were removed.

ceski-1 commented 3 months ago

@MrAlaux Can you try this with your system? To make it easy, you can copy this text into a batch file and try alt+tabbing, then quitting, for each render driver:

batch file ```bat @echo off echo testing direct3d9... set SDL_RENDER_DRIVER= woof.exe -warp 1 echo testing direct3d11... set SDL_RENDER_DRIVER=direct3d11 woof.exe -warp 1 :: no win7 support? :: echo testing direct3d12... :: set SDL_RENDER_DRIVER=direct3d12 :: woof.exe -warp 1 echo testing opengl... set SDL_RENDER_DRIVER=opengl woof.exe -warp 1 pause ```

Edit: make sure fullscreen and exclusive fullscreen are both enabled.

MrAlaux commented 3 months ago

@MrAlaux Can you try this with your system?

All three of them work.

FWIW, D3D11 switches fastest, followed by D3D9 (if not the same, not sure), then OpenGL (definitely slower and flickers the screen more, probably takes twice as long as D3D11).

rfomin commented 3 months ago

It works, but Alt-Tab is slower and there is flickering (default direct3d). To be honest, I prefer the old behaviour. Do we still need "Exclusive Fullscreen"? It seems that VRR works with borderless fullscreen?

ceski-1 commented 3 months ago

Do we still need "Exclusive Fullscreen"? It seems that VRR works with borderless fullscreen?

My understanding is that VRR only works with the "flip" presentation model. We need exclusive fullscreen so that direct3d and opengl can use "flip", otherwise "gdi copy" is used instead. It seems "flip" is more performant and has less latency.

I'm not sure if exclusive fullscreen is needed for direct3d11 because the behavior is different for Windows 10 and 11 (only 11 has "optimizations for windowed games" which forces "flip"?).

direct3d12 doesn't need exclusive fullscreen because it doesn't use it. It just fakes exclusive fullscreen with a window.

You can check the presentation mode with PresentMon's overlay and see for yourself. The whole subject is complicated:

It works, but Alt-Tab is slower and there is flickering (default direct3d). To be honest, I prefer the old behaviour.

It should be a little faster now: https://github.com/fabiangreffrath/woof/compare/f29ed0f36f6857faeb02a8c64780e46f8781508d..1215b884e79d2d4b8fb9e1c58ac2504ce9a472d3

Instead of the entire window being destroyed and recreated, only the surface is recreated. Apparently a known issue with DirectX 9 in general, not just SDL, is that textures have to be reset when alt+tabbing with exclusive fullscreen. So there's no avoiding some kind of reset if you want to prevent this issue.

Here is my justification for this PR:

details Before this PR with `direct3d`, launch into exclusive fullscreen and try to alt+tab. Bad result, window is stuck: ``` [direct3d] SDL_WINDOWEVENT_SIZE_CHANGED SDL_WINDOWEVENT_FOCUS_LOST SDL_WINDOWEVENT_LEAVE SDL_SetRenderTarget error: BeginScene(): INVALIDCALL SDL_SetRenderTarget error: BeginScene(): INVALIDCALL SDL_WINDOWEVENT_ENTER SDL_WINDOWEVENT_FOCUS_GAINED SDL_WINDOWEVENT_LEAVE SDL_UpdateTexture error: LockRect(): INVALIDCALL SDL_SetRenderTarget error: BeginScene(): INVALIDCALL SDL_SetRenderTarget error: BeginScene(): INVALIDCALL SDL_WINDOWEVENT_ENTER SDL_UpdateTexture error: LockRect(): INVALIDCALL SDL_SetRenderTarget error: BeginScene(): INVALIDCALL SDL_SetRenderTarget error: BeginScene(): INVALIDCALL SDL_UpdateTexture error: LockRect(): INVALIDCALL SDL_SetRenderTarget error: BeginScene(): INVALIDCALL SDL_SetRenderTarget error: BeginScene(): INVALIDCALL SDL_UpdateTexture error: LockRect(): INVALIDCALL SDL_SetRenderTarget error: BeginScene(): INVALIDCALL SDL_SetRenderTarget error: BeginScene(): INVALIDCALL [repeat forever] ``` Now check `direct3d11` and `direct3d12`. Launch into exclusive fullscreen and try to alt+tab. It works fine: ``` [direct3d11 or direct3d12] SDL_WINDOWEVENT_SIZE_CHANGED SDL_WINDOWEVENT_LEAVE SDL_WINDOWEVENT_MINIMIZED SDL_WINDOWEVENT_FOCUS_LOST ``` Then try to alt+tab back to Woof. Works fine: ``` [direct3d11 or direct3d12] SDL_WINDOWEVENT_FOCUS_GAINED SDL_WINDOWEVENT_SIZE_CHANGED SDL_WINDOWEVENT_RESTORED SDL_WINDOWEVENT_ENTER SDL_WINDOWEVENT_EXPOSED ``` What about `opengl`? Launch into exclusive fullscreen. The window is immediately minimized and stuck. We see that the initial window events cause problems for `HandleWindowEvent()`: ``` [opengl] // initial values screenvisible = true; window_focused = true; // init video SDL_WINDOWEVENT_SHOWN SDL_WINDOWEVENT_FOCUS_GAINED // window_focused = true; SDL_WINDOWEVENT_HIDDEN SDL_WINDOWEVENT_MINIMIZED // screenvisible = false; SDL_WINDOWEVENT_FOCUS_LOST // window_focused = false; SDL_WINDOWEVENT_SIZE_CHANGED SDL_WINDOWEVENT_SHOWN SDL_WINDOWEVENT_FOCUS_GAINED // window_focused = true; SDL_WINDOWEVENT_EXPOSED SDL_WINDOWEVENT_ENTER // final values screenvisible == false window_focused == true ``` But `direct3d`, `direct3d11`, and `direct3d12` are fine at launch: ``` [direct3d, direct3d11, or direct3d12] // initial values screenvisible = true; window_focused = true; // init video SDL_WINDOWEVENT_SIZE_CHANGED SDL_WINDOWEVENT_SHOWN SDL_WINDOWEVENT_FOCUS_GAINED // window_focused = true; SDL_WINDOWEVENT_EXPOSED SDL_WINDOWEVENT_ENTER // final values screenvisible == true window_focused == true ``` Adding this to the end of `I_InitGraphicsMode()` fixes `opengl` and doesn't affect the others: ```c SDL_PumpEvents(); SDL_FlushEvent(SDL_WINDOWEVENT); ``` After applying that fix, `opengl` can launch and alt+tab normally.