kmsdrm: separate requests in different functions so we only need one atomic commit for everything, as expected by atomic design.
diff --git a/src/video/kmsdrm/SDL_kmsdrmopengles.c b/src/video/kmsdrm/SDL_kmsdrmopengles.c
index f5f93be..582b1c1 100644
--- a/src/video/kmsdrm/SDL_kmsdrmopengles.c
+++ b/src/video/kmsdrm/SDL_kmsdrmopengles.c
@@ -80,16 +80,6 @@
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
KMSDRM_FBInfo *fb;
int ret;
- uint32_t flags = 0;
-
- /* Do we need to set video mode this time? If yes, pass the right flag and issue a blocking atomic ioctl. */
- if (dispdata->modeset_pending) {
- flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
- dispdata->modeset_pending = SDL_FALSE;
- }
- else {
- flags |= DRM_MODE_ATOMIC_NONBLOCK;
- }
/*************************************************************************/
/* Block for telling KMS to wait for GPU rendering of the current frame */
@@ -128,20 +118,14 @@
return SDL_SetError("Failed to get a new framebuffer BO");
}
- /* Don't issue another atomic ioctl until previous one has completed: it will cause errors. */
- if (dispdata->kms_fence) {
- EGLint status;
+ /* Add the pageflip to te request list. */
+ drm_atomic_request_pageflip(_this, fb->fb_id);
- do {
- status = _this->egl_data->eglClientWaitSyncKHR(_this->egl_data->egl_display, dispdata->kms_fence, 0, EGL_FOREVER_KHR);
- } while (status != EGL_CONDITION_SATISFIED_KHR);
+ /* Issue the one and only atomic commit where all changes will be requested!.
+ We need e a non-blocking atomic commit for triple buffering, because we
+ must not block on this atomic commit so we can re-enter program loop once more. */
+ ret = drm_atomic_commit(_this, SDL_FALSE);
- _this->egl_data->eglDestroySyncKHR(_this->egl_data->egl_display, dispdata->kms_fence);
- dispdata->kms_fence = NULL;
- }
-
- /* Issue atomic commit, where we request the pageflip. */
- ret = drm_atomic_commit(_this, fb->fb_id, flags);
if (ret) {
return SDL_SetError("failed to issue atomic commit");
}
@@ -180,22 +164,14 @@
KMSDRM_GLES_SwapWindowDB(_THIS, SDL_Window * window)
{
SDL_WindowData *windata = ((SDL_WindowData *) window->driverdata);
- SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
KMSDRM_FBInfo *fb;
int ret;
- uint32_t flags = 0;
/* In double-buffer mode, atomic commit will always be synchronous/blocking (ie: won't return until
the requested changes are done).
Also, there's no need to fence KMS or the GPU, because we won't be entering game loop again
(hence not building or executing a new cmdstring) until pageflip is done. */
- /* Do we need to set video mode this time? If yes, pass the right flag and issue a blocking atomic ioctl. */
- if (dispdata->modeset_pending) {
- flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
- dispdata->modeset_pending = SDL_FALSE;
- }
-
/* Mark, at EGL level, the buffer that we want to become the new front buffer.
However, it won't really happen until we request a pageflip at the KMS level and it completes. */
_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, windata->egl_surface);
@@ -211,10 +187,15 @@
return SDL_SetError("Failed to get a new framebuffer BO");
}
- /* Issue atomic commit, where we request the pageflip. */
- ret = drm_atomic_commit(_this, fb->fb_id, flags);
+ /* Add the pageflip to te request list. */
+ drm_atomic_request_pageflip(_this, fb->fb_id);
+
+ /* Issue the one and only atomic commit where all changes will be requested!.
+ Blocking for double buffering: won't return until completed. */
+ ret = drm_atomic_commit(_this, SDL_TRUE);
+
if (ret) {
- return SDL_SetError("failed to do atomic commit");
+ return SDL_SetError("failed to issue atomic commit");
}
/* Release last front buffer so EGL can chose it as back buffer and render on it again. */
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index 76c037e..8f417b8 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -197,23 +197,23 @@
static int add_plane_property(drmModeAtomicReq *req, uint32_t obj_id,
const char *name, uint64_t value)
{
- SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
- unsigned int i;
- int prop_id = -1;
+ SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
+ unsigned int i;
+ int prop_id = -1;
- for (i = 0 ; i < dispdata->plane_props->count_props ; i++) {
- if (strcmp(dispdata->plane_props_info[i]->name, name) == 0) {
- prop_id = dispdata->plane_props_info[i]->prop_id;
- break;
- }
+ for (i = 0 ; i < dispdata->plane_props->count_props ; i++) {
+ if (strcmp(dispdata->plane_props_info[i]->name, name) == 0) {
+ prop_id = dispdata->plane_props_info[i]->prop_id;
+ break;
}
+ }
- if (prop_id < 0) {
- printf("no plane property: %s\n", name);
- return -EINVAL;
- }
+ if (prop_id < 0) {
+ printf("no plane property: %s\n", name);
+ return -EINVAL;
+ }
- return KMSDRM_drmModeAtomicAddProperty(req, obj_id, prop_id, value);
+ return KMSDRM_drmModeAtomicAddProperty(req, obj_id, prop_id, value);
}
#if 0
@@ -403,51 +403,70 @@
return ret;
}
-int drm_atomic_commit(_THIS, uint32_t fb_id, uint32_t flags)
+void
+drm_atomic_request_pageflip(_THIS, uint32_t fb_id)
+{
+
+ SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
+ uint32_t plane_id = dispdata->plane->plane_id;
+
+ /* Do we have a set of changes already in the making? If not, allocate a new one. */
+ if (!dispdata->atomic_req)
+ dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
+
+ add_plane_property(dispdata->atomic_req, plane_id, "FB_ID", fb_id);
+ add_plane_property(dispdata->atomic_req, plane_id, "CRTC_ID", dispdata->crtc_id);
+ add_plane_property(dispdata->atomic_req, plane_id, "SRC_X", 0);
+ add_plane_property(dispdata->atomic_req, plane_id, "SRC_Y", 0);
+ add_plane_property(dispdata->atomic_req, plane_id, "SRC_W", dispdata->mode.hdisplay << 16);
+ add_plane_property(dispdata->atomic_req, plane_id, "SRC_H", dispdata->mode.vdisplay << 16);
+ add_plane_property(dispdata->atomic_req, plane_id, "CRTC_X", 0);
+ add_plane_property(dispdata->atomic_req, plane_id, "CRTC_Y", 0);
+ add_plane_property(dispdata->atomic_req, plane_id, "CRTC_W", dispdata->mode.hdisplay);
+ add_plane_property(dispdata->atomic_req, plane_id, "CRTC_H", dispdata->mode.vdisplay);
+
+ if (dispdata->kms_in_fence_fd != -1) {
+ add_crtc_property(dispdata->atomic_req, dispdata->crtc_id, "OUT_FENCE_PTR",
+ VOID2U64(&dispdata->kms_out_fence_fd));
+ add_plane_property(dispdata->atomic_req, plane_id, "IN_FENCE_FD", dispdata->kms_in_fence_fd);
+ }
+
+}
+
+void
+drm_atomic_request_modeset(_THIS)
{
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
- uint32_t plane_id = dispdata->plane->plane_id;
+
uint32_t blob_id;
- drmModeAtomicReq *req;
+
+ /* Do we have a set of changes already in the making? If not, allocate a new one. */
+ if (!dispdata->atomic_req)
+ dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
+
+ dispdata->atomic_flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
+
+ add_connector_property(dispdata->atomic_req, dispdata->connector->connector_id, "CRTC_ID", dispdata->crtc_id);
+ KMSDRM_drmModeCreatePropertyBlob(viddata->drm_fd, &dispdata->mode, sizeof(dispdata->mode), &blob_id);
+ add_crtc_property(dispdata->atomic_req, dispdata->crtc_id, "MODE_ID", blob_id);
+ add_crtc_property(dispdata->atomic_req, dispdata->crtc_id, "ACTIVE", 1);
+}
+
+
+int drm_atomic_commit(_THIS, SDL_bool blocking)
+{
+ SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
+ SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
int ret;
- req = KMSDRM_drmModeAtomicAlloc();
+ if (!blocking)
+ dispdata->atomic_flags |= DRM_MODE_ATOMIC_NONBLOCK;
- if (flags & DRM_MODE_ATOMIC_ALLOW_MODESET) {
- if (add_connector_property(req, dispdata->connector->connector_id, "CRTC_ID",
- dispdata->crtc_id) < 0)
- return -1;
+ /* Never issue a new atomic commit if previous has not yet completed, or it will error. */
+ drm_atomic_wait_pending(_this);
- if (KMSDRM_drmModeCreatePropertyBlob(viddata->drm_fd, &dispdata->mode, sizeof(dispdata->mode),
- &blob_id) != 0)
- return -1;
-
- if (add_crtc_property(req, dispdata->crtc_id, "MODE_ID", blob_id) < 0)
- return -1;
-
- if (add_crtc_property(req, dispdata->crtc_id, "ACTIVE", 1) < 0)
- return -1;
- }
-
- add_plane_property(req, plane_id, "FB_ID", fb_id);
- add_plane_property(req, plane_id, "CRTC_ID", dispdata->crtc_id);
- add_plane_property(req, plane_id, "SRC_X", 0);
- add_plane_property(req, plane_id, "SRC_Y", 0);
- add_plane_property(req, plane_id, "SRC_W", dispdata->mode.hdisplay << 16);
- add_plane_property(req, plane_id, "SRC_H", dispdata->mode.vdisplay << 16);
- add_plane_property(req, plane_id, "CRTC_X", 0);
- add_plane_property(req, plane_id, "CRTC_Y", 0);
- add_plane_property(req, plane_id, "CRTC_W", dispdata->mode.hdisplay);
- add_plane_property(req, plane_id, "CRTC_H", dispdata->mode.vdisplay);
-
- if (dispdata->kms_in_fence_fd != -1) {
- add_crtc_property(req, dispdata->crtc_id, "OUT_FENCE_PTR",
- VOID2U64(&dispdata->kms_out_fence_fd));
- add_plane_property(req, plane_id, "IN_FENCE_FD", dispdata->kms_in_fence_fd);
- }
-
- ret = KMSDRM_drmModeAtomicCommit(viddata->drm_fd, req, flags, NULL);
+ ret = KMSDRM_drmModeAtomicCommit(viddata->drm_fd, dispdata->atomic_req, dispdata->atomic_flags, NULL);
if (ret)
goto out;
@@ -457,13 +476,15 @@
}
out:
- KMSDRM_drmModeAtomicFree(req);
+ KMSDRM_drmModeAtomicFree(dispdata->atomic_req);
+ dispdata->atomic_req = NULL;
+ dispdata->atomic_flags = 0;
return ret;
}
void
-wait_pending_atomic(_THIS)
+drm_atomic_wait_pending(_THIS)
{
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
@@ -676,7 +697,7 @@
SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
/* Wait for pending atomic commit (like pageflips requested in SwapWindow) to complete. */
- wait_pending_atomic(_this);
+ drm_atomic_wait_pending(_this);
if (windata->bo) {
KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
@@ -746,9 +767,8 @@
windata->egl_surface_dirty = SDL_FALSE;
#endif
- /* We take note here about the need to do a modeset in the atomic_commit(),
- called in KMSDRM_GLES_SwapWindow(). */
- dispdata->modeset_pending = SDL_TRUE;
+ /* Add modeset request to the current change request list. */
+ drm_atomic_request_modeset(_this);
return 0;
}
@@ -901,12 +921,13 @@
/* Atomic block */
/****************/
- /* Initialize the fences and their fds: */
+ /* Initialize the atomic dispdata members. */
+ dispdata->atomic_flags = 0;
+ dispdata->atomic_req = NULL;
dispdata->kms_fence = NULL;
dispdata->gpu_fence = NULL;
dispdata->kms_out_fence_fd = -1,
dispdata->kms_in_fence_fd = -1,
- dispdata->modeset_pending = SDL_FALSE;
/*********************/
/* Atomic block ends */
@@ -1086,20 +1107,18 @@
viddata->max_windows = 0;
viddata->num_windows = 0;
- /* Restore original videomode. */
+ /* Restore original buffer. */
if (viddata->drm_fd >= 0 && dispdata && dispdata->connector && dispdata->crtc) {
- uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
-
/***********************************************************/
- /* Atomic block for video mode and crt->buffer restoration */
+ /* Atomic block for original crt->buffer restoration */
/***********************************************************/
- /* We could get here after an async atomic commit (as it's in triple buffer SwapWindow())
- and we don't want to issue another atomic commit before previous one is completed. */
- wait_pending_atomic(_this);
-
- /* Issue sync/blocking atomic commit that restores original video mode and points crtc to original buffer. */
- ret = drm_atomic_commit(_this, dispdata->crtc->buffer_id, flags);
+ /* Issue sync/blocking atomic commit that points crtc to original buffer.
+ SDL_video has already called SetDisplayMode() to set the original display mode at this point.
+ We are not doing pageflips anymore, so we can't rely on the SwapWindow() atomic commit
+ so we are explicitly calling it here. */
+ drm_atomic_request_pageflip(_this, dispdata->crtc->buffer_id);
+ ret = drm_atomic_commit(_this, SDL_TRUE);
/*********************/
/* Atomic block ends */
@@ -1194,6 +1213,7 @@
}
dispdata->mode = conn->modes[modedata->mode_index];
+ drm_atomic_request_modeset(_this);
for (int i = 0; i < viddata->num_windows; i++) {
SDL_Window *window = viddata->windows[i];
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.h b/src/video/kmsdrm/SDL_kmsdrmvideo.h
index 374d23b..4812e02 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.h
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.h
@@ -60,13 +60,24 @@
drmModeModeInfo mode;
uint32_t plane_id;
+ uint32_t cusor_plane_id;
uint32_t crtc_id;
uint32_t connector_id;
+ uint32_t atomic_flags;
+
+ /* All changes will be requested via this one and only atomic request,
+ that will be sent to the kernel in the one and only atomic_commit() call
+ that takes place in SwapWindow(). */
+ drmModeAtomicReq *atomic_req;
drmModePlane *plane;
drmModeObjectProperties *plane_props;
drmModePropertyRes **plane_props_info;
+ drmModePlane *cursor_plane;
+ drmModeObjectProperties *cursor_plane_props;
+ drmModePropertyRes **cursor_plane_props_info;
+
drmModeCrtc *crtc;
drmModeObjectProperties *crtc_props;
drmModePropertyRes **crtc_props_info;
@@ -81,7 +92,6 @@
EGLSyncKHR kms_fence; /* Signaled when kms completes changes requested in atomic iotcl (pageflip, etc). */
EGLSyncKHR gpu_fence; /* Signaled when GPU rendering is done. */
- SDL_bool modeset_pending;
} SDL_DisplayData;
@@ -107,10 +117,12 @@
/* Helper functions */
int KMSDRM_CreateSurfaces(_THIS, SDL_Window * window);
KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo);
-SDL_bool KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout);
/* Atomic functions that are used from SDL_kmsdrmopengles.c */
-int drm_atomic_commit(_THIS, uint32_t fb_id, uint32_t flags);
+void drm_atomic_request_modeset(_THIS);
+void drm_atomic_request_pageflip(_THIS, uint32_t fb_id);
+int drm_atomic_commit(_THIS, SDL_bool blocking);
+void drm_atomic_wait_pending(_THIS);
/****************************************************************************/
/* SDL_VideoDevice functions declaration */