diff options
Diffstat (limited to '0006-wayland-HiDPI-support.patch')
-rw-r--r-- | 0006-wayland-HiDPI-support.patch | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/0006-wayland-HiDPI-support.patch b/0006-wayland-HiDPI-support.patch new file mode 100644 index 000000000000..128f439fde41 --- /dev/null +++ b/0006-wayland-HiDPI-support.patch @@ -0,0 +1,428 @@ +From 53a8296a68c2742728339e9e38865d0434f9260c Mon Sep 17 00:00:00 2001 +From: Sebastian Krzyszkowiak <dos@dosowisko.net> +Date: Tue, 19 Feb 2019 03:59:06 +0100 +Subject: [PATCH 6/6] wayland: HiDPI support + +--- + src/video/wayland/SDL_waylandopengles.c | 39 ++++++-- + src/video/wayland/SDL_waylandopengles.h | 1 + + src/video/wayland/SDL_waylandvideo.c | 22 +++-- + src/video/wayland/SDL_waylandvideo.h | 5 + + src/video/wayland/SDL_waylandwindow.c | 116 ++++++++++++++++++++++-- + src/video/wayland/SDL_waylandwindow.h | 8 +- + 6 files changed, 170 insertions(+), 21 deletions(-) + +diff --git a/src/video/wayland/SDL_waylandopengles.c b/src/video/wayland/SDL_waylandopengles.c +index aafd71eb5..396fc0b4a 100644 +--- a/src/video/wayland/SDL_waylandopengles.c ++++ b/src/video/wayland/SDL_waylandopengles.c +@@ -71,16 +71,24 @@ Wayland_GLES_SwapWindow(_THIS, SDL_Window *window) + + // Wayland-EGL forbids drawing calls in-between SwapBuffers and wl_egl_window_resize + if (data->resize.pending) { ++ if (data->scale_factor != data->resize.scale_factor) { ++ window->w = 0; ++ window->h = 0; ++ } + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, data->resize.width, data->resize.height); + window->w = data->resize.width; + window->h = data->resize.height; +- +- WAYLAND_wl_egl_window_resize(data->egl_window, window->w, window->h, 0, 0); +- +- if (data->waylandData->shell.xdg) { +- xdg_surface_ack_configure(data->shell_surface.xdg.surface, data->resize.serial); +- } else if (data->waylandData->shell.zxdg) { +- zxdg_surface_v6_ack_configure(data->shell_surface.zxdg.surface, data->resize.serial); ++ data->scale_factor = data->resize.scale_factor; ++ wl_surface_set_buffer_scale(data->surface, data->scale_factor); ++ WAYLAND_wl_egl_window_resize(data->egl_window, window->w * data->scale_factor, window->h * data->scale_factor, 0, 0); ++ ++ if (data->resize.configure) { ++ if (data->waylandData->shell.xdg) { ++ xdg_surface_ack_configure(data->shell_surface.xdg.surface, data->resize.serial); ++ } else if (data->waylandData->shell.zxdg) { ++ zxdg_surface_v6_ack_configure(data->shell_surface.zxdg.surface, data->resize.serial); ++ } ++ data->resize.configure = SDL_FALSE; + } + + region = wl_compositor_create_region(data->waylandData->compositor); +@@ -113,6 +121,23 @@ Wayland_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) + return ret; + } + ++void ++Wayland_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h) ++{ ++ SDL_WindowData *data; ++ if (window->driverdata) { ++ data = (SDL_WindowData *) window->driverdata; ++ ++ if (w) { ++ *w = window->w * data->scale_factor; ++ } ++ ++ if (h) { ++ *h = window->h * data->scale_factor; ++ } ++ } ++} ++ + void + Wayland_GLES_DeleteContext(_THIS, SDL_GLContext context) + { +diff --git a/src/video/wayland/SDL_waylandopengles.h b/src/video/wayland/SDL_waylandopengles.h +index 58d7f9b08..d1023d612 100644 +--- a/src/video/wayland/SDL_waylandopengles.h ++++ b/src/video/wayland/SDL_waylandopengles.h +@@ -42,6 +42,7 @@ extern int Wayland_GLES_LoadLibrary(_THIS, const char *path); + extern SDL_GLContext Wayland_GLES_CreateContext(_THIS, SDL_Window * window); + extern int Wayland_GLES_SwapWindow(_THIS, SDL_Window * window); + extern int Wayland_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); ++extern void Wayland_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h); + extern void Wayland_GLES_DeleteContext(_THIS, SDL_GLContext context); + + #endif /* SDL_waylandopengles_h_ */ +diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c +index ab4fde0e6..6e54897a9 100644 +--- a/src/video/wayland/SDL_waylandvideo.c ++++ b/src/video/wayland/SDL_waylandvideo.c +@@ -172,6 +172,7 @@ Wayland_CreateDevice(int devindex) + device->GL_SwapWindow = Wayland_GLES_SwapWindow; + device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval; + device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval; ++ device->GL_GetDrawableSize = Wayland_GLES_GetDrawableSize; + device->GL_MakeCurrent = Wayland_GLES_MakeCurrent; + device->GL_CreateContext = Wayland_GLES_CreateContext; + device->GL_LoadLibrary = Wayland_GLES_LoadLibrary; +@@ -226,7 +227,6 @@ display_handle_geometry(void *data, + SDL_VideoDisplay *display = data; + + display->name = SDL_strdup(model); +- display->driverdata = output; + } + + static void +@@ -237,15 +237,15 @@ display_handle_mode(void *data, + int height, + int refresh) + { +- SDL_VideoDisplay *display = data; + SDL_DisplayMode mode; ++ SDL_VideoDisplay *display = data; + + SDL_zero(mode); + mode.format = SDL_PIXELFORMAT_RGB888; + mode.w = width; + mode.h = height; + mode.refresh_rate = refresh / 1000; // mHz to Hz +- mode.driverdata = display->driverdata; ++ mode.driverdata = ((SDL_WaylandOutputData*)display->driverdata)->output; + SDL_AddDisplayMode(display, &mode); + + if (flags & WL_OUTPUT_MODE_CURRENT) { +@@ -258,8 +258,10 @@ static void + display_handle_done(void *data, + struct wl_output *output) + { ++ /* !!! FIXME: this will fail on any further property changes! */ + SDL_VideoDisplay *display = data; + SDL_AddVideoDisplay(display); ++ wl_output_set_user_data(output, display->driverdata); + SDL_free(display->name); + SDL_free(display); + } +@@ -269,7 +271,8 @@ display_handle_scale(void *data, + struct wl_output *output, + int32_t factor) + { +- // TODO: do HiDPI stuff. ++ SDL_VideoDisplay *display = data; ++ ((SDL_WaylandOutputData*)display->driverdata)->scale_factor = factor; + } + + static const struct wl_output_listener output_listener = { +@@ -283,6 +286,7 @@ static void + Wayland_add_display(SDL_VideoData *d, uint32_t id) + { + struct wl_output *output; ++ SDL_WaylandOutputData *data; + SDL_VideoDisplay *display = SDL_malloc(sizeof *display); + if (!display) { + SDL_OutOfMemory(); +@@ -296,6 +300,10 @@ Wayland_add_display(SDL_VideoData *d, uint32_t id) + SDL_free(display); + return; + } ++ data = SDL_malloc(sizeof *data); ++ data->output = output; ++ data->scale_factor = 1.0; ++ display->driverdata = data; + + wl_output_add_listener(output, &output_listener, display); + } +@@ -351,7 +359,7 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, + /*printf("WAYLAND INTERFACE: %s\n", interface);*/ + + if (strcmp(interface, "wl_compositor") == 0) { +- d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1); ++ d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, SDL_min(3, version)); + } else if (strcmp(interface, "wl_output") == 0) { + Wayland_add_display(d, id); + } else if (strcmp(interface, "wl_seat") == 0) { +@@ -466,7 +474,9 @@ Wayland_VideoQuit(_THIS) + + for (i = 0; i < _this->num_displays; ++i) { + SDL_VideoDisplay *display = &_this->displays[i]; +- wl_output_destroy(display->driverdata); ++ ++ wl_output_destroy(((SDL_WaylandOutputData*)display->driverdata)->output); ++ SDL_free(display->driverdata); + display->driverdata = NULL; + + for (j = display->num_display_modes; j--;) { +diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h +index d173b28e5..753754d68 100644 +--- a/src/video/wayland/SDL_waylandvideo.h ++++ b/src/video/wayland/SDL_waylandvideo.h +@@ -82,6 +82,11 @@ typedef struct { + int relative_mouse_mode; + } SDL_VideoData; + ++typedef struct { ++ struct wl_output *output; ++ float scale_factor; ++} SDL_WaylandOutputData; ++ + #endif /* SDL_waylandvideo_h_ */ + + /* vi: set ts=4 sw=4 expandtab: */ +diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c +index 6c924c2cf..d5352fa74 100644 +--- a/src/video/wayland/SDL_waylandwindow.c ++++ b/src/video/wayland/SDL_waylandwindow.c +@@ -38,6 +38,10 @@ + #include "xdg-decoration-unstable-v1-client-protocol.h" + #include "org-kde-kwin-server-decoration-manager-client-protocol.h" + ++static float get_window_scale_factor(SDL_Window *window) { ++ return ((SDL_WindowData*)window->driverdata)->scale_factor; ++} ++ + /* On modern desktops, we probably will use the xdg-shell protocol instead + of wl_shell, but wl_shell might be useful on older Wayland installs that + don't have the newer protocol, or embedded things that don't have a full +@@ -107,11 +111,14 @@ handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, ui + struct wl_region *region; + + if (!wind->shell_surface.zxdg.initial_configure_seen) { ++ window->w = 0; ++ window->h = 0; + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, wind->resize.width, wind->resize.height); + window->w = wind->resize.width; + window->h = wind->resize.height; + +- WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0); ++ wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window)); ++ WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0); + + zxdg_surface_v6_ack_configure(zxdg, serial); + +@@ -123,6 +130,7 @@ handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, ui + wind->shell_surface.zxdg.initial_configure_seen = SDL_TRUE; + } else { + wind->resize.pending = SDL_TRUE; ++ wind->resize.configure = SDL_TRUE; + wind->resize.serial = serial; + } + } +@@ -208,11 +216,14 @@ handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t + struct wl_region *region; + + if (!wind->shell_surface.xdg.initial_configure_seen) { ++ window->w = 0; ++ window->h = 0; + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, wind->resize.width, wind->resize.height); + window->w = wind->resize.width; + window->h = wind->resize.height; + +- WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0); ++ wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window)); ++ WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0); + + xdg_surface_ack_configure(xdg, serial); + +@@ -224,6 +235,7 @@ handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t + wind->shell_surface.xdg.initial_configure_seen = SDL_TRUE; + } else { + wind->resize.pending = SDL_TRUE; ++ wind->resize.configure = SDL_TRUE; + wind->resize.serial = serial; + } + } +@@ -330,6 +342,78 @@ static const struct qt_extended_surface_listener extended_surface_listener = { + }; + #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + ++static void ++update_scale_factor(SDL_WindowData *window) { ++ float old_factor = window->scale_factor, new_factor = 0.0; ++ ++ if (!(window->sdlwindow->flags & SDL_WINDOW_ALLOW_HIGHDPI)) { ++ return; ++ } ++ ++ if (!window->num_outputs) { ++ new_factor = old_factor; ++ } ++ ++ if (FULLSCREEN_VISIBLE(window->sdlwindow) && window->sdlwindow->fullscreen_mode.driverdata) { ++ new_factor = ((SDL_WaylandOutputData*)(wl_output_get_user_data(window->sdlwindow->fullscreen_mode.driverdata)))->scale_factor; ++ } ++ ++ for (int i = 0; i < window->num_outputs; i++) { ++ float factor = ((SDL_WaylandOutputData*)(wl_output_get_user_data(window->outputs[i])))->scale_factor; ++ if (factor > new_factor) { ++ new_factor = factor; ++ } ++ } ++ ++ if (new_factor != old_factor) { ++ /* force the resize event to trigger, as the logical size didn't change */ ++ window->resize.width = window->sdlwindow->w; ++ window->resize.height = window->sdlwindow->h; ++ window->resize.scale_factor = new_factor; ++ window->resize.pending = SDL_TRUE; ++ } ++} ++ ++static void ++handle_surface_enter(void *data, struct wl_surface *surface, ++ struct wl_output *output) { ++ SDL_WindowData *window = data; ++ ++ window->outputs = SDL_realloc(window->outputs, (window->num_outputs + 1) * sizeof *window->outputs); ++ window->outputs[window->num_outputs++] = output; ++ update_scale_factor(window); ++} ++ ++static void ++handle_surface_leave(void *data, struct wl_surface *surface, ++ struct wl_output *output) { ++ SDL_WindowData *window = data; ++ ++ if (window->num_outputs > 1) { ++ struct wl_output **new_outputs = SDL_malloc((window->num_outputs - 1) * sizeof *window->outputs), **iter = new_outputs; ++ for (int i=0; i < window->num_outputs; i++) { ++ if (window->outputs[i] != output) { ++ *iter = window->outputs[i]; ++ iter++; ++ } ++ } ++ SDL_free(window->outputs); ++ window->outputs = new_outputs; ++ window->num_outputs--; ++ } else { ++ window->num_outputs = 0; ++ SDL_free(window->outputs); ++ window->outputs = NULL; ++ } ++ ++ update_scale_factor(window); ++} ++ ++static const struct wl_surface_listener surface_listener = { ++ handle_surface_enter, ++ handle_surface_leave ++}; ++ + SDL_bool + Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) + { +@@ -475,7 +559,7 @@ void + Wayland_SetWindowFullscreen(_THIS, SDL_Window * window, + SDL_VideoDisplay * _display, SDL_bool fullscreen) + { +- struct wl_output *output = (struct wl_output *) _display->driverdata; ++ struct wl_output *output = ((SDL_WaylandOutputData*) _display->driverdata)->output; + SetFullscreen(_this, window, fullscreen ? output : NULL); + } + +@@ -553,11 +637,28 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) + data->waylandData = c; + data->sdlwindow = window; + ++ data->scale_factor = 1.0; ++ ++ if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { ++ for (int i=0; i < SDL_GetVideoDevice()->num_displays; i++) { ++ float scale = ((SDL_WaylandOutputData*)SDL_GetVideoDevice()->displays[i].driverdata)->scale_factor; ++ if (scale > data->scale_factor) { ++ data->scale_factor = scale; ++ } ++ } ++ } ++ + data->resize.pending = SDL_FALSE; ++ data->resize.width = window->w; ++ data->resize.height = window->h; ++ data->resize.scale_factor = data->scale_factor; ++ ++ data->outputs = NULL; ++ data->num_outputs = 0; + + data->surface = + wl_compositor_create_surface(c->compositor); +- wl_surface_set_user_data(data->surface, data); ++ wl_surface_add_listener(data->surface, &surface_listener, data); + + if (c->shell.xdg) { + data->shell_surface.xdg.surface = xdg_wm_base_get_xdg_surface(c->shell.xdg, data->surface); +@@ -587,7 +688,7 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) + #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + + data->egl_window = WAYLAND_wl_egl_window_create(data->surface, +- window->w, window->h); ++ window->w * data->scale_factor, window->h * data->scale_factor); + + /* Create the GLES window surface */ + data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window); +@@ -676,9 +777,10 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) + SDL_WindowData *wind = window->driverdata; + struct wl_region *region; + +- WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0); ++ wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window)); ++ WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0); + +- region =wl_compositor_create_region(data->compositor); ++ region = wl_compositor_create_region(data->compositor); + wl_region_add(region, 0, 0, window->w, window->h); + wl_surface_set_opaque_region(wind->surface, region); + wl_region_destroy(region); +diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h +index 4b69f7a4e..7b993a19e 100644 +--- a/src/video/wayland/SDL_waylandwindow.h ++++ b/src/video/wayland/SDL_waylandwindow.h +@@ -71,11 +71,16 @@ typedef struct { + #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + + struct { +- SDL_bool pending; ++ SDL_bool pending, configure; + uint32_t serial; + int width, height; ++ float scale_factor; + } resize; + ++ struct wl_output **outputs; ++ int num_outputs; ++ ++ float scale_factor; + } SDL_WindowData; + + extern void Wayland_ShowWindow(_THIS, SDL_Window *window); +-- +2.20.1 + |