mirror of https://github.com/encounter/SDL.git
[KMS/DRM] Enable async pageflips.
This commit is contained in:
parent
9384e59561
commit
aac74db685
|
@ -72,12 +72,6 @@ SDL_EGL_CreateContext_impl(KMSDRM)
|
||||||
|
|
||||||
int KMSDRM_GLES_SetSwapInterval(_THIS, int interval) {
|
int KMSDRM_GLES_SetSwapInterval(_THIS, int interval) {
|
||||||
|
|
||||||
/* Issuing a new pageflip before the previous has completed
|
|
||||||
causes drmModePageFlip() to return EBUSY errors.
|
|
||||||
So just set egl_swapinterval to 1 to prevent that. */
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
if (!_this->egl_data) {
|
if (!_this->egl_data) {
|
||||||
return SDL_SetError("EGL not initialized");
|
return SDL_SetError("EGL not initialized");
|
||||||
}
|
}
|
||||||
|
@ -87,9 +81,6 @@ int KMSDRM_GLES_SetSwapInterval(_THIS, int interval) {
|
||||||
} else {
|
} else {
|
||||||
return SDL_SetError("Only swap intervals of 0 or 1 are supported");
|
return SDL_SetError("Only swap intervals of 0 or 1 are supported");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
_this->egl_data->egl_swapinterval = 1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -100,15 +91,15 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
|
||||||
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
|
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
|
||||||
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
||||||
KMSDRM_FBInfo *fb_info;
|
KMSDRM_FBInfo *fb_info;
|
||||||
int ret, timeout;
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Always wait for the previous issued flip before issing a new one,
|
||||||
|
even if you do async flips. */
|
||||||
|
uint32_t flip_flags = DRM_MODE_PAGE_FLIP_EVENT;
|
||||||
|
|
||||||
/* Wait for confirmation that the next front buffer has been flipped, at which
|
/* Wait for confirmation that the next front buffer has been flipped, at which
|
||||||
point the previous front buffer can be released */
|
point the previous front buffer can be released */
|
||||||
timeout = 0;
|
if (!KMSDRM_WaitPageFlip(_this, windata)) {
|
||||||
if (_this->egl_data->egl_swapinterval == 1) {
|
|
||||||
timeout = -1;
|
|
||||||
}
|
|
||||||
if (!KMSDRM_WaitPageFlip(_this, windata, timeout)) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,16 +153,27 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Issue pageflip on the next front buffer.
|
/* Issue pageflip on the next front buffer.
|
||||||
The pageflip will be done during the next vblank. */
|
Remember: drmModePageFlip() never blocks, it just issues the flip,
|
||||||
|
which will be done during the next vblank.
|
||||||
|
Since it will return EBUSY if we call it again without having
|
||||||
|
completed the last issued flip, we must pass the
|
||||||
|
DRM_MODE_PAGE_FLIP_ASYNC if we don't block on EGL (egl_swapinterval = 0).
|
||||||
|
That makes it flip immediately, without waiting for the next vblank,
|
||||||
|
so even if we don't block on EGL, it will have flipped when we
|
||||||
|
get back here. */
|
||||||
|
|
||||||
|
if (_this->egl_data->egl_swapinterval == 0) {
|
||||||
|
flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC;
|
||||||
|
}
|
||||||
|
|
||||||
ret = KMSDRM_drmModePageFlip(viddata->drm_fd, dispdata->crtc->crtc_id,
|
ret = KMSDRM_drmModePageFlip(viddata->drm_fd, dispdata->crtc->crtc_id,
|
||||||
fb_info->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &windata->waiting_for_flip);
|
fb_info->fb_id, flip_flags, &windata->waiting_for_flip);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
if (_this->egl_data->egl_swapinterval == 1) {
|
|
||||||
windata->waiting_for_flip = SDL_TRUE;
|
windata->waiting_for_flip = SDL_TRUE;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not queue pageflip: %d", ret);
|
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not queue pageflip: %d", ret);
|
||||||
|
printf("Could not queue pageflip: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we are in double-buffer mode, wait immediately for vsync
|
/* If we are in double-buffer mode, wait immediately for vsync
|
||||||
|
@ -179,7 +181,7 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
|
||||||
Run your SDL2 program with "SDL_KMSDRM_DOUBLE_BUFFER=1 <program_name>"
|
Run your SDL2 program with "SDL_KMSDRM_DOUBLE_BUFFER=1 <program_name>"
|
||||||
to enable this. */
|
to enable this. */
|
||||||
if (_this->egl_data->egl_swapinterval == 1 && windata->double_buffer) {
|
if (_this->egl_data->egl_swapinterval == 1 && windata->double_buffer) {
|
||||||
KMSDRM_WaitPageFlip(_this, windata, -1);
|
KMSDRM_WaitPageFlip(_this, windata);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -339,10 +339,12 @@ KMSDRM_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int us
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_bool
|
SDL_bool
|
||||||
KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) {
|
KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata) {
|
||||||
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
||||||
drmEventContext ev = {0};
|
drmEventContext ev = {0};
|
||||||
struct pollfd pfd = {0};
|
struct pollfd pfd = {0};
|
||||||
|
/* If the pageflip hasn't completed after 10 seconds, it nevel will. */
|
||||||
|
uint32_t timeout = 10000;
|
||||||
|
|
||||||
ev.version = DRM_EVENT_CONTEXT_VERSION;
|
ev.version = DRM_EVENT_CONTEXT_VERSION;
|
||||||
ev.page_flip_handler = KMSDRM_FlipHandler;
|
ev.page_flip_handler = KMSDRM_FlipHandler;
|
||||||
|
@ -353,21 +355,25 @@ KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) {
|
||||||
while (windata->waiting_for_flip) {
|
while (windata->waiting_for_flip) {
|
||||||
pfd.revents = 0;
|
pfd.revents = 0;
|
||||||
|
|
||||||
|
/* poll() waits for events arriving on the FD, and returns < 0 if timeout
|
||||||
|
passes with no events. */
|
||||||
if (poll(&pfd, 1, timeout) < 0) {
|
if (poll(&pfd, 1, timeout) < 0) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
|
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfd.revents & (POLLHUP | POLLERR)) {
|
if (pfd.revents & (POLLHUP | POLLERR)) {
|
||||||
|
/* An event arrived on the FD in time, but it's an error. */
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error");
|
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error");
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfd.revents & POLLIN) {
|
if (pfd.revents & POLLIN) {
|
||||||
/* Page flip? If so, drmHandleEvent will unset windata->waiting_for_flip */
|
/* There is data to read on the FD!
|
||||||
|
Is the event a pageflip? If so, drmHandleEvent will
|
||||||
|
unset windata->waiting_for_flip */
|
||||||
KMSDRM_drmHandleEvent(viddata->drm_fd, &ev);
|
KMSDRM_drmHandleEvent(viddata->drm_fd, &ev);
|
||||||
} else {
|
} else {
|
||||||
/* Timed out and page flip didn't happen */
|
|
||||||
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip");
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip");
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -650,7 +656,7 @@ KMSDRM_DestroySurfaces(_THIS, SDL_Window *window)
|
||||||
/**********************************************/
|
/**********************************************/
|
||||||
/* Wait for last issued pageflip to complete. */
|
/* Wait for last issued pageflip to complete. */
|
||||||
/**********************************************/
|
/**********************************************/
|
||||||
KMSDRM_WaitPageFlip(_this, windata, -1);
|
KMSDRM_WaitPageFlip(_this, windata);
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
/* Restore the original CRTC configuration: configue the crtc with the */
|
/* Restore the original CRTC configuration: configue the crtc with the */
|
||||||
|
|
|
@ -114,7 +114,7 @@ typedef struct KMSDRM_FBInfo
|
||||||
int KMSDRM_CreateSurfaces(_THIS, SDL_Window * window);
|
int KMSDRM_CreateSurfaces(_THIS, SDL_Window * window);
|
||||||
KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo);
|
KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo);
|
||||||
KMSDRM_FBInfo *KMSDRM_FBFromBO2(_THIS, struct gbm_bo *bo, int w, int h);
|
KMSDRM_FBInfo *KMSDRM_FBFromBO2(_THIS, struct gbm_bo *bo, int w, int h);
|
||||||
SDL_bool KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout);
|
SDL_bool KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata);
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* SDL_VideoDevice functions declaration */
|
/* SDL_VideoDevice functions declaration */
|
||||||
|
|
Loading…
Reference in New Issue