Windows 从GPU获取完整的桌面屏幕截图

Windows 从GPU获取完整的桌面屏幕截图,windows,opengl,screenshot,fullscreen,Windows,Opengl,Screenshot,Fullscreen,我一直在使用Windows API的BitBlt函数来执行屏幕抓取 但也有许多缺点: DWM和Aero造成了巨大的减速(3ms-->35ms,仅调用BitBlt)——要解决这一问题,需要禁用Aero,而我不希望这样做。屏幕忽隐忽现,东西四处移动 数据必须重新传输到GPU,才能作为纹理加载数据 如果没有CAPTUREBLT标志,则无法捕获分层窗口。启用时,捕获时鼠标光标闪烁。这似乎是一个小问题,但当应用程序没有bug时,它会非常恼人。作为一种解决方法,我打算将分层窗口渲染为一个附加光标 我已经在使

我一直在使用Windows API的
BitBlt
函数来执行屏幕抓取

但也有许多缺点:

  • DWM和Aero造成了巨大的减速(3ms-->35ms,仅调用
    BitBlt
    )——要解决这一问题,需要禁用Aero,而我不希望这样做。屏幕忽隐忽现,东西四处移动
  • 数据必须重新传输到GPU,才能作为纹理加载数据
  • 如果没有
    CAPTUREBLT
    标志,则无法捕获分层窗口。启用时,捕获时鼠标光标闪烁。这似乎是一个小问题,但当应用程序没有bug时,它会非常恼人。作为一种解决方法,我打算将分层窗口渲染为一个附加光标 我已经在使用OpenGL来显示和操作捕获的屏幕数据
    BitBlt
    提供像素数据,将其加载到纹理中相对容易。然而,这有点荒谬,因为我正在手动将数据重新发送回GPU,而GPU本来应该可以使用这些数据。数据肯定在那里,但试图访问它是另一回事


    我认为这项功能在供应商的待办事项列表中并不重要(或可能在任何列表中),但我想问问那些知情人士,AMD(ATI)或NVidia在其驱动程序中是否提供了读取屏幕缓冲区(例如,在OpenGL上下文中)的任何规定。我只是对现代GPU架构了解不够,不知道从哪里开始寻找答案

    这是一个有趣的问题。不幸的是,我不认为这是真正的支持。我发现了一些关于创建全屏不可见窗口和使用glReadPixels读取像素数据的成功报告:


    但是,我相信这样做的行为是未定义的,并且只能在特定的硬件/操作系统配置上工作。

    OpenGL只能读取上下文帧缓冲区(窗口)以及您创建的任何帧缓冲区或PBuffer。OpenGL无法触摸桌面或任何其他窗口。

    显然,Aero Peek等人可以实时捕获其他窗口,并以硬件加速。所以,这只是找到正确的API的问题。从形式上说,你是对的。然而,在出现合成窗口管理器之前,顶级窗口将接收部分可见屏幕帧缓冲区内存。这使得通过创建一个全屏OpenGL窗口并在创建后立即执行glReadPixels操作来抓取屏幕截图成为可能。如今,使用合成窗口管理器,这不再有效,因为每个窗口都有自己的屏幕外缓冲区。就像@Ben Voigt所说的,您需要使用合成API。在X11中,这一点已经得到了很好的证明:合成X11和GLX_EXT_texture_来自_pixmap GLX extensions。这种行为实际上是未定义的,并且利用了第一代窗口管理的工作原理(窗口接收像素所有权掩码和一些指针+跨步进入屏幕帧缓冲区)。在第二代中,合成窗口管理器(Aero、AIGLX、MacOS X Quartz Extreme)窗口将绘制到屏幕外缓冲区,可见的内容将从所有这些窗口合成。