8

我想使用 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 库也是不可能的。

4

3 回答 3

9

所以。更多的实验揭示了“问题”。通过获取帧缓冲区纹理的描述并将其用作创建新纹理的基础,问题得到了解决......

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 );
}
于 2012-05-16T18:08:56.263 回答
3

使用 D3D11 可以轻松保存交换链缓冲区,如下所示。

  1. 创建一个与您尝试保存的交换链的后台缓冲区相同的 Texture2D
  2. 在设备上下文上调用 CopyResource 以从后台缓冲区复制到新创建的纹理
  3. 使用文件名调用 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);
于 2012-08-10T10:36:27.590 回答
3

要复制正确的尺寸,请使用下面的代码。

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 );
}
于 2015-09-23T12:56:44.687 回答