Hopefully fix screenshots on Wayland

- screenshots on native wayland (SDL_VIDEODRIVER=wayland) were black,
  at least on Gnome
  => fixed(?) by reading from the default (back) buffer instead of
     the front buffer
- after taking a screenshot, resizing the window (or switching to
  fullscreen) was broken (window remained black or became invisible
  or partly contained garbage), both with native wayland and xwayland
  => fixed by restoring the glReadBuffer state after reading the pixels
This commit is contained in:
Daniel Gibson 2024-07-03 20:06:20 +02:00
parent 5c7aacb954
commit b2ba15425c
3 changed files with 19 additions and 2 deletions

View file

@ -93,6 +93,7 @@ typedef struct glconfig_s {
// DG: current video backend is known to need opaque default framebuffer
// used if r_fillWindowAlphaChan == -1
bool shouldFillWindowAlpha;
bool isWayland; // DG: for other wayland-specific hacks.. (does *not* detect XWayland!)
// For some reason people decided that we need displays with ultra small pixels,
// so everything rendered on them must be scaled up to be legible.

View file

@ -1251,8 +1251,22 @@ void R_ReadTiledPixels( int width, int height, byte *buffer, renderView_t *ref =
h = height - yo;
}
qglReadBuffer( GL_FRONT );
qglReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, temp );
if ( glConfig.isWayland ) {
// DG: Native Wayland (=> not XWayland) doesn't seem to support reading
// from the front buffer - screenshot is black then..
// So just read from the default (probably back-) buffer
qglReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, temp );
} else {
// DG: It's probably better to restore the glReadBuffer mode after reading the pixels..
// (at least with XWayland on GNOME changing resolutions is wonky when not doing this)
GLint oldReadBuf = GL_BACK;
qglGetIntegerv( GL_READ_BUFFER, &oldReadBuf );
qglReadBuffer( GL_FRONT );
qglReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, temp );
qglReadBuffer( oldReadBuf );
}
int row = ( w * 3 + 3 ) & ~3; // OpenGL pads to dword boundaries

View file

@ -579,10 +579,12 @@ try_again:
// for r_fillWindowAlphaChan -1, see also the big comment above
glConfig.shouldFillWindowAlpha = false;
glConfig.isWayland = false;
#if SDL_VERSION_ATLEAST(2, 0, 0)
const char* videoDriver = SDL_GetCurrentVideoDriver();
if (idStr::Icmp(videoDriver, "wayland") == 0) {
glConfig.shouldFillWindowAlpha = true;
glConfig.isWayland = true;
}
#endif