首先,你必須明確地檢查所有的返回碼即返回的HRESULT
失敗的
HRESULT hr = SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
reinterpret_cast< void** >(&g_pSurface));
if(SUCCEEDED(hr))
{
...
HRESULT hr = d3d11Device->CreateTexture2D(&description, NULL, &pNewTexture);
if(SUCCEEDED(hr))
另一種觀點是CopyResource
它返回void,所以你不能探測出你的代碼問題的功能。相反,您需要啓用Direct3D DEBUG設備並查找任何ERROR或WARNING消息。
特別是,如果您的交換鏈緩衝器是MSAA的資源,這將無法獲得任何數據。在複製之前,您必須明確使用ResolveSubresource
。反過來,由於ResolveSubresource
返回一個空格,因此在使用它之前,您需要檢查支持D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE
的格式。下面是執行此操作在DirectX Tool Kit的ScreenGrab模塊中的代碼:
static HRESULT CaptureTexture(_In_ ID3D11DeviceContext* pContext,
_In_ ID3D11Resource* pSource,
_Inout_ D3D11_TEXTURE2D_DESC& desc,
_Inout_ ComPtr<ID3D11Texture2D>& pStaging)
{
if (!pContext || !pSource)
return E_INVALIDARG;
D3D11_RESOURCE_DIMENSION resType = D3D11_RESOURCE_DIMENSION_UNKNOWN;
pSource->GetType(&resType);
if (resType != D3D11_RESOURCE_DIMENSION_TEXTURE2D)
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
ComPtr<ID3D11Texture2D> pTexture;
HRESULT hr = pSource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(pTexture.GetAddressOf()));
if (FAILED(hr))
return hr;
assert(pTexture);
pTexture->GetDesc(&desc);
ComPtr<ID3D11Device> d3dDevice;
pContext->GetDevice(d3dDevice.GetAddressOf());
if (desc.SampleDesc.Count > 1)
{
// MSAA content must be resolved before being copied to a staging texture
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
ComPtr<ID3D11Texture2D> pTemp;
hr = d3dDevice->CreateTexture2D(&desc, 0, pTemp.GetAddressOf());
if (FAILED(hr))
return hr;
assert(pTemp);
DXGI_FORMAT fmt = EnsureNotTypeless(desc.Format);
UINT support = 0;
hr = d3dDevice->CheckFormatSupport(fmt, &support);
if (FAILED(hr))
return hr;
if (!(support & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE))
return E_FAIL;
for(UINT item = 0; item < desc.ArraySize; ++item)
{
for(UINT level = 0; level < desc.MipLevels; ++level)
{
UINT index = D3D11CalcSubresource(level, item, desc.MipLevels);
pContext->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt);
}
}
desc.BindFlags = 0;
desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
hr = d3dDevice->CreateTexture2D(&desc, 0, pStaging.GetAddressOf());
if (FAILED(hr))
return hr;
assert(pStaging);
pContext->CopyResource(pStaging.Get(), pTemp.Get());
}
else if ((desc.Usage == D3D11_USAGE_STAGING) && (desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ))
{
// Handle case where the source is already a staging texture we can use directly
pStaging = pTexture;
}
else
{
// Otherwise, create a staging texture from the non-MSAA source
desc.BindFlags = 0;
desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
hr = d3dDevice->CreateTexture2D(&desc, 0, pStaging.GetAddressOf());
if (FAILED(hr))
return hr;
assert(pStaging);
pContext->CopyResource(pStaging.Get(), pSource);
}
事實上,你應該使用的DirectX工具包,而不是傳統的D3DX11
庫。 D3DX的所有版本都與傳統的DirectX SDK本身一樣被棄用(請參閱MSDN)。有一些容易獲得的replacements。
除了MSAA問題,您可能會遇到D3DX11
選擇WIC格式的問題。根據您的渲染目標格式和渲染,它可能會寫出一個全0 alpha通道的圖像,這可能會導致「空白」輸出圖像。該的DirectX工具包 ScreenGrab模塊,使您能夠明確地指定輸出格式,默認爲嘗試使用非字母輸出文件格式因爲這個原因的能力。
還有一個理由不使用傳統的D3DX11
:這是從來沒有更新的DXGI 1.1格式,因此它不支持寫出BGRA格式的資源,如DXGI_FORMAT_B8G8R8A8_UNORM
或DXGI_FORMAT_B8G8R8A8_UNORM
即使底層WIC容器文件格式支持他們。如果上面的代碼中的渲染目標DXGI_FORMAT_B8G8R8A8_UNORM
而非DXGI_FORMAT_R8G8B8A8_UNORM
然後D3DX11
會失敗,而ScreenGrab將正常工作。
我提到D3DX11
是瘋狂的老並沒有因爲年〜2009年向它提出的任何修正?
下面是ScreenGrab一些使用例子:如果表面是MSAA,或者如果它使用的是BGRA格式
ComPtr<ID3D11Texture2D> backBufferTex;
hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferTex);
if (SUCCEEDED(hr))
{
// Write out the render target as a PNG
hr = SaveWICTextureToFile(context.Get(), backBufferTex.Get(), GUID_ContainerFormatPng, L"SCREENSHOT.PNG");
// Write out the render target as JPG
hr = SaveWICTextureToFile(context.Get(), backBufferTex.Get(), GUID_ContainerFormatJpeg, L"SCREENSHOT.JPG");
// Write out the render target as BMP
hr = SaveWICTextureToFile(context.Get(), backBufferTex.Get(), GUID_ContainerFormatBmp, L"SCREENSHOT.BMP");
// Write out the render target as BMP and explicitly use a 16-bit format
hr = SaveWICTextureToFile(context.Get(), backBufferTex.Get(), GUID_ContainerFormatBmp, L"SCREENSHOT.BMP", &GUID_WICPixelFormat16bppBGR565);
// Write out the render target as a TIF
hr = SaveWICTextureToFile(context.Get(), backBufferTex.Get(), GUID_ContainerFormatTiff, L"SCREENSHOT.TIF");
// Write out the render target as a TIF with explicit WIC codec properties
hr = SaveWICTextureToFile(context.Get(), backBufferTex.Get(), GUID_ContainerFormatTiff, L"SCREENSHOT.TIF", nullptr,
[&](IPropertyBag2* props)
{
PROPBAG2 options[2] = { 0, 0 };
options[0].pstrName = L"CompressionQuality";
options[1].pstrName = L"TiffCompressionMethod";
VARIANT varValues[2];
varValues[0].vt = VT_R4;
varValues[0].fltVal = 0.75f;
varValues[1].vt = VT_UI1;
varValues[1].bVal = WICTiffCompressionNone;
(void)props->Write(2, options, varValues);
});
// Write out the render target as a DDS
hr = SaveDDSTextureToFile(context.Get(), backBufferTex.Get(), L"SCREENSHOT.DDS");
}
您的代碼也將失敗。它使用了傳統的D3DX11庫。 –
是的,我的回答與OP實際上試圖做/使用的內容非常接近,但沒有在代碼中引入太多變化,但我同意你的觀點並贊成你的回答。 – orfdorf