1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

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.
This commit is contained in:
narzoul 2017-11-12 16:12:58 +01:00
parent 46f71be51a
commit 3f1fa0fae1
7 changed files with 35 additions and 55 deletions

View File

@ -45,7 +45,6 @@ namespace DDraw
SET_COMPAT_METHOD(Lock); SET_COMPAT_METHOD(Lock);
SET_COMPAT_METHOD(ReleaseDC); SET_COMPAT_METHOD(ReleaseDC);
SET_COMPAT_METHOD(Restore); SET_COMPAT_METHOD(Restore);
SET_COMPAT_METHOD(SetClipper);
SET_COMPAT_METHOD(SetPalette); SET_COMPAT_METHOD(SetPalette);
SET_COMPAT_METHOD(Unlock); SET_COMPAT_METHOD(Unlock);

View File

@ -20,6 +20,7 @@ namespace
void onRelease(); void onRelease();
DWORD WINAPI updateThreadProc(LPVOID lpParameter); DWORD WINAPI updateThreadProc(LPVOID lpParameter);
DWORD g_primaryThreadId = 0;
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer; CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
CompatWeakPtr<IDirectDrawSurface7> g_backBuffer; CompatWeakPtr<IDirectDrawSurface7> g_backBuffer;
CompatWeakPtr<IDirectDrawSurface7> g_paletteConverter; CompatWeakPtr<IDirectDrawSurface7> g_paletteConverter;
@ -39,9 +40,28 @@ namespace
std::atomic<bool> g_isFullScreen(false); std::atomic<bool> g_isFullScreen(false);
bool compatBlt(CompatRef<IDirectDrawSurface7> dest) BOOL CALLBACK bltToWindow(HWND hwnd, LPARAM lParam)
{ {
Compat::LogEnter("RealPrimarySurface::compatBlt", dest); g_clipper->SetHWnd(g_clipper, 0, hwnd);
auto src = reinterpret_cast<IDirectDrawSurface7*>(lParam);
g_frontBuffer->Blt(g_frontBuffer, nullptr, src, nullptr, DDBLT_WAIT, nullptr);
return TRUE;
}
HRESULT bltToPrimaryChain(CompatRef<IDirectDrawSurface7> src)
{
if (g_isFullScreen)
{
return g_backBuffer->Blt(g_backBuffer, nullptr, &src, nullptr, DDBLT_WAIT, nullptr);
}
EnumThreadWindows(g_primaryThreadId, bltToWindow, reinterpret_cast<LPARAM>(&src));
return DD_OK;
}
bool compatBlt()
{
Compat::LogEnter("RealPrimarySurface::compatBlt");
bool result = false; bool result = false;
@ -64,16 +84,15 @@ namespace
if (result) if (result)
{ {
result = SUCCEEDED(dest->Blt( result = SUCCEEDED(bltToPrimaryChain(*g_paletteConverter));
&dest, nullptr, g_paletteConverter, nullptr, DDBLT_WAIT, nullptr));
} }
} }
else 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; return result;
} }
@ -124,6 +143,11 @@ namespace
backBufferCaps.dwCaps = DDSCAPS_BACKBUFFER; backBufferCaps.dwCaps = DDSCAPS_BACKBUFFER;
surface->GetAttachedSurface(surface, &backBufferCaps, &backBuffer.getRef()); 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_qpcFlipModeTimeout = Time::g_qpcFrequency / Config::minExpectedFlipsPerSec;
g_qpcLastFlip = Time::queryPerformanceCounter() - g_qpcFlipModeTimeout; g_qpcLastFlip = Time::queryPerformanceCounter() - g_qpcFlipModeTimeout;
@ -156,6 +180,7 @@ namespace
g_backBuffer = backBuffer; g_backBuffer = backBuffer;
g_surfaceDesc = desc; g_surfaceDesc = desc;
g_isFullScreen = isFlippable; g_isFullScreen = isFlippable;
g_primaryThreadId = GetCurrentThreadId();
return DD_OK; return DD_OK;
} }
@ -184,7 +209,7 @@ namespace
ResetEvent(g_updateEvent); ResetEvent(g_updateEvent);
g_frontBuffer = nullptr; g_frontBuffer = nullptr;
g_backBuffer = nullptr; g_backBuffer = nullptr;
g_clipper = nullptr; g_clipper.release();
g_isFullScreen = false; g_isFullScreen = false;
g_paletteConverter.release(); g_paletteConverter.release();
@ -197,13 +222,7 @@ namespace
{ {
ResetEvent(g_updateEvent); ResetEvent(g_updateEvent);
if (!g_isFullScreen) if (compatBlt() && g_isFullScreen)
{
compatBlt(*g_frontBuffer);
return;
}
if (compatBlt(*g_backBuffer))
{ {
D3dDdi::KernelModeThunks::overrideFlipInterval( D3dDdi::KernelModeThunks::overrideFlipInterval(
Time::queryPerformanceCounter() - g_qpcLastFlip >= g_qpcFlipModeTimeout Time::queryPerformanceCounter() - g_qpcLastFlip >= g_qpcFlipModeTimeout
@ -262,13 +281,11 @@ namespace DDraw
CompatPtr<typename Types<DirectDraw>::TCreatedSurface> surface; CompatPtr<typename Types<DirectDraw>::TCreatedSurface> surface;
result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr); result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr);
bool isFlippable = true;
if (DDERR_NOEXCLUSIVEMODE == result) if (DDERR_NOEXCLUSIVEMODE == result)
{ {
desc.dwFlags = DDSD_CAPS; desc.dwFlags = DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
desc.dwBackBufferCount = 0; desc.dwBackBufferCount = 0;
isFlippable = false;
result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr); result = dd->CreateSurface(&dd, &desc, &surface.getRef(), nullptr);
} }
@ -316,7 +333,7 @@ namespace DDraw
g_isUpdateSuspended = false; g_isUpdateSuspended = false;
g_qpcLastFlip = Time::queryPerformanceCounter(); g_qpcLastFlip = Time::queryPerformanceCounter();
compatBlt(*g_backBuffer); compatBlt();
HRESULT result = g_frontBuffer->Flip(g_frontBuffer, nullptr, flags); HRESULT result = g_frontBuffer->Flip(g_frontBuffer, nullptr, flags);
g_qpcNextUpdate = Time::queryPerformanceCounter(); g_qpcNextUpdate = Time::queryPerformanceCounter();
return result; return result;
@ -377,22 +394,6 @@ namespace DDraw
return g_frontBuffer->Restore(g_frontBuffer); return g_frontBuffer->Restore(g_frontBuffer);
} }
void RealPrimarySurface::setClipper(CompatWeakPtr<IDirectDrawClipper> 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) HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData)
{ {
auto gammaControl(CompatPtr<IDirectDrawGammaControl>::from(g_frontBuffer.get())); auto gammaControl(CompatPtr<IDirectDrawGammaControl>::from(g_frontBuffer.get()));
@ -416,7 +417,7 @@ namespace DDraw
void RealPrimarySurface::update() void RealPrimarySurface::update()
{ {
if (g_isUpdateSuspended || !(g_isFullScreen || g_clipper)) if (g_isUpdateSuspended)
{ {
return; return;
} }

View File

@ -25,7 +25,6 @@ namespace DDraw
static void release(); static void release();
static void removeUpdateThread(); static void removeUpdateThread();
static HRESULT restore(); static HRESULT restore();
static void setClipper(CompatWeakPtr<IDirectDrawClipper> clipper);
static HRESULT setGammaRamp(DDGAMMARAMP* rampData); static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
static void setPalette(); static void setPalette();
static void update(); static void update();

View File

@ -204,17 +204,6 @@ namespace DDraw
return result; return result;
} }
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper)
{
HRESULT result = m_impl.SetClipper(This, lpDDClipper);
if (SUCCEEDED(result))
{
RealPrimarySurface::setClipper(lpDDClipper);
}
return result;
}
template <typename TSurface> template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette) HRESULT PrimarySurfaceImpl<TSurface>::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette)
{ {

View File

@ -29,7 +29,6 @@ namespace DDraw
DWORD dwFlags, HANDLE hEvent) override; DWORD dwFlags, HANDLE hEvent) override;
virtual HRESULT ReleaseDC(TSurface* This, HDC hDC) override; virtual HRESULT ReleaseDC(TSurface* This, HDC hDC) override;
virtual HRESULT Restore(TSurface* This) 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 SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette) override;
virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect) override; virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect) override;

View File

@ -273,12 +273,6 @@ namespace DDraw
return s_origVtable.Restore(This); return s_origVtable.Restore(This);
} }
template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper)
{
return s_origVtable.SetClipper(This, lpDDClipper);
}
template <typename TSurface> template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette) HRESULT SurfaceImpl<TSurface>::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette)
{ {

View File

@ -49,7 +49,6 @@ namespace DDraw
DWORD dwFlags, HANDLE hEvent); DWORD dwFlags, HANDLE hEvent);
virtual HRESULT ReleaseDC(TSurface* This, HDC hDC); virtual HRESULT ReleaseDC(TSurface* This, HDC hDC);
virtual HRESULT Restore(TSurface* This); virtual HRESULT Restore(TSurface* This);
virtual HRESULT SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper);
virtual HRESULT SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette); virtual HRESULT SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette);
virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect); virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect);