D3D11 如何正确从 swap_chain/渲染目标复制

问题描述 投票:0回答:1

我一直在尝试编写一个函数,该函数只需获取后台缓冲区/帧缓冲区并将其内容保存到文件中。

internal unsigned char *r_get_backbuffer(Arena *arena, GFX_Window *window, int width, int height)
{
  D3D11_Window *w = d3d11_window_from_opaque(window);
            
  int bytes = width*height*4;
  result = arena_push_array(arena, u8, bytes); // @Note: This just allocates memory

  ID3D11Texture2D *surface = 0;
  w->swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **) &surface);

  D3D11_TEXTURE2D_DESC desc = {0};
  desc.ArraySize = 1;
  desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  desc.Width = width;
  desc.Height = height;
  desc.MipLevels = 1;
  desc.SampleDesc.Count = 1;
  desc.SampleDesc.Quality = 0;
  desc.BindFlags = 0;
  desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
  desc.Usage = D3D11_USAGE_STAGING;

  ID3D11Texture2D *tex = 0;
  d3d11_state.device->CreateTexture2D(&desc, 0, &tex);
  d3d11_state.context->CopyResource(tex, surface);
                
  D3D11_MAPPED_SUBRESOURCE texture_resource = {0};
  d3d11_state.context->Map(tex, 0, D3D11_MAP_READ, 0, &texture_resource);
  MemoryCopy(result, texture_resource.pData, bytes); // @Note: Just a wrapper for memcpy()
  d3d11_state.context->Unmap(tex, 0);
                    
  tex->Release();
  surface->Release();
}

上述函数适用于特别是 16:9: 1280x720 图像

但是,当尺寸为其他值时就会出现问题: 1000x1000 图像

这让我觉得

CopyResource();
调用(或类似的)添加了一些自己的填充? 我正在使用 stb image write 进行图像写入,我的调用如下所示:

int w = 1000;
int h = 1000;
u8 *pixels = r_get_backbuffer(frame_arena, window, w, h);
stbi_write_jpg("ss.jpg", w, h, 4, pixels, w*4);
// ...

我有什么遗漏的吗?我认为这可能是“跨步”的问题,但无论我尝试什么,它都不会改变。我可能错过了文档中的一些内容,几天来我一直在尝试寻找答案,而谷歌由于其自身的臃肿而现在并没有真正的帮助。

理想的解决方案是将交换链/渲染目标视图的内容正确复制到字节数组(颜色值)中,无论大小如何。我并不真正关心具体的实现,我只是希望能够将帧缓冲区保存到文件或将其内容作为像素数组获取。

c++ directx-11 framebuffer
1个回答
0
投票

对于任何混乱,我深表歉意,我将在这里留下答案,以防其他人遇到类似的问题(假设谷歌有帮助)。我的问题确实与步幅有关,我从纹理(其步幅为 RowPitch)复制到我的像素缓冲区(其步幅为 width*4)。这是仅用于从纹理复制的工作代码:

internal unsigned char *r_get_backbuffer(Arena *arena, GFX_Window *window, int width, int height)
{
  D3D11_Window *w = d3d11_window_from_opaque(window);
            
  int bytes = width*height*4;
  result = arena_push_array(arena, u8, bytes); // @Note: This just allocates memory

  ID3D11Texture2D *surface = 0;
  w->swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **) &surface);

  D3D11_TEXTURE2D_DESC desc = {0};
  surface->GetDesc(&desc);
  desc.BindFlags = 0;
  desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
  desc.Usage = D3D11_USAGE_STAGING;

  ID3D11Texture2D *tex = 0;
  d3d11_state.device->CreateTexture2D(&desc, 0, &tex);
  d3d11_state.context->CopyResource(tex, surface);
                
  D3D11_MAPPED_SUBRESOURCE texture_resource = {0};
  d3d11_state.context->Map(tex, 0, D3D11_MAP_READ, 0, &texture_resource);

  // @Note: This part was incorrect previously, now corrected
  u8 *dst = result;
  u8 *src = ((u8 *) texture_resource.pData);
  for (s32 i = 0; i < height; ++i) {
    MemoryCopy(dst, src, width*4);
    dst += width*4;
    src += texture_resource.RowPitch;
  }
  // ==============

  d3d11_state.context->Unmap(tex, 0);
                    
  tex->Release();
  surface->Release();
}
© www.soinside.com 2019 - 2024. All rights reserved.