mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-06-07 08:43:13 +08:00
[KMS/DRM] Rewrite KMSDRM_LEGACY backend to accomodate Vulkan compatibility. Fix several bugs on that backend.
This commit is contained in:
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);
|
||||
|
||||
Reference in New Issue
Block a user