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(ReleaseDC);
SET_COMPAT_METHOD(Restore);
SET_COMPAT_METHOD(SetClipper);
SET_COMPAT_METHOD(SetPalette);
SET_COMPAT_METHOD(Unlock);

View File

@ -20,6 +20,7 @@ namespace
void onRelease();
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
DWORD g_primaryThreadId = 0;
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
CompatWeakPtr<IDirectDrawSurface7> g_backBuffer;
CompatWeakPtr<IDirectDrawSurface7> g_paletteConverter;
@ -39,9 +40,28 @@ namespace
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;
@ -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<typename Types<DirectDraw>::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<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)
{
auto gammaControl(CompatPtr<IDirectDrawGammaControl>::from(g_frontBuffer.get()));
@ -416,7 +417,7 @@ namespace DDraw
void RealPrimarySurface::update()
{
if (g_isUpdateSuspended || !(g_isFullScreen || g_clipper))
if (g_isUpdateSuspended)
{
return;
}

View File

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

View File

@ -204,17 +204,6 @@ namespace DDraw
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>
HRESULT PrimarySurfaceImpl<TSurface>::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette)
{

View File

@ -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;

View File

@ -273,12 +273,6 @@ namespace DDraw
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>
HRESULT SurfaceImpl<TSurface>::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette)
{

View File

@ -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);