DirectX 11 帧缓冲捕获(C++,无 Win32 或 D3DX)
DirectX 11 framebuffer capture (C++, no Win32 or D3DX)
我想使用 DirectX 11 将前端或后端缓冲区的内容捕获到一个字节数组中,然后我可以将其用作纹理或创建文件的源。到目前为止,我有一个交换链设置,发生了大量渲染和以下代码 - 我确保在调用 Present 后调用它们。
ID3D11Texture2D* pSurface;
HRESULT hr = m_swapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast< void** >( &pSurface ) );
if( pSurface )
{
const int width = static_cast<int>(m_window->Bounds.Width * m_dpi / 96.0f);
const int height = static_cast<int>(m_window->Bounds.Height * m_dpi / 96.0f);
unsigned int size = width * height;
if( m_captureData )
{
freeFramebufferData( m_captureData );
}
m_captureData = new unsigned char[ width * height * 4 ];
ID3D11Texture2D* pNewTexture = NULL;
D3D11_TEXTURE2D_DESC description =
{
width, height, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
{ 1, 0 }, // DXGI_SAMPLE_DESC
D3D11_USAGE_STAGING,
0, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE, 0
};
HRESULT hr = m_d3dDevice->CreateTexture2D( &description, NULL, &pNewTexture );
if( pNewTexture )
{
m_d3dContext->CopyResource( pNewTexture, pSurface );
D3D11_MAPPED_SUBRESOURCE resource;
unsigned int subresource = D3D11CalcSubresource( 0, 0, 0 );
HRESULT hr = m_d3dContext->Map( pNewTexture, subresource, D3D11_MAP_READ, 0, &resource );
//resource.pData; // TEXTURE DATA IS HERE
const int pitch = width << 2;
const unsigned char* source = static_cast< const unsigned char* >( resource.pData );
unsigned char* dest = m_captureData;
for( int i = 0; i < height; ++i )
{
memcpy( dest, source, width * 4 );
source += pitch;
dest += pitch;
}
m_captureSize = size;
m_captureWidth = width;
m_captureHeight = height;
return;
}
freeFramebufferData( m_captureData );
}
它总是给我零阿尔法的黑色。
我通常可以选择 GDI 互操作来使用 BitBlt 将位图从交换链中复制出来 - 但是我有限制,这意味着这不是一个有效的解决方案。
此外,D3DX库,其中包含用于执行此操作的功能也是不可能的。
所以。再做一点实验就发现了"问题"。通过获取帧缓冲纹理的描述并将其用作创建新纹理的基础,问题得到了解决......
ID3D11Texture2D* pSurface;
HRESULT hr = m_swapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast< void** >( &pSurface ) );
if( pSurface )
{
const int width = static_cast<int>(m_window->Bounds.Width * m_dpi / 96.0f);
const int height = static_cast<int>(m_window->Bounds.Height * m_dpi / 96.0f);
unsigned int size = width * height;
if( m_captureData )
{
freeFramebufferData( m_captureData );
}
m_captureData = new unsigned char[ width * height * 4 ];
ID3D11Texture2D* pNewTexture = NULL;
D3D11_TEXTURE2D_DESC description;
pSurface->GetDesc( &description );
description.BindFlags = 0;
description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
description.Usage = D3D11_USAGE_STAGING;
HRESULT hr = m_d3dDevice->CreateTexture2D( &description, NULL, &pNewTexture );
if( pNewTexture )
{
m_d3dContext->CopyResource( pNewTexture, pSurface );
D3D11_MAPPED_SUBRESOURCE resource;
unsigned int subresource = D3D11CalcSubresource( 0, 0, 0 );
HRESULT hr = m_d3dContext->Map( pNewTexture, subresource, D3D11_MAP_READ_WRITE, 0, &resource );
//resource.pData; // TEXTURE DATA IS HERE
const int pitch = width << 2;
const unsigned char* source = static_cast< const unsigned char* >( resource.pData );
unsigned char* dest = m_captureData;
for( int i = 0; i < height; ++i )
{
memcpy( dest, source, width * 4 );
source += pitch;
dest += pitch;
}
m_captureSize = size;
m_captureWidth = width;
m_captureHeight = height;
return;
}
freeFramebufferData( m_captureData );
}
要复制正确的大小,请使用下面的代码。
ID3D11Texture2D* pSurface;
HRESULT hr = m_swapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast< void** >( &pSurface ) );
if( pSurface )
{
const int width = static_cast<int>(m_window->Bounds.Width * m_dpi / 96.0f);
const int height = static_cast<int>(m_window->Bounds.Height * m_dpi / 96.0f);
unsigned int size = width * height;
if( m_captureData )
{
freeFramebufferData( m_captureData );
}
m_captureData = new unsigned char[ width * height * 4 ];
ID3D11Texture2D* pNewTexture = NULL;
D3D11_TEXTURE2D_DESC description;
pSurface->GetDesc( &description );
description.BindFlags = 0;
description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
description.Usage = D3D11_USAGE_STAGING;
HRESULT hr = m_d3dDevice->CreateTexture2D( &description, NULL, &pNewTexture );
if( pNewTexture )
{
m_d3dContext->CopyResource( pNewTexture, pSurface );
D3D11_MAPPED_SUBRESOURCE resource;
unsigned int subresource = D3D11CalcSubresource( 0, 0, 0 );
HRESULT hr = m_d3dContext->Map( pNewTexture, subresource, D3D11_MAP_READ_WRITE, 0, &resource );
//resource.pData; // TEXTURE DATA IS HERE
const int pitch = width << 2;
const unsigned char* source = static_cast< const unsigned char* >( resource.pData );
unsigned char* dest = m_captureData;
for( int i = 0; i < height; ++i )
{
memcpy( dest, source, width * 4 );
source += resource.RowPitch; // <------
dest += pitch;
}
m_captureSize = size;
m_captureWidth = width;
m_captureHeight = height;
return;
}
freeFramebufferData( m_captureData );
}
交换链缓冲区可以使用 D3D11 轻松保存,如下所示。
- 创建一个与您尝试保存的交换链的后台缓冲区相同的 Texture2D
- 在设备上下文中调用 CopyResource 以从后台缓冲区复制到新创建的纹理
- 使用文件名调用 D3DX11SaveTextureToFile(...)
人为的代码片段:
ID3D11Texture2D* pBuffer;
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBuffer);
if(texture_to_save == NULL)
{
D3D11_TEXTURE2D_DESC td;
pBuffer->GetDesc(&td);
device->CreateTexture2D(&td, NULL, &texture_to_save);
}
deviceContext->CopyResource(texture_to_save, pBuffer);
D3DX11SaveTextureToFile(deviceContext,texture_to_save,D3DX11_IFF_PNG,filename);
相关文章:
- Win32编译器选项和内存分配
- C++win32 API创建多个类似视口的窗口
- WM_CTLCOLORSTATIC从未在WIN32应用程序中触发
- 检测win32服务创建和删除的最佳方法
- WIN32:C++,为什么在WM_CLOSE上调用Messagebox函数程序正在冻结
- 将 win32 hbitmap 转换为 winrt softwarebitmap
- 使用 WIN32 API (C/C++) 对特定树视图项进行着色
- Alt+Enter 在 Win32 应用中,管理大小调整和分辨率
- VSCode C++ 编译的exe感染了Win32:TrojanX-gen[Trj]
- 从预处理器获取 Windows 版本(C++ Win32)
- Issues with Win32 ReadProcessMemory API
- Win32 发送输入鼠标移动滞后并冻结
- 如何从 Win32 C++ 应用程序输出到父控制台窗口?
- C++线程:如何在一个线程仍在运行时阻止另一个线程执行 (Win32)
- 将 Win32/WinAPI 应用程序移植到 wxWidgets
- Win32 API 控制台光标在 WriteConsole 后不移动
- C++ Win32 Threads
- C++ win32 如何使密码字段可选并启用复制和粘贴?
- LNK1104:无法打开libpjproject-i386-Win32-vc14-Debug-Static.lib
- DirectX 11 帧缓冲捕获(C++,无 Win32 或 D3DX)