D3D11屏幕桌面复制到ID3D11Texture2D

时间:2015-04-15 21:37:04

标签: c++ directx direct3d

我正在编写一个DLL插件,它将读取桌面帧缓冲区(整个屏幕)并将其直接渲染到传入的Texture2D指针中。目标是将所有内容保存在视频内存中(并避免复制成本)系统内存和返回视频内存。)

我能够传递Texture2D(显示为ID3D11Texture2D),但我在使用D3D11抓取桌面帧缓冲区时遇到问题。 D3D9提供了GetFrontBufferData()但似乎D3D11解决方案是使用GetBuffer()。

我的问题是关于获取IDXGISwapChain。因为我想读取桌面帧缓冲区,只需通过GetBuffer()读取内容并将其显示在ID3D11Texture2D上。我得到一个ID3D11Device我不明白如何获得它的IDXGISwapChain。

我有如下代码来获取帧缓冲区并将其放在纹理上:

ID3D11Texture2D* src = (ID3D11Texture2D*)g_TexturePointer;
ID3D11Texture2D* dst = NULL;
HRESULT hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&dst);
g_devCon->CopyResource(dst, src);

这里我实际上使用D3D11CreateDeviceAndSwapChain()创建了自己的交换链,但我想知道是否有必要,因为我已经有了ID3D11Device。

CopyResource()似乎也失败了。

1 个答案:

答案 0 :(得分:4)

不一定所有桌面内容都将使用D3D11呈现。 DXGI是Windows上所有图形的底层系统,因此您肯定需要以某种方式使用它来捕获桌面。但是,D3D11是基于DXGI构建的(例如,ID3D11Texture2D支持IDXGIResource接口)。下面的代码示例显示了如何将整个监视器的输出捕获到D3D11分段纹理中:

// IDXGIOutput* poutput = ...; // from DXGIAdapter::EnumOutputs.

// Get description of desktop.
DXGI_OUTPUT_DESC outdesc;
poutput->GetDesc(&outdesc);

// Create destination texture, sized same as desktop.
D3D11_TEXTURE2D_DESC texDesc;
memset(&texDesc, 0, sizeof(texDesc));
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDesc.BindFlags = 0;
texDesc.Width  = outdesc.DesktopCoordinates.right - outdesc.DesktopCoordinates.left;
texDesc.Height = outdesc.DesktopCoordinates.bottom - outdesc.DesktopCoordinates.top;
texDesc.MipLevels = 1;
texDesc.SampleDesc = { 1, 0 };
texDesc.Usage = D3D11_USAGE_STAGING;
texDesc.ArraySize = 1;
ID3D11Texture2D* destinationTexture = 0;
pDevice->CreateTexture2D(&texDesc, 0, &destinationTexture); // check HRESULT.

// Get IDXGIResource from texture.
IDXGIResource* destinationResource=0;
destinationTexture->QueryInterface(IID_PPV_ARGS(&destinationResource)); // check HRESULT.

// Get data.
IDXGIOutput1* poutput1;
poutput->QueryInterface(IID_PPV_ARGS(&poutput1)); // check HRESULT.
poutput1->TakeOwnership(pDevice, TRUE);
poutput1->GetDisplaySurfaceData1(destinationResource); // check HRESULT.
poutput1->ReleaseOwnership();

// Now use destinationTexture, it contains the contents of the desktop.

不幸的是,它在IDXGIOutput::TakeOwnership调用期间将输出变为黑色具有令人讨厌的副作用。但是,如果没有此调用,GetDiplaySurfaceData1将失败。根据您的具体情况,这可能是可以接受的。