Skip to content

Commit

Permalink
egl-wayland: resize windows immediately if surface is current
Browse files Browse the repository at this point in the history
A recent change modified the behavior of our resize_callback to defer the
actual resize until the next eglSwapBuffers, since wl_egl_window_resize may
be called by a thread to which the window's surface is not current.

Unfortunately, several GUI libraries assume wl_egl_window_resize will take
effect immediately and, therefore, will only render one more frame after
calling it. With our new behavior, this results in the window contents not
matching the new size until something later prompts the application to
redraw.

As a fix, this change partially restores the old behavior. If
resize_callback detects that the window's surface is current to the calling
thread (either as EGL_DRAW or EGL_READ), the resize will be performed
immediately like it was before. If not, only then will it be deferred to
the next eglSwapBuffers.

Additionally, in the case where we do defer the resize, we will now do it
*after* the actual eglSwapBuffers operation instead of before, since
otherwise we would be presenting a newly allocated buffer with undefined
contents.
  • Loading branch information
Erik Kurzinger committed Aug 5, 2022
1 parent aaf8608 commit 885f0a5
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 42 deletions.
6 changes: 3 additions & 3 deletions include/wayland-eglsurface-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ struct WlEglSurfaceRec {
EGLBoolean isResized;
};

void wlEglResizeSurfaceIfRequired(WlEglDisplay *display,
WlEglPlatformData *pData,
WlEglSurface *surface);
void wlEglResizeSurface(WlEglDisplay *display,
WlEglPlatformData *pData,
WlEglSurface *surface);

EGLSurface wlEglCreatePlatformWindowSurfaceHook(EGLDisplay dpy,
EGLConfig config,
Expand Down
75 changes: 38 additions & 37 deletions src/wayland-eglsurface.c
Original file line number Diff line number Diff line change
Expand Up @@ -1614,53 +1614,48 @@ WlEglSurface *wlEglCreateSurfaceExport(EGLDisplay dpy,
}

void
wlEglResizeSurfaceIfRequired(WlEglDisplay *display, WlEglPlatformData *pData, WlEglSurface *surface)
wlEglResizeSurface(WlEglDisplay *display,
WlEglPlatformData *pData,
WlEglSurface *surface)
{
EGLint err = EGL_SUCCESS;
EGLint err = EGL_SUCCESS;

if (!surface) {
return;
}
// If a damage thread is in use, wait for it to finish processing all
// pending frames
finish_wl_eglstream_damage_thread(surface, &surface->ctx, 0);

pthread_mutex_lock(&surface->mutexLock);
discard_surface_context(surface);
surface->isResized = EGL_FALSE;
surface->ctx.wlStreamResource = NULL;
surface->ctx.isAttached = EGL_FALSE;
surface->ctx.eglSurface = EGL_NO_SURFACE;
surface->ctx.eglStream = EGL_NO_STREAM_KHR;
surface->ctx.damageThreadSync = EGL_NO_SYNC_KHR;
surface->ctx.damageThreadId = (pthread_t)0;

/* Resize stream only if window geometry has changed */
if (surface->isResized) {
// If a damage thread is in use, wait for it to finish processing all
// pending frames
finish_wl_eglstream_damage_thread(surface, &surface->ctx, 0);

discard_surface_context(surface);
surface->isResized = EGL_FALSE;
surface->ctx.wlStreamResource = NULL;
surface->ctx.isAttached = EGL_FALSE;
surface->ctx.eglSurface = EGL_NO_SURFACE;
surface->ctx.eglStream = EGL_NO_STREAM_KHR;
surface->ctx.damageThreadSync = EGL_NO_SYNC_KHR;
surface->ctx.damageThreadId = (pthread_t)0;

err = create_surface_context(surface);
if (err == EGL_SUCCESS) {
pData->egl.makeCurrent(display,
surface,
surface,
pData->egl.getCurrentContext());

if (surface->ctx.wlStreamResource) {
/* Set client's pendingSwapIntervalUpdate for updating client's
* swapinterval
*/
surface->pendingSwapIntervalUpdate = EGL_TRUE;
}
err = create_surface_context(surface);
if (err == EGL_SUCCESS) {
/* This looks like a no-op, but we've replaced the surface's internal
* handle with a new surface, so we need to make it current again. */
pData->egl.makeCurrent(display,
pData->egl.getCurrentSurface(EGL_DRAW),
pData->egl.getCurrentSurface(EGL_READ),
pData->egl.getCurrentContext());

if (surface->ctx.wlStreamResource) {
/* Set client's pendingSwapIntervalUpdate for updating client's
* swapinterval
*/
surface->pendingSwapIntervalUpdate = EGL_TRUE;
}
}
pthread_mutex_unlock(&surface->mutexLock);
}

static void
resize_callback(struct wl_egl_window *window, void *data)
{
WlEglDisplay *display = NULL;
WlEglPlatformData *pData;
WlEglSurface *surface = (WlEglSurface *)data;

if (!window || !surface) {
Expand All @@ -1673,15 +1668,21 @@ resize_callback(struct wl_egl_window *window, void *data)
return;
}

pData = display->data;

pthread_mutex_lock(&surface->mutexLock);

/* Resize stream only if window geometry has changed */
if ((surface->width != window->width) ||
(surface->height != window->height) ||
(surface->dx != window->dx) ||
(surface->dy != window->dy)) {
surface->isResized = EGL_TRUE;
wl_surface_commit(surface->wlSurface);
if (surface == pData->egl.getCurrentSurface(EGL_DRAW) ||
surface == pData->egl.getCurrentSurface(EGL_READ)) {
wlEglResizeSurface(display, pData, surface);
} else {
surface->isResized = EGL_TRUE;
}
}

pthread_mutex_unlock(&surface->mutexLock);
Expand Down
6 changes: 4 additions & 2 deletions src/wayland-eglswap.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ EGLBoolean wlEglSwapBuffersWithDamageHook(EGLDisplay eglDisplay, EGLSurface eglS

surface = eglSurface;

wlEglResizeSurfaceIfRequired(display, data, surface);

if (surface->pendingSwapIntervalUpdate == EGL_TRUE) {
/* Send request from client to override swapinterval value based on
* server's swapinterval for overlay compositing
Expand Down Expand Up @@ -143,6 +141,10 @@ EGLBoolean wlEglSwapBuffersWithDamageHook(EGLDisplay eglDisplay, EGLSurface eglS
}
}

if (surface->isResized) {
wlEglResizeSurface(display, data, surface);
}

done:
// Release wlEglSurface lock.
pthread_mutex_unlock(&surface->mutexLock);
Expand Down

0 comments on commit 885f0a5

Please sign in to comment.