From ac93ac087d5a443eae0d052ba9d0bbb38ca44214 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Mon, 11 Sep 2017 11:02:14 -0400 Subject: XPresent extension support - first pass --- configure.ac | 17 +++- src/compositor/compositor-xrender.c | 159 ++++++++++++++++++++++++++++++------ src/core/display.c | 4 + src/core/screen.c | 9 +- 4 files changed, 157 insertions(+), 32 deletions(-) diff --git a/configure.ac b/configure.ac index f2ac9ba3..cf2b5485 100644 --- a/configure.ac +++ b/configure.ac @@ -154,7 +154,7 @@ AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)]) AM_GLIB_GNU_GETTEXT -PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.36.0) +PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.36.0 xpresent) PKG_CHECK_MODULES(MARCO_MESSAGE, gtk+-3.0 >= $GTK_MIN_VERSION) PKG_CHECK_MODULES(MARCO_WINDOW_DEMO, gtk+-3.0 >= $GTK_MIN_VERSION) @@ -415,7 +415,19 @@ if test "x$found_xsync" = "xyes"; then AC_DEFINE(HAVE_XSYNC, , [Have the Xsync extension library]) fi -MARCO_LIBS="$MARCO_LIBS $XSYNC_LIBS $RANDR_LIBS $SHAPE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm" +XPRESENT_LIBS= +found_xpresent=no +AC_CHECK_LIB(Xpresent, XPresentPixmap, + [AC_CHECK_HEADER(X11/extensions/Xpresent.h, + XPRESENT_LIBS=-lXpresent found_xpresent=yes,, + [#include ])], + , $ALL_X_LIBS) + +if test "x$found_xpresent" = "xyes"; then + AC_DEFINE(HAVE_PRESENT, , [Have the Xpresent extension library]) +fi + +MARCO_LIBS="$MARCO_LIBS $XSYNC_LIBS $RANDR_LIBS $SHAPE_LIBS $XPRESENT_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm" MARCO_MESSAGE_LIBS="$MARCO_MESSAGE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" MARCO_WINDOW_DEMO_LIBS="$MARCO_WINDOW_DEMO_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" MARCO_PROPS_LIBS="$MARCO_PROPS_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" @@ -523,6 +535,7 @@ marco-$VERSION: Shape extension: ${found_shape} Resize-and-rotate: ${found_randr} Xsync: ${found_xsync} + Xpresent: ${found_xpresent} Render: ${have_xrender} Xcursor: ${have_xcursor} " diff --git a/src/compositor/compositor-xrender.c b/src/compositor/compositor-xrender.c index 04e89f66..34122a9f 100644 --- a/src/compositor/compositor-xrender.c +++ b/src/compositor/compositor-xrender.c @@ -39,6 +39,7 @@ #include #include "display.h" +#include "../core/display-private.h" #include "screen.h" #include "frame.h" #include "errors.h" @@ -52,6 +53,7 @@ #include #include #include +#include #define USE_IDLE_REPAINT 1 @@ -103,6 +105,9 @@ typedef struct _MetaCompositorXRender guint enabled : 1; guint show_redraw : 1; guint debug : 1; + guint has_present :1; + + int present_major; } MetaCompositorXRender; typedef struct _conv @@ -118,6 +123,7 @@ typedef struct _shadow guchar *shadow_top; } shadow; +#define NUM_BUFFER 2 typedef struct _MetaCompScreen { MetaScreen *screen; @@ -132,10 +138,13 @@ typedef struct _MetaCompScreen shadow *shadows[LAST_SHADOW_TYPE]; Picture root_picture; - Picture root_buffer; + Picture root_buffers[NUM_BUFFER]; + Pixmap root_pixmaps[NUM_BUFFER]; + int root_current; Picture black_picture; Picture trans_black_picture; Picture root_tile; + XserverRegion prev_damage; XserverRegion all_damage; guint overlays; @@ -143,6 +152,10 @@ typedef struct _MetaCompScreen gboolean clip_changed; GSList *dock_windows; + + uint32_t present_serial; + XID present_eid; + gboolean present_pending; } MetaCompScreen; typedef struct _MetaCompWindow @@ -675,6 +688,24 @@ find_window_for_child_window_in_display (MetaDisplay *display, return NULL; } +static MetaScreen * +find_screen_from_output(MetaDisplay *display, Window output) +{ + int i; + Display *xdisplay = meta_display_get_xdisplay(display); + + for (i = 0; i < ScreenCount(xdisplay); i++) + { + MetaScreen *screen = meta_display_screen_for_x_screen(display, + ScreenOfDisplay(xdisplay, i)); + MetaCompScreen *info = meta_screen_get_compositor_data(screen); + + if (info->output == output) + return screen; + } + return NULL; +} + static Picture solid_picture (MetaDisplay *display, MetaScreen *screen, @@ -796,8 +827,8 @@ root_tile (MetaScreen *screen) return picture; } -static Picture -create_root_buffer (MetaScreen *screen) +static void +create_root_buffer (MetaScreen *screen, int b) { MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); @@ -810,7 +841,7 @@ create_root_buffer (MetaScreen *screen) if (info == NULL) { - return None; + return; } meta_screen_get_size (screen, &screen_width, &screen_height); @@ -819,16 +850,15 @@ create_root_buffer (MetaScreen *screen) depth = DefaultDepth (xdisplay, screen_number); format = XRenderFindVisualFormat (xdisplay, visual); - g_return_val_if_fail (format != NULL, None); + g_return_if_fail (format != NULL); root_pixmap = XCreatePixmap (xdisplay, info->output, screen_width, screen_height, depth); - g_return_val_if_fail (root_pixmap != None, None); pict = XRenderCreatePicture (xdisplay, root_pixmap, format, 0, NULL); - XFreePixmap (xdisplay, root_pixmap); - return pict; + info->root_pixmaps[b] = root_pixmap; + info->root_buffers[b] = pict; } static void @@ -1306,16 +1336,14 @@ paint_windows (MetaScreen *screen, static void paint_all (MetaScreen *screen, - XserverRegion region) + XserverRegion region, + int b) { MetaCompScreen *info = meta_screen_get_compositor_data (screen); MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); int screen_width, screen_height; - /* Set clipping to the given region */ - XFixesSetPictureClipRegion (xdisplay, info->root_picture, 0, 0, region); - meta_screen_get_size (screen, &screen_width, &screen_height); if (DISPLAY_COMPOSITOR (display)->show_redraw) @@ -1330,6 +1358,9 @@ paint_all (MetaScreen *screen, ((double) (rand () % 100)) / 100.0, ((double) (rand () % 100)) / 100.0); + /* Set clipping to the given region */ + XFixesSetPictureClipRegion (xdisplay, info->root_picture, 0, 0, region); + XRenderComposite (xdisplay, PictOpOver, overlay, None, info->root_picture, 0, 0, 0, 0, 0, 0, screen_width, screen_height); XRenderFreePicture (xdisplay, overlay); @@ -1337,13 +1368,24 @@ paint_all (MetaScreen *screen, usleep (100 * 1000); } - if (info->root_buffer == None) - info->root_buffer = create_root_buffer (screen); - - paint_windows (screen, info->windows, info->root_buffer, region); - - XFixesSetPictureClipRegion (xdisplay, info->root_buffer, 0, 0, region); - XRenderComposite (xdisplay, PictOpSrc, info->root_buffer, None, + if (info->root_buffers[b] == None) + create_root_buffer (screen, b); + + paint_windows (screen, info->windows, info->root_buffers[b], region); + + /* FIXME: Things break here... */ + /* XPresentPixmap(xdisplay, */ + /* info->output, */ + /* info->root_pixmaps[b], */ + /* ++info->present_serial, */ + /* None, */ + /* region, */ + /* 0, 0, */ + /* None, None, None, PresentOptionNone, */ + /* 0, 1, 0, NULL, 0); */ + /* info->present_pending = True; */ + XFixesSetPictureClipRegion (xdisplay, info->root_buffers[b], 0, 0, region); + XRenderComposite (xdisplay, PictOpSrc, info->root_buffers[b], None, info->root_picture, 0, 0, 0, 0, 0, 0, screen_width, screen_height); } @@ -1355,11 +1397,19 @@ repair_screen (MetaScreen *screen) MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); - if (info!=NULL && info->all_damage != None) + if (info!=NULL && info->all_damage != None && !info->present_pending) { + XserverRegion damage = info->all_damage; meta_error_trap_push (display); - paint_all (screen, info->all_damage); - XFixesDestroyRegion (xdisplay, info->all_damage); + if (info->prev_damage) { + XFixesUnionRegion(xdisplay, info->prev_damage, info->prev_damage, damage); + damage = info->prev_damage; + } + paint_all (screen, damage, info->root_current); + if (info->prev_damage) + XFixesDestroyRegion (xdisplay, info->prev_damage); + info->root_current = !info->root_current; + info->prev_damage = info->all_damage; info->all_damage = None; info->clip_changed = FALSE; meta_error_trap_pop (display, FALSE); @@ -2143,10 +2193,18 @@ process_configure_notify (MetaCompositorXRender *compositor, return; info = meta_screen_get_compositor_data (screen); - if (info != NULL && info->root_buffer) + if (info != NULL) { - XRenderFreePicture (xdisplay, info->root_buffer); - info->root_buffer = None; + int b; + for (b = 0; b < NUM_BUFFER; b++) + { + if (info->root_buffers[b]) { + XRenderFreePicture (xdisplay, info->root_buffers[b]); + XFreePixmap (xdisplay, info->root_pixmaps[b]); + info->root_buffers[b] = None; + info->root_pixmaps[b] = None; + } + } } damage_screen (screen); @@ -2422,6 +2480,41 @@ process_shape (MetaCompositorXRender *compositor, } } +static void +xrender_present_complete(MetaScreen *screen, + XPresentCompleteNotifyEvent *ce) +{ + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + + info->present_pending = False; + repair_screen(screen); +} + +static void +process_generic(MetaCompositorXRender *compositor, + XGenericEvent *event) +{ + XGenericEventCookie *ge = (XGenericEventCookie *) event; + + if (ge->extension == compositor->present_major) { + Display *xdisplay = meta_display_get_xdisplay (compositor->display); + XGetEventData(xdisplay, ge); + switch (ge->evtype) { + case PresentConfigureNotify: + break; + case PresentCompleteNotify: { + XPresentCompleteNotifyEvent *ce = ge->data; + MetaScreen *screen = find_screen_from_output(compositor->display, ce->window); + if (screen) { + xrender_present_complete(screen, ce); + } + } + break; + } + XFreeEventData(xdisplay, ge); + } +} + static int timeout_debug (MetaCompositorXRender *compositor) { @@ -2506,6 +2599,7 @@ xrender_manage_screen (MetaCompositor *compositor, MetaScreen *screen) { #ifdef HAVE_COMPOSITE_EXTENSIONS + MetaCompositorXRender *xrc = (MetaCompositorXRender *) compositor; MetaCompScreen *info; MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); @@ -2513,6 +2607,7 @@ xrender_manage_screen (MetaCompositor *compositor, XRenderPictFormat *visual_format; int screen_number = meta_screen_get_screen_number (screen); Window xroot = meta_screen_get_xroot (screen); + int b; /* Check if the screen is already managed */ if (meta_screen_get_compositor_data (screen)) @@ -2554,7 +2649,10 @@ xrender_manage_screen (MetaCompositor *compositor, return; } - info->root_buffer = None; + for (b = 0; b < NUM_BUFFER; b++) { + info->root_buffers[b] = None; + info->root_pixmaps[b] = None; + } info->black_picture = solid_picture (display, screen, TRUE, 1, 0, 0, 0); info->root_tile = None; @@ -2578,6 +2676,10 @@ xrender_manage_screen (MetaCompositor *compositor, else meta_verbose ("Disabling shadows\n"); + if (xrc->has_present) + info->present_eid = XPresentSelectInput(xdisplay, info->output, + PresentConfigureNotifyMask|PresentCompleteNotifyMask); + XClearArea (xdisplay, info->output, 0, 0, 0, 0, TRUE); meta_screen_set_cm_selection (screen); @@ -2761,6 +2863,10 @@ xrender_process_event (MetaCompositor *compositor, process_destroy (xrc, (XDestroyWindowEvent *) event); break; + case GenericEvent: + process_generic (xrc, (XGenericEvent *) event); + break; + default: if (event->type == meta_display_get_damage_event_base (xrc->display) + XDamageNotify) process_damage (xrc, (XDamageNotifyEvent *) event); @@ -3066,6 +3172,7 @@ meta_compositor_xrender_new (MetaDisplay *display) xrc->atom_net_wm_window_type_tooltip = atoms[14]; xrc->show_redraw = FALSE; xrc->debug = FALSE; + xrc->has_present = XPresentQueryExtension(xdisplay, &xrc->present_major, NULL, NULL); #ifdef USE_IDLE_REPAINT meta_verbose ("Using idle repaint\n"); diff --git a/src/core/display.c b/src/core/display.c index 9601b4ed..a721def4 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -69,6 +69,10 @@ #include #endif +#ifdef HAVE_PRESENT + #include +#endif + #ifdef HAVE_XKB #include #endif diff --git a/src/core/screen.c b/src/core/screen.c index 28d2febf..308795e3 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -740,15 +740,16 @@ list_windows (MetaScreen *screen) children[i], &info->attrs); if (meta_error_trap_pop_with_return (screen->display, TRUE)) - { + { meta_verbose ("Failed to get attributes for window 0x%lx\n", children[i]); - g_free (info); + g_free (info); + continue; } else { - info->xwindow = children[i]; - } + info->xwindow = children[i]; + } result = g_list_prepend (result, info); } -- cgit v1.2.1