为什么DirectX全屏应用程序会提供黑屏幕截图?

时间:2014-02-03 18:36:09

标签: c++ directx hook screenshot fullscreen

您可能知道尝试使用GDI方式捕获DirectX全屏应用程序(使用BitBlt())会提供黑色屏幕截图。

我的问题很简单,但我找不到任何答案:为什么?我的意思是技术,为什么会给出黑色屏幕截图?

我正在这里阅读DirectX教程:http://www.directxtutorial.com/Lesson.aspx?lessonid=9-4-1。它写道:

  

[...]函数BeginScene()[...]执行称为锁定的操作,其中视频RAM中的缓冲区被“锁定”,授予您对此内存的独占访问权。

这是原因吗? VRAM被锁定,因此GDI无法访问它并且它提供了黑屏幕截图? 还是有其他原因吗?就像DirectX直接与图形卡“对话”而GDI没有得到它?

谢谢。

2 个答案:

答案 0 :(得分:4)

原因很简单:表现。

我们的想法是尽可能在GPU上渲染一个与CPU无关的场景。你使用CPU将渲染缓冲区发送到GPU(顶点,索引,着色器等),这总体上非常便宜,因为它们很小,然后你做你想做的任何事情,物理,多人同步等.GPU可以只是紧缩数据并自行呈现。

如果您需要在窗口上绘制场景,则必须中断GPU,请求渲染缓冲区字节(LockRect),请求窗口的图形对象(更多干扰GPU) ),渲染它并释放每一把锁。你刚刚失去了与GPU不同步的GPU所带来的任何好处。更糟糕的是当你想到所有不同的CPU内核因为忙于“渲染”而闲置时(更像是等待缓冲区传输)。

所以图形驱动程序所做的是用魔术颜色绘制渲染区域并告诉GPU场景的位置,GPU负责根据魔幻颜色像素覆盖显示屏幕上的场景(类型一个多遍像素着色器,当第一个纹理具有xy的某种颜色时从第二个纹理获取,但不是那么慢。你完全不同步渲染,但当你向操作系统询问它的视频内存时,你会得到场景所在的神奇色彩,因为它就是它实际使用的。

参考:http://en.wikipedia.org/wiki/Hardware_overlay

答案 1 :(得分:0)

我认为这实际上是由于双重缓冲。我不是百分百肯定,但实际情况是我在OpenGL中测试截图时的情况。我会注意到我窗户上的DC不一样。它在这一场比赛中使用了两个不同的DC ..对于其他游戏,我不确定它在做什么。 DC是相同的,但交换缓冲区被调用了很多次,我不认为GDI甚至足够快速截图..有时我会得到半截图和半黑..

然而,当我迷上了客户端时,我能够像正常一样询问像素。没有GDI或任何东西。我认为在绘制使用DirectX或OpenGL的游戏时我们不使用GDI是有原因的。

您可以随时查看捕获屏幕的方法:http://www.codeproject.com/Articles/5051/Various-methods-for-capturing-the-screen

无论如何,我使用以下方法从DirectX获取数据:

HRESULT DXI_Capture(IDirect3DDevice9* Device, const char* FilePath)
{
    IDirect3DSurface9* RenderTarget = nullptr;
    HRESULT result = Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &RenderTarget);
    result = D3DXSaveSurfaceToFile(FilePath, D3DXIFF_PNG, RenderTarget, nullptr, nullptr);
    SafeRelease(RenderTarget);
    return result;
}

然后在我迷上的Endscene中,我称之为:

HRESULT Direct3DDevice9Proxy::EndScene()
{
    DXI_Capture(ptr_Direct3DDevice9, "C:/Ssers/School/Desktop/Screenshot.png");

    return ptr_Direct3DDevice9->EndScene();
}

您可以使用microsoft detours来挂钩某些外部应用程序的EndScene,也可以使用包装器.dll。