Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
wayland: fix resizing and fullscreen toggling
For starters, we need to correctly respond to 0,0 configure after unsetting
fullscreen. Also, turns out that there should be no drawing calls at all
in between eglSwapBuffers and wl_egl_window_resize, as otherwise EGL can
already allocate a wrongly sized buffer for a next frame, so handle those
together.
  • Loading branch information
dos1 committed Nov 7, 2018
1 parent ed694ec commit 48917e0
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 49 deletions.
36 changes: 34 additions & 2 deletions src/video/wayland/SDL_waylandopengles.c
Expand Up @@ -22,12 +22,17 @@

#if SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL

#include "../SDL_sysvideo.h"
#include "../../events/SDL_windowevents_c.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandopengles.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylandevents_c.h"
#include "SDL_waylanddyn.h"

#include "xdg-shell-client-protocol.h"
#include "xdg-shell-unstable-v6-client-protocol.h"

/* EGL implementation of SDL OpenGL ES support */

int
Expand Down Expand Up @@ -57,10 +62,37 @@ Wayland_GLES_CreateContext(_THIS, SDL_Window * window)
int
Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
{
if (SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface) < 0) {
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
struct wl_region *region;

if (SDL_EGL_SwapBuffers(_this, data->egl_surface) < 0) {
return -1;
}
WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );

// Wayland-EGL forbids drawing calls in-between SwapBuffers and wl_egl_window_resize
if (data->resize.pending) {
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);
}

region = wl_compositor_create_region(data->waylandData->compositor);
wl_region_add(region, 0, 0, window->w, window->h);
wl_surface_set_opaque_region(data->surface, region);
wl_region_destroy(region);

data->resize.pending = SDL_FALSE;
}

WAYLAND_wl_display_flush( data->waylandData->display );

return 0;
}

Expand Down
135 changes: 89 additions & 46 deletions src/video/wayland/SDL_waylandwindow.c
Expand Up @@ -55,7 +55,6 @@ handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_sur
{
SDL_WindowData *wind = (SDL_WindowData *)data;
SDL_Window *window = wind->sdlwindow;
struct wl_region *region;

/* wl_shell_surface spec states that this is a suggestion.
Ignore if less than or greater than max/min size. */
Expand All @@ -68,7 +67,7 @@ handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_sur
if ((window->flags & SDL_WINDOW_RESIZABLE)) {
if (window->max_w > 0) {
width = SDL_min(width, window->max_w);
}
}
width = SDL_max(width, window->min_w);

if (window->max_h > 0) {
Expand All @@ -80,15 +79,9 @@ handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_sur
}
}

WAYLAND_wl_egl_window_resize(wind->egl_window, width, height, 0, 0);
region = wl_compositor_create_region(wind->waylandData->compositor);
wl_region_add(region, 0, 0, width, height);
wl_surface_set_opaque_region(wind->surface, region);
wl_region_destroy(region);

SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height);
window->w = width;
window->h = height;
wind->resize.width = width;
wind->resize.height = height;
wind->resize.pending = SDL_TRUE;
}

static void
Expand All @@ -112,15 +105,25 @@ handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, ui
SDL_Window *window = wind->sdlwindow;
struct wl_region *region;

wind->shell_surface.zxdg.initial_configure_seen = SDL_TRUE;
if (!wind->shell_surface.zxdg.initial_configure_seen) {
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);
WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);

region = wl_compositor_create_region(wind->waylandData->compositor);
wl_region_add(region, 0, 0, window->w, window->h);
wl_surface_set_opaque_region(wind->surface, region);
wl_region_destroy(region);
zxdg_surface_v6_ack_configure(zxdg, serial);
zxdg_surface_v6_ack_configure(zxdg, serial);

region = wl_compositor_create_region(wind->waylandData->compositor);
wl_region_add(region, 0, 0, window->w, window->h);
wl_surface_set_opaque_region(wind->surface, region);
wl_region_destroy(region);

wind->shell_surface.zxdg.initial_configure_seen = SDL_TRUE;
} else {
wind->resize.pending = SDL_TRUE;
wind->resize.serial = serial;
}
}

static const struct zxdg_surface_v6_listener shell_surface_listener_zxdg = {
Expand All @@ -138,32 +141,48 @@ handle_configure_zxdg_toplevel(void *data,
SDL_WindowData *wind = (SDL_WindowData *)data;
SDL_Window *window = wind->sdlwindow;

/* wl_shell_surface spec states that this is a suggestion.
Ignore if less than or greater than max/min size. */

if (width == 0 || height == 0) {
return;
enum zxdg_toplevel_v6_state *state;
SDL_bool fullscreen = SDL_FALSE;
wl_array_for_each(state, states) {
if (*state == ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN) {
fullscreen = SDL_TRUE;
}
}

if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
if (!fullscreen) {
if (width == 0 || height == 0) {
width = window->windowed.w;
height = window->windowed.h;
}

/* zxdg_toplevel spec states that this is a suggestion.
Ignore if less than or greater than max/min size. */

if ((window->flags & SDL_WINDOW_RESIZABLE)) {
if (window->max_w > 0) {
width = SDL_min(width, window->max_w);
}
}
width = SDL_max(width, window->min_w);

if (window->max_h > 0) {
height = SDL_min(height, window->max_h);
}
height = SDL_max(height, window->min_h);
} else {
wind->resize.width = window->w;
wind->resize.height = window->h;
return;
}
}

SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height);
window->w = width;
window->h = height;
if (width == 0 || height == 0) {
wind->resize.width = window->w;
wind->resize.height = window->h;
return;
}

wind->resize.width = width;
wind->resize.height = height;
}

static void
Expand All @@ -187,15 +206,25 @@ handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t
SDL_Window *window = wind->sdlwindow;
struct wl_region *region;

wind->shell_surface.xdg.initial_configure_seen = SDL_TRUE;
if (!wind->shell_surface.xdg.initial_configure_seen) {
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);
WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);

region = wl_compositor_create_region(wind->waylandData->compositor);
wl_region_add(region, 0, 0, window->w, window->h);
wl_surface_set_opaque_region(wind->surface, region);
wl_region_destroy(region);
xdg_surface_ack_configure(xdg, serial);
xdg_surface_ack_configure(xdg, serial);

region = wl_compositor_create_region(wind->waylandData->compositor);
wl_region_add(region, 0, 0, window->w, window->h);
wl_surface_set_opaque_region(wind->surface, region);
wl_region_destroy(region);

wind->shell_surface.xdg.initial_configure_seen = SDL_TRUE;
} else {
wind->resize.pending = SDL_TRUE;
wind->resize.serial = serial;
}
}

static const struct xdg_surface_listener shell_surface_listener_xdg = {
Expand All @@ -213,36 +242,48 @@ handle_configure_xdg_toplevel(void *data,
SDL_WindowData *wind = (SDL_WindowData *)data;
SDL_Window *window = wind->sdlwindow;

/* wl_shell_surface spec states that this is a suggestion.
Ignore if less than or greater than max/min size. */
enum xdg_toplevel_state *state;
SDL_bool fullscreen = SDL_FALSE;
wl_array_for_each(state, states) {
if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN) {
fullscreen = SDL_TRUE;
}
}

if (width == 0 || height == 0) {
return;
}
if (!fullscreen) {
if (width == 0 || height == 0) {
width = window->windowed.w;
height = window->windowed.h;
}

/* xdg_toplevel spec states that this is a suggestion.
Ignore if less than or greater than max/min size. */

if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
if ((window->flags & SDL_WINDOW_RESIZABLE)) {
if (window->max_w > 0) {
width = SDL_min(width, window->max_w);
}
}
width = SDL_max(width, window->min_w);

if (window->max_h > 0) {
height = SDL_min(height, window->max_h);
}
height = SDL_max(height, window->min_h);
} else {
wind->resize.width = window->w;
wind->resize.height = window->h;
return;
}
}

if (width == window->w && height == window->h) {
if (width == 0 || height == 0) {
wind->resize.width = window->w;
wind->resize.height = window->h;
return;
}

SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height);
window->w = width;
window->h = height;
wind->resize.width = width;
wind->resize.height = height;
}

static void
Expand Down Expand Up @@ -508,6 +549,8 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
data->waylandData = c;
data->sdlwindow = window;

data->resize.pending = SDL_FALSE;

data->surface =
wl_compositor_create_surface(c->compositor);
wl_surface_set_user_data(data->surface, data);
Expand Down
8 changes: 7 additions & 1 deletion src/video/wayland/SDL_waylandwindow.h
Expand Up @@ -66,7 +66,13 @@ typedef struct {

#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct qt_extended_surface *extended_surface;
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */

struct {
SDL_bool pending;
uint32_t serial;
int width, height;
} resize;
} SDL_WindowData;

extern void Wayland_ShowWindow(_THIS, SDL_Window *window);
Expand Down

0 comments on commit 48917e0

Please sign in to comment.