mirror of https://github.com/encounter/SDL.git
Fixed bug 3943 - General SDL_HINT_VIDEO_DOUBLE_BUFFER hint support
This commit is contained in:
parent
5cc46f3d30
commit
9f4e4be8e0
|
@ -798,14 +798,22 @@ extern "C" {
|
||||||
#define SDL_HINT_RPI_VIDEO_LAYER "SDL_RPI_VIDEO_LAYER"
|
#define SDL_HINT_RPI_VIDEO_LAYER "SDL_RPI_VIDEO_LAYER"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Tell SDL the KMS/DRM video driver that we want double buffer only.
|
* \brief Tell the video driver that we only want a double buffer.
|
||||||
*
|
*
|
||||||
* By default KMS/DRM will use a triple buffer solution that wastes no CPU
|
* By default, most lowlevel 2D APIs will use a triple buffer scheme that
|
||||||
* time on waiting for vsync after issuing a flip, but introduces a frame of
|
* wastes no CPU time on waiting for vsync after issuing a flip, but
|
||||||
* latency. Waiting for vsync immediately after issuing a flip on the other
|
* introduces a frame of latency. On the other hand, using a double buffer
|
||||||
* hand is recommended for cases where low latency is an important factor.
|
* scheme instead is recommended for cases where low latency is an important
|
||||||
|
* factor because we save a whole frame of latency.
|
||||||
|
* We do so by waiting for vsync immediately after issuing a flip, usually just
|
||||||
|
* after eglSwapBuffers call in the backend's *_SwapWindow function.
|
||||||
|
*
|
||||||
|
* Since it's driver-specific, it's only supported where possible and
|
||||||
|
* implemented. Currently supported the following drivers:
|
||||||
|
* - KMSDRM (kmsdrm)
|
||||||
|
* - Raspberry Pi (raspberrypi)
|
||||||
*/
|
*/
|
||||||
#define SDL_HINT_KMSDRM_DOUBLE_BUFFER "SDL_KMSDRM_DOUBLE_BUFFER"
|
#define SDL_HINT_VIDEO_DOUBLE_BUFFER "SDL_VIDEO_DOUBLE_BUFFER"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief A variable controlling what driver to use for OpenGL ES contexts.
|
* \brief A variable controlling what driver to use for OpenGL ES contexts.
|
||||||
|
|
|
@ -525,7 +525,7 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
|
||||||
|
|
||||||
/* In case we want low-latency, double-buffer video, we take note here */
|
/* In case we want low-latency, double-buffer video, we take note here */
|
||||||
wdata->double_buffer = SDL_FALSE;
|
wdata->double_buffer = SDL_FALSE;
|
||||||
if (SDL_GetHintBoolean(SDL_HINT_KMSDRM_DOUBLE_BUFFER, SDL_FALSE)) {
|
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) {
|
||||||
wdata->double_buffer = SDL_TRUE;
|
wdata->double_buffer = SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
#include "../../SDL_internal.h"
|
#include "../../SDL_internal.h"
|
||||||
|
#include "SDL_hints.h"
|
||||||
|
#include "SDL_log.h"
|
||||||
|
|
||||||
#if SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL
|
#if SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL
|
||||||
|
|
||||||
|
@ -40,8 +42,27 @@ RPI_GLES_LoadLibrary(_THIS, const char *path) {
|
||||||
return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0);
|
return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
RPI_GLES_SwapWindow(_THIS, SDL_Window * window) {
|
||||||
|
SDL_WindowData *wdata = ((SDL_WindowData *) window->driverdata);
|
||||||
|
|
||||||
|
if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, wdata->egl_surface))) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait immediately for vsync (as if we only had two buffers), for low input-lag scenarios.
|
||||||
|
* Run your SDL2 program with "SDL_RPI_DOUBLE_BUFFER=1 <program_name>" to enable this. */
|
||||||
|
if (wdata->double_buffer) {
|
||||||
|
SDL_LockMutex(wdata->vsync_cond_mutex);
|
||||||
|
SDL_CondWait(wdata->vsync_cond, wdata->vsync_cond_mutex);
|
||||||
|
SDL_UnlockMutex(wdata->vsync_cond_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_EGL_CreateContext_impl(RPI)
|
SDL_EGL_CreateContext_impl(RPI)
|
||||||
SDL_EGL_SwapWindow_impl(RPI)
|
|
||||||
SDL_EGL_MakeCurrent_impl(RPI)
|
SDL_EGL_MakeCurrent_impl(RPI)
|
||||||
|
|
||||||
#endif /* SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL */
|
#endif /* SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL */
|
||||||
|
|
|
@ -214,6 +214,16 @@ RPI_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RPI_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
|
||||||
|
{
|
||||||
|
SDL_WindowData *wdata = ((SDL_WindowData *) data);
|
||||||
|
|
||||||
|
SDL_LockMutex(wdata->vsync_cond_mutex);
|
||||||
|
SDL_CondSignal(wdata->vsync_cond);
|
||||||
|
SDL_UnlockMutex(wdata->vsync_cond_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
RPI_CreateWindow(_THIS, SDL_Window * window)
|
RPI_CreateWindow(_THIS, SDL_Window * window)
|
||||||
{
|
{
|
||||||
|
@ -289,6 +299,15 @@ RPI_CreateWindow(_THIS, SDL_Window * window)
|
||||||
return SDL_SetError("Could not create GLES window surface");
|
return SDL_SetError("Could not create GLES window surface");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start generating vsync callbacks if necesary */
|
||||||
|
wdata->double_buffer = SDL_FALSE;
|
||||||
|
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) {
|
||||||
|
wdata->vsync_cond = SDL_CreateCond();
|
||||||
|
wdata->vsync_cond_mutex = SDL_CreateMutex();
|
||||||
|
wdata->double_buffer = SDL_TRUE;
|
||||||
|
vc_dispmanx_vsync_callback(displaydata->dispman_display, RPI_vsync_callback, (void*)wdata);
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup driver data for this window */
|
/* Setup driver data for this window */
|
||||||
window->driverdata = wdata;
|
window->driverdata = wdata;
|
||||||
|
|
||||||
|
@ -304,7 +323,22 @@ void
|
||||||
RPI_DestroyWindow(_THIS, SDL_Window * window)
|
RPI_DestroyWindow(_THIS, SDL_Window * window)
|
||||||
{
|
{
|
||||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||||
|
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
|
||||||
|
SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
|
||||||
|
|
||||||
if(data) {
|
if(data) {
|
||||||
|
if (data->double_buffer) {
|
||||||
|
/* Wait for vsync, and then stop vsync callbacks and destroy related stuff, if needed */
|
||||||
|
SDL_LockMutex(data->vsync_cond_mutex);
|
||||||
|
SDL_CondWait(data->vsync_cond, data->vsync_cond_mutex);
|
||||||
|
SDL_UnlockMutex(data->vsync_cond_mutex);
|
||||||
|
|
||||||
|
vc_dispmanx_vsync_callback(displaydata->dispman_display, NULL, NULL);
|
||||||
|
|
||||||
|
SDL_DestroyCond(data->vsync_cond);
|
||||||
|
SDL_DestroyMutex(data->vsync_cond_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
#if SDL_VIDEO_OPENGL_EGL
|
#if SDL_VIDEO_OPENGL_EGL
|
||||||
if (data->egl_surface != EGL_NO_SURFACE) {
|
if (data->egl_surface != EGL_NO_SURFACE) {
|
||||||
SDL_EGL_DestroySurface(_this, data->egl_surface);
|
SDL_EGL_DestroySurface(_this, data->egl_surface);
|
||||||
|
|
|
@ -48,6 +48,12 @@ typedef struct SDL_WindowData
|
||||||
#if SDL_VIDEO_OPENGL_EGL
|
#if SDL_VIDEO_OPENGL_EGL
|
||||||
EGLSurface egl_surface;
|
EGLSurface egl_surface;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Vsync callback cond and mutex */
|
||||||
|
SDL_cond *vsync_cond;
|
||||||
|
SDL_mutex *vsync_cond_mutex;
|
||||||
|
SDL_bool double_buffer;
|
||||||
|
|
||||||
} SDL_WindowData;
|
} SDL_WindowData;
|
||||||
|
|
||||||
#define SDL_RPI_VIDEOLAYER 10000 /* High enough so to occlude everything */
|
#define SDL_RPI_VIDEOLAYER 10000 /* High enough so to occlude everything */
|
||||||
|
|
Loading…
Reference in New Issue