From 3f1fa0fae1f20bec86bcb5fef9771a9f47aff4d1 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 12 Nov 2017 16:12:58 +0100 Subject: [PATCH] Updated windowed mode presentation to use multiple window-clipped blits Windowed mode presentation is changed to use a series of blits clipped to each top level window to work around performance issues when a clipper uses a clip list instead of a window. Otherwise DirectDraw uses StretchBlt rather than the driver Present call even if the clip list is a single rectangle matching the window client area. Fixes a performance issue reported in issue #24. --- DDrawCompat/DDraw/DirectDrawSurface.cpp | 1 - DDrawCompat/DDraw/RealPrimarySurface.cpp | 69 ++++++++++--------- DDrawCompat/DDraw/RealPrimarySurface.h | 1 - .../DDraw/Surfaces/PrimarySurfaceImpl.cpp | 11 --- .../DDraw/Surfaces/PrimarySurfaceImpl.h | 1 - DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp | 6 -- DDrawCompat/DDraw/Surfaces/SurfaceImpl.h | 1 - 7 files changed, 35 insertions(+), 55 deletions(-) diff --git a/DDrawCompat/DDraw/DirectDrawSurface.cpp b/DDrawCompat/DDraw/DirectDrawSurface.cpp index c059f50..d10fad3 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.cpp +++ b/DDrawCompat/DDraw/DirectDrawSurface.cpp @@ -45,7 +45,6 @@ namespace DDraw SET_COMPAT_METHOD(Lock); SET_COMPAT_METHOD(ReleaseDC); SET_COMPAT_METHOD(Restore); - SET_COMPAT_METHOD(SetClipper); SET_COMPAT_METHOD(SetPalette); SET_COMPAT_METHOD(Unlock); diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 7390e59..ded4686 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -20,6 +20,7 @@ namespace void onRelease(); DWORD WINAPI updateThreadProc(LPVOID lpParameter); + DWORD g_primaryThreadId = 0; CompatWeakPtr g_frontBuffer; CompatWeakPtr g_backBuffer; CompatWeakPtr g_paletteConverter; @@ -39,9 +40,28 @@ namespace std::atomic g_isFullScreen(false); - bool compatBlt(CompatRef dest) + BOOL CALLBACK bltToWindow(HWND hwnd, LPARAM lParam) { - Compat::LogEnter("RealPrimarySurface::compatBlt", dest); + g_clipper->SetHWnd(g_clipper, 0, hwnd); + auto src = reinterpret_cast(lParam); + g_frontBuffer->Blt(g_frontBuffer, nullptr, src, nullptr, DDBLT_WAIT, nullptr); + return TRUE; + } + + HRESULT bltToPrimaryChain(CompatRef src) + { + if (g_isFullScreen) + { + return g_backBuffer->Blt(g_backBuffer, nullptr, &src, nullptr, DDBLT_WAIT, nullptr); + } + + EnumThreadWindows(g_primaryThreadId, bltToWindow, reinterpret_cast(&src)); + return DD_OK; + } + + bool compatBlt() + { + Compat::LogEnter("RealPrimarySurface::compatBlt"); bool result = false; @@ -64,16 +84,15 @@ namespace if (result) { - result = SUCCEEDED(dest->Blt( - &dest, nullptr, g_paletteConverter, nullptr, DDBLT_WAIT, nullptr)); + result = SUCCEEDED(bltToPrimaryChain(*g_paletteConverter)); } } else { - result = SUCCEEDED(dest->Blt(&dest, nullptr, primary, nullptr, DDBLT_WAIT, nullptr)); + result = SUCCEEDED(bltToPrimaryChain(*primary)); } - Compat::LogLeave("RealPrimarySurface::compatBlt", dest) << result; + Compat::LogLeave("RealPrimarySurface::compatBlt") << result; return result; } @@ -124,6 +143,11 @@ namespace backBufferCaps.dwCaps = DDSCAPS_BACKBUFFER; surface->GetAttachedSurface(surface, &backBufferCaps, &backBuffer.getRef()); } + else + { + CALL_ORIG_PROC(DirectDrawCreateClipper, 0, &g_clipper.getRef(), nullptr); + surface->SetClipper(surface, g_clipper); + } g_qpcFlipModeTimeout = Time::g_qpcFrequency / Config::minExpectedFlipsPerSec; g_qpcLastFlip = Time::queryPerformanceCounter() - g_qpcFlipModeTimeout; @@ -156,6 +180,7 @@ namespace g_backBuffer = backBuffer; g_surfaceDesc = desc; g_isFullScreen = isFlippable; + g_primaryThreadId = GetCurrentThreadId(); return DD_OK; } @@ -184,7 +209,7 @@ namespace ResetEvent(g_updateEvent); g_frontBuffer = nullptr; g_backBuffer = nullptr; - g_clipper = nullptr; + g_clipper.release(); g_isFullScreen = false; g_paletteConverter.release(); @@ -197,13 +222,7 @@ namespace { ResetEvent(g_updateEvent); - if (!g_isFullScreen) - { - compatBlt(*g_frontBuffer); - return; - } - - if (compatBlt(*g_backBuffer)) + if (compatBlt() && g_isFullScreen) { D3dDdi::KernelModeThunks::overrideFlipInterval( Time::queryPerformanceCounter() - g_qpcLastFlip >= g_qpcFlipModeTimeout @@ -262,13 +281,11 @@ namespace DDraw CompatPtr::TCreatedSurface> surface; result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr); - bool isFlippable = true; if (DDERR_NOEXCLUSIVEMODE == result) { desc.dwFlags = DDSD_CAPS; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; desc.dwBackBufferCount = 0; - isFlippable = false; result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr); } @@ -316,7 +333,7 @@ namespace DDraw g_isUpdateSuspended = false; g_qpcLastFlip = Time::queryPerformanceCounter(); - compatBlt(*g_backBuffer); + compatBlt(); HRESULT result = g_frontBuffer->Flip(g_frontBuffer, nullptr, flags); g_qpcNextUpdate = Time::queryPerformanceCounter(); return result; @@ -377,22 +394,6 @@ namespace DDraw return g_frontBuffer->Restore(g_frontBuffer); } - void RealPrimarySurface::setClipper(CompatWeakPtr clipper) - { - if (g_backBuffer) - { - return; - } - - HRESULT result = g_frontBuffer->SetClipper(g_frontBuffer, clipper); - if (FAILED(result)) - { - LOG_ONCE("Failed to set clipper on the real primary surface: " << result); - return; - } - g_clipper = clipper; - } - HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData) { auto gammaControl(CompatPtr::from(g_frontBuffer.get())); @@ -416,7 +417,7 @@ namespace DDraw void RealPrimarySurface::update() { - if (g_isUpdateSuspended || !(g_isFullScreen || g_clipper)) + if (g_isUpdateSuspended) { return; } diff --git a/DDrawCompat/DDraw/RealPrimarySurface.h b/DDrawCompat/DDraw/RealPrimarySurface.h index 03d6be2..3506512 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.h +++ b/DDrawCompat/DDraw/RealPrimarySurface.h @@ -25,7 +25,6 @@ namespace DDraw static void release(); static void removeUpdateThread(); static HRESULT restore(); - static void setClipper(CompatWeakPtr clipper); static HRESULT setGammaRamp(DDGAMMARAMP* rampData); static void setPalette(); static void update(); diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp index 5dda0a8..5c8007c 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp @@ -204,17 +204,6 @@ namespace DDraw return result; } - template - HRESULT PrimarySurfaceImpl::SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper) - { - HRESULT result = m_impl.SetClipper(This, lpDDClipper); - if (SUCCEEDED(result)) - { - RealPrimarySurface::setClipper(lpDDClipper); - } - return result; - } - template HRESULT PrimarySurfaceImpl::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette) { diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.h b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.h index 41f8a9c..9fe714c 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.h +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.h @@ -29,7 +29,6 @@ namespace DDraw DWORD dwFlags, HANDLE hEvent) override; virtual HRESULT ReleaseDC(TSurface* This, HDC hDC) override; virtual HRESULT Restore(TSurface* This) override; - virtual HRESULT SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper) override; virtual HRESULT SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette) override; virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect) override; diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index 265972b..c95d356 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -273,12 +273,6 @@ namespace DDraw return s_origVtable.Restore(This); } - template - HRESULT SurfaceImpl::SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper) - { - return s_origVtable.SetClipper(This, lpDDClipper); - } - template HRESULT SurfaceImpl::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette) { diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h index 9e4d56f..f288019 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h @@ -49,7 +49,6 @@ namespace DDraw DWORD dwFlags, HANDLE hEvent); virtual HRESULT ReleaseDC(TSurface* This, HDC hDC); virtual HRESULT Restore(TSurface* This); - virtual HRESULT SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper); virtual HRESULT SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette); virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect);