Skip to content

Commit

Permalink
video: wayland: Display non-native fullscreen aspect ratios centered …
Browse files Browse the repository at this point in the history
…with a black border

Employ subsurfaces and viewports to maintain a proper aspect ratio for fullscreen modes that don't match the display's native aspect ratio, and display the content centered, with a black border.  The mask surface uses a 1x1 SHM buffer, which is scaled to the display output dimensions using a viewport.  The draw surface becomes a subsurface of the parent mask surface and runs in desynced mode.
  • Loading branch information
Kontrabant committed Apr 15, 2022
1 parent edb473c commit 1d967d4
Show file tree
Hide file tree
Showing 9 changed files with 419 additions and 64 deletions.
16 changes: 16 additions & 0 deletions CMakeLists.txt
Expand Up @@ -905,6 +905,22 @@ if(SDL_LIBC)
check_symbol_exists(getauxval "sys/auxv.h" HAVE_GETAUXVAL)
check_symbol_exists(elf_aux_info "sys/auxv.h" HAVE_ELF_AUX_INFO)
check_symbol_exists(poll "poll.h" HAVE_POLL)
check_symbol_exists(posix_fallocate "fcntl.h" HAVE_POSIX_FALLOCATE)

# memfd_create() and mkostemp() require _GNU_SOURCE to be defined on Linux
if(LINUX)
list(FIND CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE" GNU_SOURCE_DEFINED)
else()
set(GNU_SOURCE_DEFINED 0)
endif()
if(GNU_SOURCE_DEFINED EQUAL -1)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
endif()
check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE)
check_symbol_exists(mkostemp "stdlib.h" HAVE_MKOSTEMP)
if(GNU_SOURCE_DEFINED EQUAL -1)
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
endif()

check_library_exists(m pow "" HAVE_LIBM)
if(HAVE_LIBM)
Expand Down
18 changes: 17 additions & 1 deletion configure.ac
Expand Up @@ -337,7 +337,23 @@ dnl Checks for library functions.
AC_DEFINE(HAVE_MPROTECT, 1, [ ])
],[]),
)
AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove wcslen wcslcpy wcslcat _wcsdup wcsdup wcsstr wcscmp wcsncmp wcscasecmp _wcsicmp wcsncasecmp _wcsnicmp strlen strlcpy strlcat _strrev _strupr _strlwr index rindex strchr strrchr strstr strtok_r itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp vsscanf vsnprintf fopen64 fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname getauxval elf_aux_info poll _Exit)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#if defined(_linux_) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include <sys/mman.h>
]],[[int fd = memfd_create("x", 0);]])], [
AC_DEFINE(HAVE_MEMFD_CREATE, 1, [ ])], [ ]
)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#if defined(_linux_) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include <stdlib.h>
]],[[int fd = mkostemp("x", 0);]])], [
AC_DEFINE(HAVE_MKOSTEMP, 1, [ ])], [ ]
)
AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove wcslen wcslcpy wcslcat _wcsdup wcsdup wcsstr wcscmp wcsncmp wcscasecmp _wcsicmp wcsncasecmp _wcsnicmp strlen strlcpy strlcat _strrev _strupr _strlwr index rindex strchr strrchr strstr strtok_r itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp vsscanf vsnprintf fopen64 fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname getauxval elf_aux_info poll posix_fallocate _Exit)

AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"])
AC_CHECK_FUNCS(acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf copysign copysignf cos cosf exp expf fabs fabsf floor floorf trunc truncf fmod fmodf log logf log10 log10f lround lroundf pow powf round roundf scalbn scalbnf sin sinf sqrt sqrtf tan tanf)
Expand Down
3 changes: 3 additions & 0 deletions include/SDL_config.h.cmake
Expand Up @@ -202,6 +202,9 @@
#cmakedefine HAVE_GETAUXVAL 1
#cmakedefine HAVE_ELF_AUX_INFO 1
#cmakedefine HAVE_POLL 1
#cmakedefine HAVE_POSIX_FALLOCATE 1
#cmakedefine HAVE_MEMFD_CREATE 1
#cmakedefine HAVE_MKOSTEMP 1
#cmakedefine HAVE__EXIT 1

#elif defined(__WIN32__)
Expand Down
3 changes: 3 additions & 0 deletions include/SDL_config.h.in
Expand Up @@ -207,6 +207,9 @@
#undef HAVE_GETAUXVAL
#undef HAVE_ELF_AUX_INFO
#undef HAVE_POLL
#undef HAVE_MEMFD_CREATE
#undef HAVE_MKOSTEMP
#undef HAVE_POSIX_FALLOCATE
#undef HAVE__EXIT

#else
Expand Down
33 changes: 20 additions & 13 deletions src/video/wayland/SDL_waylandevents.c
Expand Up @@ -391,8 +391,8 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer,
if (input->pointer_focus) {
const float sx_f = (float)wl_fixed_to_double(sx_w);
const float sy_f = (float)wl_fixed_to_double(sy_w);
const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x);
const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y);
const int sx = (int)SDL_floorf((sx_f - window->pointer_offset_x) * window->pointer_scale_x);
const int sy = (int)SDL_floorf((sy_f - window->pointer_offset_y) * window->pointer_scale_y);
SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
}
}
Expand Down Expand Up @@ -719,10 +719,10 @@ touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
int id, wl_fixed_t fx, wl_fixed_t fy)
{
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x;
const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y;
const float x = dblx / window_data->sdlwindow->w;
const float y = dbly / window_data->sdlwindow->h;
const double dblx = (wl_fixed_to_double(fx) - window_data->pointer_offset_x) * window_data->pointer_scale_x;
const double dbly = (wl_fixed_to_double(fy) - window_data->pointer_offset_y) * window_data->pointer_scale_y;
const float x = dblx / (float)window_data->sdlwindow->w;
const float y = dbly / (float)window_data->sdlwindow->h;

touch_add(id, x, y, surface);

Expand Down Expand Up @@ -752,8 +752,8 @@ touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
int id, wl_fixed_t fx, wl_fixed_t fy)
{
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x;
const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y;
const double dblx = (wl_fixed_to_double(fx) - window_data->pointer_offset_x) * window_data->pointer_scale_x;
const double dbly = (wl_fixed_to_double(fy) - window_data->pointer_offset_y) * window_data->pointer_scale_y;
const float x = dblx / window_data->sdlwindow->w;
const float y = dbly / window_data->sdlwindow->h;

Expand Down Expand Up @@ -1824,8 +1824,8 @@ tablet_tool_handle_motion(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_
input->sx_w = sx_w;
input->sy_w = sy_w;
if (input->tool_focus) {
const float sx_f = (float)wl_fixed_to_double(sx_w);
const float sy_f = (float)wl_fixed_to_double(sy_w);
const float sx_f = (float)wl_fixed_to_double(sx_w) - window->pointer_offset_x;
const float sy_f = (float)wl_fixed_to_double(sy_w) - window->pointer_offset_y;
const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x);
const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y);
SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
Expand Down Expand Up @@ -2197,6 +2197,13 @@ static const struct zwp_relative_pointer_v1_listener relative_pointer_listener =
relative_pointer_handle_relative_motion,
};

SDL_FORCE_INLINE struct wl_surface *
get_input_lock_surface(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
return data->parent_surface ? data->parent_surface : data->surface;
}

static void
locked_pointer_locked(void *data,
struct zwp_locked_pointer_v1 *locked_pointer)
Expand Down Expand Up @@ -2227,7 +2234,7 @@ lock_pointer_to_window(SDL_Window *window,

locked_pointer =
zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
w->surface,
get_input_lock_surface(window),
input->pointer,
NULL,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
Expand Down Expand Up @@ -2371,7 +2378,7 @@ int Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *wi

confined_pointer =
zwp_pointer_constraints_v1_confine_pointer(d->pointer_constraints,
w->surface,
get_input_lock_surface(window),
input->pointer,
confine_rect,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
Expand Down Expand Up @@ -2406,7 +2413,7 @@ int Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *inp

w->key_inhibitor =
zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(d->key_inhibitor_manager,
w->surface,
get_input_lock_surface(window),
input->seat);

return 0;
Expand Down
6 changes: 6 additions & 0 deletions src/video/wayland/SDL_waylandvideo.c
Expand Up @@ -850,6 +850,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
Wayland_init_xdg_output(d);
} else if (SDL_strcmp(interface, "wp_viewporter") == 0) {
d->viewporter = wl_registry_bind(d->registry, id, &wp_viewporter_interface, 1);
} else if (SDL_strcmp(interface, "wl_subcompositor") == 0) {
d->subcompositor = wl_registry_bind(d->registry, id, &wl_subcompositor_interface, 1);

#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
} else if (SDL_strcmp(interface, "qt_touch_extension") == 0) {
Expand Down Expand Up @@ -1066,6 +1068,10 @@ Wayland_VideoQuit(_THIS)
wp_viewporter_destroy(data->viewporter);
}

if (data->subcompositor) {
wl_subcompositor_destroy(data->subcompositor);
}

if (data->compositor)
wl_compositor_destroy(data->compositor);

Expand Down
1 change: 1 addition & 0 deletions src/video/wayland/SDL_waylandvideo.h
Expand Up @@ -75,6 +75,7 @@ typedef struct {
struct zwp_text_input_manager_v3 *text_input_manager;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wp_viewporter *viewporter;
struct wl_subcompositor *subcompositor;

EGLDisplay edpy;
EGLContext context;
Expand Down

0 comments on commit 1d967d4

Please sign in to comment.