summarylogtreecommitdiffstats
path: root/0006-wayland-HiDPI-support.patch
diff options
context:
space:
mode:
authorSebastian Krzyszkowiak2019-04-11 01:53:09 +0200
committerSebastian Krzyszkowiak2019-04-11 01:53:09 +0200
commitfbac4d6fc6e34081eba92a392b5525e397197aef (patch)
treefe6da259c2c551675ca3fc7f674484b23531ade5 /0006-wayland-HiDPI-support.patch
parent23a4008bf89e437cd35ae24af33f59ca687bf886 (diff)
downloadaur-sdl2-hidpi-hg.tar.gz
hidpi on wayland patch
Diffstat (limited to '0006-wayland-HiDPI-support.patch')
-rw-r--r--0006-wayland-HiDPI-support.patch428
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
+