2012-05-16 10 views
8

Ich möchte den Inhalt meiner Front-oder Back-Puffer mit DirectX 11 in einem Array von Bytes erfassen, die ich dann als Textur oder als Quelle für die Erstellung verwenden kann eine Datei. Ich habe ein Swap-Chain-Setup, viel Rendering passiert und den folgenden Code bis jetzt - den ich nach dem Aufruf von Present sicher anrufen werde.DirectX 11 Framebuffer-Capture (C++, kein Win32 oder 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 = 
    { 
     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); 
} 

Es gibt mir immer schwarz mit Null-Alpha.

Normalerweise hätte ich die Option von GDI-Interop BitBlt zu verwenden, um eine Bitmap aus der Swap-Kette zu kopieren - allerdings habe ich Einschränkungen, was bedeutet, dass dies keine gültige Lösung ist.

Auch die D3DX-Bibliothek, die Funktionalität für Bits davon enthält, ist ebenfalls nicht in Frage.

Antwort

8

So. Ein wenig mehr Experimente zeigten das "Problem". Durch die sich die Beschreibung der Framebuffer-Textur und die Verwendung dieser als Grundlage die neue Textur zu schaffen wurde das Problem gelöst ...

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); 
} 
2

Swapkette Puffer leicht mit D3D11 gespeichert werden können, wie unten dargestellt.

  1. erstellen Texture2D genauso wie der Rücken Puffer des Swapkette Sie versuchen
  2. Anruf CopyResource auf dem Gerätekontext von Back-Puffer auf die neu erstellte Textur
  3. Anruf D3DX11SaveTextureToFile (zum Kopieren zu speichern. ..) mit Dateinamen

gekünstelt Codefragment:

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); 
+0

das Problem ist, dass d3dx11 ist/war für WinRT Apps zum Zeitpunkt des Schreibens nicht verfügbar - selbst zu zitieren: „Auch die D3DX Bibliothek, die Funktionalität enthält für Bits, dies zu tun ist auch nicht in Frage. " – jheriko

2

Um die richtige Größe zu kopieren, verwenden Sie den folgenden Code.

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); 
} 
+1

Bitte [bearbeiten] mit mehr Informationen. Code-only und "try this" -Antworten werden [entmutigt] (// meta.stackexchange.com/questions/196187), weil sie keinen durchsuchbaren Inhalt enthalten und nicht erklären, warum jemand "das versuchen sollte". Wir bemühen uns, eine Ressource für Wissen zu sein. – IKavanagh

Verwandte Themen