x11: Deal with difference in GLX_EXT_swap_control_tear behavior.
Mesa and Nvidia handle it differently, and one or the other may fix their implementation in the future, so test which way it works at runtime. Reference Issue #8004.main
parent
08fac5b1b2
commit
74a2542564
|
@ -237,6 +237,8 @@ int X11_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||||
return SDL_SetError("GLX is not supported");
|
return SDL_SetError("GLX is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_UNTESTED;
|
||||||
|
|
||||||
/* Initialize extensions */
|
/* Initialize extensions */
|
||||||
/* See lengthy comment about the inc/dec in
|
/* See lengthy comment about the inc/dec in
|
||||||
../windows/SDL_windowsopengl.c. */
|
../windows/SDL_windowsopengl.c. */
|
||||||
|
@ -902,7 +904,6 @@ int X11_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval)
|
||||||
X11_GL_GetSwapInterval(_this, ¤tInterval);
|
X11_GL_GetSwapInterval(_this, ¤tInterval);
|
||||||
_this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
|
_this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
|
||||||
_this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
|
_this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
|
||||||
|
|
||||||
status = 0;
|
status = 0;
|
||||||
swapinterval = interval;
|
swapinterval = interval;
|
||||||
} else if (_this->gl_data->glXSwapIntervalMESA) {
|
} else if (_this->gl_data->glXSwapIntervalMESA) {
|
||||||
|
@ -925,6 +926,53 @@ int X11_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_GLSwapIntervalTearBehavior CheckSwapIntervalTearBehavior(SDL_VideoDevice *_this, Window drawable, unsigned int current_val, unsigned int current_allow_late)
|
||||||
|
{
|
||||||
|
/* Mesa and Nvidia interpret GLX_EXT_swap_control_tear differently, as of this writing, so
|
||||||
|
figure out which behavior we have.
|
||||||
|
Technical details: https://github.com/libsdl-org/SDL/issues/8004#issuecomment-1819603282 */
|
||||||
|
if (_this->gl_data->swap_interval_tear_behavior == SDL_SWAPINTERVALTEAR_UNTESTED) {
|
||||||
|
if (!_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
|
||||||
|
_this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_UNKNOWN;
|
||||||
|
} else {
|
||||||
|
Display *display = _this->driverdata->display;
|
||||||
|
unsigned int allow_late_swap_tearing = 22;
|
||||||
|
int original_val = (int) current_val;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a workaround for a bug in NVIDIA drivers. Bug has been reported
|
||||||
|
* and will be fixed in a future release (probably 319.xx).
|
||||||
|
*
|
||||||
|
* There's a bug where glXSetSwapIntervalEXT ignores updates because
|
||||||
|
* it has the wrong value cached. To work around it, we just run a no-op
|
||||||
|
* update to the current value.
|
||||||
|
*/
|
||||||
|
_this->gl_data->glXSwapIntervalEXT(display, drawable, current_val);
|
||||||
|
|
||||||
|
/* set it to no swap interval and see how it affects GLX_LATE_SWAPS_TEAR_EXT... */
|
||||||
|
_this->gl_data->glXSwapIntervalEXT(display, drawable, 0);
|
||||||
|
_this->gl_data->glXQueryDrawable(display, drawable, GLX_LATE_SWAPS_TEAR_EXT, &allow_late_swap_tearing);
|
||||||
|
|
||||||
|
if (allow_late_swap_tearing == 0) { /* GLX_LATE_SWAPS_TEAR_EXT says whether late swapping is currently in use */
|
||||||
|
_this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_NVIDIA;
|
||||||
|
if (current_allow_late) {
|
||||||
|
original_val = -original_val;
|
||||||
|
}
|
||||||
|
} else if (allow_late_swap_tearing == 1) { /* GLX_LATE_SWAPS_TEAR_EXT says whether the Drawable can use late swapping at all */
|
||||||
|
_this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_MESA;
|
||||||
|
} else { /* unexpected outcome! */
|
||||||
|
_this->gl_data->swap_interval_tear_behavior = SDL_SWAPINTERVALTEAR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set us back to what it was originally... */
|
||||||
|
_this->gl_data->glXSwapIntervalEXT(display, drawable, original_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _this->gl_data->swap_interval_tear_behavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int X11_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
|
int X11_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
|
||||||
{
|
{
|
||||||
if (_this->gl_data->glXSwapIntervalEXT) {
|
if (_this->gl_data->glXSwapIntervalEXT) {
|
||||||
|
@ -935,6 +983,7 @@ int X11_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
|
||||||
unsigned int val = 0;
|
unsigned int val = 0;
|
||||||
|
|
||||||
if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
|
if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
|
||||||
|
allow_late_swap_tearing = 22; /* set this to nonsense. */
|
||||||
_this->gl_data->glXQueryDrawable(display, drawable,
|
_this->gl_data->glXQueryDrawable(display, drawable,
|
||||||
GLX_LATE_SWAPS_TEAR_EXT,
|
GLX_LATE_SWAPS_TEAR_EXT,
|
||||||
&allow_late_swap_tearing);
|
&allow_late_swap_tearing);
|
||||||
|
@ -943,12 +992,21 @@ int X11_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
|
||||||
_this->gl_data->glXQueryDrawable(display, drawable,
|
_this->gl_data->glXQueryDrawable(display, drawable,
|
||||||
GLX_SWAP_INTERVAL_EXT, &val);
|
GLX_SWAP_INTERVAL_EXT, &val);
|
||||||
|
|
||||||
if ((allow_late_swap_tearing) && (val > 0)) {
|
*interval = (int)val;
|
||||||
*interval = -((int)val);
|
|
||||||
return 0;
|
switch (CheckSwapIntervalTearBehavior(_this, drawable, val, allow_late_swap_tearing)) {
|
||||||
|
case SDL_SWAPINTERVALTEAR_MESA:
|
||||||
|
*interval = (int)val; /* unsigned int cast to signed that generates negative value if necessary. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_SWAPINTERVALTEAR_NVIDIA:
|
||||||
|
default:
|
||||||
|
if ((allow_late_swap_tearing) && (val > 0)) {
|
||||||
|
*interval = -((int)val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
*interval = (int)val;
|
|
||||||
return 0;
|
return 0;
|
||||||
} else if (_this->gl_data->glXGetSwapIntervalMESA) {
|
} else if (_this->gl_data->glXGetSwapIntervalMESA) {
|
||||||
int val = _this->gl_data->glXGetSwapIntervalMESA();
|
int val = _this->gl_data->glXGetSwapIntervalMESA();
|
||||||
|
|
|
@ -29,6 +29,14 @@
|
||||||
|
|
||||||
typedef void (*__GLXextFuncPtr)(void);
|
typedef void (*__GLXextFuncPtr)(void);
|
||||||
|
|
||||||
|
typedef enum SDL_GLSwapIntervalTearBehavior
|
||||||
|
{
|
||||||
|
SDL_SWAPINTERVALTEAR_UNTESTED,
|
||||||
|
SDL_SWAPINTERVALTEAR_UNKNOWN,
|
||||||
|
SDL_SWAPINTERVALTEAR_MESA,
|
||||||
|
SDL_SWAPINTERVALTEAR_NVIDIA
|
||||||
|
} SDL_GLSwapIntervalTearBehavior;
|
||||||
|
|
||||||
struct SDL_GLDriverData
|
struct SDL_GLDriverData
|
||||||
{
|
{
|
||||||
int errorBase, eventBase;
|
int errorBase, eventBase;
|
||||||
|
@ -50,6 +58,8 @@ struct SDL_GLDriverData
|
||||||
int minor;
|
int minor;
|
||||||
} es_profile_max_supported_version;
|
} es_profile_max_supported_version;
|
||||||
|
|
||||||
|
SDL_GLSwapIntervalTearBehavior swap_interval_tear_behavior;
|
||||||
|
|
||||||
Bool (*glXQueryExtension)(Display *, int *, int *);
|
Bool (*glXQueryExtension)(Display *, int *, int *);
|
||||||
__GLXextFuncPtr (*glXGetProcAddress)(const GLubyte *);
|
__GLXextFuncPtr (*glXGetProcAddress)(const GLubyte *);
|
||||||
XVisualInfo *(*glXChooseVisual)(Display *, int, int *);
|
XVisualInfo *(*glXChooseVisual)(Display *, int, int *);
|
||||||
|
|
|
@ -199,6 +199,17 @@ static void Render(void)
|
||||||
ctx.glRotatef(5.0, 1.0, 1.0, 1.0);
|
ctx.glRotatef(5.0, 1.0, 1.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void LogSwapInterval(void)
|
||||||
|
{
|
||||||
|
int interval = 0;
|
||||||
|
const int ret_interval = SDL_GL_GetSwapInterval(&interval);
|
||||||
|
if (ret_interval < 0) {
|
||||||
|
SDL_Log("Swap Interval : %d error: %s\n", interval, SDL_GetError());
|
||||||
|
} else {
|
||||||
|
SDL_Log("Swap Interval : %d\n", interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int fsaa, accel;
|
int fsaa, accel;
|
||||||
|
@ -211,8 +222,6 @@ int main(int argc, char *argv[])
|
||||||
int status;
|
int status;
|
||||||
int dw, dh;
|
int dw, dh;
|
||||||
int swap_interval = 0;
|
int swap_interval = 0;
|
||||||
int interval = 0;
|
|
||||||
int ret_interval = 0;
|
|
||||||
|
|
||||||
/* Initialize parameters */
|
/* Initialize parameters */
|
||||||
fsaa = 0;
|
fsaa = 0;
|
||||||
|
@ -304,12 +313,7 @@ int main(int argc, char *argv[])
|
||||||
SDL_Log("Screen BPP : %" SDL_PRIu32 "\n", SDL_BITSPERPIXEL(mode->format));
|
SDL_Log("Screen BPP : %" SDL_PRIu32 "\n", SDL_BITSPERPIXEL(mode->format));
|
||||||
}
|
}
|
||||||
|
|
||||||
ret_interval = SDL_GL_GetSwapInterval(&interval);
|
LogSwapInterval();
|
||||||
if (ret_interval < 0) {
|
|
||||||
SDL_Log("Swap Interval : %d error: %s\n", interval, SDL_GetError());
|
|
||||||
} else {
|
|
||||||
SDL_Log("Swap Interval : %d\n", interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GetWindowSize(state->windows[0], &dw, &dh);
|
SDL_GetWindowSize(state->windows[0], &dw, &dh);
|
||||||
SDL_Log("Window Size : %d,%d\n", dw, dh);
|
SDL_Log("Window Size : %d,%d\n", dw, dh);
|
||||||
|
@ -421,6 +425,7 @@ int main(int argc, char *argv[])
|
||||||
SDL_GL_MakeCurrent(state->windows[i], context);
|
SDL_GL_MakeCurrent(state->windows[i], context);
|
||||||
if (update_swap_interval) {
|
if (update_swap_interval) {
|
||||||
SDL_GL_SetSwapInterval(swap_interval);
|
SDL_GL_SetSwapInterval(swap_interval);
|
||||||
|
LogSwapInterval();
|
||||||
}
|
}
|
||||||
SDL_GetWindowSizeInPixels(state->windows[i], &w, &h);
|
SDL_GetWindowSizeInPixels(state->windows[i], &w, &h);
|
||||||
ctx.glViewport(0, 0, w, h);
|
ctx.glViewport(0, 0, w, h);
|
||||||
|
|
Loading…
Reference in New Issue