绘制缓冲区到 D3D9 纹理
Drawing buffer to D3D9 texture
我正在尝试将 CEF 缓冲区(在 OnPaint 上返回)绘制为游戏的 D3D9 纹理,并且游戏随机预永久冻结。我想通了下面提供的代码是游戏冻结的原因,但仍然无法理解。我错过了什么?
// 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();
}
需要说明的是:CEF 按预期渲染,没有错误,这里只是纹理渲染问题。希望得到任何帮助
经过评论讨论,我对代码做了一些修改:
// 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();
}
如上所述,绘制事件(和覆盖方法)都被调用 on the CefBrowser UI thread,并且在同一纹理被释放之前多次锁定它会导致整个 D3D 上下文死锁。
修复是将绘制事件处理程序(负责将渲染的 Chrome 图像保存到内部缓冲区)与 D3D 渲染线程(负责将内部缓冲区上传到 D3D纹理和渲染)。
我正在尝试将 CEF 缓冲区(在 OnPaint 上返回)绘制为游戏的 D3D9 纹理,并且游戏随机预永久冻结。我想通了下面提供的代码是游戏冻结的原因,但仍然无法理解。我错过了什么?
// 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();
}
需要说明的是:CEF 按预期渲染,没有错误,这里只是纹理渲染问题。希望得到任何帮助
经过评论讨论,我对代码做了一些修改:
// 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();
}
如上所述,绘制事件(和覆盖方法)都被调用 on the CefBrowser UI thread,并且在同一纹理被释放之前多次锁定它会导致整个 D3D 上下文死锁。
修复是将绘制事件处理程序(负责将渲染的 Chrome 图像保存到内部缓冲区)与 D3D 渲染线程(负责将内部缓冲区上传到 D3D纹理和渲染)。