Skip to content

Commit aac74db

Browse files
committed
[KMS/DRM] Enable async pageflips.
1 parent 9384e59 commit aac74db

File tree

3 files changed

+35
-27
lines changed

3 files changed

+35
-27
lines changed

src/video/kmsdrm/SDL_kmsdrmopengles.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,6 @@ SDL_EGL_CreateContext_impl(KMSDRM)
7272

7373
int KMSDRM_GLES_SetSwapInterval(_THIS, int interval) {
7474

75-
/* Issuing a new pageflip before the previous has completed
76-
causes drmModePageFlip() to return EBUSY errors.
77-
So just set egl_swapinterval to 1 to prevent that. */
78-
79-
#if 0
80-
8175
if (!_this->egl_data) {
8276
return SDL_SetError("EGL not initialized");
8377
}
@@ -87,9 +81,6 @@ int KMSDRM_GLES_SetSwapInterval(_THIS, int interval) {
8781
} else {
8882
return SDL_SetError("Only swap intervals of 0 or 1 are supported");
8983
}
90-
#endif
91-
92-
_this->egl_data->egl_swapinterval = 1;
9384

9485
return 0;
9586
}
@@ -100,15 +91,15 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
10091
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
10192
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
10293
KMSDRM_FBInfo *fb_info;
103-
int ret, timeout;
94+
int ret = 0;
95+
96+
/* Always wait for the previous issued flip before issing a new one,
97+
even if you do async flips. */
98+
uint32_t flip_flags = DRM_MODE_PAGE_FLIP_EVENT;
10499

105100
/* Wait for confirmation that the next front buffer has been flipped, at which
106101
point the previous front buffer can be released */
107-
timeout = 0;
108-
if (_this->egl_data->egl_swapinterval == 1) {
109-
timeout = -1;
110-
}
111-
if (!KMSDRM_WaitPageFlip(_this, windata, timeout)) {
102+
if (!KMSDRM_WaitPageFlip(_this, windata)) {
112103
return 0;
113104
}
114105

@@ -162,24 +153,35 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
162153
}
163154

164155
/* Issue pageflip on the next front buffer.
165-
The pageflip will be done during the next vblank. */
156+
Remember: drmModePageFlip() never blocks, it just issues the flip,
157+
which will be done during the next vblank.
158+
Since it will return EBUSY if we call it again without having
159+
completed the last issued flip, we must pass the
160+
DRM_MODE_PAGE_FLIP_ASYNC if we don't block on EGL (egl_swapinterval = 0).
161+
That makes it flip immediately, without waiting for the next vblank,
162+
so even if we don't block on EGL, it will have flipped when we
163+
get back here. */
164+
165+
if (_this->egl_data->egl_swapinterval == 0) {
166+
flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC;
167+
}
168+
166169
ret = KMSDRM_drmModePageFlip(viddata->drm_fd, dispdata->crtc->crtc_id,
167-
fb_info->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &windata->waiting_for_flip);
170+
fb_info->fb_id, flip_flags, &windata->waiting_for_flip);
168171

169172
if (ret == 0) {
170-
if (_this->egl_data->egl_swapinterval == 1) {
171-
windata->waiting_for_flip = SDL_TRUE;
172-
}
173+
windata->waiting_for_flip = SDL_TRUE;
173174
} else {
174175
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not queue pageflip: %d", ret);
176+
printf("Could not queue pageflip: %s\n", strerror(errno));
175177
}
176178

177179
/* If we are in double-buffer mode, wait immediately for vsync
178180
(as if we only had two buffers),
179181
Run your SDL2 program with "SDL_KMSDRM_DOUBLE_BUFFER=1 <program_name>"
180182
to enable this. */
181183
if (_this->egl_data->egl_swapinterval == 1 && windata->double_buffer) {
182-
KMSDRM_WaitPageFlip(_this, windata, -1);
184+
KMSDRM_WaitPageFlip(_this, windata);
183185
}
184186

185187
return 0;

src/video/kmsdrm/SDL_kmsdrmvideo.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,13 @@ KMSDRM_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int us
339339
}
340340

341341
SDL_bool
342-
KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) {
342+
KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata) {
343343
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
344344
drmEventContext ev = {0};
345345
struct pollfd pfd = {0};
346-
346+
/* If the pageflip hasn't completed after 10 seconds, it nevel will. */
347+
uint32_t timeout = 10000;
348+
347349
ev.version = DRM_EVENT_CONTEXT_VERSION;
348350
ev.page_flip_handler = KMSDRM_FlipHandler;
349351

@@ -353,21 +355,25 @@ KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) {
353355
while (windata->waiting_for_flip) {
354356
pfd.revents = 0;
355357

358+
/* poll() waits for events arriving on the FD, and returns < 0 if timeout
359+
passes with no events. */
356360
if (poll(&pfd, 1, timeout) < 0) {
357361
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
358362
return SDL_FALSE;
359363
}
360364

361365
if (pfd.revents & (POLLHUP | POLLERR)) {
366+
/* An event arrived on the FD in time, but it's an error. */
362367
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error");
363368
return SDL_FALSE;
364369
}
365370

366371
if (pfd.revents & POLLIN) {
367-
/* Page flip? If so, drmHandleEvent will unset windata->waiting_for_flip */
372+
/* There is data to read on the FD!
373+
Is the event a pageflip? If so, drmHandleEvent will
374+
unset windata->waiting_for_flip */
368375
KMSDRM_drmHandleEvent(viddata->drm_fd, &ev);
369376
} else {
370-
/* Timed out and page flip didn't happen */
371377
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip");
372378
return SDL_FALSE;
373379
}
@@ -650,7 +656,7 @@ KMSDRM_DestroySurfaces(_THIS, SDL_Window *window)
650656
/**********************************************/
651657
/* Wait for last issued pageflip to complete. */
652658
/**********************************************/
653-
KMSDRM_WaitPageFlip(_this, windata, -1);
659+
KMSDRM_WaitPageFlip(_this, windata);
654660

655661
/***********************************************************************/
656662
/* Restore the original CRTC configuration: configue the crtc with the */

src/video/kmsdrm/SDL_kmsdrmvideo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ typedef struct KMSDRM_FBInfo
114114
int KMSDRM_CreateSurfaces(_THIS, SDL_Window * window);
115115
KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo);
116116
KMSDRM_FBInfo *KMSDRM_FBFromBO2(_THIS, struct gbm_bo *bo, int w, int h);
117-
SDL_bool KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout);
117+
SDL_bool KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata);
118118

119119
/****************************************************************************/
120120
/* SDL_VideoDevice functions declaration */

0 commit comments

Comments
 (0)