1
votes

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.

2
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.Chuck Walbourn
@ChuckWalbourn Actually doing it all the way..Removed here for the sake of simplicity.Michael IV
An example based on multi hooks a old project : github.com/headmax/Cplus/blob/master/Projet4/Main.cpp dunno if really help you ...user8556290
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
@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

2 Answers

1
votes

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.

0
votes

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.