kmsdrm: wait for pending atomic commits before restoring videomode and crtc->buffer on VideoQuit, and simplify double-buffer SwapWindow() implementation.
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 162 163 164 165
diff --git a/src/video/kmsdrm/SDL_kmsdrmopengles.c b/src/video/kmsdrm/SDL_kmsdrmopengles.c
index c3c1434..2b54b49 100644
--- a/src/video/kmsdrm/SDL_kmsdrmopengles.c
+++ b/src/video/kmsdrm/SDL_kmsdrmopengles.c
@@ -101,7 +101,7 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window)
dispdata->gpu_fence = create_fence(EGL_NO_NATIVE_FENCE_FD_ANDROID, _this);
assert(dispdata->gpu_fence);
- /* Mark in the EGL level the buffer that we want to become the new front buffer.
+ /* 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);
@@ -187,33 +187,18 @@ KMSDRM_GLES_SwapWindowDB(_THIS, SDL_Window * window)
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;
}
- else {
- flags |= DRM_MODE_ATOMIC_NONBLOCK;
- }
- /* Create the fence that will be inserted in the cmdstream exactly at the end
- of the gl commands that form a frame. KMS will have to wait on it before doing a pageflip.
- (NOTE this fence is not really neeeded in double-buffer mode because the program will be
- blocked in eglClientWaitSyncKMHR() until pageflip completes, but we need an in-fence FD anyway
- to issue the atomic ioctl).
- */
- dispdata->gpu_fence = create_fence(EGL_NO_NATIVE_FENCE_FD_ANDROID, _this);
- assert(dispdata->gpu_fence);
-
- /* It's safe to get the gpu_fence FD now, because eglSwapBuffers flushes it down the cmdstream,
- so it's now in place in the cmdstream.
- Atomic ioctl will pass the in-fence fd into the kernel, telling KMS that it has to wait for GPU to
- finish rendering the frame before doing the changes requested in the atomic ioct (pageflip in this case). */
- dispdata->kms_in_fence_fd = _this->egl_data->eglDupNativeFenceFDANDROID(_this->egl_data->egl_display, dispdata->gpu_fence);
- _this->egl_data->eglDestroySyncKHR(_this->egl_data->egl_display, dispdata->gpu_fence);
- assert(dispdata->kms_in_fence_fd != -1);
-
- /* Mark in the EGL level the buffer that we want to become the new front buffer.
+ /* 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);
@@ -245,24 +230,6 @@ KMSDRM_GLES_SwapWindowDB(_THIS, SDL_Window * window)
/* Take note of current front buffer, so we can free it next time we come here. */
windata->bo = windata->next_bo;
- /* Import the kms fence from the out fence fd. We need it to tell GPU to wait for pageflip to complete. */
- dispdata->kms_fence = create_fence(dispdata->kms_out_fence_fd, _this);
- assert(dispdata->kms_fence);
-
- /* Reset out fence FD value because the fence is now away from us, on the driver side. */
- dispdata->kms_out_fence_fd = -1;
-
- /* Wait for pageflip to complete, and destroy kms_fence. */
- 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);
- }
-
return ret;
}
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index 1ce1a44..debc186 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -1051,27 +1051,14 @@ cleanup:
return ret;
}
-/* Fn to restore original video mode and crtc buffer on quit, using the atomic interface. */
-/*int
-restore_video (_THIS)
-{
- SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
-
- ret = drm_atomic_commit(_this, fb->fb_id, flags);
-
-}*/
-
void
KMSDRM_VideoQuit(_THIS)
{
+ int ret;
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoQuit()");
- if (_this->gl_config.driver_loaded) {
- SDL_GL_UnloadLibrary();
- }
-
/* Clear out the window list */
SDL_free(viddata->windows);
viddata->windows = NULL;
@@ -1082,15 +1069,41 @@ KMSDRM_VideoQuit(_THIS)
if (viddata->drm_fd >= 0 && dispdata && dispdata->connector && dispdata->crtc) {
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
- int ret = drm_atomic_commit(_this, dispdata->crtc->buffer_id, flags);
+ /***********************************************************/
+ /* 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);
+ }
+
+ /* 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 */
+ /*********************/
if (ret != 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not restore original videomode");
}
}
- /****************/
- /* Atomic block */
- /****************/
+
+ if (_this->gl_config.driver_loaded) {
+ SDL_GL_UnloadLibrary();
+ }
+
+ /**************************************************/
+ /* Atomic block for freeing up property pointers. */
+ /**************************************************/
if (dispdata && dispdata->connector_props_info) {
SDL_free(dispdata->connector_props_info);
dispdata->connector_props_info = NULL;
@@ -1106,6 +1119,7 @@ KMSDRM_VideoQuit(_THIS)
/*********************/
/* Atomic block ends */
/*********************/
+
if (dispdata && dispdata->connector) {
KMSDRM_drmModeFreeConnector(dispdata->connector);
dispdata->connector = NULL;