Skip to content

Commit

Permalink
kmsdrm: reimplement modesetting for fullscreen window scaling and AR-…
Browse files Browse the repository at this point in the history
…correction.
  • Loading branch information
vanfanel committed Sep 12, 2020
1 parent 4575c69 commit 9e9227a
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 34 deletions.
17 changes: 17 additions & 0 deletions src/video/kmsdrm/SDL_kmsdrmopengles.c
Expand Up @@ -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");
}

/* 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 */
/* for the GPU-side FENCE. */
Expand Down
91 changes: 67 additions & 24 deletions src/video/kmsdrm/SDL_kmsdrmvideo.c
Expand Up @@ -978,11 +978,12 @@ KMSDRM_CreateSurfaces(_THIS, SDL_Window * window)
/* Destroy the surfaces and buffers before creating the new ones. */
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;
height = dispdata->mode.vdisplay;
}
else {
} else {
width = window->w;
height = window->h;
}
Expand Down Expand Up @@ -1064,25 +1065,31 @@ KMSDRM_ReconfigureWindow( _THIS, SDL_Window * window) {
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
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_h = dispdata->mode.vdisplay;
windata->output_w = dispdata->mode.hdisplay;
windata->output_h = dispdata->mode.vdisplay;
windata->output_x = 0;

} 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;
windata->src_w = window->w;
windata->src_h = window->h;
windata->output_w = dispdata->mode.vdisplay * ratio;
windata->output_h = dispdata->mode.vdisplay;
windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2;

}

if (KMSDRM_CreateSurfaces(_this, window)) {
return -1;
}
}

return 0;
}
Expand All @@ -1109,6 +1116,7 @@ KMSDRM_VideoInit(_THIS)
dispdata->gpu_fence = NULL;
dispdata->kms_out_fence_fd = -1;
dispdata->dumb_buffer = NULL;
dispdata->modeset_pending = SDL_FALSE;

if (!dispdata) {
return SDL_OutOfMemory();
Expand Down Expand Up @@ -1373,6 +1381,8 @@ KMSDRM_VideoQuit(_THIS)
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
KMSDRM_PlaneInfo plane_info = {0};
drmModeModeInfo mode = dispdata->crtc->crtc->mode;
uint32_t blob_id;

/*****************************************************************/
/* */
Expand Down Expand Up @@ -1409,10 +1419,10 @@ KMSDRM_VideoQuit(_THIS)
plane_info.plane = dispdata->display_plane;
plane_info.crtc_id = dispdata->crtc->crtc->crtc_id;
plane_info.fb_id = dispdata->crtc->crtc->buffer_id;
plane_info.src_w = dispdata->mode.hdisplay;
plane_info.src_h = dispdata->mode.vdisplay;
plane_info.crtc_w = dispdata->mode.hdisplay;
plane_info.crtc_h = dispdata->mode.vdisplay;
plane_info.src_w = mode.hdisplay;
plane_info.src_h = mode.vdisplay;
plane_info.crtc_w = mode.hdisplay;
plane_info.crtc_h = mode.vdisplay;

drm_atomic_set_plane_props(&plane_info);

Expand All @@ -1432,6 +1442,13 @@ KMSDRM_VideoQuit(_THIS)

#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. */
if (drm_atomic_commit(_this, SDL_TRUE)) {
SDL_SetError("Failed to issue atomic commit on DestroyWindow().");
Expand Down Expand Up @@ -1518,12 +1535,9 @@ KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
}
#endif

/* We are NOT really changing the physical display mode, but using
the PRIMARY PLANE and CRTC to scale as we please. But we need that SDL
has knowledge of the video modes we are going to use for fullscreen
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. */
/* We only change the video mode for FULLSCREEN windows
that are not FULLSCREEN_DESKTOP.
Normal non-fullscreen windows are scaled using the CRTC. */
void
KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
Expand Down Expand Up @@ -1553,12 +1567,35 @@ KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
int
KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
/************************************************************************/
/* DO NOT add dynamic videomode changes. It makes NO SENSE, since the */
/* PRIMARY PLANE and the CRTC can be used to scale image, so any window */
/* will appear fullscren with AR correction with NO extra video memory */
/* bandwidth usage. */
/************************************************************************/
/* Set the dispdata->mode to the new mode and leave actual modesetting
pending to be done on SwapWindow(), to be included on next atomic
commit changeset. */

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;
}
Expand Down Expand Up @@ -1586,20 +1623,26 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
display = SDL_GetDisplayForWindow(window);
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_h = dispdata->mode.vdisplay;
windata->output_w = dispdata->mode.hdisplay;
windata->output_h = dispdata->mode.vdisplay;
windata->output_x = 0;

} 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;
windata->src_w = window->w;
windata->src_h = window->h;
windata->output_w = dispdata->mode.vdisplay * ratio;
windata->output_h = dispdata->mode.vdisplay;
windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2;

}

/* Don't force fullscreen on all windows: it confuses programs that try
Expand Down
19 changes: 9 additions & 10 deletions src/video/kmsdrm/SDL_kmsdrmvideo.h
Expand Up @@ -116,29 +116,28 @@ typedef struct SDL_DisplayData
drmModeModeInfo mode;
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 *cursor_plane;
crtc *crtc;
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_out_fence_fd;

EGLSyncKHR kms_fence; /* Signaled when kms completes changes *
* requested in atomic iotcl (pageflip, etc). */

EGLSyncKHR gpu_fence; /* Signaled when GPU rendering is done. */
EGLSyncKHR kms_fence;
EGLSyncKHR gpu_fence;

#if SDL_VIDEO_OPENGL_EGL
EGLSurface old_egl_surface;
#endif

dumb_buffer *dumb_buffer; /* Aux dumb buffer to keep the PRIMARY PLANE
entertained with when we destroy GBM surface. */
dumb_buffer *dumb_buffer;

SDL_bool modeset_pending;

} SDL_DisplayData;

Expand Down

0 comments on commit 9e9227a

Please sign in to comment.