[KMS/DRM] Fix for bug #5470: ratio correction for fullscreen windows with no matching resolution. Correct bracket position in else statements so they follow the coding style.
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 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index 66280e4..dfdf47a 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -386,8 +386,7 @@ KMSDRM_WaitPageflip(_THIS, SDL_WindowData *windata) {
/* poll() returning < 0 and setting errno = EINTR means there was a signal before
any requested event, so we immediately poll again. */
continue;
- }
- else {
+ } else {
/* There was another error. Don't pull again or we could get into a busy loop. */
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
return SDL_FALSE; /* Return number 1. */
@@ -425,19 +424,33 @@ KMSDRM_WaitPageflip(_THIS, SDL_WindowData *windata) {
return SDL_TRUE;
}
-/* Given w and h, returns a DRM video mode from the modes available on the connector.
- Returns NULL if no mode matching the specified size is found. */
+/* Given w, h and refresh rate, returns the closest DRM video mode
+ available on the DRM connector of the display.
+ We use the SDL mode list (which we filled in KMSDRM_GetDisplayModes)
+ because it's ordered, while the list on the connector is mostly random.*/
drmModeModeInfo*
-KMSDRM_GetConnectorMode(drmModeConnector *connector, uint32_t width, uint32_t height) {
- int i = 0;
- for (i = 0; i < connector->count_modes; i++) {
- if (connector->modes[i].hdisplay == width &&
- connector->modes[i].vdisplay == height)
- {
- return &connector->modes[i];
- }
+KMSDRM_GetClosestDisplayMode(SDL_VideoDisplay * display,
+uint32_t width, uint32_t height, uint32_t refresh_rate){
+
+ SDL_DisplayData *dispdata = (SDL_DisplayData *) display->driverdata;
+ drmModeConnector *connector = dispdata->connector;
+
+ SDL_DisplayMode target, closest;
+ drmModeModeInfo *drm_mode;
+
+ target.w = width;
+ target.h = height;
+ target.format = 0; /* Will use the default mode format. */
+ target.refresh_rate = refresh_rate;
+ target.driverdata = 0; /* Initialize to 0 */
+
+ if (!SDL_GetClosestDisplayMode(0, &target, &closest)) {
+ return NULL;
+ } else {
+ SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)closest.driverdata;
+ drm_mode = &connector->modes[modedata->mode_index];
+ return drm_mode;
}
- return NULL;
}
/*****************************************************************************/
@@ -1016,9 +1029,9 @@ KMSDRM_DestroyWindow(_THIS, SDL_Window *window)
/* Free display plane, and destroy GBM device. */
KMSDRM_GBMDeinit(_this, dispdata);
- }
- else {
+ } else {
+
/* If we were in Vulkan mode, get out of it. */
if (viddata->vulkan_mode) {
viddata->vulkan_mode = SDL_FALSE;
@@ -1044,14 +1057,14 @@ KMSDRM_DestroyWindow(_THIS, SDL_Window *window)
/*********************************************************************/
/* Free the window driverdata. Bye bye, surface and buffer pointers! */
/*********************************************************************/
+ SDL_free(window->driverdata);
window->driverdata = NULL;
- SDL_free(windata);
}
/**********************************************************************/
/* We simply IGNORE if it's a fullscreen window, window->flags don't */
-/* reflect it: if it's fullscreen, KMSDRM_SetWindwoFullscreen() which */
-/* will be called by SDL later, and we can manage it there. */
+/* reflect it: if it's fullscreen, KMSDRM_SetWindwoFullscreen() will */
+/* be called by SDL later, and we can manage it there. */
/**********************************************************************/
int
KMSDRM_CreateWindow(_THIS, SDL_Window * window)
@@ -1066,6 +1079,11 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
int ret = 0;
drmModeModeInfo *mode;
+ /* Only 1 window is allowed: we can't flip on several windows in KMSDRM. */
+ if (viddata->num_windows > 0) {
+ return -1;
+ }
+
/* Allocate window internal data */
windata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
if (!windata) {
@@ -1127,25 +1145,31 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
KMSDRM_InitCursor();
}
- /* Try to find a matching video mode for the window, fallback to the
- original mode if not available, and configure the mode we chose
- into the CRTC.
- You may be tempted to not do a videomode change, remaining always on
+ /* Try to find the videomode that is the closest to the original size
+ of the window, and configure the mode we chose into the CRTC.
+
+ (You may be tempted to not do a videomode change, remaining always on
the original resolution, and use the SendWindowEvent() parameters to
make SDL2 pre-scale the image for us to an AR-corrected size inside
the original mode, but DON'T: vectorized games (GL games) are rendered
with the size specified in SendWindowEvent(),instead of being rendered
at the original size and then scaled.
It makes sense because GL is used to render the scene in GL games,
- so the scene is rendered at the window size. */
- mode = KMSDRM_GetConnectorMode(dispdata->connector, window->w, window->h );
+ so the scene is rendered at the window size).
+
+ The FULLSCREEN flags are cut out from window->flags at this point,
+ so we can't know if a window is fullscreen or not, hence all windows
+ are considered "windowed" at this point of their life.
+ If a window is fullscreen, SDL internals will call
+ KMSDRM_SetWindowFullscreen() to reconfigure it if necessary. */
+ mode = KMSDRM_GetClosestDisplayMode(display,
+ window->windowed.w, window->windowed.h, 0 );
if (mode) {
- windata->surface_w = window->w;
- windata->surface_h = window->h;
+ windata->surface_w = mode->hdisplay;
+ windata->surface_h = mode->vdisplay;
dispdata->mode = *mode;
- }
- else {
+ } else {
windata->surface_w = dispdata->original_mode.hdisplay;
windata->surface_h = dispdata->original_mode.vdisplay;
dispdata->mode = dispdata->original_mode;
@@ -1163,25 +1187,21 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
/* Tell app about the size we have determined for the window,
so SDL pre-scales to that size for us. */
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED,
- windata->surface_w, windata->surface_h);
+ windata->surface_w, windata->surface_h);
} /* NON-Vulkan block ends. */
- /* Add window to the internal list of tracked windows. Note, while it may
- seem odd to support multiple fullscreen windows, some apps create an
- extra window as a dummy surface when working with multiple contexts */
- if (viddata->num_windows >= viddata->max_windows) {
- unsigned int new_max_windows = viddata->max_windows + 1;
- viddata->windows = (SDL_Window **)SDL_realloc(viddata->windows,
- new_max_windows * sizeof(SDL_Window *));
- viddata->max_windows = new_max_windows;
-
- if (!viddata->windows) {
- ret = SDL_OutOfMemory();
- goto cleanup;
- }
+ /* Add window to the internal list of tracked windows, which will
+ have 1 member only. */
+ viddata->windows = (SDL_Window **)SDL_calloc(1, sizeof(SDL_Window *));
+ viddata->num_windows++;
+ viddata->max_windows = 1;
+
+ if (!viddata->windows) {
+ ret = SDL_OutOfMemory();
+ goto cleanup;
}
- viddata->windows[viddata->num_windows++] = window;
+ viddata->windows[0] = window;
/* If we have just created a Vulkan window, establish that we are in Vulkan mode now. */
viddata->vulkan_mode = is_vulkan;
@@ -1215,8 +1235,11 @@ cleanup:
/*****************************************************************************/
void
KMSDRM_ReconfigureWindow( _THIS, SDL_Window * window) {
- SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
+
SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
+ SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+ SDL_DisplayData *dispdata = display->driverdata;
+ uint32_t refresh_rate = 0;
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) ==
SDL_WINDOW_FULLSCREEN_DESKTOP)
@@ -1227,21 +1250,27 @@ KMSDRM_ReconfigureWindow( _THIS, SDL_Window * window) {
windata->surface_w = dispdata->original_mode.hdisplay;
windata->surface_h = dispdata->original_mode.vdisplay;
dispdata->mode = dispdata->original_mode;
- }
- else
- {
+ } else {
+ drmModeModeInfo *mode;
+
+ /* Refresh rate is only important for fullscreen windows. */
+ if ((window->flags & SDL_WINDOW_FULLSCREEN) ==
+ SDL_WINDOW_FULLSCREEN)
+ {
+ refresh_rate = (uint32_t)window->fullscreen_mode.refresh_rate;
+ }
+
/* Try to find a valid video mode matching the size of the window. */
- drmModeModeInfo *mode = KMSDRM_GetConnectorMode(dispdata->connector,
- window->windowed.w, window->windowed.h );
+ mode = KMSDRM_GetClosestDisplayMode(display,
+ window->windowed.w, window->windowed.h, refresh_rate );
if (mode) {
/* If matching mode found, recreate the GBM surface with the size
of that mode and configure it on the CRTC. */
- windata->surface_w = window->windowed.w;
- windata->surface_h = window->windowed.h;
+ windata->surface_w = mode->hdisplay;
+ windata->surface_h = mode->vdisplay;
dispdata->mode = *mode;
- }
- else {
+ } else {
/* If not matching mode found, recreate the GBM surfaces with the
size of the mode that was originally configured on the CRTC,
and setup that mode on the CRTC. */