Reputation: 11
I am trying to capture a window (not a part of the screen) using swap chains on a Windows 10 machine without WinRT.
I ran a project with WinRT and it worked, suggesting my graphics card is capable of capturing windows.
However, I'm not getting any errors, but pStagingTexture
is blank and imageData
is full of zeroes. I tested SaveTextureAsPng()
with the Windows Duplication API, capturing a screen rather than a window, and it worked, so SaveTextureAsPng()
is likely not the issue.
I also tried capturing windows that are visible and minimized, but no luck. I have tried different surface flags. I know I can use GDI+ (I think), but I want to use the GPU (like a Quadro P4000, driver 472.98). I would also prefer that it works with C++14.
bool CaptureWindow(HWND hwnd, LPCWSTR filepath)
{
HRESULT hr = S_OK;
ID3D11Device* pDevice = nullptr;
IDXGIDevice* pDXGIDevice = nullptr;
IDXGIAdapter* pDXGIAdapter = nullptr;
IDXGIOutput* pOutput = nullptr;
IDXGIOutput1* pOutput1 = nullptr;
IDXGIOutputDuplication* pOutputDuplication = nullptr;
IDXGIFactory2* pFactory = nullptr;
ID3D11Texture2D* pStagingTexture = nullptr;
ID3D11DeviceContext* pImmediateContext = nullptr;
RECT rect;
UINT width, height;
if (GetWindowRect(hwnd, &rect))
{
width = rect.right - rect.left;
height = rect.bottom - rect.top;
}
else
{
std::cout << "hwnd doesn't have any dimensions" << std::endl;
return false;
}
hr = D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
0,
nullptr,
0,
D3D11_SDK_VERSION,
&pDevice,
nullptr,
&pImmediateContext);
if (FAILED(hr))
{
std::cout << "Failed to create D3D11 device." << std::endl;
return false;
}
hr = pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&pDXGIDevice));
if (FAILED(hr))
{
std::cout << "Failed to retrieve DXGI device." << std::endl;
pDevice->Release();
return false;
}
hr = pDXGIDevice->GetAdapter(&pDXGIAdapter);
if (FAILED(hr))
{
std::cout << "Failed to retrieve DXGI adapter." << std::endl;
pDXGIDevice->Release();
pDevice->Release();
return false;
}
hr = pDXGIAdapter->EnumOutputs(0, &pOutput);
if (FAILED(hr))
{
std::cout << "Failed to enumerate DXGI output." << std::endl;
pDXGIAdapter->Release();
pDXGIDevice->Release();
pDevice->Release();
return false;
}
// Get the DXGI factory
hr = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(&pFactory));
if (FAILED(hr))
{
std::cout << "Failed to retrieve DXGI factory." << std::endl;
pOutput->Release();
pDXGIAdapter->Release();
pDXGIDevice->Release();
pDevice->Release();
return false;
}
// Create swap chain description
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapChainDesc.Flags = 0;
// Create swap chain
IDXGISwapChain1* pSwapChain = nullptr;
hr = pFactory->CreateSwapChainForHwnd(
pDevice,
hwnd,
&swapChainDesc,
nullptr,
nullptr,
&pSwapChain);
if (FAILED(hr))
{
std::cout << "Failed to create swap chain." << std::endl;
pFactory->Release();
pOutput->Release();
pDXGIAdapter->Release();
pDXGIDevice->Release();
pDevice->Release();
return false;
}
// Get the back buffer
ID3D11Texture2D* pBackBuffer = nullptr;
hr = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackBuffer));
if (FAILED(hr))
{
std::cout << "Failed to get back buffer from swap chain." << std::endl;
pSwapChain->Release();
pFactory->Release();
pOutput->Release();
pDXGIAdapter->Release();
pDXGIDevice->Release();
pDevice->Release();
return false;
}
ID3D11RenderTargetView* pRenderTargetView = nullptr;
hr = pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &pRenderTargetView);
if (FAILED(hr))
{
std::cout << "Failed to create render target view" << std::endl;
pBackBuffer->Release();
pSwapChain->Release();
pFactory->Release();
pOutput->Release();
pDXGIAdapter->Release();
pDXGIDevice->Release();
pDevice->Release();
return false;
}
// Unbind the back buffer and staging texture
pImmediateContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr);
pRenderTargetView->Release();
// Create a staging texture
D3D11_TEXTURE2D_DESC textureDesc = {};
textureDesc.Width = width;
textureDesc.Height = height;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_STAGING;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
textureDesc.MiscFlags = 0;
textureDesc.BindFlags = 0; //D3D11_BIND_RENDER_TARGET; // | D3D11_BIND_SHADER_RESOURCE
hr = pDevice->CreateTexture2D(&textureDesc, nullptr, &pStagingTexture);
if (FAILED(hr))
{
std::cout << "Failed to create staging texture." << std::endl;
pBackBuffer->Release();
pSwapChain->Release();
pFactory->Release();
pOutput->Release();
pDXGIAdapter->Release();
pDXGIDevice->Release();
pDevice->Release();
return false;
}
// Copy the back buffer to the staging texture
pImmediateContext->CopyResource(pStagingTexture, pBackBuffer);
pImmediateContext->Flush();
// Map the staging texture
D3D11_MAPPED_SUBRESOURCE mappedResource = {};
hr = pImmediateContext->Map(pStagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource);
if (FAILED(hr))
{
std::cout << "Failed to map staging texture." << std::endl;
pStagingTexture->Release();
pBackBuffer->Release();
pSwapChain->Release();
pFactory->Release();
pOutput->Release();
pDXGIAdapter->Release();
pDXGIDevice->Release();
pDevice->Release();
return false;
}
// Save the mapped resource as an image
//SaveMappedResourceAsPng(mappedResource, filename);
// Calculate image size
const UINT rowPitch = mappedResource.RowPitch;
const UINT imageSize = rowPitch * textureDesc.Height;
// Copy image data
std::vector<BYTE> imageData(imageSize);
memcpy(imageData.data(), mappedResource.pData, imageSize);
// Unmap the staging texture
pImmediateContext->Unmap(pStagingTexture, 0);
SaveTextureAsPng(pStagingTexture, filepath);
// Cleanup
pStagingTexture->Release();
pBackBuffer->Release();
pSwapChain->Release();
pFactory->Release();
pOutput->Release();
pDXGIAdapter->Release();
pDXGIDevice->Release();
pDevice->Release();
return true;
}
Upvotes: 0
Views: 148