Skip to content

Commit

Permalink
kmsdrm: wait for possible pending atomic commits before destroying su…
Browse files Browse the repository at this point in the history
…rfaces, and before restoring video on quit. Move messages to the SDL_Log* functions.
  • Loading branch information
vanfanel committed Aug 7, 2020
1 parent 96c9969 commit 3b9f107
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 26 deletions.
19 changes: 7 additions & 12 deletions src/video/kmsdrm/SDL_kmsdrmopengles.c
Expand Up @@ -121,13 +121,11 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window)
be chosen by EGL as back buffer to draw on), and get a handle to it to request the pageflip on it. */
windata->next_bo = KMSDRM_gbm_surface_lock_front_buffer(windata->gs);
if (!windata->next_bo) {
printf("Failed to lock frontbuffer\n");
return -1;
return SDL_SetError("Failed to lock frontbuffer");
}
fb = KMSDRM_FBFromBO(_this, windata->next_bo);
if (!fb) {
printf("Failed to get a new framebuffer BO\n");
return -1;
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. */
Expand All @@ -139,13 +137,13 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window)
} while (status != EGL_CONDITION_SATISFIED_KHR);

_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) {
printf("failed to do atomic commit\n");
return -1;
return SDL_SetError("failed to issue atomic commit");
}

/* Release the last front buffer so EGL can chose it as back buffer and render on it again. */
Expand Down Expand Up @@ -206,20 +204,17 @@ KMSDRM_GLES_SwapWindowDB(_THIS, SDL_Window * window)
be chosen by EGL as back buffer to draw on), and get a handle to it to request the pageflip on it. */
windata->next_bo = KMSDRM_gbm_surface_lock_front_buffer(windata->gs);
if (!windata->next_bo) {
printf("Failed to lock frontbuffer\n");
return -1;
return SDL_SetError("Failed to lock frontbuffer");
}
fb = KMSDRM_FBFromBO(_this, windata->next_bo);
if (!fb) {
printf("Failed to get a new framebuffer BO\n");
return -1;
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);
if (ret) {
printf("failed to do atomic commit\n");
return -1;
return SDL_SetError("failed to do atomic commit");
}

/* Release last front buffer so EGL can chose it as back buffer and render on it again. */
Expand Down
41 changes: 27 additions & 14 deletions src/video/kmsdrm/SDL_kmsdrmvideo.c
Expand Up @@ -462,12 +462,30 @@ int drm_atomic_commit(_THIS, uint32_t fb_id, uint32_t flags)
return ret;
}

void
wait_pending_atomic(_THIS)
{
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);

/* Will return immediately if we have already destroyed the fence, because we NULL-ify it just after.
Also, will return immediately in double-buffer mode, because kms_fence will alsawys be NULL. */
if (dispdata->kms_fence) {
EGLint status;

do {
status = _this->egl_data->eglClientWaitSyncKHR(_this->egl_data->egl_display,
dispdata->kms_fence, 0, EGL_FOREVER_KHR);
} while (status != EGL_CONDITION_SATISFIED_KHR);

_this->egl_data->eglDestroySyncKHR(_this->egl_data->egl_display, dispdata->kms_fence);
dispdata->kms_fence = NULL;
}
}

/***************************************/
/* End of Atomic helper functions block*/
/***************************************/



static int
KMSDRM_Available(void)
{
Expand Down Expand Up @@ -657,6 +675,9 @@ KMSDRM_DestroySurfaces(_THIS, SDL_Window * window)
{
SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;

/* Wait for pending atomic commit (like pageflips requested in SwapWindow) to complete. */
wait_pending_atomic(_this);

if (windata->bo) {
KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
windata->bo = NULL;
Expand Down Expand Up @@ -1073,21 +1094,13 @@ KMSDRM_VideoQuit(_THIS)
/* Atomic block for video mode and crt->buffer restoration */
/***********************************************************/

/* It could happen that we will 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. */
if (dispdata->kms_fence) {
EGLint status;

do {
status = _this->egl_data->eglClientWaitSyncKHR(_this->egl_data->egl_display,
dispdata->kms_fence, 0, EGL_FOREVER_KHR);
} while (status != EGL_CONDITION_SATISFIED_KHR);

_this->egl_data->eglDestroySyncKHR(_this->egl_data->egl_display, dispdata->kms_fence);
}
/* 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);

/*********************/
/* Atomic block ends */
/*********************/
Expand Down

0 comments on commit 3b9f107

Please sign in to comment.