Drawing buffer to D3D9 texture

0

I'm trying to draw CEF buffer (returned on OnPaint) to D3D9 texture of the game, and game randomly premanently freezes. I figured out that code provided below is the reason of the game freeze, but still can't understand. What did I miss?

// To create texture I use this code
LPDIRECT3DTEXTURE9 tWebPNG;
D3DXCreateTexture(device, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tWebPNG);

// And the problem in that method

    void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height)
    {

        D3DLOCKED_RECT LockedRect;
        D3DSURFACE_DESC SurfaceDesc;
        IDirect3DSurface9* pSurface;
        tWebPNG->GetSurfaceLevel(0, &pSurface);

        pSurface->GetDesc(&SurfaceDesc);
        pSurface->LockRect(&LockedRect, nullptr, 0);
        
        auto dest = (unsigned char*)LockedRect.pBits;
        auto src = (const char*)buffer;

        for (int i = 0; i < height; ++i)
        {
            memcpy(dest, src, width * 4);
            dest += LockedRect.Pitch;
            src += width * 4;
        }


        pSurface->UnlockRect();
    }

To be clear: CEF is rendered as expected, it have no errors and here is just texture render problem. Hope to get any help

After discussing in comments, I have modified my code a bit:

// Modified OnPaint to work with mutaxes
    void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height)
    {
        {
            std::lock_guard<std::mutex> lock(m_RenderData.dataMutex);

            // Store render data
            m_RenderData.buffer = buffer;
            m_RenderData.width = width;
            m_RenderData.height = height;
            m_RenderData.dirtyRects = dirtyRects;
            m_RenderData.changed = true;
        }

        // Wait for the main thread to handle drawing the texture
        std::unique_lock<std::mutex> lock(m_RenderData.cvMutex);
        m_RenderData.cv.wait(lock);
    }


// This method is intended to draw into d3d9 layer
void Browser::draw()
{
    std::lock_guard<std::mutex> lock(m_RenderData.dataMutex);

    IDirect3DSurface9* pSurface;

    tWebPNG->GetSurfaceLevel(0, &pSurface);

    if (m_RenderData.changed)
    {
        // Lock surface
        D3DLOCKED_RECT LockedRect;
        if (FAILED(pSurface->LockRect(&LockedRect, nullptr, 0))) {
            m_RenderData.cv.notify_all();
            return;
        }

        // Update changed state
        m_RenderData.changed = false;

        D3DSURFACE_DESC SurfaceDesc;
        IDirect3DSurface9* pSurface;
        tWebPNG->GetSurfaceLevel(0, &pSurface);

        pSurface->GetDesc(&SurfaceDesc);
        pSurface->LockRect(&LockedRect, nullptr, 0);

        auto dest = (unsigned char*)LockedRect.pBits;
        auto src = (const char*)m_RenderData.buffer;

        for (int i = 0; i < height; ++i)
        {
            memcpy(dest, src, width * 4);
            dest += LockedRect.Pitch;
            src += width * 4;
        }

        // Unlock surface
        pSurface->UnlockRect();
    }

    D3DXVECTOR3* vector = new D3DXVECTOR3(0, 0, 0);

    sprite->Begin(D3DXSPRITE_ALPHABLEND);
    sprite->Draw(tWebPNG, NULL, NULL, vector, 0xFFFFFFFF);
    sprite->End();
    
    m_RenderData.cv.notify_all();

}
c++
directx
directx-9
asked on Stack Overflow Apr 28, 2021 by Ydm • edited Apr 28, 2021 by Ydm

1 Answer

0

As discussed above, the paint event (and override method) are both called on the CefBrowser UI thread, and locking the same texture multiple times before it gets released will deadlock your entire D3D context.

The fix is to separate the paint event handler (which is responsible for saving the rendered Chrome image to an internal buffer) from the D3D render thread (which is responsible for uploading the internal buffer to the D3D texture and rendering with it).

answered on Stack Overflow Apr 28, 2021 by Blindy

User contributions licensed under CC BY-SA 3.0