mirror of https://github.com/encounter/SDL.git
kmsdrm: greatly improve comments in SwapBuffersFenced() for future reference.
This commit is contained in:
parent
3c6004feb7
commit
47e2d0304e
|
@ -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 */
|
||||
/***************************************/
|
||||
|
|
Loading…
Reference in New Issue