问题描述
将Texture2d保存到文件时出现问题,它总是给我黑色图像。
这是代码:
i've got problem with saving texture2d to file, it always gives me black image.Here is code:
HRESULT hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast< void** >( &g_pSurface ) );
if( g_pSurface )
{
ID3D11Texture2D* pNewTexture = NULL;
D3D11_TEXTURE2D_DESC description;
g_pSurface->GetDesc( &description );
description.BindFlags = 0;
description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
description.Usage = D3D11_USAGE_STAGING;
HRESULT hr = d3d11Device->CreateTexture2D( &description, NULL, &pNewTexture );
if( pNewTexture )
{
d3d11DevCon->CopyResource( pNewTexture, g_pSurface );
hr=D3DX11SaveTextureToFileA(d3d11DevCon, pNewTexture, D3DX11_IFF_BMP, "screen.bmp");
return;
}
}
我在做什么错了?
推荐答案
首先,您需要明确检查所有返回HRESULT的函数的返回代码
First, you need to be explicitly checking the return code for all functions that returned HRESULTs
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 设备并查找任何错误或警告消息。
One possible point of failure is CopyResource
which returns void so you can't detect the problem in your code. Instead you need to enable the Direct3D DEBUG device and look for any ERROR or WARNING messages.
特别是,如果交换链缓冲区是MSAA资源,它将无法获取任何消息。数据。复制之前,必须显式使用 ResolveSubresource
。反过来,由于 ResolveSubresource
返回一个空值,因此在使用该格式之前,需要检查格式是否支持 D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE
。这是 ScreenGrab 模块中的代码。 com / Microsoft / DirectXTK rel = noreferrer> DirectX工具套件即可执行以下操作:
In particular, if your swap chain buffer is a MSAA resource this will fail to get any data. You have to explicitly use ResolveSubresource
before doing the copy. In turn since ResolveSubresource
returns a void, you need to check the format supports D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE
before using it. Here's the code in the ScreenGrab module in DirectX Tool Kit that does this handling:
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 );
}
除了MSAA问题,您可能还会遇到 D3DX11
的WIC格式选择。根据您的渲染目标格式和渲染,它可能会写出全为Alpha通道的图像,这可能会导致输出图像空白。 DirectX Tool Kit ScreenGrab模块使您能够显式指定输出格式,并且正因为如此,默认情况下尝试使用非alpha输出文件格式。
In addition to the MSAA issue, you might be running into problems with D3DX11
's choice of WIC formats. Depending on your render target format and rendering, it might be writing out an image with an all 0 alpha channel which can result in a 'blank' output image. The DirectX Tool Kit ScreenGrab module gives you the ability to explicitly specify the output format and defaults to trying to use a non-alpha output file format for just this reason.
不使用旧版 D3DX11
的另一个原因:从未针对DXGI 1.1格式进行过更新,因此它不支持写出<$这样的BGRA格式资源。 c $ c> DXGI_FORMAT_B8G8R8A8_UNORM 或 DXGI_FORMAT_B8G8R8A8_UNORM
,即使基础WIC容器文件格式支持它们也是如此。如果上面代码中的渲染目标是 DXGI_FORMAT_B8G8R8A8_UNORM
而不是 DXGI_FORMAT_R8G8B8A8_UNORM
然后是 D3DX11
会失败,而ScreenGrab会正常工作。
One more reason not to use legacy D3DX11
: It was never updated for DXGI 1.1 formats so it won't support writing out BGRA format resources like DXGI_FORMAT_B8G8R8A8_UNORM
or DXGI_FORMAT_B8G8R8A8_UNORM
even when the underlying WIC container file format supports them. If your render target in your code above is DXGI_FORMAT_B8G8R8A8_UNORM
rather than DXGI_FORMAT_R8G8B8A8_UNORM
then D3DX11
will fail while ScreenGrab will work fine.
我是否提到 D3DX11
疯了而且还没有自2009年以来,是否有任何修复?
Did I mention D3DX11
is crazy old and hasn't had any fixes made to it since ~2009?
以下是 ScreenGrab 的一些用法示例:
Here's some example usage for ScreenGrab:
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" );
}
这篇关于c ++ Directx11捕获屏幕并保存到文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!