kmsdrm: greatly improve comments in SwapBuffersFenced() for future reference.
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 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
diff --git a/src/video/kmsdrm/SDL_kmsdrmopengles.c b/src/video/kmsdrm/SDL_kmsdrmopengles.c
index 5eaa11b..72eb370 100644
--- a/src/video/kmsdrm/SDL_kmsdrmopengles.c
+++ b/src/video/kmsdrm/SDL_kmsdrmopengles.c
@@ -100,7 +100,13 @@ static EGLSyncKHR create_fence(int fd, _THIS)
return fence;
}
-static int
+/***********************************************************************************/
+/* Comments about buffer access protection mechanism (=fences) are the ones boxed. */
+/* Also, DON'T remove the asserts: if a fence-related call fails, it's better that */
+/* program exits immediately, or we could leave KMS waiting for a failed/missing */
+/* fence forevever. */
+/***********************************************************************************/
+int
KMSDRM_GLES_SwapWindowFenced(_THIS, SDL_Window * window)
{
SDL_WindowData *windata = ((SDL_WindowData *) window->driverdata);
@@ -108,36 +114,47 @@ KMSDRM_GLES_SwapWindowFenced(_THIS, SDL_Window * window)
KMSDRM_FBInfo *fb;
KMSDRM_PlaneInfo info = {0};
- /*************************************************************************/
- /* Block for telling KMS to wait for GPU rendering of the current frame */
- /* before applying the KMS changes requested in the atomic ioctl. */
- /*************************************************************************/
- /* 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. */
+ /******************************************************************/
+ /* Create the GPU-side FENCE OBJECT. It will be inserted into the */
+ /* GL CMDSTREAM exactly at the end of the gl commands that form a */
+ /* frame.(KMS will have to wait on it before doing a pageflip.) */
+ /******************************************************************/
dispdata->gpu_fence = create_fence(EGL_NO_NATIVE_FENCE_FD_ANDROID, _this);
assert(dispdata->gpu_fence);
- /* 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. */
+ /******************************************************************/
+ /* eglSwapBuffers flushes the fence down the GL CMDSTREAM, so we */
+ /* know for sure it's there now. */
+ /* Also it marks, at EGL level, the buffer that we want to become */
+ /* the new front buffer. (Remember that won't really happen until */
+ /* we request a pageflip at the KMS level and it completes. */
+ /******************************************************************/
if (! _this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, windata->egl_surface)) {
return SDL_EGL_SetError("Failed to swap EGL buffers", "eglSwapBuffers");
}
-
- /* 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);
+ /******************************************************************/
+ /* EXPORT the GPU-side FENCE OBJECT to the fence INPUT FD, so we */
+ /* can pass it into the kernel. Atomic ioctl will pass the */
+ /* in-fence fd into the kernel, thus telling KMS that it has to */
+ /* wait for GPU to finish rendering the frame (remember where we */
+ /* put the fence in the GL CMDSTREAM) before doing the changes */
+ /* requested in the atomic ioct (the pageflip in this case). */
+ /* (We export the GPU-side FENCE OJECT to the fence INPUT FD now, */
+ /* not sooner, because now we are sure that the GPU-side fence is */
+ /* in the CMDSTREAM to be lifted when the CMDSTREAM to this point */
+ /* is completed). */
+ /******************************************************************/
+ 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);
- /***************/
- /* Block ends. */
- /***************/
-
- /* Lock the buffer that is marked by eglSwapBuffers() to become the next front buffer (so it can not
- be chosen by EGL as back buffer to draw on), and get a handle to it to request the pageflip on it.
- REMEMBER that gbm_surface_lock_front_buffer() ALWAYS has to be called after eglSwapBuffers(). */
+ /* Lock the buffer that is marked by eglSwapBuffers() to become the
+ next front buffer (so it can not be chosen by EGL as back buffer
+ to draw on), and get a handle to it to request the pageflip on it.
+ REMEMBER that gbm_surface_lock_front_buffer() ALWAYS has to be
+ called after eglSwapBuffers(). */
windata->next_bo = KMSDRM_gbm_surface_lock_front_buffer(windata->gs);
if (!windata->next_bo) {
return SDL_SetError("Failed to lock frontbuffer");
@@ -162,56 +179,77 @@ KMSDRM_GLES_SwapWindowFenced(_THIS, SDL_Window * window)
return SDL_SetError("Failed to request prop changes for setting plane buffer and CRTC");
}
- /* Set the IN_FENCE and OUT_FENCE props only here, since this is the only place
- on which we're interested in managing who and when should access the buffers
- that the display plane uses, and that's what these props are for. */
+ /*****************************************************************/
+ /* Tell the display (KMS) that it will have to wait on the fence */
+ /* for the GPU-side FENCE. */
+ /* */
+ /* Since KMS is a kernel thing, we have to pass an FD into */
+ /* the kernel, and get another FD out of the kernel. */
+ /* */
+ /* 1) To pass the GPU-side fence into the kernel, we set the */
+ /* INPUT FD as the IN_FENCE_FD prop of the PRIMARY PLANE. */
+ /* This FD tells KMS (the kernel) to wait for the GPU-side fence.*/
+ /* */
+ /* 2) To get the KMS-side fence out of the kernel, we set the */
+ /* OUTPUT FD as the OUT_FEWNCE_FD prop of the CRTC. */
+ /* This FD will be later imported as a FENCE OBJECT which will be*/
+ /* used to tell the GPU to wait for KMS to complete the changes */
+ /* requested in atomic_commit (the pageflip in this case). */
+ /*****************************************************************/
if (dispdata->kms_in_fence_fd != -1)
{
- if (add_crtc_property(dispdata->atomic_req, dispdata->crtc, "OUT_FENCE_PTR",
- VOID2U64(&dispdata->kms_out_fence_fd)) < 0)
- return SDL_SetError("Failed to set CRTC OUT_FENCE_PTR prop");
- if (add_plane_property(dispdata->atomic_req, dispdata->display_plane, "IN_FENCE_FD", dispdata->kms_in_fence_fd) < 0)
+ if (add_plane_property(dispdata->atomic_req, dispdata->display_plane,
+ "IN_FENCE_FD", dispdata->kms_in_fence_fd) < 0)
return SDL_SetError("Failed to set plane IN_FENCE_FD prop");
+ if (add_crtc_property(dispdata->atomic_req, dispdata->crtc,
+ "OUT_FENCE_PTR", VOID2U64(&dispdata->kms_out_fence_fd)) < 0)
+ return SDL_SetError("Failed to set CRTC OUT_FENCE_PTR prop");
}
- /* 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. */
+ /*****************************************************************/
+ /* Issue a non-blocking atomic commit: for triple buffering, */
+ /* this must not block so the game can start building another */
+ /* frame, even if the just-requested pageflip hasnt't completed. */
+ /*****************************************************************/
if (drm_atomic_commit(_this, SDL_FALSE)) {
return SDL_SetError("Failed to issue atomic commit on pageflip");
}
- /* Release the last front buffer so EGL can chose it as back buffer and render on it again. */
+ /* Release the previous front buffer so EGL can chose it as back buffer
+ and render on it again. */
if (windata->bo) {
KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
}
- /* Take note of current front buffer, so we can free it next time we come here. */
+ /* Take note of the buffer about to become front buffer, so next
+ time we come here we can free it like we just did with the previous
+ front buffer. */
windata->bo = windata->next_bo;
- /**************************************************************************/
- /* Block for telling GPU to wait for completion of requested KMS changes */
- /* before starting cmdstream execution (=next frame rendering). */
- /**************************************************************************/
-
- /* Import the kms fence from the out fence fd. We need it to tell GPU to wait for pageflip to complete. */
+ /****************************************************************/
+ /* Import the KMS-side FENCE OUTPUT FD from the kernel to the */
+ /* KMS-side FENCE OBJECT so we can use use it to fence the GPU. */
+ /****************************************************************/
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. */
+ /****************************************************************/
+ /* "Delete" the fence OUTPUT FD, because we already have the */
+ /* KMS FENCE OBJECT, the fence itself is away from us, on the */
+ /* kernel side. */
+ /****************************************************************/
dispdata->kms_out_fence_fd = -1;
- /* Tell the GPU to wait until the requested pageflip has completed. */
+ /*****************************************************************/
+ /* Tell the GPU to wait on the fence for the KMS-side FENCE, */
+ /* which means waiting until the requested pageflip is completed.*/
+ /*****************************************************************/
_this->egl_data->eglWaitSyncKHR(_this->egl_data->egl_display, dispdata->kms_fence, 0);
- /***************/
- /* Block ends. */
- /***************/
-
return 0;
}
-static int
+int
KMSDRM_GLES_SwapWindowDoubleBuffered(_THIS, SDL_Window * window)
{
SDL_WindowData *windata = ((SDL_WindowData *) window->driverdata);
@@ -220,10 +258,11 @@ KMSDRM_GLES_SwapWindowDoubleBuffered(_THIS, SDL_Window * window)
KMSDRM_PlaneInfo info = {0};
/****************************************************************************************************/
- /* In double-buffer mode, atomic commit will always be synchronous/blocking (ie: won't return until */
+ /* In double-buffer mode, atomic_commit will always be synchronous/blocking (ie: won't return until */
/* the requested changes are really 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. */
+ /* (hence not building or executing a new cmdstring) until pageflip is done, so we don't need to */
+ /* protect the KMS/GPU access to the buffer. */
/****************************************************************************************************/
/* Mark, at EGL level, the buffer that we want to become the new front buffer.
@@ -312,7 +351,6 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window)
return windata->swap_window(_this, window);
}
-
/***************************************/
/* End of Atomic functions block */
/***************************************/