r_fillWindowAlphaChan: controls filling alpha chan in RB_SwapBuffers()

added that, removed r_waylandcompat (it never worked properly anyway),
so now the window always has an alpha chan, and by default dhewm3 tries
to guess whether it should be made opaque at the end of a frame or not
This commit is contained in:
Daniel Gibson 2022-02-05 06:08:46 +01:00
parent ded470f137
commit 1108c16034
3 changed files with 93 additions and 53 deletions

View file

@ -88,6 +88,10 @@ typedef struct glconfig_s {
bool allowARB2Path;
bool isInitialized;
// DG: current video backend is known to need opaque default framebuffer
// used if r_fillWindowAlphaChan == -1
bool shouldFillWindowAlpha;
} glconfig_t;

View file

@ -29,6 +29,8 @@ 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)" );
frameData_t *frameData;
backEndState_t backEnd;
@ -529,69 +531,71 @@ const void RB_SwapBuffers( const void *data ) {
RB_ShowImages();
}
#if 01 // set alpha chan to 1.0:
bool blendEnabled = qglIsEnabled( GL_BLEND );
if ( !blendEnabled )
qglEnable( GL_BLEND );
int fillAlpha = r_fillWindowAlphaChan.GetInteger();
if ( fillAlpha == 1 || (fillAlpha == -1 && glConfig.shouldFillWindowAlpha) )
{
// make sure the whole alpha chan of the (default) framebuffer is opaque.
// at least Wayland needs this, see also the big comment in GLimp_Init()
// TODO: GL_DEPTH_TEST ? (should be disabled, if it needs changing at all)
bool blendEnabled = qglIsEnabled( GL_BLEND );
if ( !blendEnabled )
qglEnable( GL_BLEND );
bool scissorEnabled = qglIsEnabled( GL_SCISSOR_TEST );
if( scissorEnabled )
qglDisable( GL_SCISSOR_TEST );
// TODO: GL_DEPTH_TEST ? (should be disabled, if it needs changing at all)
bool tex2Denabled = qglIsEnabled( GL_TEXTURE_2D );
if( tex2Denabled )
qglDisable( GL_TEXTURE_2D );
bool scissorEnabled = qglIsEnabled( GL_SCISSOR_TEST );
if( scissorEnabled )
qglDisable( GL_SCISSOR_TEST );
qglDisable( GL_VERTEX_PROGRAM_ARB );
qglDisable( GL_FRAGMENT_PROGRAM_ARB );
bool tex2Denabled = qglIsEnabled( GL_TEXTURE_2D );
if( tex2Denabled )
qglDisable( GL_TEXTURE_2D );
qglBlendEquation( GL_FUNC_ADD );
//qglBlendEquation(GL_MAX);
qglDisable( GL_VERTEX_PROGRAM_ARB );
qglDisable( GL_FRAGMENT_PROGRAM_ARB );
qglBlendFunc( GL_ONE, GL_ONE );
qglBlendEquation( GL_FUNC_ADD );
// setup transform matrices so we can easily/reliably draw a fullscreen quad
qglMatrixMode( GL_MODELVIEW );
qglPushMatrix();
qglLoadIdentity();
qglBlendFunc( GL_ONE, GL_ONE );
qglMatrixMode( GL_PROJECTION );
qglPushMatrix();
qglLoadIdentity();
qglOrtho( 0, 1, 0, 1, -1, 1 );
// setup transform matrices so we can easily/reliably draw a fullscreen quad
qglMatrixMode( GL_MODELVIEW );
qglPushMatrix();
qglLoadIdentity();
// draw screen-sized quad with color (0.0, 0.0, 0.0, 1.0)
float x=0, y=0, w=1, h=1;
qglColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
// debug values:
//float x = 0.1, y = 0.1, w = 0.8, h = 0.8;
//qglColor4f( 0.0f, 0.0f, 0.5f, 1.0f );
qglBegin( GL_QUADS );
qglVertex2f( x, y ); // ( 0,0 );
qglVertex2f( x, y+h ); // ( 0,1 );
qglVertex2f( x+w, y+h ); // ( 1,1 );
qglVertex2f( x+w, y ); // ( 1,0 );
qglEnd();
qglMatrixMode( GL_PROJECTION );
qglPushMatrix();
qglLoadIdentity();
qglOrtho( 0, 1, 0, 1, -1, 1 );
// restore previous transform matrix states
qglPopMatrix(); // for projection
qglMatrixMode( GL_MODELVIEW );
qglPopMatrix(); // for modelview
// draw screen-sized quad with color (0.0, 0.0, 0.0, 1.0)
const float x=0, y=0, w=1, h=1;
qglColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
// debug values:
//const float x = 0.1, y = 0.1, w = 0.8, h = 0.8;
//qglColor4f( 0.0f, 0.0f, 0.5f, 1.0f );
// restore default or previous states
qglBlendEquation( GL_FUNC_ADD );
if ( !blendEnabled )
qglDisable( GL_BLEND );
if( tex2Denabled )
qglEnable( GL_TEXTURE_2D );
if( scissorEnabled )
qglEnable( GL_SCISSOR_TEST );
qglBegin( GL_QUADS );
qglVertex2f( x, y ); // ( 0,0 );
qglVertex2f( x, y+h ); // ( 0,1 );
qglVertex2f( x+w, y+h ); // ( 1,1 );
qglVertex2f( x+w, y ); // ( 1,0 );
qglEnd();
// TODO: theoretically I should restore the glColor value, but I'm sure it'll be set before it's needed anyway
#endif
// restore previous transform matrix states
qglPopMatrix(); // for projection
qglMatrixMode( GL_MODELVIEW );
qglPopMatrix(); // for modelview
// restore default or previous states
qglBlendEquation( GL_FUNC_ADD );
if ( !blendEnabled )
qglDisable( GL_BLEND );
if( tex2Denabled )
qglEnable( GL_TEXTURE_2D );
if( scissorEnabled )
qglEnable( GL_SCISSOR_TEST );
}
// force a gl sync if requested
if ( r_finish.GetBool() ) {

View file

@ -97,7 +97,6 @@ If you have questions concerning this license or the applicable additional terms
#endif // _WIN32 and ID_ALLOW_TOOLS
idCVar r_waylandcompat("r_waylandcompat", "0", CVAR_SYSTEM | CVAR_NOCHEAT | CVAR_ARCHIVE, "wayland compatible framebuffer");
#if SDL_VERSION_ATLEAST(2, 0, 0)
static SDL_Window *window = NULL;
@ -163,6 +162,30 @@ bool GLimp_Init(glimpParms_t parms) {
flags |= SDL_WINDOW_FULLSCREEN;
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
/* Doom3 has the nasty habit of modifying the default framebuffer's alpha channel and then
* relying on those modifications in blending operations (using GL_DST_(ONE_MINUS_)ALPHA).
* So far that hasn't been much of a problem, because Windows, macOS, X11 etc
* just ignore the alpha chan (unless maybe you explicitly tell a window it should be transparent).
* Unfortunately, Wayland by default *does* use the alpha channel, which often leads to
* 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
* 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) */
#ifdef SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY
SDL_SetHint(SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, "1");
#else // 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
#endif
int colorbits = 24;
int depthbits = 24;
int stencilbits = 8;
@ -227,7 +250,7 @@ bool GLimp_Init(glimpParms_t parms) {
if (tcolorbits == 24)
channelcolorbits = 8;
int talphabits = r_waylandcompat.GetBool() ? 0 : channelcolorbits;
int talphabits = channelcolorbits;
try_again:
@ -535,6 +558,15 @@ try_again:
glConfig.displayFrequency = 0;
// for r_fillWindowAlphaChan -1, see also the big comment above
glConfig.shouldFillWindowAlpha = false;
#if SDL_VERSION_ATLEAST(2, 0, 0)
const char* videoDriver = SDL_GetCurrentVideoDriver();
if (idStr::Icmp(videoDriver, "wayland") == 0) {
glConfig.shouldFillWindowAlpha = true;
}
#endif
break;
}