chjj / compton

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

Screenshot doesnt work correctly when paint-on-overlay = true #204

Open ashleysommer opened 10 years ago

ashleysommer commented 10 years ago

After changing from opensource radeon drivers to the latest fglrx dirvers, I have found if I use a screen capture app to take a screen shot (any popular screen shot app) it gives me an image of the screen from several minutes in the past. If I change my compton configuration to paint-on-overlay = false; then the screenshot app works correctly and gives me a current image of the contents of the screen.

Im guessing the screeshot apps are not capturing from the overlay buffer? If so, then why did it work correctly with the opensource radeon drivers with paint-on-overlay = true?

Is this a known issue, and is there a workaround?

At the moment, if I know I will need to take a screenshot, I simply restart compton with paint-on-overlay disabled, but after Im done I have to restart compton with paint-on-overlay re-enabled because the graphics performance with it disabled is terrible and I have lots of glitches.

richardgv commented 10 years ago
  1. We have received no similar reports so far.
  2. Does changing compton's backend help? Does using an empty configuration (compton --config /dev/null --backend YOUR-WANTED-BACKEND) help?
  3. Does it only happen when you are taking a full-screen screenshot?
  4. As you may already know, fglrx is one of the most buggy graphic drivers in the Unix world. :-D We have encountered quite a few bugs with it in the past years, and it won't be too surprising if there's another one.
  5. You could try a few different screenshot takers: scrot, shutter, ImageMagick, etc. I suppose they all use very similar techniques (XGetImage() / XGetShmImage() on root window), though.
  6. As far as I know the screenshot tools read from the root window. X might then copy from the overlay window into the root window somehow, not really sure.
  7. fglrx has a few options in xorg.conf that can be tuned. Specifically, the OpenGLOverlay option may bring something interesting.
  8. You could get capture a screenshot of the overlay window directly with xwd, but it's pretty complicated. Firstly, compile compton with debugging symbols (CFLAGS=-g make -B), then do some debugging with gdb to figure out the overlay window ID (note that you need to run gdb in screen/tmux and attach it in a virtual console, because the X screen may not be updated when you are debugging compton):

    $ gdb --args ./compton --paint-on-overlay
    GNU gdb (Gentoo 7.7.1 p1) 7.7.1
    Copyright (C) 2014 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-pc-linux-gnu".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    <http://bugs.gentoo.org/>.
    Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
    For help, type "help".
    Type "apropos word" to search for commands related to "word"...
    Reading symbols from ./compton...done.
    (gdb) b init_overlay
    Breakpoint 1 at 0x417f5c: file src/compton.c, line 6377.
    (gdb) r
    Starting program: /home/richard/git/compton/compton --paint-on-overlay
    warning: Could not load shared library symbols for linux-vdso.so.1.
    Do you need "set solib-search-path" or "set sysroot"?
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib64/libthread_db.so.1".
    
    Breakpoint 1, init_overlay (ps=0x43c090) at src/compton.c:6377
    6377      ps->overlay = XCompositeGetOverlayWindow(ps->dpy, ps->root);
    (gdb) fin
    Run till exit from #0  init_overlay (ps=0x43c090) at src/compton.c:6377
    session_init (ps_old=0x0, argc=2, argv=0x7fffffffde38) at src/compton.c:7169
    7169      if (ps->o.dbe && BKEND_XRENDER != ps->o.backend) {
    (gdb) p/x ps->overlay
    $1 = 0x290
    (gdb) c

    So the overlay window ID here is 0x290. Now take a screenshot with xwd and convert it to PNG with ImageMagick:

    $ xwd -id 0x290 -out /tmp/out.xwd
    $ convert /tmp/out.xwd /tmp/out.png
raidermax commented 10 years ago

While I can't offer any technical details, I can only confirm that I have a similar issue when paint on overlay is true with the fglrx drivers. However, my experience would be that the same screenshot would be completely black.

richardgv commented 10 years ago

@raidermax:

Sounds somewhat like a driver issue, still. Thanks for the info! :-)

ashleysommer commented 10 years ago

Sorry it has taken a while to reply. I had forgotten about this issue, though it still exists. I agree, I think it is an internal driver issue with fglrx. I updated to the latest fglrx release and it has the same behavior.

To answer your questions.. Yes the problem disappears when using different backends, it only exists when using glx. I tried using an empty config (with glx backend), problem persists. Yes it occurs when when capturing full-screen shots as well as partial screen shots and area captures. I tried various different screenshot tools, including the XFCE screenshot applet, shutter, imagemagic, scrot, xwd, etc. They all give the same incorrect image. After reading your suggestion, I tried some options in xorg.conf, including playing with the OpenGLOverlay option, but no option helped with this problem.

I could try your instructions to use xwd to capture the overlay window image, but I don't think theres much point. I agree it would most likely give me the correct image, but it is not practical to do this every time I need a screenshot (I assume the overlay window address ID changes between X sessions).

Some random thoughts: I haven't tried a screen video recording application, I dont know if they capture the screen image with the same methods.

Is there a way of forcing X to copy the overlay image to the root window when XGetImage() is called? Alternatively, is there a way of calling XGetImage() to get the overlay window instead of the root window?

How about adding rudimentary screenshot support to compton, when the user presses the PrntScrn key, use the loaded configuration to determine the best method of grabbing the screen image, if paint-on-overlay is on, then get it from the overlay window, otherwise get it from the root window. The various backends have even better methods of grabbing a screenshot.

Thanks for your help.

ashleysommer commented 10 years ago

Another update: I download the source for XFCE-Screenshooter and modified the capture code to get the x11 overlay window rather than the root window. Interestingly, it gives the exactly the same image as the root window (image of my desktop from 2 hours before). This comes as a surprise to me, as I really expected it to give me the correct image.

So this leads me to another interesting revelation, it looks as if the GLX backend is not actually painting onto the X11 overlay window. And its not painting onto the root window either. So what exactly is fglrx painting onto? Does it use some kind of OpenGL overlay window which runs in fullscreen on top of X11? I will have a look at the compton glx code, specifically where it paints to the overlay window, and see if I can debug the process to see where glx is painting to.

ashleysommer commented 10 years ago

And a final update: I worked out the problem. You were correct when you suggested to look at the OpenGLOverlay option in xorg.conf. I had tried playing with this option in the past, but I took another look at it just now. This option is on by default, and causes fglrx to create overlay windows on a OpenGL window, rather than an X11 overlay window.

In the past, if you set OpenGLOverlay = "False", you were able to set VideoOverlay = "True" which forces fglrx to use the Xv overlay functionality. In fact, there was even a handy aticonfig command to help set that up: $ sudo aticonfig --overlay-type=Xv

However, it looks like modern versions of fglrx (all releases in the last two years) do not allow Xv as an overlay type. I get:

$ sudo aticonfig --overlay-type=Xv
    Error: invalid string value for --ovt option. 
    Please check aticonfig help info for supported overlay type.
    aticonfig: parsing the command-line failed.

Looking in the aticonfig --help text, it shows:

    Change the overlay for the X server.  STRING can be one of:
         opengl
         disable

If I manually put OpenGLOverlay = "False" and VideoOverlay = "True" into xorg.conf, this comes up in Xorg.0.log [ 11199.776] (WW) fglrx(0): Option "VideoOverlay" is not used

For more information regarding this specific screenshot problem, there is actually a relevant section in the Wikipedia article on OpenGL Overlays. http://en.wikipedia.org/wiki/Hardware_overlay#Screen_shots

So in summary, with modern fglrx versions, OpenGL Overlays cant be turned off, VideoOverlay (Xv overlays) cannot be turned on, and all available screenshot applications cannot capture images of OpenGL Overlay windows.

Now I have a new plan. Im going to take my own advice, and implement a screenshot function into Compton itself. I think this is the reason the Compiz guys had an screenshot module/plugin which you could enable and configure to a key combination, they must have run into the same issues with OpenGL Overlay windows too. I will take a look at their code. I think I will either need to find some kind of GLX method which can dump out the contents of the OpenGL Overlay window, or set up an offscreen display and render a frame to that and save it. Either way, fun times ahead.

richardgv commented 10 years ago

@flubba86:

Sorry for the late reply. I got a lot of annoying things to deal with recently.

Thanks for all your testing results, firstly!

I'm not really sure about how the hardware overlay stuffs work, and unfortunately I don't have the time and device to look deeply into the issue right now.

My advice is to switch to X Render backend when you take a screenshot, or the xr-glx-hybrid backend.

To assist you to with the screenshot taking feature, I wrote glx_take_screenshot() in src/opengl.c, of 8c88b4d6f1 in richardgv-dev branch, together with a few auxiliary functions. (Check the changes and message in 8c88b4d6f1 for more info.) To fully implement the feature is non-trivial: Writing screenshot in an appropriate format, handling screenshot taking in X Render backend (which is so complicated because of the unpredictable XImage output), properly deal with the security risk, byte-order handling, etc., and it would most likely make compton much more bloated, so I don't have a plan to further develop the feature right now.

wyatt8740 commented 4 years ago

I'd like to add that this also happens on my system with the i915 driver (named intel in my xorg.conf file). Specifically, I am using a thinkpad X201 Tablet, ironlake Intel GPU. It's not just radeons.

I have seen both the 'black screen' and the 'several minutes in the past' behavior when screenshotting Firefox, Seamonkey, and also gnome-terminal and mate-terminal windows. Strangely, this does not always occur (sometimes screenshots are successful). Feels like the longer I have a window open the more likely it is to be 'de-synced.'

I have not tried it with the modesetting driver because that driver introduces performance bugs with xdm (login form takes much longer to render than it should. The xdm bug is not related to compton, though, as compton is not running at that point).

FFmpeg's x11grab device always works, since it does not use XGetImage(). My workaround was writing a script to select a region of the screen by parsing xwininfo's output and then restricting the region to grab to the area on-screen (out of bounds coordinates cause errors when invoking ffmpeg). I use xprop _NET_FRAME_EXTENTS -id (window-id) to get the window decoration widths/heights and add them/subtract them from my coordinates.

Overall it's highly convoluted, but I just mention it in case it helps anyone else out. For any onlookers, my full script is here. I think it should work in bash, as well; I just prefer ksh93.