[KMS/DRM] Rewrite KMSDRM_LEGACY backend to accomodate Vulkan compatibility. Fix several bugs on that backend.

This commit is contained in:
Manuel Alfayate Corchete
2021-01-06 22:15:26 +01:00
parent 57a5c45372
commit 67e0b1dd4e
7 changed files with 1172 additions and 604 deletions
File diff suppressed because it is too large Load Diff
@@ -31,15 +31,24 @@
typedef struct _KMSDRM_LEGACY_CursorData
{
struct gbm_bo *bo;
uint32_t crtc_id;
int hot_x, hot_y;
int w, h;
/* The buffer where we store the mouse bitmap ready to be used.
We get it ready and filled in CreateCursor(), and copy it
to a GBM BO in ShowCursor().*/
uint32_t *buffer;
size_t buffer_size;
size_t buffer_pitch;
} KMSDRM_LEGACY_CursorData;
extern void KMSDRM_LEGACY_InitMouse(_THIS);
extern void KMSDRM_LEGACY_DeinitMouse(_THIS);
extern void KMSDRM_LEGACY_QuitMouse(_THIS);
extern void KMSDRM_LEGACY_InitCursor();
#endif /* SDL_KMSDRM_LEGACY_mouse_h_ */
/* vi: set ts=4 sw=4 expandtab: */
@@ -35,10 +35,36 @@
/* EGL implementation of SDL OpenGL support */
void
KMSDRM_LEGACY_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor)
{
/* if SDL was _also_ built with the Raspberry Pi driver (so we're
definitely a Pi device), default to GLES2. */
#if SDL_VIDEO_DRIVER_RPI
*mask = SDL_GL_CONTEXT_PROFILE_ES;
*major = 2;
*minor = 0;
#endif
}
int
KMSDRM_LEGACY_GLES_LoadLibrary(_THIS, const char *path) {
NativeDisplayType display = (NativeDisplayType)((SDL_VideoData *)_this->driverdata)->gbm;
/* Just pretend you do this here, but don't do it until KMSDRM_CreateWindow(),
where we do the same library load we would normally do here.
because this gets called by SDL_CreateWindow() before KMSDR_CreateWindow(),
so gbm dev isn't yet created when this is called, AND we can't alter the
call order in SDL_CreateWindow(). */
#if 0
NativeDisplayType display = (NativeDisplayType)((SDL_VideoData *)_this->driverdata)->gbm_dev;
return SDL_EGL_LoadLibrary(_this, path, display, EGL_PLATFORM_GBM_MESA);
#endif
return 0;
}
void
KMSDRM_LEGACY_GLES_UnloadLibrary(_THIS) {
/* As with KMSDRM_GLES_LoadLibrary(), we define our own "dummy" unloading function
so we manually unload the library whenever we want. */
}
SDL_EGL_CreateContext_impl(KMSDRM_LEGACY)
@@ -81,16 +107,17 @@ KMSDRM_LEGACY_GLES_SwapWindow(_THIS, SDL_Window * window) {
}
/* Release the previous front buffer */
if (windata->curr_bo) {
KMSDRM_LEGACY_gbm_surface_release_buffer(windata->gs, windata->curr_bo);
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Released GBM surface %p", (void *)windata->curr_bo); */
windata->curr_bo = NULL;
if (windata->bo) {
KMSDRM_LEGACY_gbm_surface_release_buffer(windata->gs, windata->bo);
windata->bo = NULL;
}
windata->curr_bo = windata->next_bo;
windata->bo = windata->next_bo;
/* Make the current back buffer the next front buffer */
if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, windata->egl_surface))) {
/* Mark a buffer to becume the next front buffer.
This won't happen until pagelip completes. */
if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display,
windata->egl_surface))) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed.");
return 0;
}
@@ -100,46 +127,60 @@ KMSDRM_LEGACY_GLES_SwapWindow(_THIS, SDL_Window * window) {
if (!windata->next_bo) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not lock GBM surface front buffer");
return 0;
/* } else {
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Locked GBM surface %p", (void *)windata->next_bo); */
}
/* Get the fb_info for the next front buffer. */
fb_info = KMSDRM_LEGACY_FBFromBO(_this, windata->next_bo);
if (!fb_info) {
return 0;
}
if (!windata->curr_bo) {
/* On the first swap, immediately present the new front buffer. Before
drmModePageFlip can be used the CRTC has to be configured to use
the current connector and mode with drmModeSetCrtc */
ret = KMSDRM_LEGACY_drmModeSetCrtc(viddata->drm_fd, dispdata->crtc_id, fb_info->fb_id, 0,
0, &dispdata->conn->connector_id, 1, &dispdata->mode);
if (!windata->bo) {
/***************************************************************************/
/* This is fundamental. */
/* We can't display an fb smaller than the resolution currently configured */
/* on the CRTC, because the CRTC would be scanning out of bounds. */
/* So instead of using drmModeSetCrtc() to tell CRTC to scan the fb */
/* directly, we use a plane (overlay or primary, doesn't mind if we */
/* activated the UNVERSAL PLANES cap) to scale the buffer to the */
/* resolution currently configured on the CRTC. */
/* */
/* We can't do this sooner, on CreateWindow(), because we don't have a */
/* framebuffer there yet, and DRM doesn't like 0 or -1 as the fb_id. */
/***************************************************************************/
ret = KMSDRM_LEGACY_drmModeSetPlane(viddata->drm_fd, dispdata->plane_id,
dispdata->crtc->crtc_id, fb_info->fb_id, 0,
windata->output_x, 0,
windata->output_w, windata->output_h,
0, 0,
windata->src_w << 16, windata->src_h << 16);
if (ret) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not configure CRTC");
}
} else {
/* On subsequent swaps, queue the new front buffer to be flipped during
the next vertical blank */
ret = KMSDRM_LEGACY_drmModePageFlip(viddata->drm_fd, dispdata->crtc_id, fb_info->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, &windata->waiting_for_flip);
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "drmModePageFlip(%d, %u, %u, DRM_MODE_PAGE_FLIP_EVENT, &windata->waiting_for_flip)",
viddata->drm_fd, displaydata->crtc_id, fb_info->fb_id); */
if (_this->egl_data->egl_swapinterval == 1) {
if (ret == 0) {
windata->waiting_for_flip = SDL_TRUE;
} else {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not queue pageflip: %d", ret);
}
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not set PLANE");
}
/* Wait immediately for vsync (as if we only had two buffers), for low input-lag scenarios.
Run your SDL2 program with "SDL_KMSDRM_LEGACY_DOUBLE_BUFFER=1 <program_name>" to enable this. */
if (_this->egl_data->egl_swapinterval == 1 && windata->double_buffer) {
KMSDRM_LEGACY_WaitPageFlip(_this, windata, -1);
}
return 0;
}
/* Issue pageflip on the next front buffer.
The pageflip will be done during the next vblank. */
ret = KMSDRM_LEGACY_drmModePageFlip(viddata->drm_fd, dispdata->crtc->crtc_id,
fb_info->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &windata->waiting_for_flip);
if (_this->egl_data->egl_swapinterval == 1) {
if (ret == 0) {
windata->waiting_for_flip = SDL_TRUE;
} else {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not queue pageflip: %d", ret);
}
}
/* If we are in double-buffer mode, wait immediately for vsync
(as if we only had two buffers),
Run your SDL2 program with "SDL_KMSDRM_LEGACY_DOUBLE_BUFFER=1 <program_name>"
to enable this. */
if (_this->egl_data->egl_swapinterval == 1 && windata->double_buffer) {
KMSDRM_LEGACY_WaitPageFlip(_this, windata, -1);
}
return 0;
@@ -31,10 +31,10 @@
/* OpenGLES functions */
#define KMSDRM_LEGACY_GLES_GetAttribute SDL_EGL_GetAttribute
#define KMSDRM_LEGACY_GLES_GetProcAddress SDL_EGL_GetProcAddress
#define KMSDRM_LEGACY_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define KMSDRM_LEGACY_GLES_DeleteContext SDL_EGL_DeleteContext
#define KMSDRM_LEGACY_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
extern void KMSDRM_LEGACY_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor);
extern int KMSDRM_LEGACY_GLES_SetSwapInterval(_THIS, int interval);
extern int KMSDRM_LEGACY_GLES_LoadLibrary(_THIS, const char *path);
extern SDL_GLContext KMSDRM_LEGACY_GLES_CreateContext(_THIS, SDL_Window * window);
@@ -40,6 +40,7 @@ SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeFB,(drmModeFBPtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeCrtc,(drmModeCrtcPtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeConnector,(drmModeConnectorPtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeEncoder,(drmModeEncoderPtr ptr))
SDL_KMSDRM_LEGACY_SYM(int,drmGetCap,(int fd, uint64_t capability, uint64_t *value))
SDL_KMSDRM_LEGACY_SYM(drmModeResPtr,drmModeGetResources,(int fd))
SDL_KMSDRM_LEGACY_SYM(int,drmModeAddFB,(int fd, uint32_t width, uint32_t height, uint8_t depth,
uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
@@ -62,6 +63,24 @@ SDL_KMSDRM_LEGACY_SYM(int,drmHandleEvent,(int fd,drmEventContextPtr evctx))
SDL_KMSDRM_LEGACY_SYM(int,drmModePageFlip,(int fd, uint32_t crtc_id, uint32_t fb_id,
uint32_t flags, void *user_data))
/* Planes stuff. */
SDL_KMSDRM_LEGACY_SYM(int,drmSetClientCap,(int fd, uint64_t capability, uint64_t value))
SDL_KMSDRM_LEGACY_SYM(drmModePlaneResPtr,drmModeGetPlaneResources,(int fd))
SDL_KMSDRM_LEGACY_SYM(drmModePlanePtr,drmModeGetPlane,(int fd, uint32_t plane_id))
SDL_KMSDRM_LEGACY_SYM(drmModeObjectPropertiesPtr,drmModeObjectGetProperties,(int fd,uint32_t object_id,uint32_t object_type))
SDL_KMSDRM_LEGACY_SYM(drmModePropertyPtr,drmModeGetProperty,(int fd, uint32_t propertyId))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeProperty,(drmModePropertyPtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeObjectProperties,(drmModeObjectPropertiesPtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreePlane,(drmModePlanePtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreePlaneResources,(drmModePlaneResPtr ptr))
SDL_KMSDRM_LEGACY_SYM(int,drmModeSetPlane,(int fd, uint32_t plane_id, uint32_t crtc_id,
uint32_t fb_id, uint32_t flags,
int32_t crtc_x, int32_t crtc_y,
uint32_t crtc_w, uint32_t crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h))
/* Planes stuff ends. */
SDL_KMSDRM_LEGACY_MODULE(GBM)
SDL_KMSDRM_LEGACY_SYM(int,gbm_device_get_fd,(struct gbm_device *gbm))
File diff suppressed because it is too large Load Diff
@@ -37,7 +37,12 @@ typedef struct SDL_VideoData
{
int devindex; /* device index that was passed on creation */
int drm_fd; /* DRM file desc */
struct gbm_device *gbm;
char devpath[32]; /* DRM dev path. */
struct gbm_device *gbm_dev;
SDL_bool video_init; /* Has VideoInit succeeded? */
SDL_bool vulkan_mode; /* Are we in Vulkan mode? One VK window is enough to be. */
SDL_Window **windows;
int max_windows;
@@ -53,26 +58,53 @@ typedef struct SDL_DisplayModeData
typedef struct SDL_DisplayData
{
uint32_t crtc_id;
drmModeConnector *conn;
drmModeConnector *connector;
drmModeCrtc *crtc;
drmModeModeInfo mode;
drmModeCrtc *saved_crtc; /* CRTC to restore on quit */
} SDL_DisplayData;
drmModeModeInfo original_mode;
drmModeModeInfo preferred_mode;
drmModeCrtc *saved_crtc; /* CRTC to restore on quit */
uint32_t plane_id; /* ID of the primary plane used by the CRTC */
SDL_bool gbm_init;
/* DRM & GBM cursor stuff lives here, not in an SDL_Cursor's driverdata struct,
because setting/unsetting up these is done on window creation/destruction,
where we may not have an SDL_Cursor at all (so no SDL_Cursor driverdata).
There's only one cursor GBM BO because we only support one cursor. */
struct gbm_bo *cursor_bo;
uint64_t cursor_w, cursor_h;
SDL_bool modeset_pending;
} SDL_DisplayData;
typedef struct SDL_WindowData
{
SDL_VideoData *viddata;
/* SDL internals expect EGL surface to be here, and in KMSDRM the GBM surface is
what supports the EGL surface on the driver side, so all these surfaces and buffers
are expected to be here, in the struct pointed by SDL_Window driverdata pointer:
this one. So don't try to move these to dispdata! */
struct gbm_surface *gs;
struct gbm_bo *curr_bo;
struct gbm_bo *bo;
struct gbm_bo *next_bo;
struct gbm_bo *crtc_bo;
SDL_bool waiting_for_flip;
SDL_bool double_buffer;
int egl_surface_dirty;
EGLSurface egl_surface;
/* For scaling and AR correction. */
int32_t src_w;
int32_t src_h;
int32_t output_w;
int32_t output_h;
int32_t output_x;
} SDL_WindowData;
typedef struct KMSDRM_LEGACY_FBInfo
@@ -101,6 +133,7 @@ void KMSDRM_LEGACY_SetWindowTitle(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon);
void KMSDRM_LEGACY_SetWindowPosition(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_SetWindowSize(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen);
void KMSDRM_LEGACY_ShowWindow(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_HideWindow(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_RaiseWindow(_THIS, SDL_Window * window);