kmsdrm: use PLANE and CRTC to do hardware-driven window scaling and AR-correction.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
diff --git a/src/video/kmsdrm/SDL_kmsdrmopengles.c b/src/video/kmsdrm/SDL_kmsdrmopengles.c
index 53c6fcd..01d5a8b 100644
--- a/src/video/kmsdrm/SDL_kmsdrmopengles.c
+++ b/src/video/kmsdrm/SDL_kmsdrmopengles.c
@@ -142,10 +142,12 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window)
info.plane = dispdata->display_plane;
info.crtc_id = dispdata->crtc->crtc->crtc_id;
info.fb_id = fb->fb_id;
- info.src_w = dispdata->mode.hdisplay;
- info.src_h = dispdata->mode.vdisplay;
- info.crtc_w = dispdata->mode.hdisplay;
- info.crtc_h = dispdata->mode.vdisplay;
+
+ info.src_w = window->w;
+ info.src_h = window->h;
+ info.crtc_w = windata->output_w;
+ info.crtc_h = windata->output_h;
+ info.crtc_x = windata->output_x;
ret = drm_atomic_set_plane_props(&info);
if (ret) {
@@ -237,10 +239,12 @@ KMSDRM_GLES_SwapWindowDB(_THIS, SDL_Window * window)
info.plane = dispdata->display_plane;
info.crtc_id = dispdata->crtc->crtc->crtc_id;
info.fb_id = fb->fb_id;
- info.src_w = dispdata->mode.hdisplay;
- info.src_h = dispdata->mode.vdisplay;
- info.crtc_w = dispdata->mode.hdisplay;
- info.crtc_h = dispdata->mode.vdisplay;
+
+ info.src_w = window->w;
+ info.src_h = window->h;
+ info.crtc_w = windata->output_w;
+ info.crtc_h = windata->output_h;
+ info.crtc_x = windata->output_x;
ret = drm_atomic_set_plane_props(&info);
if (ret) {
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index 7678812..4756a84 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -629,6 +629,7 @@ KMSDRM_CreateDevice(int devindex)
device->SetWindowIcon = KMSDRM_SetWindowIcon;
device->SetWindowPosition = KMSDRM_SetWindowPosition;
device->SetWindowSize = KMSDRM_SetWindowSize;
+ device->SetWindowFullscreen = KMSDRM_SetWindowFullscreen;
device->ShowWindow = KMSDRM_ShowWindow;
device->HideWindow = KMSDRM_HideWindow;
device->RaiseWindow = KMSDRM_RaiseWindow;
@@ -814,9 +815,8 @@ 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 width = dispdata->mode.hdisplay;
- Uint32 height = dispdata->mode.vdisplay;
+ Uint32 width = window->w;
+ Uint32 height = window->h;
Uint32 surface_fmt = GBM_FORMAT_ARGB8888;
Uint32 surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
#if SDL_VIDEO_OPENGL_EGL
@@ -1273,12 +1273,12 @@ int
KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
/************************************************************************/
- /* DO NOT add dynamic videomode changes unless you can REALLY test */
- /* on all available KMS drivers and fix them in-kernel, and also test */
- /* all SDL2 software: things will fail one way or another, and it */
- /* greatly increases backend complexiity thus compromising it's */
- /* maintenance. It's NOT as easy as reconstructing GBM and EGL surfaces.*/
- /************************************************************************/
+ /* DO NOT add dynamic videomode changes. It makes NO SENSE since the */
+ /* PRIMARY PLANE and the CRTC reading it can be used to scale image, */
+ /* so any window will appear fullscren with AR correction with NO extra */
+ /* video memory bandwidth usage. */
+ /************************************************************************/
+
return 0;
}
@@ -1287,7 +1287,9 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
{
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
SDL_VideoDisplay *display = NULL;
+ SDL_DisplayData *dispdata = NULL;
SDL_WindowData *windata = NULL;
+ float ratio;
#if SDL_VIDEO_OPENGL_EGL
if (!_this->egl_data) {
@@ -1301,10 +1303,22 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
windata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
display = SDL_GetDisplayForWindow(window);
-
- /* Windows have one size for now */
- window->w = display->desktop_mode.w;
- window->h = display->desktop_mode.h;
+ dispdata = display->driverdata;
+
+ if (window->flags & SDL_WINDOW_FULLSCREEN) {
+ /* Windows only have one possible size in fullscreen mode. */
+ window->w = dispdata->mode.hdisplay;
+ window->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. */
+ ratio = (float)window->w / (float)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
to set a window fullscreen after creating it as non-fullscreen (sm64ex) */
@@ -1401,6 +1415,36 @@ KMSDRM_SetWindowSize(_THIS, SDL_Window * window)
{
}
void
+KMSDRM_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
+{
+
+ SDL_WindowData *windata = window->driverdata;
+ SDL_DisplayData *dispdata = display->driverdata;
+ float ratio;
+
+ KMSDRM_SetPendingSurfacesDestruction(_this, window);
+
+ if (fullscreen) {
+ /* Windows only have one possible size in fullscreen mode. */
+ window->w = dispdata->mode.hdisplay;
+ window->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. */
+ ratio = (float)window->w / (float)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)) {
+ SDL_SetError("Can't recreate window surfaces on SetWindowFullscreen.");
+ }
+}
+void
KMSDRM_ShowWindow(_THIS, SDL_Window * window)
{
}
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.h b/src/video/kmsdrm/SDL_kmsdrmvideo.h
index 0b6543d..72acb10 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.h
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.h
@@ -125,6 +125,12 @@ typedef struct SDL_WindowData
#if SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
#endif
+
+ /* For scaling and AR correction. */
+ int32_t output_w;
+ int32_t output_h;
+ int32_t output_x;
+
} SDL_WindowData;
typedef struct KMSDRM_FBInfo
@@ -133,21 +139,19 @@ typedef struct KMSDRM_FBInfo
uint32_t fb_id; /* DRM framebuffer ID */
} KMSDRM_FBInfo;
-/* Info passed to set_plane_props calls. hdisplay and vdisplay in a drm mode are uint16_t,
- so that's what we use for sizes and positions here. IDs are uint32_t as always. */
typedef struct KMSDRM_PlaneInfo
{
struct plane *plane;
uint32_t fb_id;
uint32_t crtc_id;
- uint16_t src_x;
- uint16_t src_y;
- uint16_t src_w;
- uint16_t src_h;
- uint16_t crtc_x;
- uint16_t crtc_y;
- uint16_t crtc_w;
- uint16_t crtc_h;
+ int32_t src_x;
+ int32_t src_y;
+ int32_t src_w;
+ int32_t src_h;
+ int32_t crtc_x;
+ int32_t crtc_y;
+ int32_t crtc_w;
+ int32_t crtc_h;
} KMSDRM_PlaneInfo;
/* Helper functions */
@@ -182,6 +186,7 @@ void KMSDRM_SetWindowTitle(_THIS, SDL_Window * window);
void KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon);
void KMSDRM_SetWindowPosition(_THIS, SDL_Window * window);
void KMSDRM_SetWindowSize(_THIS, SDL_Window * window);
+void KMSDRM_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen);
void KMSDRM_ShowWindow(_THIS, SDL_Window * window);
void KMSDRM_HideWindow(_THIS, SDL_Window * window);
void KMSDRM_RaiseWindow(_THIS, SDL_Window * window);