1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-12 13:08:50 +01:00

[d3d9] Fall back to GDI blit for partial presents

This commit is contained in:
Robin Kertels 2023-04-13 04:20:01 +02:00 committed by Joshie
parent 5c8ed491ab
commit a42643b235
4 changed files with 66 additions and 5 deletions

View File

@ -7342,7 +7342,8 @@ namespace dxvk {
" - Format: ", backBufferFmt, "\n"
" - Auto Depth Stencil: ", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false", "\n",
" ^ Format: ", EnumerateFormat(pPresentationParameters->AutoDepthStencilFormat), "\n",
" - Windowed: ", pPresentationParameters->Windowed ? "true" : "false", "\n"));
" - Windowed: ", pPresentationParameters->Windowed ? "true" : "false", "\n",
" - Swap effect: ", pPresentationParameters->SwapEffect, "\n"));
if (backBufferFmt != D3D9Format::Unknown) {
if (!IsSupportedBackBufferFormat(backBufferFmt)) {

View File

@ -165,7 +165,9 @@ namespace dxvk {
createInfo.hBitmap = nullptr;
createInfo.hDc = nullptr;
D3DKMTCreateDCFromMemory(&createInfo);
if (D3DKMTCreateDCFromMemory(&createInfo))
Logger::err("D3D9: Failed to create GDI DC");
DeleteDC(createInfo.hDeviceDc);
// These should now be set...

View File

@ -139,6 +139,12 @@ namespace dxvk {
m_lastDialog = m_dialog;
#ifdef _WIN32
const bool useGDIFallback = m_partialCopy && m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY;
if (useGDIFallback)
return BlitGDI(window);
#endif
try {
if (recreate)
CreatePresenter();
@ -156,10 +162,47 @@ namespace dxvk {
return D3D_OK;
} catch (const DxvkError& e) {
Logger::err(e.message());
#ifdef _WIN32
return BlitGDI(window);
#else
return D3DERR_DEVICEREMOVED;
#endif
}
}
#ifdef _WIN32
HRESULT D3D9SwapChainEx::BlitGDI(HWND Window) {
if (!std::exchange(m_warnedAboutFallback, true))
Logger::warn("Using GDI for swapchain presentation. This will impact performance.");
HDC hDC;
HRESULT result = m_backBuffers[0]->GetDC(&hDC);
if (result) {
Logger::err("D3D9SwapChainEx::BlitGDI Surface GetDC failed");
return D3DERR_DEVICEREMOVED;
}
HDC dstDC = GetDCEx(Window, 0, DCX_CACHE);
if (!dstDC) {
Logger::err("D3D9SwapChainEx::BlitGDI: GetDCEx failed");
m_backBuffers[0]->ReleaseDC(hDC);
return D3DERR_DEVICEREMOVED;
}
bool success = StretchBlt(dstDC, m_dstRect.left, m_dstRect.top, m_dstRect.right - m_dstRect.left,
m_dstRect.bottom - m_dstRect.top, hDC, m_srcRect.left, m_srcRect.top,
m_srcRect.right - m_srcRect.left, m_srcRect.bottom - m_srcRect.top, SRCCOPY);
if (!success) {
Logger::err("D3D9SwapChainEx::BlitGDI: StretchBlt failed");
m_backBuffers[0]->ReleaseDC(hDC);
return D3DERR_DEVICEREMOVED;
}
m_backBuffers[0]->ReleaseDC(hDC);
return S_OK;
}
#endif
HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetFrontBufferData(IDirect3DSurface9* pDestSurface) {
D3D9DeviceLock lock = m_parent->LockDevice();
@ -1155,20 +1198,28 @@ namespace dxvk {
else
m_srcRect = *pSourceRect;
UINT width, height;
wsi::getWindowSize(m_window, &width, &height);
RECT dstRect;
if (pDestRect == nullptr) {
// TODO: Should we hook WM_SIZE message for this?
UINT width, height;
wsi::getWindowSize(m_window, &width, &height);
dstRect.top = 0;
dstRect.left = 0;
dstRect.right = LONG(width);
dstRect.bottom = LONG(height);
}
else
dstRect = *pDestRect;
m_partialCopy =
dstRect.left != 0
|| dstRect.top != 0
|| dstRect.right - dstRect.left != LONG(width)
|| dstRect.bottom - dstRect.top != LONG(height);
bool recreate =
m_dstRect.left != dstRect.left
|| m_dstRect.top != dstRect.top

View File

@ -40,6 +40,10 @@ namespace dxvk {
const RGNDATA* pDirtyRegion,
DWORD dwFlags);
#ifdef _WIN32
HRESULT BlitGDI(HWND Window);
#endif
HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9* pDestSurface);
HRESULT STDMETHODCALLTYPE GetBackBuffer(
@ -103,6 +107,7 @@ namespace dxvk {
RECT m_srcRect;
RECT m_dstRect;
bool m_partialCopy = false;
DxvkSubmitStatus m_presentStatus;
@ -126,6 +131,8 @@ namespace dxvk {
double m_displayRefreshRate = 0.0;
bool m_warnedAboutFallback = false;
void PresentImage(UINT PresentInterval);
void SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId);