kmsdrm: fix first frame display: no need to wait for SwapWindow() for EGL surface creation.
parent
68ac9349aa
commit
daa752b10e
|
@ -82,12 +82,16 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window)
|
||||||
KMSDRM_FBInfo *fb;
|
KMSDRM_FBInfo *fb;
|
||||||
KMSDRM_PlaneInfo info = {0};
|
KMSDRM_PlaneInfo info = {0};
|
||||||
|
|
||||||
/* Recreate the GBM / EGL surfaces if the window has been reconfigured. */
|
/* Get the EGL context, now that SDL_CreateRenderer() has already been called,
|
||||||
if (windata->egl_surface_dirty) {
|
and call eglMakeCurrent() on it and the EGL surface. */
|
||||||
if (KMSDRM_CreateSurfaces(_this, window)) {
|
#if SDL_VIDEO_OPENGL_EGL
|
||||||
return SDL_SetError("Failed to do pending surfaces creation");
|
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 */
|
/* Block for telling KMS to wait for GPU rendering of the current frame */
|
||||||
|
@ -210,12 +214,16 @@ KMSDRM_GLES_SwapWindowDB(_THIS, SDL_Window * window)
|
||||||
KMSDRM_FBInfo *fb;
|
KMSDRM_FBInfo *fb;
|
||||||
KMSDRM_PlaneInfo info = {0};
|
KMSDRM_PlaneInfo info = {0};
|
||||||
|
|
||||||
/* Recreate the GBM / EGL surfaces if the window has been reconfigured. */
|
/* Get the EGL context, now that SDL_CreateRenderer() has already been called,
|
||||||
if (windata->egl_surface_dirty) {
|
and call eglMakeCurrent() on it and the EGL surface. */
|
||||||
if (KMSDRM_CreateSurfaces(_this, window)) {
|
#if SDL_VIDEO_OPENGL_EGL
|
||||||
return SDL_SetError("Failed to do pending surfaces creation");
|
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 */
|
/* In double-buffer mode, atomic commit will always be synchronous/blocking (ie: won't return until */
|
||||||
|
|
|
@ -758,100 +758,20 @@ KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo)
|
||||||
be disconnected by the kernel. */
|
be disconnected by the kernel. */
|
||||||
void
|
void
|
||||||
KMSDRM_DestroySurfaces(_THIS, SDL_Window *window)
|
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_WindowData *windata = (SDL_WindowData *) window->driverdata;
|
||||||
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
||||||
KMSDRM_PlaneInfo plane_info = {0};
|
KMSDRM_PlaneInfo plane_info = {0};
|
||||||
|
|
||||||
SDL_VideoData *viddata;
|
#if SDL_VIDEO_OPENGL_EGL
|
||||||
if (!windata) {
|
EGLContext egl_context;
|
||||||
return;
|
#endif
|
||||||
}
|
|
||||||
|
/********************************************************************/
|
||||||
|
/* BLOCK 1: protect the PRIMARY PLANE before destroying the buffers */
|
||||||
|
/* it's using. */
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
#if AMDGPU_COMPAT
|
#if AMDGPU_COMPAT
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* We can't do the usual CRTC_ID+FB_ID to 0 with AMDGPU, because */
|
/* We can't do the usual CRTC_ID+FB_ID to 0 with AMDGPU, because */
|
||||||
|
@ -901,9 +821,110 @@ KMSDRM_DestroyWindow(_THIS, SDL_Window *window)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* We can finally destroy the window GBM and EGL surfaces, and GBM buffers, */
|
/* BLOCK 2: We can finally destroy the window GBM and EGL surfaces, and */
|
||||||
/* now that the buffers are not being used by the PRIMARY PLANE anymore. */
|
/* 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);
|
KMSDRM_DestroySurfaces(_this, window);
|
||||||
|
|
||||||
/********************************************/
|
/********************************************/
|
||||||
|
@ -957,19 +978,9 @@ KMSDRM_ReconfigureWindow( _THIS, SDL_Window * window) {
|
||||||
windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2;
|
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)) {
|
if (KMSDRM_CreateSurfaces(_this, window)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,9 @@ typedef struct SDL_WindowData
|
||||||
int32_t output_h;
|
int32_t output_h;
|
||||||
int32_t output_x;
|
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;
|
} SDL_WindowData;
|
||||||
|
|
||||||
|
@ -152,7 +154,7 @@ typedef struct KMSDRM_PlaneInfo
|
||||||
} KMSDRM_PlaneInfo;
|
} KMSDRM_PlaneInfo;
|
||||||
|
|
||||||
/* Helper functions */
|
/* 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);
|
KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo);
|
||||||
|
|
||||||
/* Atomic functions that are used from SDL_kmsdrmopengles.c and SDL_kmsdrmmouse.c */
|
/* Atomic functions that are used from SDL_kmsdrmopengles.c and SDL_kmsdrmmouse.c */
|
||||||
|
|
Loading…
Reference in New Issue