Compare commits

...

5 Commits

Author SHA1 Message Date
Ray Strode
c660175c76 xxx! add alex's hack for getting reproducible timings 2020-05-29 09:26:12 -04:00
Ray Strode
f3cced142c wip! gdkglcontext-x11: freeze frame clock while driver finishes swapping buffers
...and thaw it after the driver says it's finished and after the
X server says the window has been updated.
2020-05-29 09:24:30 -04:00
Ray Strode
52246a504f wip! gdkdisplay-x11: flag nvidia as needing special damage handling 2020-05-29 09:24:30 -04:00
Ray Strode
93f1e72b94 wip! gdkdisplay-x11: Add support for the damage extension
The GL code needs to watch for its own damage to know when
it's okay to proceed to after-paint.
2020-05-29 09:24:30 -04:00
Ray Strode
504f8905a3 gdkframeclockidle: handle frame clock getting frozen during paint
At the moment if the frame clock is frozen while in the paint phase,
when it's later thawed, it redoes the paint phase instead of
correctly proceeding to after_paint.

This commit fixes that.
2020-05-29 09:24:30 -04:00
11 changed files with 152 additions and 14 deletions

View File

@@ -146,6 +146,9 @@
/* Have the Xcursor library */
#mesondefine HAVE_XCURSOR
/* Have the XDAMAGE X extension */
#mesondefine HAVE_XDAMAGE
/* Have the XFIXES X extension */
#mesondefine HAVE_XFIXES

View File

@@ -50,6 +50,7 @@
<object class="GtkToggleButton" id="changes_allow">
<property name="icon-name">changes-allow</property>
<property name="has-frame">0</property>
<property name="active">1</property>
<signal name="notify::active" handler="fishbowl_changes_toggled_cb"/>
</object>
</child>

View File

@@ -160,7 +160,7 @@ static double
new_speed (void)
{
/* 5s to 50s to cross screen seems fair */
return g_random_double_range (0.02, 0.2);
return 0.4;//g_random_double_range (0.02, 0.2);
}
static void
@@ -574,23 +574,23 @@ gtk_fishbowl_tick (GtkWidget *widget,
if (child->x <= 0)
{
child->x = 0;
child->x = -child->x;
child->dx = new_speed ();
}
else if (child->x >= 1)
{
child->x = 1;
child->x = 2 - child->x;
child->dx = - new_speed ();
}
if (child->y <= 0)
{
child->y = 0;
child->y = -child->y;
child->dy = new_speed ();
}
else if (child->y >= 1)
{
child->y = 1;
child->y = 2 - child->y;
child->dy = - new_speed ();
}
}

View File

@@ -10,6 +10,7 @@
#include "demos.h"
static gboolean is_run;
static GtkWidget *info_view;
static GtkWidget *source_view;
@@ -1031,7 +1032,8 @@ activate (GApplication *app)
gtk_tree_view_collapse_all (GTK_TREE_VIEW (treeview));
gtk_widget_show (GTK_WIDGET (window));
if (!is_run)
gtk_widget_show (GTK_WIDGET (window));
g_object_unref (builder);
}
@@ -1077,13 +1079,17 @@ command_line (GApplication *app,
GDoDemoFunc func = 0;
GtkWidget *window, *demo;
activate (app);
options = g_application_command_line_get_options_dict (cmdline);
g_variant_dict_lookup (options, "run", "&s", &name);
g_variant_dict_lookup (options, "autoquit", "b", &autoquit);
g_variant_dict_lookup (options, "list", "b", &list);
is_run = name != NULL;
activate (app);
if (list)
{
list_demos ();

View File

@@ -207,6 +207,7 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
#define RUN_PAINT_IDLE(priv) \
((priv)->freeze_count == 0 && \
(((priv)->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0 || \
(priv)->phase > GDK_FRAME_CLOCK_PHASE_PAINT || \
(priv)->updating_count > 0))
static void
@@ -235,6 +236,12 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle)
g_source_set_name_by_id (priv->flush_idle_id, "[gtk] gdk_frame_clock_flush_idle");
}
/* If we've already painted the frame, then we should finish up this tick as quickly
* as possible
*/
if (priv->phase > GDK_FRAME_CLOCK_PHASE_PAINT)
min_interval = 0;
if (!priv->in_paint_idle &&
priv->paint_idle_id == 0 && RUN_PAINT_IDLE (priv))
{
@@ -452,6 +459,7 @@ gdk_frame_clock_paint_idle (void *data)
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_PAINT;
_gdk_frame_clock_emit_paint (clock);
}
priv->phase = GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
}
G_GNUC_FALLTHROUGH;
@@ -463,11 +471,11 @@ gdk_frame_clock_paint_idle (void *data)
/* the ::after-paint phase doesn't get repeated on freeze/thaw,
*/
priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
}
#ifdef G_ENABLE_DEBUG
if (GDK_DEBUG_CHECK (FRAMES))
timings->frame_end_time = g_get_monotonic_time ();
if (GDK_DEBUG_CHECK (FRAMES))
timings->frame_end_time = g_get_monotonic_time ();
#endif /* G_ENABLE_DEBUG */
}
G_GNUC_FALLTHROUGH;
case GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS:

View File

@@ -1603,6 +1603,14 @@ gdk_x11_display_open (const gchar *display_name)
}
#endif
display_x11->have_damage = FALSE;
#ifdef HAVE_XDAMAGE
if (XDamageQueryExtension (display_x11->xdisplay,
&display_x11->damage_event_base,
&display_x11->damage_error_base))
display_x11->have_damage = TRUE;
#endif
display->clipboard = gdk_x11_clipboard_new (display, "CLIPBOARD");
display->primary_clipboard = gdk_x11_clipboard_new (display, "PRIMARY");

View File

@@ -149,6 +149,11 @@ struct _GdkX11Display
guint has_glx_multisample : 1;
guint has_glx_visual_rating : 1;
guint has_glx_create_es2_context : 1;
guint has_glx_implicit_damage : 1;
gint damage_event_base;
gint damage_error_base;
guint have_damage;
};
struct _GdkX11DisplayClass

View File

@@ -183,6 +183,16 @@ gdk_x11_gl_context_end_frame (GdkDrawContext *draw_context,
gdk_x11_surface_pre_damage (surface);
#ifdef HAVE_XDAMAGE
if (context_x11->xdamage != 0)
{
g_assert (context_x11->frame_fence == 0);
context_x11->frame_fence = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
gdk_surface_freeze_updates (surface);
}
#endif
glXSwapBuffers (dpy, drawable);
if (context_x11->do_frame_sync && info != NULL && display_x11->has_glx_video_sync)
@@ -565,6 +575,45 @@ create_legacy_context (GdkDisplay *display,
return res;
}
#ifdef HAVE_XDAMAGE
static gboolean
on_gl_surface_xevent (GdkGLContext *context,
XEvent *xevent,
GdkX11Display *display_x11)
{
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
GdkSurface *surface = gdk_gl_context_get_surface (context);
XDamageNotifyEvent *damage_xevent;
if (!context_x11->is_attached)
return FALSE;
if (xevent->type != (display_x11->damage_event_base + XDamageNotify))
return FALSE;
damage_xevent = (XDamageNotifyEvent *) xevent;
if (damage_xevent->damage != context_x11->xdamage)
return FALSE;
if (context_x11->frame_fence)
{
GLenum wait_result;
wait_result = glClientWaitSync (context_x11->frame_fence, 0, 0);
if (wait_result == GL_ALREADY_SIGNALED)
{
glDeleteSync (context_x11->frame_fence);
context_x11->frame_fence = 0;
gdk_surface_thaw_updates (surface);
}
}
return FALSE;
}
#endif
static gboolean
gdk_x11_gl_context_realize (GdkGLContext *context,
GError **error)
@@ -737,6 +786,29 @@ gdk_x11_gl_context_realize (GdkGLContext *context,
context_x11->attached_drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_surface_get_xid (surface);
context_x11->unattached_drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
#ifdef HAVE_XDAMAGE
if (display_x11->have_damage && display_x11->has_glx_implicit_damage)
{
gdk_x11_display_error_trap_push (display);
context_x11->xdamage = XDamageCreate (dpy,
gdk_x11_surface_get_xid (surface),
XDamageReportRawRectangles);
if (gdk_x11_display_error_trap_pop (display))
{
XDamageDestroy (dpy, context_x11->xdamage);
context_x11->xdamage = 0;
}
else
{
g_signal_connect_object (G_OBJECT (display),
"xevent",
G_CALLBACK (on_gl_surface_xevent),
context,
G_CONNECT_SWAPPED);
}
}
#endif
context_x11->is_direct = glXIsDirect (dpy, context_x11->glx_context);
GDK_DISPLAY_NOTE (display, OPENGL,
@@ -751,13 +823,15 @@ static void
gdk_x11_gl_context_dispose (GObject *gobject)
{
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (gobject);
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
GdkDisplay *display = gdk_gl_context_get_display (context);
Display *dpy = NULL;
if (display != NULL)
dpy = gdk_x11_display_get_xdisplay (display);
if (context_x11->glx_context != NULL)
{
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
GdkDisplay *display = gdk_gl_context_get_display (context);
Display *dpy = gdk_x11_display_get_xdisplay (display);
if (glXGetCurrentContext () == context_x11->glx_context)
glXMakeContextCurrent (dpy, None, None, NULL);
@@ -766,6 +840,14 @@ gdk_x11_gl_context_dispose (GObject *gobject)
context_x11->glx_context = NULL;
}
#ifdef HAVE_XDAMAGE
if (context_x11->xdamage != 0)
{
XDamageDestroy (dpy, context_x11->xdamage);
context_x11->xdamage = 0;
}
#endif
G_OBJECT_CLASS (gdk_x11_gl_context_parent_class)->dispose (gobject);
}
@@ -841,6 +923,16 @@ gdk_x11_screen_init_gl (GdkX11Screen *screen)
display_x11->has_glx_visual_rating =
epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_visual_rating");
if (g_strcmp0 (glXGetClientString (dpy, GLX_VENDOR), "NVIDIA Corporation") == 0)
{
/* NVidia doesn't send damage from the client library during buffer swap.
* Instead, damage only gets sent by the Xserver later, and we can't
* continue the frame paint cycle until we know the compositor has seen
* the damage.
*/
display_x11->has_glx_implicit_damage = TRUE;
}
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("GLX version %d.%d found\n"
" - Vendor: %s\n"

View File

@@ -24,6 +24,10 @@
#include <X11/X.h>
#include <X11/Xlib.h>
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#include <epoxy/gl.h>
#include <epoxy/glx.h>
@@ -44,6 +48,11 @@ struct _GdkX11GLContext
GLXDrawable attached_drawable;
GLXDrawable unattached_drawable;
#ifdef HAVE_XDAMAGE
GLsync frame_fence;
Damage xdamage;
#endif
guint is_attached : 1;
guint is_direct : 1;
guint do_frame_sync : 1;

View File

@@ -65,6 +65,7 @@ gdk_x11_deps = [
xext_dep,
x11_dep,
xcursor_dep,
xdamage_dep,
xfixes_dep,
xcomposite_dep,
xrandr_dep,

View File

@@ -507,6 +507,7 @@ if x11_enabled
xi_dep = dependency('xi')
xext_dep = dependency('xext')
xcursor_dep = dependency('xcursor', required: false)
xdamage_dep = dependency('xdamage', required: false)
xfixes_dep = dependency('xfixes', required: false)
xcomposite_dep = dependency('xcomposite', required: false)
fontconfig_dep = dependency('fontconfig')
@@ -519,6 +520,9 @@ if x11_enabled
if xcursor_dep.found()
x11_pkgs += ['xcursor']
endif
if xdamage_dep.found()
x11_pkgs += ['xdamage']
endif
if xfixes_dep.found()
x11_pkgs += ['xfixes']
endif
@@ -529,6 +533,7 @@ if x11_enabled
atk_pkgs += ['atk-bridge-2.0']
cdata.set('HAVE_XCURSOR', xcursor_dep.found())
cdata.set('HAVE_XDAMAGE', xdamage_dep.found())
cdata.set('HAVE_XCOMPOSITE', xcomposite_dep.found())
cdata.set('HAVE_XFIXES', xfixes_dep.found())