Commit 3b9f1073c68539cbdee884c6ebcd70064eabab3f

Manuel Alfayate Corchete 2020-08-07T11:53:04

kmsdrm: wait for possible pending atomic commits before destroying surfaces, and before restoring video on quit. Move messages to the SDL_Log* functions.

diff --git a/src/video/kmsdrm/SDL_kmsdrmopengles.c b/src/video/kmsdrm/SDL_kmsdrmopengles.c
index 2b54b49..f5f93be 100644
--- a/src/video/kmsdrm/SDL_kmsdrmopengles.c
+++ b/src/video/kmsdrm/SDL_kmsdrmopengles.c
@@ -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. */
@@ -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. */
@@ -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. */
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index debc186..76c037e 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -462,12 +462,30 @@ out:
     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)
 {
@@ -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;
@@ -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 */
         /*********************/