Accessing to RGB color of a mapped frame with DirectX 11

Started by
0 comments, last by mmarcoluca 1 year, 7 months ago

Hi,

I have found this code:

// BGRA U8 Bitmap
struct Bitmap {
    int                  Width  = 0;
    int                  Height = 0;
    std::vector<uint8_t> Buf;
};

// WinDesktopDup hides the gory details of capturing the screen using the
// Windows Desktop Duplication API
class WinDesktopDup {
public:
    Bitmap Latest;
    int    OutputNumber = 0;

    ~WinDesktopDup();

    Error Initialize();
    void  Close();
    bool  CaptureNext();

private:
    ID3D11Device*           D3DDevice        = nullptr;
    ID3D11DeviceContext*    D3DDeviceContext = nullptr;
    IDXGIOutputDuplication* DeskDupl         = nullptr;
    DXGI_OUTPUT_DESC        OutputDesc;
    bool                    HaveFrameLock = false;
};





bool WinDesktopDup::CaptureNext() 
{
    if (!DeskDupl)
        return false;

    HRESULT hr;

    // according to the docs, it's best for performance if we hang onto the frame for as long as possible,
    // and only release the previous frame immediately before acquiring the next one. Something about
    // the OS coalescing updates, so that it doesn't have to store them as distinct things.
    if (HaveFrameLock) {
        HaveFrameLock = false;
        hr            = DeskDupl->ReleaseFrame();
        // ignore response
    }

    IDXGIResource*          deskRes = nullptr;
    DXGI_OUTDUPL_FRAME_INFO frameInfo;
    hr = DeskDupl->AcquireNextFrame(0, &frameInfo, &deskRes);
    if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
        // nothing to see here
        return false;
    }
    if (FAILED(hr)) {
        // perhaps shutdown and reinitialize
        auto msg = tsf::fmt("Acquire failed: %x\n", hr);
        OutputDebugStringA(msg.c_str());
        return false;
    }

    HaveFrameLock = true;

    ID3D11Texture2D* gpuTex = nullptr;
    hr  = deskRes->QueryInterface(__uuidof(ID3D11Texture2D), (void**) &gpuTex);
    deskRes->Release();
    deskRes = nullptr;
    if (FAILED(hr)) {
        // not expected
        return false;
    }

    bool ok = true;

    D3D11_TEXTURE2D_DESC desc;
    gpuTex->GetDesc(&desc);
    desc.CPUAccessFlags     = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
    desc.Usage              = D3D11_USAGE_STAGING;
    desc.BindFlags          = 0;
    desc.MiscFlags          = 0; // D3D11_RESOURCE_MISC_GDI_COMPATIBLE ?
    ID3D11Texture2D* cpuTex = nullptr;
    hr                      = D3DDevice->CreateTexture2D(&desc, nullptr, &cpuTex);
    if (SUCCEEDED(hr)) {
        D3DDeviceContext->CopyResource(cpuTex, gpuTex);
    } else {
        // not expected
        ok = false;
    }

    D3D11_MAPPED_SUBRESOURCE sr;
    hr = D3DDeviceContext->Map(cpuTex, 0, D3D11_MAP_READ, 0, &sr);
    if (SUCCEEDED(hr)) {
        if (Latest.Width != desc.Width || Latest.Height != desc.Height) {
            Latest.Width  = desc.Width;
            Latest.Height = desc.Height;
            Latest.Buf.resize(desc.Width * desc.Height * 4);
        }
        for (int y = 0; y < (int) desc.Height; y++)
            memcpy(Latest.Buf.data() + y * desc.Width * 4, (uint8_t*) sr.pData + sr.RowPitch * y, desc.Width * 4);
        D3DDeviceContext->Unmap(cpuTex, 0);
    } else {
        ok = false;
    }

    cpuTex->Release();
    gpuTex->Release();

    return ok;
}

that get a complete bitmap buffer of a frame and after do a test I see that work.

I need to extract on "Buf" or other the RGBTRIPLE rgb of a single pixel.

In short I need a function like this or similar:

RGBTRIPLE GetPixelColor(BITMAP Buf, int X, Y)
{
  RGBTRIPLE Rgb;

    rgb.rgbtRed = Buf(red);
    rgb.rgbtGreen =  Buf(green);
    rgbtBlue=    Buf(Blue);
  
  return Rgb;
}

another solution will be use CopySubresourceRegion instead CopyResource and you can copy a single pixel but I don't known how use it.

Can you help me please ?

This topic is closed to new replies.

Advertisement