kmsdrm: fix first frame display: no need to wait for SwapWindow() for EGL surface creation.
diff --git a/src/video/kmsdrm/SDL_kmsdrmopengles.c b/src/video/kmsdrm/SDL_kmsdrmopengles.c
index e9c55c9..31204f0 100644
--- a/src/video/kmsdrm/SDL_kmsdrmopengles.c
+++ b/src/video/kmsdrm/SDL_kmsdrmopengles.c
@@ -82,12 +82,16 @@
KMSDRM_FBInfo *fb;
KMSDRM_PlaneInfo info = {0};
- /* Recreate the GBM / EGL surfaces if the window has been reconfigured. */
- if (windata->egl_surface_dirty) {
- if (KMSDRM_CreateSurfaces(_this, window)) {
- return SDL_SetError("Failed to do pending surfaces creation");
- }
+ /* Get the EGL context, now that SDL_CreateRenderer() has already been called,
+ and call eglMakeCurrent() on it and the EGL surface. */
+#if SDL_VIDEO_OPENGL_EGL
+ if (windata->egl_context_pending) {
+ EGLContext egl_context;
+ egl_context = (EGLContext)SDL_GL_GetCurrentContext();
+ SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
+ windata->egl_context_pending = SDL_FALSE;
}
+#endif
/*************************************************************************/
/* Block for telling KMS to wait for GPU rendering of the current frame */
@@ -210,12 +214,16 @@
KMSDRM_FBInfo *fb;
KMSDRM_PlaneInfo info = {0};
- /* Recreate the GBM / EGL surfaces if the window has been reconfigured. */
- if (windata->egl_surface_dirty) {
- if (KMSDRM_CreateSurfaces(_this, window)) {
- return SDL_SetError("Failed to do pending surfaces creation");
- }
+ /* Get the EGL context, now that SDL_CreateRenderer() has already been called,
+ and call eglMakeCurrent() on it and the EGL surface. */
+#if SDL_VIDEO_OPENGL_EGL
+ if (windata->egl_context_pending) {
+ EGLContext egl_context;
+ egl_context = (EGLContext)SDL_GL_GetCurrentContext();
+ SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
+ windata->egl_context_pending = SDL_FALSE;
}
+#endif
/****************************************************************************************************/
/* In double-buffer mode, atomic commit will always be synchronous/blocking (ie: won't return until */
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index 7d9245f..d441290 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -760,98 +760,18 @@
KMSDRM_DestroySurfaces(_THIS, SDL_Window *window)
{
SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
-
- /* Destroy the GBM surface and buffers. */
- if (windata->bo) {
- KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
- windata->bo = NULL;
- }
-
- if (windata->next_bo) {
- KMSDRM_gbm_surface_release_buffer(windata->gs, windata->next_bo);
- windata->next_bo = NULL;
- }
-
- /* Destroy the EGL surface. */
-#if SDL_VIDEO_OPENGL_EGL
- SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
- if (windata->egl_surface != EGL_NO_SURFACE) {
- SDL_EGL_DestroySurface(_this, windata->egl_surface);
- windata->egl_surface = EGL_NO_SURFACE;
- }
-#endif
-
- if (windata->gs) {
- KMSDRM_gbm_surface_destroy(windata->gs);
- windata->gs = NULL;
- }
-}
-
-int
-KMSDRM_CreateSurfaces(_THIS, SDL_Window * window)
-{
- SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
- SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
- SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
- uint32_t surface_fmt = GBM_FORMAT_ARGB8888;
- uint32_t surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
- uint32_t width, height;
-
-#if SDL_VIDEO_OPENGL_EGL
- EGLContext egl_context;
- SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
- egl_context = (EGLContext)SDL_GL_GetCurrentContext();
-#endif
-
- /* Destroy the surfaces and buffers before creating the new ones. */
- KMSDRM_DestroySurfaces(_this, window);
-
- if (window->flags & SDL_WINDOW_FULLSCREEN) {
- width = dispdata->mode.hdisplay;
- height = dispdata->mode.vdisplay;
- }
- else {
- width = window->w;
- height = window->h;
- }
-
- if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, surface_fmt, surface_flags)) {
- SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
- }
-
- windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev, width, height, surface_fmt, surface_flags);
-
- if (!windata->gs) {
- return SDL_SetError("Could not create GBM surface");
- }
-
-#if SDL_VIDEO_OPENGL_EGL
- windata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windata->gs);
-
- if (windata->egl_surface == EGL_NO_SURFACE) {
- return SDL_SetError("Could not create EGL window surface");
- }
-
- SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
-
- windata->egl_surface_dirty = 0;
-#endif
-
- return 0;
-}
-
-void
-KMSDRM_DestroyWindow(_THIS, SDL_Window *window)
-{
- SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
KMSDRM_PlaneInfo plane_info = {0};
- SDL_VideoData *viddata;
- if (!windata) {
- return;
- }
+#if SDL_VIDEO_OPENGL_EGL
+ EGLContext egl_context;
+#endif
+
+ /********************************************************************/
+ /* BLOCK 1: protect the PRIMARY PLANE before destroying the buffers */
+ /* it's using. */
+ /********************************************************************/
+
#if AMDGPU_COMPAT
/************************************************************************/
/* We can't do the usual CRTC_ID+FB_ID to 0 with AMDGPU, because */
@@ -901,9 +821,110 @@
#endif
/****************************************************************************/
- /* We can finally destroy the window GBM and EGL surfaces, and GBM buffers, */
- /* now that the buffers are not being used by the PRIMARY PLANE anymore. */
+ /* BLOCK 2: We can finally destroy the window GBM and EGL surfaces, and */
+ /* GBM buffers now that the buffers are not being used by the PRIMARY PLANE */
+ /* anymore. */
/****************************************************************************/
+
+ /* Destroy the GBM surface and buffers. */
+ if (windata->bo) {
+ KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
+ windata->bo = NULL;
+ }
+
+ if (windata->next_bo) {
+ KMSDRM_gbm_surface_release_buffer(windata->gs, windata->next_bo);
+ windata->next_bo = NULL;
+ }
+
+ /* Destroy the EGL surface. */
+#if SDL_VIDEO_OPENGL_EGL
+ /***************************************************************************/
+ /* In this eglMakeCurrent() call, we disable the current EGL surface */
+ /* because we're going to destroy it, but DON'T disable the EGL context, */
+ /* because it won't be enabled again until the programs ask for a pageflip */
+ /* so we get to SwapWindow(). */
+ /* If we disable the context until then and a program tries to retrieve */
+ /* the context version info before calling for a pageflip, the program */
+ /* will get wrong info and we will be in trouble. */
+ /***************************************************************************/
+ egl_context = (EGLContext)SDL_GL_GetCurrentContext();
+ SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, egl_context);
+
+ if (windata->egl_surface != EGL_NO_SURFACE) {
+ SDL_EGL_DestroySurface(_this, windata->egl_surface);
+ windata->egl_surface = EGL_NO_SURFACE;
+ }
+#endif
+
+ if (windata->gs) {
+ KMSDRM_gbm_surface_destroy(windata->gs);
+ windata->gs = NULL;
+ }
+}
+
+int
+KMSDRM_CreateSurfaces(_THIS, SDL_Window * window)
+{
+ SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
+ SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
+ SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
+ uint32_t surface_fmt = GBM_FORMAT_ARGB8888;
+ uint32_t surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
+ uint32_t width, height;
+
+ /* Destroy the surfaces and buffers before creating the new ones. */
+ KMSDRM_DestroySurfaces(_this, window);
+
+ if (window->flags & SDL_WINDOW_FULLSCREEN) {
+ width = dispdata->mode.hdisplay;
+ height = dispdata->mode.vdisplay;
+ }
+ else {
+ width = window->w;
+ height = window->h;
+ }
+
+ if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, surface_fmt, surface_flags)) {
+ SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
+ }
+
+ windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev, width, height, surface_fmt, surface_flags);
+
+ if (!windata->gs) {
+ return SDL_SetError("Could not create GBM surface");
+ }
+
+#if SDL_VIDEO_OPENGL_EGL
+ /* We can't get the EGL context yet because SDL_CreateRenderer has not been called,
+ but we need an EGL surface NOW, or GL won't be able to render into any surface
+ and we won't see the first frame. */
+ SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
+ windata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windata->gs);
+
+ if (windata->egl_surface == EGL_NO_SURFACE) {
+ return SDL_SetError("Could not create EGL window surface");
+ }
+
+ /* Take note that we're still missing the EGL contex,
+ so we can get it in SwapWindow, when SDL_CreateRenderer()
+ has already been called. */
+ windata->egl_context_pending = SDL_TRUE;
+#endif
+
+ return 0;
+}
+
+void
+KMSDRM_DestroyWindow(_THIS, SDL_Window *window)
+{
+ SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
+ SDL_VideoData *viddata;
+
+ if (!windata) {
+ return;
+ }
+
KMSDRM_DestroySurfaces(_this, window);
/********************************************/
@@ -957,19 +978,9 @@
windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2;
}
-#if SDL_VIDEO_OPENGL_EGL
- /* Can't recreate EGL surfaces right now, need to wait until SwapWindow
- so the EGL context is available. That's because SDL_CreateRenderer(),
- where the EGL context is created, is always called after SDL_CreateWindow()
- since SDL_CreateRenderer() takes a window as parameter.
- On window destruction, SDL_DestroyRenderer() is called before SDL_DestroWindow(),
- so on SDL_DestroyWindow() the EGL context isn't available anymore. */
- windata->egl_surface_dirty = SDL_TRUE;
-#else
if (KMSDRM_CreateSurfaces(_this, window)) {
return -1;
}
-#endif
return 0;
}
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.h b/src/video/kmsdrm/SDL_kmsdrmvideo.h
index bb16237..16bee13 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.h
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.h
@@ -126,7 +126,9 @@
int32_t output_h;
int32_t output_x;
- SDL_bool egl_surface_dirty;
+ /* This is for deferred eglMakeCurrent() call: we can't call it until
+ the EGL context is available, but we need the EGL surface sooner. */
+ SDL_bool egl_context_pending;
} SDL_WindowData;
@@ -152,7 +154,7 @@
} KMSDRM_PlaneInfo;
/* Helper functions */
-int KMSDRM_CreateSurfaces(_THIS, SDL_Window * window);
+int KMSDRM_CreateEGLSurface(_THIS, SDL_Window * window);
KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo);
/* Atomic functions that are used from SDL_kmsdrmopengles.c and SDL_kmsdrmmouse.c */