1

I perform a capture of Direct3D back buffer. When I download the pixels the image frame is flipped along its vertical axis.Is it possible to "tell" D3D to flip the frame when copying resource,or when creating target ID3D11Texture2D ?

Here is how I do it:

The texture into which I copy the frame buffer is created like this:

    D3D11_TEXTURE2D_DESC description =
    {
        desc.BufferDesc.Width, desc.BufferDesc.Height, 1, 1,
        DXGI_FORMAT_R8G8B8A8_UNORM,
        { 1, 0 }, // DXGI_SAMPLE_DESC
        D3D11_USAGE_STAGING,//transder from GPU to CPU
        0, D3D11_CPU_ACCESS_READ, 0
    };
    D3D11_SUBRESOURCE_DATA data = { buffer, desc.BufferDesc.Width * PIXEL_SIZE, 0 };
     device->CreateTexture2D(&description, &data, &pNewTexture);

Then on each frame I do:

     pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast< void** >(&pSurface));
     pContext->CopyResource(pNewTexture, pSurface);
     D3D11_MAPPED_SUBRESOURCE resource; 
     pContext->Map(pNewTexture, 0, D3D11_MAP_READ , 0, &resource);
     //reading from resource.pData
     //...

PS: I don't have a control of the rendering pipeline. I hook an external app with this code. Also,I don't want to mess with the pixel buffer on the CPU, like reverse copy in a loop etc.. The low latency of the copy is high priority.

UPDATE:

I also tried this:

    D3D11_BOX box;
    box.left = 0;
    box.right = desc.BufferDesc.Width;
    box.top = desc.BufferDesc.Height;
    box.bottom = 0;
    box.front = 0;
    box.back = 1;
    pContext->CopySubresourceRegion(pNewTexture, 0, 0, 0, 0, pSurface, 0, &box);

Which causes the frame to be empty from its content.

Michael IV
  • 11,016
  • 12
  • 92
  • 223
  • Don't forget to check the ``HRESULT`` values on those functions that return non-``void``. You are currently assuming it always works. Use ``SUCCEEDED``, ``FAILED``, or something like [ThrowIfFailed](https://github.com/Microsoft/DirectXTK/wiki/ThrowIfFailed). – Chuck Walbourn Oct 19 '17 at 07:06
  • @ChuckWalbourn Actually doing it all the way..Removed here for the sake of simplicity. – Michael IV Oct 19 '17 at 07:07
  • An example based on multi hooks a old project : https://github.com/headmax/Cplus/blob/master/Projet4/Main.cpp dunno if really help you ... –  Oct 19 '17 at 07:20
  • What do you want to do with the image data and how do you realize it was flipped? Did you copy the image data into a hbitmap? The HBitmap stores the image data bottom-up. If you are copying the image data to display it then it won't cost you much to copy it in reverse order regarding Y. – VuVirt Oct 19 '17 at 07:33
  • I copy the whole data buffer and send it to a screen in another app. It is "flipped" compared to a frame I am getting when hooking into OpenGL backbuffer. So it is possible it is not "flipped" if D3D specs say it is default..But it doesn't matter to me as I want to flip it.And better not on my app's side. – Michael IV Oct 19 '17 at 07:35
  • Please check my answer – VuVirt Oct 19 '17 at 18:11
  • 1
    @MichaelIV Regarding your Update section, MSDN docs for `ID3D11DeviceContext::CopySubresourceRegion()` state that "An empty box results in a no-op. A box is empty if the top value is greater than or equal to the bottom value, or [...]". – Pablo H Apr 03 '18 at 19:34

2 Answers2

1

Create a texture with D3D11_USAGE_DEAFULT, with CPUAccessFlags=0 and BindFlags=D3D11_BIND_SHADER_RESOURCE. CopyResource the swapchain's backbuffer to it. Create another texture with D3D11_BIND_RENDER_TARGET. Set it as a render target, set a pixel shader and draw a flipped quad using the first texture. Now you should be able to CopyResource the second texture to the staging texture that you use now. This should be faster than copying a flipped image data using the CPU. However, this solution would take more resources on the GPU and might be hard to setup in a hook.

VuVirt
  • 1,887
  • 11
  • 13
  • 1
    If the backbuffer has the D3D11_BIND_SHADER_RESOURCE flag then the first copy can be omitted. – Pablo H Apr 03 '18 at 19:32
0

All Direct3D mapped resources should be processed scanline-by-scanline, so just reverse the copy:

auto ptr = reinterpret_cast<const uint8_t>(resource.pData)
           + (desc.BufferDesc.Height - 1) * resource.RowPitch;

for(unsigned int y = 0; y < desc.BufferDesc.Height; ++y )
{
    // do something with the data in ptr
    // which is desc.BufferDesc.Width * BytesPerPixel(desc.Format) bytes
    // i.e. DXGI_FORMAT_R8G8B8A8_UNORM would be desc.BufferDesc.Width * 4
    ptr -= resource.RowPitch;
}

For lots of examples of working with Direct3D resources, see DirectXTex.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • Not an option. I need the copy to be extremely fast.I seek a way to do the flip on driver or GPU side.I will emphasize it in my question. – Michael IV Oct 19 '17 at 07:12