Merge branch 'wip/on-the-surface-good-fences-can-make-bad-neighbors' into 'master'

x11: Handle window getting unmap while frame still pending

Closes #2902

See merge request GNOME/gtk!2168
This commit is contained in:
Matthias Clasen 2020-06-30 19:21:45 +00:00
commit e25c25fcb5
2 changed files with 50 additions and 11 deletions

View File

@ -1184,7 +1184,7 @@ _gdk_wm_protocols_filter (const XEvent *xevent,
if (timings) if (timings)
timings->drawn_time = frame_drawn_time; timings->drawn_time = frame_drawn_time;
if (surface_impl->toplevel->frame_pending) if (!surface_impl->toplevel->frame_still_painting && surface_impl->toplevel->frame_pending)
{ {
surface_impl->toplevel->frame_pending = FALSE; surface_impl->toplevel->frame_pending = FALSE;
gdk_surface_thaw_updates (win); gdk_surface_thaw_updates (win);

View File

@ -582,6 +582,23 @@ create_legacy_context (GdkDisplay *display,
} }
#ifdef HAVE_XDAMAGE #ifdef HAVE_XDAMAGE
static void
finish_frame (GdkGLContext *context)
{
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
GdkSurface *surface = gdk_gl_context_get_surface (context);
if (context_x11->xdamage == 0)
return;
if (context_x11->frame_fence == 0)
return;
glDeleteSync (context_x11->frame_fence);
context_x11->frame_fence = 0;
_gdk_x11_surface_set_frame_still_painting (surface, FALSE);
}
static void static void
bind_context_for_frame_fence (GdkGLContext *context) bind_context_for_frame_fence (GdkGLContext *context)
{ {
@ -628,7 +645,6 @@ on_gl_surface_xevent (GdkGLContext *context,
GdkX11Display *display_x11) GdkX11Display *display_x11)
{ {
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context); GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
GdkSurface *surface = gdk_gl_context_get_surface (context);
XDamageNotifyEvent *damage_xevent; XDamageNotifyEvent *damage_xevent;
if (!context_x11->is_attached) if (!context_x11->is_attached)
@ -675,9 +691,7 @@ on_gl_surface_xevent (GdkGLContext *context,
case GL_WAIT_FAILED: case GL_WAIT_FAILED:
if (wait_result == GL_WAIT_FAILED) if (wait_result == GL_WAIT_FAILED)
g_warning ("failed to wait on GL fence associated with last swap buffers call"); g_warning ("failed to wait on GL fence associated with last swap buffers call");
glDeleteSync (context_x11->frame_fence); finish_frame (context);
context_x11->frame_fence = 0;
_gdk_x11_surface_set_frame_still_painting (surface, FALSE);
break; break;
/* We assume that if the fence hasn't been signaled, that this /* We assume that if the fence hasn't been signaled, that this
@ -696,6 +710,21 @@ on_gl_surface_xevent (GdkGLContext *context,
return FALSE; return FALSE;
} }
static void
on_surface_state_changed (GdkGLContext *context)
{
GdkSurface *surface = gdk_gl_context_get_surface (context);
if ((surface->state & GDK_SURFACE_STATE_WITHDRAWN) == 0)
return;
/* If we're about to withdraw the surface, then we don't care if the frame is
* still getting rendered by the GPU. The compositor is going to remove the surface
* from the scene anyway, so wrap up the frame.
*/
finish_frame (context);
}
#endif #endif
static gboolean static gboolean
@ -878,13 +907,23 @@ gdk_x11_gl_context_realize (GdkGLContext *context,
gdk_x11_surface_get_xid (surface), gdk_x11_surface_get_xid (surface),
XDamageReportRawRectangles); XDamageReportRawRectangles);
if (gdk_x11_display_error_trap_pop (display)) if (gdk_x11_display_error_trap_pop (display))
context_x11->xdamage = 0; {
context_x11->xdamage = 0;
}
else else
g_signal_connect_object (G_OBJECT (display), {
"xevent", g_signal_connect_object (G_OBJECT (display),
G_CALLBACK (on_gl_surface_xevent), "xevent",
context, G_CALLBACK (on_gl_surface_xevent),
G_CONNECT_SWAPPED); context,
G_CONNECT_SWAPPED);
g_signal_connect_object (G_OBJECT (surface),
"notify::state",
G_CALLBACK (on_surface_state_changed),
context,
G_CONNECT_SWAPPED);
}
} }
#endif #endif