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

Updated presentation logic

This commit is contained in:
narzoul 2022-04-15 23:49:46 +02:00
parent 55eab96f78
commit 80863f77a7
22 changed files with 315 additions and 162 deletions

View File

@ -5,11 +5,26 @@
namespace Time
{
long long g_qpcFrequency = 0;
HANDLE g_waitableTimer = nullptr;
void init()
{
LARGE_INTEGER qpc;
QueryPerformanceFrequency(&qpc);
g_qpcFrequency = qpc.QuadPart;
g_waitableTimer = CreateWaitableTimer(nullptr, FALSE, nullptr);
}
void waitForNextTick()
{
LARGE_INTEGER due = {};
due.QuadPart = -1;
if (!g_waitableTimer ||
!SetWaitableTimer(g_waitableTimer, &due, 0, nullptr, nullptr, FALSE) ||
WAIT_OBJECT_0 != WaitForSingleObject(g_waitableTimer, INFINITE))
{
Sleep(1);
}
}
}

View File

@ -25,10 +25,5 @@ namespace Time
return qpc.QuadPart;
}
inline ULONG64 queryThreadCycleTime()
{
ULONG64 cycleTime = 0;
QueryThreadCycleTime(GetCurrentThread(), &cycleTime);
return cycleTime;
}
void waitForNextTick();
}

View File

@ -21,9 +21,6 @@
namespace Config
{
const unsigned delayedFlipModeTimeout = 200;
const unsigned maxPaletteUpdatesPerMs = 5;
extern Settings::AlternatePixelCenter alternatePixelCenter;
extern Settings::Antialiasing antialiasing;
extern Settings::ConfigHotKey configHotKey;

View File

@ -27,6 +27,7 @@ namespace D3dDdi
: m_origVtable(CompatVtable<D3DDDI_DEVICEFUNCS>::s_origVtable)
, m_adapter(adapter)
, m_device(device)
, m_eventQuery(nullptr)
, m_renderTarget(nullptr)
, m_renderTargetSubResourceIndex(0)
, m_sharedPrimary(nullptr)
@ -34,6 +35,10 @@ namespace D3dDdi
, m_state(*this)
, m_shaderBlitter(*this)
{
D3DDDIARG_CREATEQUERY createQuery = {};
createQuery.QueryType = D3DDDIQUERYTYPE_EVENT;
m_origVtable.pfnCreateQuery(m_device, &createQuery);
m_eventQuery = createQuery.hQuery;
}
void Device::add(Adapter& adapter, HANDLE device)
@ -388,6 +393,33 @@ namespace D3dDdi
m_state.updateConfig();
}
void Device::waitForIdle()
{
D3dDdi::ScopedCriticalSection lock;
flushPrimitives();
D3DDDIARG_ISSUEQUERY issueQuery = {};
issueQuery.hQuery = m_eventQuery;
issueQuery.Flags.End = 1;
m_origVtable.pfnIssueQuery(m_device, &issueQuery);
if (m_origVtable.pfnFlush1)
{
m_origVtable.pfnFlush1(m_device, 0);
}
else
{
m_origVtable.pfnFlush(m_device);
}
BOOL result = FALSE;
D3DDDIARG_GETQUERYDATA getQueryData = {};
getQueryData.hQuery = m_eventQuery;
getQueryData.pData = &result;
while (S_FALSE == m_origVtable.pfnGetQueryData(m_device, &getQueryData))
{
}
}
std::map<HANDLE, Device> Device::s_devices;
bool Device::s_isFlushEnabled = true;
}

View File

@ -58,6 +58,7 @@ namespace D3dDdi
void prepareForGpuWrite();
void setRenderTarget(const D3DDDIARG_SETRENDERTARGET& data);
void updateConfig();
void waitForIdle();
static void add(Adapter& adapter, HANDLE device);
static Device& get(HANDLE device) { return s_devices.find(device)->second; }
@ -75,6 +76,7 @@ namespace D3dDdi
D3DDDI_DEVICEFUNCS m_origVtable;
Adapter& m_adapter;
HANDLE m_device;
HANDLE m_eventQuery;
std::map<HANDLE, std::unique_ptr<Resource>> m_resources;
Resource* m_renderTarget;
UINT m_renderTargetSubResourceIndex;

View File

@ -2,7 +2,6 @@
#include <string>
#include <Windows.h>
#include <VersionHelpers.h>
#include <Common/Log.h>
#include <Common/Hook.h>
@ -107,6 +106,21 @@ namespace
return LOG_RESULT(result);
}
NTSTATUS APIENTRY createDevice(D3DKMT_CREATEDEVICE* pData)
{
LOG_FUNC("D3DKMTCreateDevice", pData);
NTSTATUS result = D3DKMTCreateDevice(pData);
if (SUCCEEDED(result))
{
D3DKMT_SETQUEUEDLIMIT limit = {};
limit.hDevice = pData->hDevice;
limit.Type = D3DKMT_SET_QUEUEDLIMIT_PRESENT;
limit.QueuedPresentLimit = 1;
D3DKMTSetQueuedLimit(&limit);
}
return LOG_RESULT(result);
}
HDC WINAPI ddrawCreateDcA(LPCSTR pwszDriver, LPCSTR pwszDevice, LPCSTR pszPort, const DEVMODEA* pdm)
{
LOG_FUNC("ddrawCreateDCA", pwszDriver, pwszDevice, pszPort, pdm);
@ -152,7 +166,7 @@ namespace
{
D3DKMT_GETSCANLINE data = {};
getVidPnSource(data.hAdapter, data.VidPnSourceId);
if (!data.hAdapter || FAILED(D3DKMTGetScanLine(&data)) || data.InVerticalBlank)
if (!data.hAdapter || FAILED(D3DKMTGetScanLine(&data)))
{
return -1;
}
@ -189,19 +203,6 @@ namespace
return LOG_RESULT(result);
}
void pollForVerticalBlank()
{
int scanLine = getScanLine();
int prevScanLine = scanLine;
auto qpcStart = Time::queryPerformanceCounter();
while (scanLine >= prevScanLine && Time::queryPerformanceCounter() - qpcStart < Time::g_qpcFrequency / 60)
{
Sleep(1);
prevScanLine = scanLine;
scanLine = getScanLine();
}
}
NTSTATUS APIENTRY present(D3DKMT_PRESENT* pData)
{
LOG_FUNC("D3DKMTPresent", pData);
@ -252,6 +253,7 @@ namespace
{
LOG_FUNC("D3DKMTSetGammaRamp", pData);
UINT vsyncCounter = D3dDdi::KernelModeThunks::getVsyncCounter();
DDraw::RealPrimarySurface::setUpdateReady();
DDraw::RealPrimarySurface::flush();
HRESULT result = D3DKMTSetGammaRamp(pData);
if (SUCCEEDED(result))
@ -324,30 +326,24 @@ namespace
void waitForVerticalBlank()
{
if (IsWindows8OrGreater())
auto qpcStart = Time::queryPerformanceCounter();
int scanLine = getScanLine();
int prevScanLine = 0;
while (scanLine >= prevScanLine)
{
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};
{
Compat::ScopedSrwLockShared lock(g_adapterInfoSrwLock);
data.hAdapter = g_lastOpenAdapterInfo.adapter;
data.VidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
}
if (!data.hAdapter)
{
updateGdiAdapterInfo();
data.hAdapter = g_gdiAdapterInfo.adapter;
data.VidPnSourceId = g_gdiAdapterInfo.vidPnSourceId;
}
if (data.hAdapter && SUCCEEDED(D3DKMTWaitForVerticalBlankEvent(&data)))
{
return;
}
Time::waitForNextTick();
prevScanLine = scanLine;
scanLine = getScanLine();
}
pollForVerticalBlank();
if (scanLine < 0)
{
auto msElapsed = static_cast<DWORD>(Time::qpcToMs(Time::queryPerformanceCounter() - qpcStart));
if (msElapsed < 16)
{
Sleep(16 - msElapsed);
}
}
}
}
@ -412,6 +408,7 @@ namespace D3dDdi
Compat::hookIatFunction(Dll::g_origDDrawModule, "CreateDCA", ddrawCreateDcA);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTCloseAdapter", closeAdapter);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTCreateDCFromMemory", createDcFromMemory);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTCreateDevice", createDevice);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTOpenAdapterFromHdc", openAdapterFromHdc);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTPresent", present);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTQueryAdapterInfo", queryAdapterInfo);

View File

@ -832,6 +832,16 @@ namespace D3dDdi
auto rtIndex = rtSurface.resource ? 0 : data.DstSubResourceIndex;
auto rtRect = rtSurface.resource ? data.SrcRect : data.DstRect;
if (D3DDDIPOOL_SYSTEMMEM == srcResource->m_fixedData.Pool)
{
srcResource = repo.getTempTexture(srcWidth, srcHeight, getPixelFormat(srcResource->m_fixedData.Format)).resource;
if (!srcResource)
{
return E_OUTOFMEMORY;
}
copySubResourceRegion(*srcResource, 0, data.SrcRect, data.hSrcResource, data.SrcSubResourceIndex, data.SrcRect);
}
if (D3DDDIFMT_P8 == srcResource->m_origData.Format)
{
auto entries(Gdi::Palette::getHardwarePalette());

View File

@ -27,6 +27,7 @@ namespace D3dDdi
operator HANDLE() const { return m_handle; }
const Resource* getCustomResource() { return m_msaaSurface.resource ? m_msaaSurface.resource : m_msaaResolvedSurface.resource; }
Device& getDevice() const { return m_device; }
const D3DDDIARG_CREATERESOURCE2& getFixedDesc() const { return m_fixedData; }
const D3DDDIARG_CREATERESOURCE2& getOrigDesc() const { return m_origData; }
bool isClampable() const { return m_isClampable; }

View File

@ -73,6 +73,7 @@ namespace
template <typename TDirectDraw>
HRESULT STDMETHODCALLTYPE WaitForVerticalBlank(TDirectDraw* This, DWORD dwFlags, HANDLE hEvent)
{
DDraw::RealPrimarySurface::setUpdateReady();
DDraw::RealPrimarySurface::flush();
return getOrigVtable(This).WaitForVerticalBlank(This, dwFlags, hEvent);
}

View File

@ -49,7 +49,8 @@ namespace DDraw
updatesInLastMs.pop_front();
}
if (updatesInLastMs.size() >= Config::maxPaletteUpdatesPerMs)
const unsigned maxPaletteUpdatesPerMs = 5;
if (updatesInLastMs.size() >= maxPaletteUpdatesPerMs)
{
Sleep(1);
updatesInLastMs.clear();

View File

@ -1,10 +1,10 @@
#include <atomic>
#include <memory>
#include <vector>
#include <Common/Comparison.h>
#include <Common/CompatPtr.h>
#include <Common/Hook.h>
#include <Common/ScopedCriticalSection.h>
#include <Common/Time.h>
#include <Config/Config.h>
#include <D3dDdi/Device.h>
@ -29,6 +29,8 @@
namespace
{
const unsigned DELAYED_FLIP_MODE_TIMEOUT_MS = 200;
void onRelease();
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
@ -40,11 +42,18 @@ namespace
bool g_isFullscreen = false;
DDraw::Surface* g_lastFlipSurface = nullptr;
Compat::CriticalSection g_presentCs;
bool g_isDelayedFlipPending = false;
bool g_isUpdatePending = false;
bool g_waitingForPrimaryUnlock = false;
std::atomic<long long> g_qpcLastUpdate = 0;
bool g_isUpdateReady = false;
DWORD g_lastUpdateThreadId = 0;
long long g_qpcLastUpdate = 0;
long long g_qpcUpdateStart = 0;
long long g_qpcDelayedFlipEnd = 0;
UINT g_flipEndVsyncCount = 0;
UINT g_presentEndVsyncCount = 0;
HWND g_devicePresentationWindow = nullptr;
HWND g_deviceWindow = nullptr;
HWND* g_deviceWindowPtr = nullptr;
@ -112,24 +121,14 @@ namespace
return 1;
}
bool isFlipPending()
{
return static_cast<INT>(D3dDdi::KernelModeThunks::getVsyncCounter() - g_flipEndVsyncCount) < 0;
}
bool isPresentPending()
{
return static_cast<INT>(D3dDdi::KernelModeThunks::getVsyncCounter() - g_presentEndVsyncCount) < 0;
}
void onRelease()
{
LOG_FUNC("RealPrimarySurface::onRelease");
g_frontBuffer = nullptr;
g_lastFlipSurface = nullptr;
g_clipper.release();
g_isFullscreen = false;
g_waitingForPrimaryUnlock = false;
g_surfaceDesc = {};
DDraw::RealPrimarySurface::updateDevicePresentationWindowPos();
@ -152,16 +151,20 @@ namespace
const bool isFlippable = 0 != (desc.ddsCaps.dwCaps & DDSCAPS_FLIP);
g_surfaceDesc = desc;
g_isFullscreen = isFlippable;
g_isUpdatePending = true;
g_qpcLastUpdate = Time::queryPerformanceCounter() - Time::msToQpc(Config::delayedFlipModeTimeout);
if (isFlippable)
{
g_frontBuffer->Flip(g_frontBuffer, getLastSurface(), DDFLIP_WAIT);
g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + 1;
g_presentEndVsyncCount = g_flipEndVsyncCount;
D3dDdi::KernelModeThunks::waitForVsyncCounter(g_flipEndVsyncCount);
D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1);
}
Compat::ScopedCriticalSection lock(g_presentCs);
g_isUpdatePending = false;
g_isUpdateReady = false;
g_qpcLastUpdate = Time::queryPerformanceCounter() - Time::msToQpc(DELAYED_FLIP_MODE_TIMEOUT_MS);
g_qpcUpdateStart = g_qpcLastUpdate;
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
g_flipEndVsyncCount = g_presentEndVsyncCount;
}
void presentToPrimaryChain(CompatWeakPtr<IDirectDrawSurface7> src)
@ -202,11 +205,15 @@ namespace
D3dDdi::KernelModeThunks::setDcPaletteOverride(nullptr);
}
void updateNow(CompatWeakPtr<IDirectDrawSurface7> src, UINT flipInterval)
void updateNow(CompatWeakPtr<IDirectDrawSurface7> src)
{
{
Compat::ScopedCriticalSection lock(g_presentCs);
g_isUpdatePending = false;
g_isUpdateReady = false;
}
presentToPrimaryChain(src);
g_isUpdatePending = false;
g_waitingForPrimaryUnlock = false;
if (g_isFullscreen && g_devicePresentationWindow)
{
@ -214,60 +221,26 @@ namespace
g_frontBuffer->Flip(g_frontBuffer, getBackBuffer(), DDFLIP_WAIT);
*g_deviceWindowPtr = g_deviceWindow;
}
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + max(flipInterval, 1);
}
void updateNowIfNotBusy()
{
auto primary(DDraw::PrimarySurface::getPrimary());
RECT emptyRect = {};
HRESULT result = primary ? primary->BltFast(primary, 0, 0, primary, &emptyRect, DDBLTFAST_WAIT) : DD_OK;
g_waitingForPrimaryUnlock = DDERR_SURFACEBUSY == result || DDERR_LOCKEDSURFACES == result;
if (!g_waitingForPrimaryUnlock)
{
const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate);
updateNow(primary, msSinceLastUpdate > Config::delayedFlipModeTimeout ? 0 : 1);
}
g_presentEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + 1;
}
unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/)
{
bool skipWaitForVsync = false;
int msUntilUpdateReady = 0;
while (true)
{
if (!skipWaitForVsync)
if (msUntilUpdateReady > 0)
{
Sleep(1);
}
else
{
D3dDdi::KernelModeThunks::waitForVsyncCounter(D3dDdi::KernelModeThunks::getVsyncCounter() + 1);
}
skipWaitForVsync = false;
Sleep(1);
DDraw::ScopedThreadLock lock;
Gdi::Caret::blink();
if (Gdi::Cursor::update())
{
g_isUpdatePending = true;
}
if (g_isUpdatePending && !isPresentPending())
{
auto qpcNow = Time::queryPerformanceCounter();
auto qpcLastVsync = D3dDdi::KernelModeThunks::getQpcLastVsync();
if (Time::qpcToMs(qpcNow - qpcLastVsync) < 1 ||
Time::qpcToMs(qpcNow - g_qpcLastUpdate) < 1 && Time::qpcToMs(qpcNow - qpcLastVsync) <= 3)
{
skipWaitForVsync = true;
}
else
{
updateNowIfNotBusy();
}
}
msUntilUpdateReady = DDraw::RealPrimarySurface::flush();
}
return 0;
}
}
@ -325,27 +298,19 @@ namespace DDraw
HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
{
const DWORD flipInterval = getFlipInterval(flags);
if (0 == flipInterval)
if (0 == flipInterval ||
Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate) < DELAYED_FLIP_MODE_TIMEOUT_MS)
{
g_isUpdatePending = true;
return DD_OK;
}
const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate);
const bool isFlipDelayed = msSinceLastUpdate >= 0 && msSinceLastUpdate <= Config::delayedFlipModeTimeout;
if (isFlipDelayed)
{
if (!isPresentPending())
{
CompatPtr<IDirectDrawSurface7> prevPrimarySurface(
surfaceTargetOverride ? surfaceTargetOverride : PrimarySurface::getLastSurface());
updateNow(prevPrimarySurface, 0);
}
g_isUpdatePending = true;
PrimarySurface::waitForIdle();
Compat::ScopedCriticalSection lock(g_presentCs);
g_isDelayedFlipPending = true;
g_isUpdatePending = false;
g_isUpdateReady = false;
g_lastUpdateThreadId = GetCurrentThreadId();
}
else
{
updateNow(PrimarySurface::getPrimary(), flipInterval);
updateNow(PrimarySurface::getPrimary());
}
g_flipEndVsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter() + flipInterval;
@ -358,16 +323,60 @@ namespace DDraw
{
g_lastFlipSurface = nullptr;
}
g_qpcDelayedFlipEnd = Time::queryPerformanceCounter();
return DD_OK;
}
void RealPrimarySurface::flush()
int RealPrimarySurface::flush()
{
DDraw::ScopedThreadLock lock;
if (g_isUpdatePending && !isPresentPending())
auto vsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
if (static_cast<int>(vsyncCount - g_presentEndVsyncCount) < 0)
{
updateNowIfNotBusy();
return -1;
}
{
Compat::ScopedCriticalSection lock(g_presentCs);
if (!g_isUpdateReady)
{
if (g_isUpdatePending)
{
auto msSinceUpdateStart = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcUpdateStart);
if (msSinceUpdateStart < 10)
{
return 10 - static_cast<int>(msSinceUpdateStart);
}
g_isUpdateReady = true;
}
else if (g_isDelayedFlipPending)
{
auto msSinceDelayedFlipEnd = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcDelayedFlipEnd);
if (msSinceDelayedFlipEnd < 3)
{
return 3 - static_cast<int>(msSinceDelayedFlipEnd);
}
g_isDelayedFlipPending = false;
g_isUpdateReady = true;
}
}
if (!g_isUpdateReady)
{
return -1;
}
}
auto src(g_isDelayedFlipPending ? g_lastFlipSurface->getDDS() : DDraw::PrimarySurface::getPrimary());
RECT emptyRect = {};
HRESULT result = src ? src->BltFast(src, 0, 0, src, &emptyRect, DDBLTFAST_WAIT) : DD_OK;
if (DDERR_SURFACEBUSY == result || DDERR_LOCKEDSURFACES == result)
{
return 1;
}
updateNow(src);
return 0;
}
HWND RealPrimarySurface::getDevicePresentationWindow()
@ -441,8 +450,16 @@ namespace DDraw
void RealPrimarySurface::scheduleUpdate()
{
Compat::ScopedCriticalSection lock(g_presentCs);
g_qpcLastUpdate = Time::queryPerformanceCounter();
g_isUpdatePending = true;
if (!g_isUpdatePending)
{
g_qpcUpdateStart = g_qpcLastUpdate;
g_isUpdatePending = true;
g_isDelayedFlipPending = false;
g_lastUpdateThreadId = GetCurrentThreadId();
}
g_isUpdateReady = false;
}
HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData)
@ -457,14 +474,13 @@ namespace DDraw
return gammaControl->SetGammaRamp(gammaControl, 0, rampData);
}
void RealPrimarySurface::update()
void RealPrimarySurface::setUpdateReady()
{
DDraw::ScopedThreadLock lock;
g_qpcLastUpdate = Time::queryPerformanceCounter();
g_isUpdatePending = true;
if (g_waitingForPrimaryUnlock)
Compat::ScopedCriticalSection lock(g_presentCs);
if ((g_isUpdatePending || g_isDelayedFlipPending) && GetCurrentThreadId() == g_lastUpdateThreadId)
{
updateNowIfNotBusy();
g_isUpdateReady = true;
g_isDelayedFlipPending = false;
}
}
@ -490,17 +506,23 @@ namespace DDraw
});
}
bool RealPrimarySurface::waitForFlip(Surface* surface)
bool RealPrimarySurface::waitForFlip(CompatWeakPtr<IDirectDrawSurface7> surface)
{
auto primary(DDraw::PrimarySurface::getPrimary());
if (!surface || !primary ||
surface != g_lastFlipSurface &&
surface != Surface::getSurface(*DDraw::PrimarySurface::getPrimary()))
if (!surface || !primary || !g_lastFlipSurface ||
surface != primary && surface != g_lastFlipSurface->getDDS())
{
return true;
}
D3dDdi::KernelModeThunks::waitForVsyncCounter(g_flipEndVsyncCount);
auto vsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
while (static_cast<int>(vsyncCount - g_flipEndVsyncCount) < 0)
{
flush();
++vsyncCount;
D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCount);
g_qpcDelayedFlipEnd = Time::queryPerformanceCounter();
}
return true;
}
}

View File

@ -16,7 +16,7 @@ namespace DDraw
static HRESULT create(CompatRef<DirectDraw> dd);
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
static void flush();
static int flush();
static HWND getDevicePresentationWindow();
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
static RECT getMonitorRect();
@ -29,8 +29,8 @@ namespace DDraw
static HRESULT restore();
static void scheduleUpdate();
static HRESULT setGammaRamp(DDGAMMARAMP* rampData);
static void update();
static void setUpdateReady();
static void updateDevicePresentationWindowPos();
static bool waitForFlip(Surface* surface);
static bool waitForFlip(CompatWeakPtr<IDirectDrawSurface7> surface);
};
}

View File

@ -14,6 +14,7 @@
namespace
{
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
D3dDdi::Device* g_device = nullptr;
HANDLE g_gdiResourceHandle = nullptr;
HANDLE g_frontResource = nullptr;
DWORD g_origCaps = 0;
@ -28,6 +29,7 @@ namespace DDraw
{
LOG_FUNC("PrimarySurface::~PrimarySurface");
g_device = nullptr;
g_gdiResourceHandle = nullptr;
g_frontResource = nullptr;
g_primarySurface = nullptr;
@ -91,6 +93,7 @@ namespace DDraw
ResizePalette(g_palette, 256);
}
g_device = D3dDdi::Device::findDeviceByResource(DirectDrawSurface::getDriverResourceHandle(*surface));
data->restore();
D3dDdi::Device::updateAllConfig();
return DD_OK;
@ -265,7 +268,15 @@ namespace DDraw
ReleaseDC(g_deviceWindow, dc);
}
RealPrimarySurface::update();
RealPrimarySurface::scheduleUpdate();
}
void PrimarySurface::waitForIdle()
{
if (g_device)
{
g_device->waitForIdle();
}
}
CompatWeakPtr<IDirectDrawPalette> PrimarySurface::s_palette;

View File

@ -31,6 +31,7 @@ namespace DDraw
static bool isGdiSurface(TSurface* surface);
static void updateFrontResource();
static void waitForIdle();
virtual void restore();

View File

@ -91,11 +91,13 @@ namespace DDraw
return DDERR_SURFACELOST;
}
RealPrimarySurface::flush();
HRESULT result = SurfaceImpl::Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
if (SUCCEEDED(result))
{
bltToGdi(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
RealPrimarySurface::update();
RealPrimarySurface::scheduleUpdate();
PrimarySurface::waitForIdle();
}
return result;
}
@ -109,10 +111,12 @@ namespace DDraw
return DDERR_SURFACELOST;
}
RealPrimarySurface::flush();
HRESULT result = SurfaceImpl::BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
if (SUCCEEDED(result))
{
RealPrimarySurface::update();
RealPrimarySurface::scheduleUpdate();
PrimarySurface::waitForIdle();
}
return result;
}
@ -120,7 +124,9 @@ namespace DDraw
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags)
{
DDraw::RealPrimarySurface::waitForFlip(m_data);
RealPrimarySurface::setUpdateReady();
RealPrimarySurface::flush();
RealPrimarySurface::waitForFlip(m_data->getDDS());
auto surfaceTargetOverride(CompatPtr<TSurface>::from(lpDDSurfaceTargetOverride));
const bool isFlipEmulated = 0 != (PrimarySurface::getOrigCaps() & DDSCAPS_SYSTEMMEMORY);
if (isFlipEmulated)
@ -155,6 +161,13 @@ namespace DDraw
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC)
{
RealPrimarySurface::flush();
return SurfaceImpl::GetDC(This, lphDC);
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc)
{
@ -187,6 +200,7 @@ namespace DDraw
return DDERR_SURFACELOST;
}
RealPrimarySurface::flush();
HRESULT result = SurfaceImpl::Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
if (SUCCEEDED(result))
{
@ -201,7 +215,7 @@ namespace DDraw
HRESULT result = SurfaceImpl::ReleaseDC(This, hDC);
if (SUCCEEDED(result))
{
RealPrimarySurface::update();
RealPrimarySurface::scheduleUpdate();
}
return result;
}
@ -244,7 +258,7 @@ namespace DDraw
HRESULT result = SurfaceImpl::Unlock(This, lpRect);
if (SUCCEEDED(result))
{
RealPrimarySurface::update();
RealPrimarySurface::scheduleUpdate();
}
return result;
}

View File

@ -21,6 +21,7 @@ namespace DDraw
TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans) override;
virtual HRESULT Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags) override;
virtual HRESULT GetCaps(TSurface* This, TDdsCaps* lpDDSCaps) override;
virtual HRESULT GetDC(TSurface* This, HDC* lphDC);
virtual HRESULT GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc) override;
virtual HRESULT IsLost(TSurface* This) override;
virtual HRESULT Lock(TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,

View File

@ -30,6 +30,8 @@ namespace DDraw
template <typename TSurface>
static Surface* getSurface(TSurface& dds);
CompatWeakPtr<IDirectDrawSurface7> getDDS() const { return m_surface; };
template <typename TSurface>
SurfaceImpl<TSurface>* getImpl() const;

View File

@ -109,7 +109,7 @@ namespace DDraw
TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,
DWORD dwFlags, LPDDBLTFX lpDDBltFx)
{
RealPrimarySurface::waitForFlip(m_data);
RealPrimarySurface::waitForFlip(m_data->getDDS());
DirectDrawClipper::update();
return blt(This, lpDDSrcSurface, lpSrcRect, [=](TSurface* This, TSurface* lpDDSrcSurface, LPRECT lpSrcRect)
{ return getOrigVtable(This).Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); });
@ -119,7 +119,7 @@ namespace DDraw
HRESULT SurfaceImpl<TSurface>::BltFast(
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
{
RealPrimarySurface::waitForFlip(m_data);
RealPrimarySurface::waitForFlip(m_data->getDDS());
return blt(This, lpDDSrcSurface, lpSrcRect, [=](TSurface* This, TSurface* lpDDSrcSurface, LPRECT lpSrcRect)
{ return getOrigVtable(This).BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans); });
}
@ -144,7 +144,7 @@ namespace DDraw
template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC)
{
RealPrimarySurface::waitForFlip(m_data);
RealPrimarySurface::waitForFlip(m_data->getDDS());
HRESULT result = getOrigVtable(This).GetDC(This, lphDC);
if (SUCCEEDED(result))
{
@ -181,7 +181,7 @@ namespace DDraw
TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
DWORD dwFlags, HANDLE hEvent)
{
RealPrimarySurface::waitForFlip(m_data);
RealPrimarySurface::waitForFlip(m_data->getDDS());
HRESULT result = getOrigVtable(This).Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
if (SUCCEEDED(result))
{

View File

@ -2,6 +2,7 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/Cursor.h>
#include <Win32/DisplayMode.h>
@ -222,7 +223,7 @@ namespace Gdi
}
}
bool update()
void update()
{
Compat::ScopedCriticalSection lock(g_cs);
if (!IsRectEmpty(&g_monitorClipRect))
@ -238,11 +239,9 @@ namespace Gdi
(cursorInfo.hCursor != g_prevCursorInfo.hCursor || cursorInfo.ptScreenPos != g_prevCursorInfo.ptScreenPos))
{
g_prevCursorInfo = cursorInfo;
return true;
DDraw::RealPrimarySurface::scheduleUpdate();
}
}
return false;
}
}
}

View File

@ -12,6 +12,6 @@ namespace Gdi
HCURSOR setCursor(HCURSOR cursor);
void setMonitorClipRect(const RECT& rect);
void setEmulated(bool isEmulated);
bool update();
void update();
}
}

View File

@ -4,6 +4,9 @@
#include <Common/Hook.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <Dll/Dll.h>
#include <DDraw/RealPrimarySurface.h>
#include <Gdi/Caret.h>
#include <Gdi/Cursor.h>
#include <Gdi/GuiThread.h>
#include <Gdi/Region.h>
#include <Gdi/WinProc.h>
@ -83,7 +86,7 @@ namespace
}
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0))
while (CALL_ORIG_FUNC(GetMessageA)(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
@ -91,6 +94,16 @@ namespace
return 0;
}
unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/)
{
while (true)
{
Sleep(5);
Gdi::Caret::blink();
Gdi::Cursor::update();
}
}
}
namespace Gdi
@ -154,6 +167,7 @@ namespace Gdi
void start()
{
Dll::createThread(messageWindowThreadProc, &g_threadId, THREAD_PRIORITY_TIME_CRITICAL, 0);
Dll::createThread(updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL, 0);
}
}
}

View File

@ -147,6 +147,23 @@ namespace
return ddcWindowProc(hwnd, uMsg, wParam, lParam, CallWindowProcW, getWindowProc(hwnd).wndProcW);
}
BOOL WINAPI getMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
decltype(&GetMessageA) origGetMessage)
{
DDraw::RealPrimarySurface::setUpdateReady();
return origGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
}
BOOL WINAPI getMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
{
return getMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, CALL_ORIG_FUNC(GetMessageA));
}
BOOL WINAPI getMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
{
return getMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, CALL_ORIG_FUNC(GetMessageW));
}
LONG getWindowLong(HWND hWnd, int nIndex,
decltype(&GetWindowLongA) origGetWindowLong, WNDPROC(WindowProc::* wndProc))
{
@ -290,6 +307,23 @@ namespace
}
}
BOOL peekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg,
decltype(&PeekMessageA) origPeekMessage)
{
DDraw::RealPrimarySurface::setUpdateReady();
return origPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
}
BOOL WINAPI peekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
return peekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg, CALL_ORIG_FUNC(PeekMessageA));
}
BOOL WINAPI peekMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
return peekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg, CALL_ORIG_FUNC(PeekMessageW));
}
BOOL WINAPI setLayeredWindowAttributes(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags)
{
LOG_FUNC("SetLayeredWindowAttributes", hwnd, crKey, bAlpha, dwFlags);
@ -455,8 +489,12 @@ namespace Gdi
void installHooks()
{
HOOK_FUNCTION(user32, GetMessageA, getMessageA);
HOOK_FUNCTION(user32, GetMessageW, getMessageW);
HOOK_FUNCTION(user32, GetWindowLongA, getWindowLongA);
HOOK_FUNCTION(user32, GetWindowLongW, getWindowLongW);
HOOK_FUNCTION(user32, PeekMessageA, peekMessageA);
HOOK_FUNCTION(user32, PeekMessageW, peekMessageW);
HOOK_FUNCTION(user32, SetLayeredWindowAttributes, setLayeredWindowAttributes);
HOOK_FUNCTION(user32, SetWindowLongA, setWindowLongA);
HOOK_FUNCTION(user32, SetWindowLongW, setWindowLongW);