mirror of https://github.com/encounter/SDL.git
kmsdrm: reimplement modesetting for fullscreen window scaling and AR-correction.
This commit is contained in:
parent
4575c6942a
commit
9e9227add3
|
@ -179,6 +179,23 @@ KMSDRM_GLES_SwapWindowFenced(_THIS, SDL_Window * window)
|
||||||
return SDL_SetError("Failed to request prop changes for setting plane buffer and CRTC");
|
return SDL_SetError("Failed to request prop changes for setting plane buffer and CRTC");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do we have a pending modesetting? If so, set the necessary
|
||||||
|
props so it's included in the incoming atomic commit. */
|
||||||
|
if (dispdata->modeset_pending) {
|
||||||
|
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
|
||||||
|
uint32_t blob_id;
|
||||||
|
dispdata->atomic_flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||||
|
if (add_connector_property(dispdata->atomic_req, dispdata->connector, "CRTC_ID", dispdata->crtc->crtc->crtc_id) < 0)
|
||||||
|
return -1;
|
||||||
|
if (KMSDRM_drmModeCreatePropertyBlob(viddata->drm_fd, &dispdata->mode, sizeof(dispdata->mode), &blob_id) != 0)
|
||||||
|
return -1;
|
||||||
|
if (add_crtc_property(dispdata->atomic_req, dispdata->crtc, "MODE_ID", blob_id) < 0)
|
||||||
|
return -1;
|
||||||
|
if (add_crtc_property(dispdata->atomic_req, dispdata->crtc, "ACTIVE", 1) < 0)
|
||||||
|
return -1;
|
||||||
|
dispdata->modeset_pending = SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
/* Tell the display (KMS) that it will have to wait on the fence */
|
/* Tell the display (KMS) that it will have to wait on the fence */
|
||||||
/* for the GPU-side FENCE. */
|
/* for the GPU-side FENCE. */
|
||||||
|
|
|
@ -978,11 +978,12 @@ KMSDRM_CreateSurfaces(_THIS, SDL_Window * window)
|
||||||
/* Destroy the surfaces and buffers before creating the new ones. */
|
/* Destroy the surfaces and buffers before creating the new ones. */
|
||||||
KMSDRM_DestroySurfaces(_this, window);
|
KMSDRM_DestroySurfaces(_this, window);
|
||||||
|
|
||||||
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
|
if (((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) ||
|
||||||
|
((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)) {
|
||||||
|
|
||||||
width = dispdata->mode.hdisplay;
|
width = dispdata->mode.hdisplay;
|
||||||
height = dispdata->mode.vdisplay;
|
height = dispdata->mode.vdisplay;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
width = window->w;
|
width = window->w;
|
||||||
height = window->h;
|
height = window->h;
|
||||||
}
|
}
|
||||||
|
@ -1064,20 +1065,26 @@ KMSDRM_ReconfigureWindow( _THIS, SDL_Window * window) {
|
||||||
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
|
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
|
||||||
float ratio;
|
float ratio;
|
||||||
|
|
||||||
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
|
if (((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) ||
|
||||||
|
((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)) {
|
||||||
|
|
||||||
windata->src_w = dispdata->mode.hdisplay;
|
windata->src_w = dispdata->mode.hdisplay;
|
||||||
windata->src_h = dispdata->mode.vdisplay;
|
windata->src_h = dispdata->mode.vdisplay;
|
||||||
windata->output_w = dispdata->mode.hdisplay;
|
windata->output_w = dispdata->mode.hdisplay;
|
||||||
windata->output_h = dispdata->mode.vdisplay;
|
windata->output_h = dispdata->mode.vdisplay;
|
||||||
windata->output_x = 0;
|
windata->output_x = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Get output (CRTC) size and position, for AR correction. */
|
|
||||||
|
/* Normal non-fullscreen windows are scaled using the CRTC,
|
||||||
|
so get output (CRTC) size and position, for AR correction. */
|
||||||
ratio = (float)window->w / (float)window->h;
|
ratio = (float)window->w / (float)window->h;
|
||||||
windata->src_w = window->w;
|
windata->src_w = window->w;
|
||||||
windata->src_h = window->h;
|
windata->src_h = window->h;
|
||||||
windata->output_w = dispdata->mode.vdisplay * ratio;
|
windata->output_w = dispdata->mode.vdisplay * ratio;
|
||||||
windata->output_h = dispdata->mode.vdisplay;
|
windata->output_h = dispdata->mode.vdisplay;
|
||||||
windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2;
|
windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (KMSDRM_CreateSurfaces(_this, window)) {
|
if (KMSDRM_CreateSurfaces(_this, window)) {
|
||||||
|
@ -1109,6 +1116,7 @@ KMSDRM_VideoInit(_THIS)
|
||||||
dispdata->gpu_fence = NULL;
|
dispdata->gpu_fence = NULL;
|
||||||
dispdata->kms_out_fence_fd = -1;
|
dispdata->kms_out_fence_fd = -1;
|
||||||
dispdata->dumb_buffer = NULL;
|
dispdata->dumb_buffer = NULL;
|
||||||
|
dispdata->modeset_pending = SDL_FALSE;
|
||||||
|
|
||||||
if (!dispdata) {
|
if (!dispdata) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
|
@ -1373,6 +1381,8 @@ KMSDRM_VideoQuit(_THIS)
|
||||||
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->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};
|
||||||
|
drmModeModeInfo mode = dispdata->crtc->crtc->mode;
|
||||||
|
uint32_t blob_id;
|
||||||
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
/* */
|
/* */
|
||||||
|
@ -1409,10 +1419,10 @@ KMSDRM_VideoQuit(_THIS)
|
||||||
plane_info.plane = dispdata->display_plane;
|
plane_info.plane = dispdata->display_plane;
|
||||||
plane_info.crtc_id = dispdata->crtc->crtc->crtc_id;
|
plane_info.crtc_id = dispdata->crtc->crtc->crtc_id;
|
||||||
plane_info.fb_id = dispdata->crtc->crtc->buffer_id;
|
plane_info.fb_id = dispdata->crtc->crtc->buffer_id;
|
||||||
plane_info.src_w = dispdata->mode.hdisplay;
|
plane_info.src_w = mode.hdisplay;
|
||||||
plane_info.src_h = dispdata->mode.vdisplay;
|
plane_info.src_h = mode.vdisplay;
|
||||||
plane_info.crtc_w = dispdata->mode.hdisplay;
|
plane_info.crtc_w = mode.hdisplay;
|
||||||
plane_info.crtc_h = dispdata->mode.vdisplay;
|
plane_info.crtc_h = mode.vdisplay;
|
||||||
|
|
||||||
drm_atomic_set_plane_props(&plane_info);
|
drm_atomic_set_plane_props(&plane_info);
|
||||||
|
|
||||||
|
@ -1432,6 +1442,13 @@ KMSDRM_VideoQuit(_THIS)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Set props that restore the original video mode. */
|
||||||
|
dispdata->atomic_flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||||
|
add_connector_property(dispdata->atomic_req, dispdata->connector, "CRTC_ID", dispdata->crtc->crtc->crtc_id);
|
||||||
|
KMSDRM_drmModeCreatePropertyBlob(viddata->drm_fd, &mode, sizeof(mode), &blob_id);
|
||||||
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc, "MODE_ID", blob_id);
|
||||||
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc, "ACTIVE", 1);
|
||||||
|
|
||||||
/* Issue blocking atomic commit. */
|
/* Issue blocking atomic commit. */
|
||||||
if (drm_atomic_commit(_this, SDL_TRUE)) {
|
if (drm_atomic_commit(_this, SDL_TRUE)) {
|
||||||
SDL_SetError("Failed to issue atomic commit on DestroyWindow().");
|
SDL_SetError("Failed to issue atomic commit on DestroyWindow().");
|
||||||
|
@ -1518,12 +1535,9 @@ KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* We are NOT really changing the physical display mode, but using
|
/* We only change the video mode for FULLSCREEN windows
|
||||||
the PRIMARY PLANE and CRTC to scale as we please. But we need that SDL
|
that are not FULLSCREEN_DESKTOP.
|
||||||
has knowledge of the video modes we are going to use for fullscreen
|
Normal non-fullscreen windows are scaled using the CRTC. */
|
||||||
window sizes, even if we are faking their use. If not, SDL only considers
|
|
||||||
the in-use video mode as available, and sets every window to that size
|
|
||||||
before we get to CreateWindow or ReconfigureWindow. */
|
|
||||||
void
|
void
|
||||||
KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
||||||
{
|
{
|
||||||
|
@ -1553,12 +1567,35 @@ KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
||||||
int
|
int
|
||||||
KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
||||||
{
|
{
|
||||||
/************************************************************************/
|
/* Set the dispdata->mode to the new mode and leave actual modesetting
|
||||||
/* DO NOT add dynamic videomode changes. It makes NO SENSE, since the */
|
pending to be done on SwapWindow(), to be included on next atomic
|
||||||
/* PRIMARY PLANE and the CRTC can be used to scale image, so any window */
|
commit changeset. */
|
||||||
/* will appear fullscren with AR correction with NO extra video memory */
|
|
||||||
/* bandwidth usage. */
|
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
|
||||||
/************************************************************************/
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)display->driverdata;
|
||||||
|
SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
|
||||||
|
drmModeConnector *conn = dispdata->connector->connector;
|
||||||
|
|
||||||
|
if (!modedata) {
|
||||||
|
return SDL_SetError("Mode doesn't have an associated index");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Take note of the new mode. It will be used in SwapWindow to
|
||||||
|
set the props needed for mode setting. */
|
||||||
|
dispdata->mode = conn->modes[modedata->mode_index];
|
||||||
|
|
||||||
|
dispdata->modeset_pending = SDL_TRUE;
|
||||||
|
|
||||||
|
for (int i = 0; i < viddata->num_windows; i++) {
|
||||||
|
SDL_Window *window = viddata->windows[i];
|
||||||
|
|
||||||
|
if (KMSDRM_CreateSurfaces(_this, window)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell app about the window resize */
|
||||||
|
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode->w, mode->h);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1586,20 +1623,26 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
|
||||||
display = SDL_GetDisplayForWindow(window);
|
display = SDL_GetDisplayForWindow(window);
|
||||||
dispdata = display->driverdata;
|
dispdata = display->driverdata;
|
||||||
|
|
||||||
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
|
if (((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) ||
|
||||||
|
((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)) {
|
||||||
|
|
||||||
windata->src_w = dispdata->mode.hdisplay;
|
windata->src_w = dispdata->mode.hdisplay;
|
||||||
windata->src_h = dispdata->mode.vdisplay;
|
windata->src_h = dispdata->mode.vdisplay;
|
||||||
windata->output_w = dispdata->mode.hdisplay;
|
windata->output_w = dispdata->mode.hdisplay;
|
||||||
windata->output_h = dispdata->mode.vdisplay;
|
windata->output_h = dispdata->mode.vdisplay;
|
||||||
windata->output_x = 0;
|
windata->output_x = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Get output (CRTC) size and position, for AR correction. */
|
|
||||||
|
/* Normal non-fullscreen windows are scaled using the CRTC,
|
||||||
|
so get output (CRTC) size and position, for AR correction. */
|
||||||
ratio = (float)window->w / (float)window->h;
|
ratio = (float)window->w / (float)window->h;
|
||||||
windata->src_w = window->w;
|
windata->src_w = window->w;
|
||||||
windata->src_h = window->h;
|
windata->src_h = window->h;
|
||||||
windata->output_w = dispdata->mode.vdisplay * ratio;
|
windata->output_w = dispdata->mode.vdisplay * ratio;
|
||||||
windata->output_h = dispdata->mode.vdisplay;
|
windata->output_h = dispdata->mode.vdisplay;
|
||||||
windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2;
|
windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't force fullscreen on all windows: it confuses programs that try
|
/* Don't force fullscreen on all windows: it confuses programs that try
|
||||||
|
|
|
@ -116,29 +116,28 @@ typedef struct SDL_DisplayData
|
||||||
drmModeModeInfo mode;
|
drmModeModeInfo mode;
|
||||||
uint32_t atomic_flags;
|
uint32_t atomic_flags;
|
||||||
|
|
||||||
/* All changes will be requested via this one and only atomic request,
|
|
||||||
that will be sent to the kernel in the one and only atomic_commit()
|
|
||||||
call that takes place in SwapWindow(). */
|
|
||||||
drmModeAtomicReq *atomic_req;
|
|
||||||
plane *display_plane;
|
plane *display_plane;
|
||||||
plane *cursor_plane;
|
plane *cursor_plane;
|
||||||
crtc *crtc;
|
crtc *crtc;
|
||||||
connector *connector;
|
connector *connector;
|
||||||
|
|
||||||
|
/* Central atomic request list, used for the prop
|
||||||
|
changeset related to pageflip in SwapWindow. */
|
||||||
|
drmModeAtomicReq *atomic_req;
|
||||||
|
|
||||||
int kms_in_fence_fd;
|
int kms_in_fence_fd;
|
||||||
int kms_out_fence_fd;
|
int kms_out_fence_fd;
|
||||||
|
|
||||||
EGLSyncKHR kms_fence; /* Signaled when kms completes changes *
|
EGLSyncKHR kms_fence;
|
||||||
* requested in atomic iotcl (pageflip, etc). */
|
EGLSyncKHR gpu_fence;
|
||||||
|
|
||||||
EGLSyncKHR gpu_fence; /* Signaled when GPU rendering is done. */
|
|
||||||
|
|
||||||
#if SDL_VIDEO_OPENGL_EGL
|
#if SDL_VIDEO_OPENGL_EGL
|
||||||
EGLSurface old_egl_surface;
|
EGLSurface old_egl_surface;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dumb_buffer *dumb_buffer; /* Aux dumb buffer to keep the PRIMARY PLANE
|
dumb_buffer *dumb_buffer;
|
||||||
entertained with when we destroy GBM surface. */
|
|
||||||
|
SDL_bool modeset_pending;
|
||||||
|
|
||||||
} SDL_DisplayData;
|
} SDL_DisplayData;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue