DirectX将后备缓冲区数据写入文件

时间:2013-03-10 16:33:52

标签: directx textures staging

我正在尝试将DirectX程序的每一帧转换为YUV(用于视频编码)。因此,我首先需要每帧上每个像素的RGB(A)值。我需要从后备缓冲区获取这些内容。

因为DirectX中没有glReadPixels,所以我会执行以下操作:

  1. 获取指向backbuffer的renderTargetView的指针并获取后备缓冲区资源
  2. 将此资源投射到ID3D10Texture2D
  3. 制作一个舞台纹理,并CopyResource上一步中的texture2D。
  4. 此时我可以使用D3DX10SaveTextureToFile,这个分段纹理会正确地将后备缓冲区保存为图像。

    但是,我不想将磁盘用作绕道,我想立即获取RGB数据,所以我会做以下事情:

    1. 映射暂存资源
    2. 读取映射纹理的pData以获取RGB(A)值
    3. 问题:RGB值是垃圾。这是像素(1,1)

      的示例
        

      (1,1)=( - 170141183460469230000000000000000000000.000000,   -170141183460469230000000000000000000000.000000,-17014118346046923000000000000000000000000.000000)

      这特别奇怪,因为我使用相同的代码来映​​射另一个登台纹理(来自另一个屏幕外渲染目标),这段代码在那里工作得很好。

      这是我的代码:

      // Get resource pointer to backbuffer
      ID3D10Resource *backbufferRes;
      m_D3D->GetRenderTargetView()->GetResource(&backbufferRes);
      
      // Cast backbuffer resource to texture2D
      ID3D10Texture2D* tempTexture = 0;
      backbufferRes->QueryInterface(__uuidof(ID3D10Texture2D),(LPVOID*) &tempTexture);
      backbufferRes->Release();
      
      // Get the descriptor of this texture2D
      D3D10_TEXTURE2D_DESC descDefault; 
      tempTexture->GetDesc(&descDefault);
      
      // Create a staging texture desc based on the texture of the backbuffer
      D3D10_TEXTURE2D_DESC descStaging;
      descStaging = descDefault;
      descStaging.Usage = D3D10_USAGE_STAGING;
      descStaging.CPUAccessFlags = D3D10_CPU_ACCESS_READ;  
      descStaging.BindFlags = 0;
      
      // Create the new empty staging texture
      ID3D10Texture2D *texture = 0;
      m_D3D->GetDevice()->CreateTexture2D( &descStaging, NULL, &texture);
      
      // Copy the backbuffer texture data (tempTexture) to the staging texture (texture)
      m_D3D->GetDevice()->CopyResource(texture, tempTexture);
      
      // This call works perfectly, image is correct!
      // D3DX10SaveTextureToFile(texture, D3DX10_IFF_BMP, L"D:\\img.bmp");
      
      // We want to avoid disk access, so instead let's map the texture and read its RGB data
      D3D10_MAPPED_TEXTURE2D mappedTexture;
      hr = texture->Map(D3D10CalcSubresource(0, 0, 1), D3D10_MAP_READ, 0, &mappedTexture);
      FLOAT* m_pBits = (FLOAT*) malloc(4 * descStaging.Width * descStaging.Height * sizeof(FLOAT));
      if(!FAILED(hr)) {
          memcpy(m_pBits, mappedTexture.pData, 4 * descStaging.Width * descStaging.Height);
          texture->Unmap(D3D10CalcSubresource(0, 0, 1));
      }
      texture->Release();
      tempTexture->Release();
      
      fp = fopen("D:\\output.txt", "a");
      for( UINT row = 0; row < descStaging.Height; row++ )
      {
          UINT rowStart = row * mappedTexture.RowPitch / 4;
          for( UINT col = 0; col < descStaging.Width; col++ )
          {
              r = m_pBits[rowStart + col*4 + 0]; // Red (X)
              g = m_pBits[rowStart + col*4 + 1]; // Green (Y)
              b = m_pBits[rowStart + col*4 + 2]; // Blue (Z)
              a = m_pBits[rowStart + col*4 + 3]; // Alpha (W)
      
              // Save pixel values to disk
              fprintf(fp, "%d %d - %f %f %f\n",  col + 1, row + 1, r, g, b);
          }
      }
      fclose(fp);
      

      有没有人知道问题可能是什么? 非常感谢所有帮助。

1 个答案:

答案 0 :(得分:2)

老问题,但我认为这可能是问题所在:

使用texture->Map()映射纹理后,您尝试将其一次性复制到m_pBits。除非映射纹理的RowPitch与其宽度相同,否则这将不起作用(请参阅here)。

相反,您必须逐行复制图像:

BYTE* source = static_cast<BYTE*>(mappedTexture.pData);
BYTE& dest = m_pBits;
for (int i = 0; i < IMAGE_HEIGHT; ++i) {
    memcpy(dest, source, IMAGE_WIDTH * 4); // for 4 bytes per pixel
    source += mappedTexture.RowPitch;
    dest += IMAGE_WIDTH * 4;
}