chjj / compton

A compositor for X11.
Other
2.25k stars 498 forks source link

Feature Request: Add some kind of unredir exclude list option #140

Closed dflock closed 11 years ago

dflock commented 11 years ago

It would work the same way as fade-exclude but allow you to specify a list of window conditions that, when matched, would mean that unredir-if-possible is ignored. Something like:

unredir-exclude = [ ];

and used like:

unredir-exclude = [
    "name *= 'Sublime Text'"
];

The problem I'm having is that I have two monitors, and tend to have a code editor (sublimetext) open full-screen on the right monitor and other stuff non-fullscreen on the left one.

When I switch from one virtual workspace to another, to or from one with a full screen sublimetext, I tend to get flickering and corruption and sometimes freezes - especially if I flick rapidly between workspaces.

I think this is largely because of me having unredir-if-possible set, for full screen games performance. My full config is here: http://duncanlock.net/blog/2013/06/07/how-to-switch-to-compton-for-beautiful-tear-free-compositing-in-xfce/

If there's a better way to fix this problem, or this feature wouldn't work, then I'd love to know :)

Thanks for all your work on Compton - much appreciated!

Feltzer commented 11 years ago

This feature would also be useful for excluding video players out of the unredirect list (in order to keep vsync active and eliminate tearing).

richardgv commented 11 years ago

The feature is in richardgv-dev branch, and it should be rather intuitive to use, I guess. See the commit log above and compton -h. I hope there aren't any big issues. Sorry for the long delay, I don't have as much time to invest since I got a job.

In addition to --unredir-if-possible-exclude, --unredir-if-possible-delay may be helpful for flickering of high frequency.

And, the problem probably isn't that simple. Flickering when (un)redirecting screen is normal, but corruptions and freezes may be hints of bugs in compton or your driver. You may wish to further investigate the issue by, for example, debugging compton with gdb when it's freezing.

Also, you may use the D-Bus interface to (un)redirect screen (see dbus-examples/cdbus-driver.sh) for more fine-grained control.

@dflock:

Your blog entry is one of the most extensive introduction to compton I've seen. :-) And the illustration in your other posts are interesting.

We typically recommend against matching with window name, because, huh, you could very well have a Firefox window with "Chrome" in its name when you are visiting a web page with such title.

glx-no-rebind-pixmap is a pretty safe optimization. It's only known to break on LLVMpipe.

glx-swap-method should be helpful on older cards. Although nvidia-driver supports GLX_EXT_buffer_age, it seemingly doesn't return the correct value, and I typically use 3. (Note if you use both --blur-background and --glx-swap-method, --resize-damage may be needed to eliminate some artifacts.)

Feltzer commented 11 years ago

--unredir-if-possible-exclude works great for me so far. I have yet to encounter any issues. Looking forward to seeing this added as a config option.


I don't know if this is the right place to ask but I have a somewhat related problem:

I am sometimes running a graphically intensive 3D application on one screen while having a regular desktop and windows render on the other. From my experience 3D rendering does take quite a significant hit when compositing is enabled. That's why I am wondering if unredirecting the content on one screen - if technically feasible - could maybe alleviate that.

To take things further, would it be possible to disable compositing for single applications? And if so, could this increase the performance when working with this particular application or does composition have to be disabled altogether to see any performance gains?

I don't know too much about the linux graphic stack and/or compositing so please excuse me if these ideas are completely stupid or out of touch with reality :). I would love to hear your thoughts, though.

Thanks, again, for taking the time to read this.

richardgv commented 11 years ago

--unredir-if-possible-exclude works great for me so far. I have yet to encounter any issues. Looking forward to seeing this added as a config option.

Could you please test if --unredir-if-possible-delay works as well? I wish to add both to configuration file at once.

I am sometimes running a graphically intensive 3D application on one screen while having a regular desktop and windows render on the other. From my experience 3D rendering does take quite a significant hit when compositing is enabled. That's why I am wondering if unredirecting the content on one screen - if technically feasible - could maybe alleviate that.

If you have several separate X screens, then yes, just avoid running compton on the screen you don't wish to redirect; if you use Xinerama/TwinView that combines your screens to one big virtual screen, then no, I'm not aware of a way to redirect a specific region on the screen. For redirecting a specific window, see below.

To take things further, would it be possible to disable compositing for single applications? And if so, could this increase the performance when working with this particular application or does composition have to be disabled altogether to see any performance gains?

Although technically possible, I suppose it actually breaks window stacking. I don't think you could have a unredirected window sitting below any redirected windows correctly. Remember how X composite works: It lets a client composite pictures of redirected windows to the final composited screen image with all the fancy effects, and paints it to the root window. How could X then correctly stack one unredirected window into this image if the unredirected window is not on the top of all redirected windows?

And even if it works, removing a single window probably isn't going to bring massive performance improvement anyway.

I would say if you have used some painting-rate throttling options (--vsync=drm/opengl/opengl-oml, --sw-opti), and your CPU/GPU is not fully occupied, compton shouldn't bring too much impact on performance.

Perhaps, the source of a large part of the performance loss is not in compton but somewhere else -- X composite, maybe. With a full-screen glxgears, a properly optimized compton (without using VSync, aka --opengl --glx-swap-method 3 --glx-no-stencil --glx-no-rebind-pixmap) only introduces about 3% performance loss (FPS 6000 vs. 5800), but when there are lots of windows, the performance loss is around 25% here (FPS 33000 vs. 25000), even when I limit painting rate to 60Hz, and disabling painting of all windows with --paint-exclude. Wayland is probably the solution.

Some articles about compositor performance I found. People say compositing is not going to bring performance loss, and god knows how it happened.

http://blog.martin-graesslin.com/blog/2013/05/compositing-and-lightweight-desktops/ http://blog.fishsoup.net/2011/06/13/benchmarking-compositor-performance/ http://www.phoronix.com/scan.php?page=article&item=linux_desktop_managers1&num=1 http://www.phoronix.com/scan.php?page=article&item=ubuntu_unity_64&num=1

Feltzer commented 11 years ago

Richard, thank you for your very detailed response. Both your remarks and the links were very interesting to read and I can now safely say that I understand the performance impact of compositing much better than before.

Most of my particular issues with graphics performance probably stem from FGLRX. And believe me, as soon as Linux 3.12 and the new Mesa drivers become more stable I'll say farewell to proprietary AMD drivers.

Could you please test if --unredir-if-possible-delay works as well? I wish to add both to configuration file at once.

I have done some testing with this option active and found a few problems:

Here's a recording of top and compton's output while setting a newly spawned window to fullscreen:

compton --config '/home/bob/.config/compton/compton.conf' --unredir-if-possible-delay 3
restack_win(0x0100f6de, 0x0100f670): Failed to found new above window.
[   112.80 ] error 3 (BadWindow) request 2 minor 0 serial 1658413 ("BadWindow (invalid Window parameter)")
[   130.91 ] error 3 (BadWindow) request 20 minor 0 serial 1676397 ("BadWindow (invalid Window parameter)")
[   130.91 ] error 3 (BadWindow) request 20 minor 0 serial 1676398 ("BadWindow (invalid Window parameter)")
[   130.91 ] error 3 (BadWindow) request 20 minor 0 serial 1676399 ("BadWindow (invalid Window parameter)")
[   130.91 ] error 3 (BadWindow) request 20 minor 0 serial 1676400 ("BadWindow (invalid Window parameter)")  

    # Recording start

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
     2737 root      20   0  484m 224m 196m S    2  5.9  11:59.08 Xorg               
    16106 bob       20   0  108m  29m  18m S    0  0.8   0:34.42 compton            

    # Window in fullscreen

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
    16106 bob       20   0  108m  29m  18m R   23  0.8   0:35.55 compton            
     2737 root      20   0  520m 245m 218m S   16  6.4  11:59.86 Xorg               

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
    16106 bob       20   0  108m  29m  18m R   98  0.8   0:40.47 compton            
     2737 root      20   0  512m 237m 210m S    3  6.2  12:00.03 Xorg               

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
    16106 bob       20   0  108m  29m  18m R   97  0.8   0:45.31 compton            
     2737 root      20   0  519m 245m 218m S   12  6.4  12:00.61 Xorg               

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
    16106 bob       20   0  108m  29m  18m R   96  0.8   0:50.13 compton            
     2737 root      20   0  520m 245m 218m S    9  6.4  12:01.06 Xorg               

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
    16106 bob       20   0  108m  29m  18m R   95  0.8   0:54.86 compton            
     2737 root      20   0  520m 245m 218m R   16  6.4  12:01.85 Xorg               

    # Window restored

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
    16106 bob       20   0  108m  29m  18m S   18  0.8   1:26.57 compton            
     2737 root      20   0  493m 232m 205m R   11  6.1  12:12.07 Xorg               

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
     2737 root      20   0  528m 250m 222m S   16  6.6  12:12.89 Xorg               
    16106 bob       20   0  108m  29m  18m S    2  0.8   1:26.65 compton            

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
     2737 root      20   0  519m 241m 214m S    4  6.3  12:13.08 Xorg               
    16106 bob       20   0  108m  29m  18m S    0  0.8   1:26.67 compton    
richardgv commented 11 years ago

@Feltzer:

Modify some primary sections to attempt to resolve the issues, but it may bring other problems. I'm at work, can't test much:

diff --git a/src/compton.c b/src/compton.c
index b8f1fc6..77b44b6 100644
--- a/src/compton.c
+++ b/src/compton.c
@@ -1102,9 +1102,16 @@ paint_preprocess(session_t *ps, win *list) {
     next = w->next;
     opacity_t opacity_old = w->opacity;

-    // Destroy reg_ignore on all windows if they should expire
-    if (ps->reg_ignore_expire)
-      free_region(ps, &w->reg_ignore);
+    // Data expiration
+    {
+      // Remove built shadow if needed
+      if (w->flags & WFLAG_SIZE_CHANGE)
+        free_paint(ps, &w->shadow_paint);
+
+      // Destroy reg_ignore on all windows if they should expire
+      if (ps->reg_ignore_expire)
+        free_region(ps, &w->reg_ignore);
+    }

     // Update window opacity target and dim state if asked
     if (WFLAG_OPCT_CHANGE & w->flags) {
@@ -1115,43 +1122,33 @@ paint_preprocess(session_t *ps, win *list) {
     // Run fading
     run_fade(ps, w, steps);

+    // Opacity will not change, for now on.
+
     // Give up if it's not damaged or invisible, or it's unmapped and its
-    // pixmap is gone (for example due to a ConfigureNotify)
+    // pixmap is gone (for example due to a ConfigureNotify), or when it's
+    // excluded
     if (!w->damaged
         || w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1
         || w->a.x >= ps->root_width || w->a.y >= ps->root_height
-        || ((IsUnmapped == w->a.map_state || w->destroyed)
-          && !w->paint.pixmap)) {
+        || ((IsUnmapped == w->a.map_state || w->destroyed) && !w->paint.pixmap)
+        || get_alpha_pict_o(ps, w->opacity) == ps->alpha_picts[0]
+        || w->paint_excluded)
       to_paint = false;
-    }

-    to_paint = to_paint && !w->paint_excluded;
+    // to_paint will never change afterward

-    if (to_paint) {
-      // If opacity changes
-      if (w->opacity != opacity_old) {
-        win_determine_mode(ps, w);
-        add_damage_win(ps, w);
-      }
-
-      if (get_alpha_pict_o(ps, w->opacity) == ps->alpha_picts[0])
-        to_paint = false;
-    }
+    // Determine mode as early as possible
+    if ((to_paint && !w->to_paint) || w->opacity != opacity_old)
+      win_determine_mode(ps, w);

     if (to_paint) {
       // Fetch bounding region
-      if (!w->border_size) {
+      if (!w->border_size)
         w->border_size = border_size(ps, w, true);
-      }

       // Fetch window extents
-      if (!w->extents) {
+      if (!w->extents)
         w->extents = win_extents(ps, w);
-        // If w->extents does not exist, the previous add_damage_win()
-        // call when opacity changes has no effect, so redo it here.
-        if (w->opacity != opacity_old)
-          add_damage_win(ps, w);
-      }

       // Calculate frame_opacity
       {
@@ -1164,6 +1161,8 @@ paint_preprocess(session_t *ps, win *list) {
         else
           w->frame_opacity = 0.0;

+        // Destroy all reg_ignore above when frame opacity changes on
+        // SOLID mode
         if (w->to_paint && WMODE_SOLID == mode_old
             && (0.0 == frame_opacity_old) != (0.0 == w->frame_opacity))
           ps->reg_ignore_expire = true;
@@ -1174,24 +1173,18 @@ paint_preprocess(session_t *ps, win *list) {
         w->shadow_opacity = ps->o.shadow_opacity * w->frame_opacity;
       else
         w->shadow_opacity = ps->o.shadow_opacity * get_opacity_percent(w);
-
-      // Rebuild shadow if necessary
-      if (w->flags & WFLAG_SIZE_CHANGE) {
-        free_paint(ps, &w->shadow_paint);
-      }
-
-      if (w->shadow && !paint_isvalid(ps, &w->shadow_paint))
-        win_build_shadow(ps, w, 1);
     }

+    // Add window to damaged area if its painting status changes
+    // or opacity changes
+    if (to_paint != w->to_paint || w->opacity != opacity_old)
+      add_damage_win(ps, w);
+
+    // Destroy all reg_ignore above when window mode changes
     if ((to_paint && WMODE_SOLID == w->mode)
         != (w->to_paint && WMODE_SOLID == mode_old))
       ps->reg_ignore_expire = true;

-    // Add window to damaged area if its painting status changes
-    if (to_paint != w->to_paint)
-      add_damage_win(ps, w);
-
     if (to_paint) {
       // Generate ignore region for painting to reduce GPU load
       if (ps->reg_ignore_expire || !w->to_paint) {
@@ -1264,6 +1257,10 @@ paint_preprocess(session_t *ps, win *list) {
   if (UNSET != ps->o.redirected_force)
     unredir_possible = !ps->o.redirected_force;

+  // If there's no window to paint, and the screen isn't redirected,
+  // don't redirect it.
+  if (ps->o.unredir_if_possible && is_highest && !ps->redirected)
+    unredir_possible = true;
   if (unredir_possible) {
     if (ps->redirected) {
       if (!ps->o.unredir_if_possible_delay || ps->tmout_unredir_hit)
@@ -1785,6 +1782,10 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
   for (win *w = t; w; w = w->prev_trans) {
     // Painting shadow
     if (w->shadow) {
+      // Lazy shadow building
+      if (!paint_isvalid(ps, &w->shadow_paint))
+        win_build_shadow(ps, w, 1);
+
       // Shadow is to be painted based on the ignore region of current
       // window
       if (w->reg_ignore) {
@@ -2050,6 +2051,13 @@ wid_get_prop_wintype(session_t *ps, Window wid) {

 static void
 map_win(session_t *ps, Window id) {
+  // Unmap overlay window if it got mapped but we are currently not
+  // in redirected state.
+  if (ps->overlay && id == ps->overlay && !ps->redirected) {
+    XUnmapWindow(ps->dpy, ps->overlay);
+    XFlush(ps->dpy);
+  }
+
   win *w = find_win(ps, id);

   // Don't care about window mapping if it's an InputOnly window
@@ -2831,14 +2839,13 @@ add_win(session_t *ps, Window id, Window prev) {
   assert(IsViewable == map_state || IsUnmapped == map_state);
   new->a.map_state = IsUnmapped;

-  // Get window picture format
-  if (InputOutput == new->a.class)
+  if (InputOutput == new->a.class) {
+       // Get window picture format
     new->pictfmt = XRenderFindVisualFormat(ps->dpy, new->a.visual);

-  // Create Damage for window
-  if (InputOutput == new->a.class) {
-    set_ignore_next(ps);
-    new->damage = XDamageCreate(ps->dpy, id, XDamageReportNonEmpty);
+       // Create Damage for window
+       set_ignore_next(ps);
+       new->damage = XDamageCreate(ps->dpy, id, XDamageReportNonEmpty);
   }

   calc_win_size(ps, new);
@@ -6097,6 +6104,11 @@ init_overlay(session_t *ps) {
     // Retrieve DamageNotify on root window if we are painting on an
     // overlay
     // root_damage = XDamageCreate(ps->dpy, root, XDamageReportNonEmpty);
+
+    // Unmap overlay, firstly. But this typically does not work because
+    // the window isn't created yet.
+    // XUnmapWindow(ps->dpy, ps->overlay);
+    // XFlush(ps->dpy);
   }
   else {
     fprintf(stderr, "Cannot get X Composite overlay window. Falling "
@@ -6371,6 +6383,9 @@ tmout_unredir_callback(session_t *ps, timeout_t *tmout) {
  */
 static bool
 mainloop(session_t *ps) {
+  // Don't miss timeouts even when we have a LOT of other events!
+  timeout_run(ps);
+
   // Process existing events
   // Sometimes poll() returns 1 but no events are actually read,
   // causing XNextEvent() to block, I have no idea what's wrong, so we
@@ -6444,8 +6459,6 @@ mainloop(session_t *ps) {
   free(ptv);
   ptv = NULL;

-  timeout_run(ps);
-
   return true;
 }

@@ -6732,6 +6745,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
     | ExposureMask
     | StructureNotifyMask
     | PropertyChangeMask);
+  XFlush(ps->dpy);

   ps->root_width = DisplayWidth(ps->dpy, ps->scr);
   ps->root_height = DisplayHeight(ps->dpy, ps->scr);
richardgv commented 11 years ago

Updated patch: https://gist.github.com/richardgv/6524881

The reason I don't merge it is I found a very strange bug after applying the patch: With GTX 670 and x11-drivers/nvidia-drivers-325.15, and compton --unredir-if-possible --config /dev/null, if you send a SIGUSR1 to compton when a full-screen solid window is there, in which case compton either redirects then immediately unredirects the screen, or just don't redirect it altogether, X freezes after compton unredirects the screen. Requests sent by other X clients are not responded until compton is killed, which indicates the possibility of a bug in X. Attaching to X process shows X is on ./os/waitFor.c. Backend does not matter. --paint-on-overlay fixes the issue somehow. compton-git-v0.1_beta1-5-g4600f43-2013-08-28 doesn't exhibit the issue, but it's probably timing-related.

richardgv commented 11 years ago

@Feltzer:

Changed pushed to richardgv-dev branch despite the problem, since it's very rare and probably is a X bug. Does it solve your problems?

Feltzer commented 11 years ago

@richardgv:

Everything working fine here! Delay is correctly applied to both new and old windows and the performance issues are gone. Once again: Good work and thanks for the quick fix!

Feltzer commented 11 years ago

@richardgv

Hey Richard,

I just wanted to drop in quickly to ask if you are still planning to add these options to the config file. I'd love to be able to use the unredir exclude option this way.

Thanks in advance!

richardgv commented 11 years ago

@Feltzer:

Ooooops, sorry, I forgot about it! Just added it as f202223 (richardgv-dev branch).

Feltzer commented 11 years ago

Thanks for adding this, @richardgv. Unfortunately I can't seem to be able to get this to work again. Neither compton --unredir-if-possible --unredir-if-possible-exclude 'class_g = "vlc"' nor

unredir-if-possible = true;
unredir-if-possible-exclude = [
        "class_g ?= 'vlc'"
];

in the config file will work for me.

Can you confirm this or am I doing something wrong?

richardgv commented 11 years ago

@Feltzer:

Well, I put the very content at the end of compton.sample.conf, and it works here: Full-screen qvlc-2.0.7 no longer get unredirected, including "Full-screen interface" (F11) and full-screen video playback (after the control bar disappears). I dropped unredir-if-possible-exclude and unredirection works correctly, as well.

The commandline argument --unredir-if-possible-exclude 'class_g = "vlc"' will not work, because the general WM_CLASS of a qvlc window (not sure about the themed vlc one) is "Vlc", not "vlc".

I would say most likely you made some tiny mistakes here: Wrote the content to the wrong file, case mistakes, forgot to build compton after git pull, etc. Building compton with CPPFLAGS='-DDEBUG_REDIR -DDEBUG_C2' might show you something helpful.