SDL3: Handle r_fillWindowAlphaChan, cleanups and comments

r_fillWindowAlphaChan is a hack to work around an older issue with
Wayland/Mesa, which has been fixed in Mesa 24.1 (and also seems to work
with current NVIDIA drivers). Additionally, in SDL3 the EGL-specific
(and thus mostly only affecting Wayland)
SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY has been replaced with the generic
SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN (that could also affect
other platforms), so it's harder to enable this only for Wayland.
I think most people using SDL3 will use a recent Mesa/driver versions,
so I don't enable it by default for SDL3 (SDL2 behaves like before).
However, with `r_fillWindowAlphaChan 1` the hack can be enabled anyway
(r_fillWindowAlphaChan defaults to "-1" which means "let dhewm3 decide
 whether to enable this")
This commit is contained in:
Daniel Gibson 2024-10-09 22:57:35 +02:00
parent 3a6210b154
commit 81ba620984
5 changed files with 39 additions and 22 deletions

View file

@ -30,7 +30,7 @@ If you have questions concerning this license or the applicable additional terms
#include "renderer/tr_local.h" #include "renderer/tr_local.h"
static idCVar r_fillWindowAlphaChan( "r_fillWindowAlphaChan", "-1", CVAR_SYSTEM | CVAR_NOCHEAT | CVAR_ARCHIVE, "Make sure alpha channel of windows default framebuffer is completely opaque at the end of each frame. Needed at least when using Wayland.\n 1: do this, 0: don't do it, -1: let dhewm3 decide (default)" ); static idCVar r_fillWindowAlphaChan( "r_fillWindowAlphaChan", "-1", CVAR_SYSTEM | CVAR_NOCHEAT | CVAR_ARCHIVE, "Make sure alpha channel of windows default framebuffer is completely opaque at the end of each frame. Needed at least when using Wayland with older drivers.\n 1: do this, 0: don't do it, -1: let dhewm3 decide (default)" );
frameData_t *frameData; frameData_t *frameData;
backEndState_t backEnd; backEndState_t backEnd;

View file

@ -1073,7 +1073,7 @@ typedef struct {
bool fullScreen; bool fullScreen;
bool fullScreenDesktop; bool fullScreenDesktop;
bool stereo; bool stereo;
int displayHz; int displayHz; // TODO: SDL3 uses float
int multiSamples; int multiSamples;
} glimpParms_t; } glimpParms_t;

View file

@ -30,9 +30,6 @@ If you have questions concerning this license or the applicable additional terms
#ifdef D3_SDL3 #ifdef D3_SDL3
#include <SDL3/SDL_cpuinfo.h> #include <SDL3/SDL_cpuinfo.h>
// in SDL3, SDL_Has3DNow() has been removed, and nowadays it's not really relevant anyway,
// so just replace it with 0/false
#define SDL_Has3DNow() 0
#else // SDL1.2 or SDL2 #else // SDL1.2 or SDL2
#include <SDL_cpuinfo.h> #include <SDL_cpuinfo.h>
#endif #endif
@ -208,8 +205,11 @@ int Sys_GetProcessorId( void ) {
if (SDL_HasMMX()) if (SDL_HasMMX())
flags |= CPUID_MMX; flags |= CPUID_MMX;
// SDL3 doesn't support detecting 3DNow, and current CPUs (even from AMD) don't support it either
#ifndef D3_SDL3
if (SDL_Has3DNow()) if (SDL_Has3DNow())
flags |= CPUID_3DNOW; flags |= CPUID_3DNOW;
#endif
if (SDL_HasSSE()) if (SDL_HasSSE())
flags |= CPUID_SSE; flags |= CPUID_SSE;

View file

@ -152,8 +152,6 @@ If you have questions concerning this license or the applicable additional terms
#define IS_SDL_BTN_DOWN(EV) EV.down #define IS_SDL_BTN_DOWN(EV) EV.down
// FIXME: at some point I need to enable (and possibly later disable) SDL_TextInput!
#else // SDL2 and SDL1.2 #else // SDL2 and SDL1.2
#define IS_SDL_BTN_DOWN(EV) (EV.state == SDL_PRESSED) #define IS_SDL_BTN_DOWN(EV) (EV.state == SDL_PRESSED)
@ -1209,7 +1207,9 @@ sysEvent_t Sys_GetEvent() {
} }
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
// s used to have SDL_TEXTINPUTEVENT_TEXT_SIZE (32) bytes, but in SDL3 the string can have // s holds the string from the last SDL_TEXTINPUT event, to generate SE_CHARS D3 events,
// one event per call to this function until all chars have been handled
// it used to have SDL_TEXTINPUTEVENT_TEXT_SIZE (32) bytes, but in SDL3 the string can have
// arbitrary size, however I assume that 128 should still be more than enough // arbitrary size, however I assume that 128 should still be more than enough
static char s[128] = {0}; static char s[128] = {0};
static size_t s_pos = 0; static size_t s_pos = 0;
@ -1229,6 +1229,9 @@ sysEvent_t Sys_GetEvent() {
} }
#endif #endif
// c holds a single char for a SE_CHAR event, probably coming from a SDL_KEYDOWN event
// (that was also returned as SE_KEY), or from a SDL_TEXTINPUT event that contained just one char.
// It's 0 when not currently holding a char to generate an event
static byte c = 0; static byte c = 0;
if (c) { if (c) {
@ -1421,6 +1424,7 @@ sysEvent_t Sys_GetEvent() {
if (ev.key.state == SDL_PRESSED && (ev.key.keysym.unicode & 0xff00) == 0) if (ev.key.state == SDL_PRESSED && (ev.key.keysym.unicode & 0xff00) == 0)
c = ev.key.keysym.unicode & 0xff; c = ev.key.keysym.unicode & 0xff;
#endif #endif
// Note: c will be sent as SE_CHAR next time this function is called
return res; return res;
@ -1440,7 +1444,9 @@ sysEvent_t Sys_GetEvent() {
memcpy( s, ev.text.text, SDL_TEXTINPUTEVENT_TEXT_SIZE ); memcpy( s, ev.text.text, SDL_TEXTINPUTEVENT_TEXT_SIZE );
s[SDL_TEXTINPUTEVENT_TEXT_SIZE] = '\0'; s[SDL_TEXTINPUTEVENT_TEXT_SIZE] = '\0';
#endif #endif
s_pos = 1; // pos 0 is returned // pos 0 is returned, the rest of s is returned as SE_CHAR events
// at the next times this function is called
s_pos = 1;
} }
return res; return res;
} else if( D3_UTF8toISO8859_1( ev.text.text, s, sizeof(s) ) && s[0] != '\0' ) { } else if( D3_UTF8toISO8859_1( ev.text.text, s, sizeof(s) ) && s[0] != '\0' ) {
@ -1449,7 +1455,9 @@ sysEvent_t Sys_GetEvent() {
s_pos = 0; s_pos = 0;
s[0] = '\0'; s[0] = '\0';
} else { } else {
s_pos = 1; // pos 0 is returned // pos 0 is returned, the rest of s is returned as SE_CHAR events
// at the next times this function is called
s_pos = 1;
} }
return res; return res;
} }

View file

@ -219,20 +219,25 @@ bool GLimp_Init(glimpParms_t parms) {
* rendering bugs (the window is partly transparent or very white in areas with low alpha). * rendering bugs (the window is partly transparent or very white in areas with low alpha).
* Mesa introduced an EGL extension that's supposed to fix that (EGL_EXT_present_opaque) * Mesa introduced an EGL extension that's supposed to fix that (EGL_EXT_present_opaque)
* and newer SDL2 versions use it by default (in the Wayland backend). * and newer SDL2 versions use it by default (in the Wayland backend).
* Unfortunately, the implementation of that extension is (currently?) broken (at least * Unfortunately, the implementation of that extension was broken (at least in Mesa before 24.1),
* in Mesa), seems like they just give you a visual without any alpha chan - which doesn't * seems like they just give you a visual without any alpha chan - which doesn't
* work for Doom3, as it needs a functioning alpha chan for blending operations, see above. * work for Doom3, as it needs a functioning alpha chan for blending operations, see above.
* See also: https://gitlab.freedesktop.org/mesa/mesa/-/issues/5886 * See also: https://gitlab.freedesktop.org/mesa/mesa/-/issues/5886
* *
* So to make sure dhewm3 (finally) works as expected on Wayland, we tell SDL2 to * So to make sure dhewm3 (finally) works as expected on Wayland, we tell SDL2 to
* allow transparency and then fill the alpha-chan ourselves in RB_SwapBuffers() * allow transparency and then fill the alpha-chan ourselves in RB_SwapBuffers()
* (unless the user disables that with r_fillWindowAlphaChan 0) */ * (unless the user disables that with r_fillWindowAlphaChan 0)
*
* NOTE: This bug is fixed in Mesa 24.1 and newer, and doesn't seem to occur with recent
* NVIDIA drivers either, so for SDL3 (which should be mostly used with current drivers/mesa)
* I don't enable this hack by default. If r_fillWindowAlphaChan == 1, it's enabled
* when creating the window, though.
*/
#ifdef SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY #ifdef SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY
SDL_SetHint(SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, "1"); SDL_SetHint(SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, "1");
#elif SDL_MAJOR_VERSION == 2 // little hack so this works if the SDL2 version used for building is older than runtime version #elif SDL_MAJOR_VERSION == 2 // little hack so this works if the SDL2 version used for building is older than runtime version
SDL_SetHint("SDL_VIDEO_EGL_ALLOW_TRANSPARENCY", "1"); SDL_SetHint("SDL_VIDEO_EGL_ALLOW_TRANSPARENCY", "1");
#endif #endif
// Note: for SDL3 we use SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN below
#endif #endif
int colorbits = 24; int colorbits = 24;
@ -401,15 +406,17 @@ try_again:
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, parms.width); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, parms.width);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, parms.height); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, parms.height);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, flags); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, flags);
// TODO: the following is probably redundant with the flag already set
//if ( parms.fullScreen && parms.fullScreenDesktop ) {
// SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
//} // for exclusive fullscreen, create in windowed mode first, need to call
// TODO: SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN, true); // See above for the big comment about Wayland and alpha channels.
// as replacement for SDL_VIDEO_EGL_ALLOW_TRANSPARENCY - but when? // When using SDL3 I assume that people usually won't be affected by this bug,
// I don't want this on all platforms.. but can I already detect wayland at this point? // because it's fixed in recent Mesa versions (and also works with the NVIDIA driver).
// Also: recent mesa versions should have this fixed, so maybe ignore the issue for SDL3? what about nvidia? // However, with `r_fillWindowAlphaChan 1` its usage can still be enforced
// on Unix-like platforms (I don't think there's a point in this on Windows or Mac)
#if defined(__unix__) && !defined(__APPLE__)
if ( cvarSystem->GetCVarInteger( "r_fillWindowAlphaChan" ) == 1 ) {
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN, true);
}
#endif
window = SDL_CreateWindowWithProperties(props); window = SDL_CreateWindowWithProperties(props);
SDL_DestroyProperties(props); SDL_DestroyProperties(props);
@ -753,7 +760,9 @@ try_again:
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
const char* videoDriver = SDL_GetCurrentVideoDriver(); const char* videoDriver = SDL_GetCurrentVideoDriver();
if (idStr::Icmp(videoDriver, "wayland") == 0) { if (idStr::Icmp(videoDriver, "wayland") == 0) {
#if SDL_MAJOR_VERSION == 2 // don't enable this hack by default with SDL3
glConfig.shouldFillWindowAlpha = true; glConfig.shouldFillWindowAlpha = true;
#endif
glConfig.isWayland = true; glConfig.isWayland = true;
} }
#endif #endif