2012-05-16 8 views
8

Vorrei acquisire il contenuto del mio buffer anteriore o posteriore utilizzando DirectX 11 in una matrice di byte che posso quindi utilizzare come texture o come sorgente per la creazione un file. Ho una configurazione della catena di scambio, un sacco di rendering e il seguente codice fino ad ora - che mi assicurerò di chiamare dopo la chiamata a Present.Acquisizione framebuffer DirectX 11 (C++, senza Win32 o 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); 
} 

Mi dà sempre il nero con zero alpha.

Avrei normalmente l'opzione di interoperabilità GDI per utilizzare BitBlt per copiare una bitmap dalla catena di scambio, tuttavia ho delle restrizioni che indicano che questa non è una soluzione valida.

Anche la libreria D3DX, che contiene funzionalità per eseguire bit di questo è anche fuori questione.

risposta

8

Così. Un po 'più di sperimentazione ha rivelato il "problema". Ottenendo la descrizione della trama framebuffer e l'utilizzo che come base per creare la nuova texture il problema è stato risolto ... buffer catena

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 possono essere facilmente salvati con D3D11 come illustrato di seguito.

  1. Creare un Texture2D come stessi back buffer della catena di swap che si sta tentando di salvare
  2. chiamata CopyResource sul contesto di dispositivo per copiare dal buffer di nuovo alla struttura appena creata
  3. chiamata D3DX11SaveTextureToFile (. ..) con il nome del file

artificiosa frammento di codice:

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

Il problema è che d3dx11 è/non era disponibile per le applicazioni WinRT al momento della scrittura - per citare me stesso: "Anche la biblioteca D3DX, che contiene la funzionalità per fare pezzi di questo è anche fuori discussione. " – jheriko

2

Per copiare la dimensione corretta, utilizzare il seguente codice.

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

Si prega di [modificare] con ulteriori informazioni. Le risposte solo per codice e "prova questo" sono [scoraggiate] (// meta.stackexchange.com/questions/196187), perché non contengono contenuti ricercabili e non spiegano perché qualcuno dovrebbe "provare questo". Facciamo uno sforzo qui per essere una risorsa per la conoscenza. – IKavanagh