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"
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;
backEndState_t backEnd;

View file

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

View file

@ -30,9 +30,6 @@ If you have questions concerning this license or the applicable additional terms
#ifdef D3_SDL3
#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
#include <SDL_cpuinfo.h>
#endif
@ -208,8 +205,11 @@ int Sys_GetProcessorId( void ) {
if (SDL_HasMMX())
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())
flags |= CPUID_3DNOW;
#endif
if (SDL_HasSSE())
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
// FIXME: at some point I need to enable (and possibly later disable) SDL_TextInput!
#else // SDL2 and SDL1.2
#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)
// 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
static char s[128] = {0};
static size_t s_pos = 0;
@ -1229,6 +1229,9 @@ sysEvent_t Sys_GetEvent() {
}
#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;
if (c) {
@ -1421,6 +1424,7 @@ sysEvent_t Sys_GetEvent() {
if (ev.key.state == SDL_PRESSED && (ev.key.keysym.unicode & 0xff00) == 0)
c = ev.key.keysym.unicode & 0xff;
#endif
// Note: c will be sent as SE_CHAR next time this function is called
return res;
@ -1440,7 +1444,9 @@ sysEvent_t Sys_GetEvent() {
memcpy( s, ev.text.text, SDL_TEXTINPUTEVENT_TEXT_SIZE );
s[SDL_TEXTINPUTEVENT_TEXT_SIZE] = '\0';
#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;
} 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[0] = '\0';
} 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;
}

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).
* 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).
* Unfortunately, the implementation of that extension is (currently?) broken (at least
* in Mesa), seems like they just give you a visual without any alpha chan - which doesn't
* Unfortunately, the implementation of that extension was broken (at least in Mesa before 24.1),
* 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.
* 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
* 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
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
SDL_SetHint("SDL_VIDEO_EGL_ALLOW_TRANSPARENCY", "1");
#endif
// Note: for SDL3 we use SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN below
#endif
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_HEIGHT_NUMBER, parms.height);
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);
// as replacement for SDL_VIDEO_EGL_ALLOW_TRANSPARENCY - but when?
// I don't want this on all platforms.. but can I already detect wayland at this point?
// Also: recent mesa versions should have this fixed, so maybe ignore the issue for SDL3? what about nvidia?
// See above for the big comment about Wayland and alpha channels.
// When using SDL3 I assume that people usually won't be affected by this bug,
// because it's fixed in recent Mesa versions (and also works with the NVIDIA driver).
// 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);
SDL_DestroyProperties(props);
@ -753,7 +760,9 @@ try_again:
#if SDL_VERSION_ATLEAST(2, 0, 0)
const char* videoDriver = SDL_GetCurrentVideoDriver();
if (idStr::Icmp(videoDriver, "wayland") == 0) {
#if SDL_MAJOR_VERSION == 2 // don't enable this hack by default with SDL3
glConfig.shouldFillWindowAlpha = true;
#endif
glConfig.isWayland = true;
}
#endif