您可能知道尝试使用GDI方式捕获DirectX全屏应用程序(使用BitBlt()
)会提供黑色屏幕截图。
我的问题很简单,但我找不到任何答案:为什么?我的意思是技术,为什么会给出黑色屏幕截图?
我正在这里阅读DirectX教程:http://www.directxtutorial.com/Lesson.aspx?lessonid=9-4-1。它写道:
[...]函数BeginScene()[...]执行称为锁定的操作,其中视频RAM中的缓冲区被“锁定”,授予您对此内存的独占访问权。
这是原因吗? VRAM被锁定,因此GDI无法访问它并且它提供了黑屏幕截图? 还是有其他原因吗?就像DirectX直接与图形卡“对话”而GDI没有得到它?
谢谢。
答案 0 :(得分:4)
原因很简单:表现。
我们的想法是尽可能在GPU上渲染一个与CPU无关的场景。你使用CPU将渲染缓冲区发送到GPU(顶点,索引,着色器等),这总体上非常便宜,因为它们很小,然后你做你想做的任何事情,物理,多人同步等.GPU可以只是紧缩数据并自行呈现。
如果您需要在窗口上绘制场景,则必须中断GPU,请求渲染缓冲区字节(LockRect
),请求窗口的图形对象(更多干扰GPU) ),渲染它并释放每一把锁。你刚刚失去了与GPU不同步的GPU所带来的任何好处。更糟糕的是当你想到所有不同的CPU内核因为忙于“渲染”而闲置时(更像是等待缓冲区传输)。
所以图形驱动程序所做的是用魔术颜色绘制渲染区域并告诉GPU场景的位置,GPU负责根据魔幻颜色像素覆盖显示屏幕上的场景(类型一个多遍像素着色器,当第一个纹理具有x
,y
的某种颜色时从第二个纹理获取,但不是那么慢。你完全不同步渲染,但当你向操作系统询问它的视频内存时,你会得到场景所在的神奇色彩,因为它就是它实际使用的。
答案 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。