2012-05-16 13 views
8

Chciałbym przechwycić zawartość mojego bufora przedniego lub tylnego używając DirectX 11 do tablicy bajtów, które mogę następnie wykorzystać jako teksturę lub jako źródło do stworzenia plik. Mam konfigurację z zamianą, dużo renderowania i poniższy kod, do którego zadzwonię po wywołaniu Present.Przechwytywanie framebufferów DirectX 11 (C++, bez Win32 lub 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); 
} 

Zawsze daje mi czerń z zerowymi alfami.

Zwykle mam opcję interakcji GDI, aby użyć BitBlt do skopiowania bitmapy z łańcucha wymiany - jednak mam ograniczenia, co oznacza, że ​​nie jest to poprawne rozwiązanie.

Również biblioteka D3DX, która zawiera funkcje do robienia bitów tego, również nie wchodzi w grę.

Odpowiedz

8

So. Nieco więcej eksperymentów ujawniło "problem". Przez uzyskanie opisu tekstury bufora ramki i przy użyciu tego jako podstawy do tworzenia nowego tekstury problem został rozwiązany ... bufory łańcuchowe

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

swap mogą być łatwo zapisane z D3D11 jak pokazano poniżej.

  1. Tworzenie Texture2D tak samo jak tylnym buforze do sieci SWAP za którą próbujesz zapisać
  2. połączeń CopyResource kontekstu urządzenia do kopiowania z tylnym buforze do nowo utworzonej tekstury
  3. połączeń D3DX11SaveTextureToFile (. ..) z nazwą pliku

kod wymyślony fragment:

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

problemem jest to, że d3dx11 jest/nie była dostępna dla aplikacji winrt w chwili pisania - aby zacytować sobie: „Również biblioteka D3DX, która zawiera funkcjonalność robi bity to również nie wchodzi w rachubę. " – jheriko

2

Aby skopiować prawidłowy rozmiar, użyj poniższego kodu.

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

Proszę [edytuj] z dodatkowymi informacjami. Tylko kod i odpowiedzi "spróbuj tego" są zniechęcane (// meta.stackexchange.com/questions/196187), ponieważ nie zawierają treści do wyszukiwania i nie wyjaśniają, dlaczego ktoś powinien "spróbować tego". Staramy się być źródłem wiedzy. – IKavanagh