[KMS/DRM] Enable async pageflips.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
diff --git a/src/video/kmsdrm/SDL_kmsdrmopengles.c b/src/video/kmsdrm/SDL_kmsdrmopengles.c
index a20a494..8881907 100644
--- a/src/video/kmsdrm/SDL_kmsdrmopengles.c
+++ b/src/video/kmsdrm/SDL_kmsdrmopengles.c
@@ -72,12 +72,6 @@ SDL_EGL_CreateContext_impl(KMSDRM)
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) {
return SDL_SetError("EGL not initialized");
}
@@ -87,9 +81,6 @@ int KMSDRM_GLES_SetSwapInterval(_THIS, int interval) {
} else {
return SDL_SetError("Only swap intervals of 0 or 1 are supported");
}
-#endif
-
- _this->egl_data->egl_swapinterval = 1;
return 0;
}
@@ -100,15 +91,15 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
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
point the previous front buffer can be released */
- timeout = 0;
- if (_this->egl_data->egl_swapinterval == 1) {
- timeout = -1;
- }
- if (!KMSDRM_WaitPageFlip(_this, windata, timeout)) {
+ if (!KMSDRM_WaitPageFlip(_this, windata)) {
return 0;
}
@@ -162,16 +153,27 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
}
/* 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,
- 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 (_this->egl_data->egl_swapinterval == 1) {
- windata->waiting_for_flip = SDL_TRUE;
- }
+ windata->waiting_for_flip = SDL_TRUE;
} else {
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
@@ -179,7 +181,7 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
Run your SDL2 program with "SDL_KMSDRM_DOUBLE_BUFFER=1 <program_name>"
to enable this. */
if (_this->egl_data->egl_swapinterval == 1 && windata->double_buffer) {
- KMSDRM_WaitPageFlip(_this, windata, -1);
+ KMSDRM_WaitPageFlip(_this, windata);
}
return 0;
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index 1099c35..b47e90f 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -339,11 +339,13 @@ KMSDRM_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int us
}
SDL_bool
-KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) {
+KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata) {
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
drmEventContext ev = {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.page_flip_handler = KMSDRM_FlipHandler;
@@ -353,21 +355,25 @@ KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) {
while (windata->waiting_for_flip) {
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) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
return SDL_FALSE;
}
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");
return SDL_FALSE;
}
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);
} else {
- /* Timed out and page flip didn't happen */
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip");
return SDL_FALSE;
}
@@ -650,7 +656,7 @@ KMSDRM_DestroySurfaces(_THIS, SDL_Window *window)
/**********************************************/
/* 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 */
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.h b/src/video/kmsdrm/SDL_kmsdrmvideo.h
index d089e10..aeff052 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.h
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.h
@@ -114,7 +114,7 @@ typedef struct KMSDRM_FBInfo
int KMSDRM_CreateSurfaces(_THIS, SDL_Window * window);
KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo);
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 */