11

I have been using the Windows API's BitBlt function to perform the screen grab.

There are many drawbacks however:

  1. DWM and Aero cause a massive slowdown (3ms --> 35ms just to call BitBlt) -- to work around this would require disabling Aero which I'd just rather not do. The screen flickers and things shift around.
  2. Data must be re-transferred to the GPU in order to load data as texture
  3. Layered Windows cannot be captured without CAPTUREBLT flag. When enabled, the mouse cursor blinks when capturing. This may seem like a minor issue, but it is exceedingly annoying when the application is otherwise bug-free. As a workaround for this I intend to render a layered window as an additional cursor.

I am already using OpenGL to display and manipulate the captured screen data. BitBlt gives me the pixel data and it is relatively easy to load it into a texture. However this is slightly absurd because I am manually re-sending the data back to the GPU when it should be available on the GPU to begin with. The data most certainly is there, but trying to access it is a different matter.

I presume that this functionality is not high on the to-do list (or likely on any list for that matter) for vendors but I would like to ask those in the know if there are any provisions at all provided by AMD(ATI) or NVidia in their drivers for reading the screen buffer (into an OpenGL context for instance). I simply do not know enough about modern GPU architecture to know where to start digging for answers.

Steven Lu
  • 41,389
  • 58
  • 210
  • 364

2 Answers2

4

OpenGL can only read the context framebuffer (a window), and any framebuffers or pbuffers you have created. OpenGL cannot touch the desktop or any other window.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    Clearly Aero Peek et al capture other windows, in real-time, hardware accelerated. So it's just a matter of finding the right API. – Ben Voigt Jun 29 '11 at 00:16
  • 2
    Formally you're right. However before there were compositing window managers, a toplevel window would recieve some part of the visible screen framebuffer memory. This made it possible to grab a screenshot by creating a fullscreen OpenGL window and doing a glReadPixels right after creation. Today, with compositing window managers this no longer works, as every window gets its own off screen buffer. Like @Ben Voigt said, you need to use the Compositing API then. In X11 this is rather well documented: Composite X11 and GLX_EXT_texture_from_pixmap GLX extensions. – datenwolf Jun 29 '11 at 06:32
1

This is an interesting question. Unfortunately I don't think this is really supported. I have found reports of some level of success with creating a full screen invisible window and reading the pixel data with glReadPixels:

http://www.virtualdub.org/blog/pivot/entry.php?id=142

http://www.opentk.com/node/2430

However, I believe the behavior when doing this is undefined and will only work on specific hardware/OS configurations.

dschaeffer
  • 618
  • 6
  • 15
  • 2
    This behaviour is indeed undefined and exploits the working principle of 1st generation window management (the window recieves a pixel ownership mask and some pointer + stride into the screen framebuffer). On 2nd generation, compositing window managers (Aero, AIGLX, MacOS X Quartz Extreme) windows draw to an offscreen buffers and what's visible is composited from all those. – datenwolf Jun 29 '11 at 06:59