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:
parent
46f71be51a
commit
3f1fa0fae1
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user