mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Fixed black screen issue with Windows 10 Creators Update
Also added v-sync to direct primary surface updates (i.e. those that are not using a back buffer and flip). Fixes issues #3 and #15.
This commit is contained in:
parent
640f746633
commit
5c91706b03
@ -4,8 +4,7 @@ typedef unsigned long DWORD;
|
|||||||
|
|
||||||
namespace Config
|
namespace Config
|
||||||
{
|
{
|
||||||
const int maxPaletteUpdatesPerMs = 10;
|
const int maxPaletteUpdatesPerMs = 5;
|
||||||
const int maxPrimaryUpdateRate = 60;
|
const int minExpectedFlipsPerSec = 5;
|
||||||
const int primaryUpdateDelayAfterFlip = 100;
|
|
||||||
const DWORD preallocatedGdiDcCount = 4;
|
const DWORD preallocatedGdiDcCount = 4;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,9 @@ namespace
|
|||||||
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
|
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
|
||||||
decltype(D3DKMTSetVidPnSourceOwner1)* g_origD3dKmtSetVidPnSourceOwner1 = nullptr;
|
decltype(D3DKMTSetVidPnSourceOwner1)* g_origD3dKmtSetVidPnSourceOwner1 = nullptr;
|
||||||
|
|
||||||
|
D3DDDI_FLIPINTERVAL_TYPE g_overrideFlipInterval = D3DDDI_FLIPINTERVAL_NOOVERRIDE;
|
||||||
|
UINT g_presentCount = 0;
|
||||||
|
|
||||||
NTSTATUS APIENTRY createDevice(D3DKMT_CREATEDEVICE* pData)
|
NTSTATUS APIENTRY createDevice(D3DKMT_CREATEDEVICE* pData)
|
||||||
{
|
{
|
||||||
Compat::LogEnter("D3DKMTCreateDevice", pData);
|
Compat::LogEnter("D3DKMTCreateDevice", pData);
|
||||||
@ -101,19 +104,37 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isPresentReady(D3DKMT_HANDLE device, D3DDDI_VIDEO_PRESENT_SOURCE_ID vidPnSourceId)
|
||||||
|
{
|
||||||
|
D3DKMT_GETDEVICESTATE deviceState = {};
|
||||||
|
deviceState.hDevice = device;
|
||||||
|
deviceState.StateType = D3DKMT_DEVICESTATE_PRESENT;
|
||||||
|
deviceState.PresentState.VidPnSourceId = vidPnSourceId;
|
||||||
|
NTSTATUS stateResult = D3DKMTGetDeviceState(&deviceState);
|
||||||
|
return FAILED(stateResult) ||
|
||||||
|
g_presentCount == deviceState.PresentState.PresentStats.PresentCount ||
|
||||||
|
0 == deviceState.PresentState.PresentStats.PresentCount;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS APIENTRY present(D3DKMT_PRESENT* pData)
|
NTSTATUS APIENTRY present(D3DKMT_PRESENT* pData)
|
||||||
{
|
{
|
||||||
Compat::LogEnter("D3DKMTPresent", pData);
|
Compat::LogEnter("D3DKMTPresent", pData);
|
||||||
|
|
||||||
static UINT presentCount = 0;
|
if (pData->Flags.Flip && D3DDDI_FLIPINTERVAL_NOOVERRIDE != g_overrideFlipInterval)
|
||||||
++presentCount;
|
{
|
||||||
|
pData->FlipInterval = g_overrideFlipInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
++g_presentCount;
|
||||||
pData->Flags.PresentCountValid = 1;
|
pData->Flags.PresentCountValid = 1;
|
||||||
pData->PresentCount = presentCount;
|
pData->PresentCount = g_presentCount;
|
||||||
|
|
||||||
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTPresent)(pData);
|
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTPresent)(pData);
|
||||||
if (SUCCEEDED(result) &&
|
if (SUCCEEDED(result) &&
|
||||||
1 == DDraw::PrimarySurface::getDesc().dwBackBufferCount &&
|
1 == DDraw::PrimarySurface::getDesc().dwBackBufferCount &&
|
||||||
pData->Flags.Flip && pData->FlipInterval != D3DDDI_FLIPINTERVAL_IMMEDIATE)
|
pData->Flags.Flip &&
|
||||||
|
D3DDDI_FLIPINTERVAL_IMMEDIATE != pData->FlipInterval &&
|
||||||
|
D3DDDI_FLIPINTERVAL_NOOVERRIDE == g_overrideFlipInterval)
|
||||||
{
|
{
|
||||||
auto contextIt = g_contexts.find(pData->hContext);
|
auto contextIt = g_contexts.find(pData->hContext);
|
||||||
auto deviceIt = (contextIt != g_contexts.end())
|
auto deviceIt = (contextIt != g_contexts.end())
|
||||||
@ -126,19 +147,12 @@ namespace
|
|||||||
vbEvent.hDevice = deviceIt->first;
|
vbEvent.hDevice = deviceIt->first;
|
||||||
vbEvent.VidPnSourceId = deviceIt->second.vidPnSourceId;
|
vbEvent.VidPnSourceId = deviceIt->second.vidPnSourceId;
|
||||||
|
|
||||||
D3DKMT_GETDEVICESTATE deviceState = {};
|
while (!isPresentReady(deviceIt->first, deviceIt->second.vidPnSourceId))
|
||||||
deviceState.hDevice = deviceIt->first;
|
|
||||||
deviceState.StateType = D3DKMT_DEVICESTATE_PRESENT;
|
|
||||||
deviceState.PresentState.VidPnSourceId = deviceIt->second.vidPnSourceId;
|
|
||||||
NTSTATUS stateResult = D3DKMTGetDeviceState(&deviceState);
|
|
||||||
while (SUCCEEDED(stateResult) &&
|
|
||||||
presentCount != deviceState.PresentState.PresentStats.PresentCount)
|
|
||||||
{
|
{
|
||||||
if (FAILED(D3DKMTWaitForVerticalBlankEvent(&vbEvent)))
|
if (FAILED(D3DKMTWaitForVerticalBlankEvent(&vbEvent)))
|
||||||
{
|
{
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
}
|
}
|
||||||
stateResult = D3DKMTGetDeviceState(&deviceState);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,6 +234,18 @@ namespace D3dDdi
|
|||||||
{
|
{
|
||||||
namespace KernelModeThunks
|
namespace KernelModeThunks
|
||||||
{
|
{
|
||||||
|
bool isPresentReady()
|
||||||
|
{
|
||||||
|
for (auto it : g_devices)
|
||||||
|
{
|
||||||
|
if (D3DDDI_ID_UNINITIALIZED != it.second.vidPnSourceId)
|
||||||
|
{
|
||||||
|
return ::isPresentReady(it.first, it.second.vidPnSourceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void installHooks()
|
void installHooks()
|
||||||
{
|
{
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTCreateContext, createContext);
|
HOOK_FUNCTION(gdi32, D3DKMTCreateContext, createContext);
|
||||||
@ -238,6 +264,11 @@ namespace D3dDdi
|
|||||||
reinterpret_cast<void*&>(g_origD3dKmtSetVidPnSourceOwner1), setVidPnSourceOwner1);
|
reinterpret_cast<void*&>(g_origD3dKmtSetVidPnSourceOwner1), setVidPnSourceOwner1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void overrideFlipInterval(D3DDDI_FLIPINTERVAL_TYPE flipInterval)
|
||||||
|
{
|
||||||
|
g_overrideFlipInterval = flipInterval;
|
||||||
|
}
|
||||||
|
|
||||||
void releaseVidPnSources()
|
void releaseVidPnSources()
|
||||||
{
|
{
|
||||||
for (auto it : g_devices)
|
for (auto it : g_devices)
|
||||||
|
@ -2,11 +2,15 @@
|
|||||||
|
|
||||||
#include "D3dDdi/Log/KernelModeThunksLog.h"
|
#include "D3dDdi/Log/KernelModeThunksLog.h"
|
||||||
|
|
||||||
|
static const auto D3DDDI_FLIPINTERVAL_NOOVERRIDE = static_cast<D3DDDI_FLIPINTERVAL_TYPE>(5);
|
||||||
|
|
||||||
namespace D3dDdi
|
namespace D3dDdi
|
||||||
{
|
{
|
||||||
namespace KernelModeThunks
|
namespace KernelModeThunks
|
||||||
{
|
{
|
||||||
void installHooks();
|
void installHooks();
|
||||||
|
bool isPresentReady();
|
||||||
|
void overrideFlipInterval(D3DDDI_FLIPINTERVAL_TYPE flipInterval);
|
||||||
void releaseVidPnSources();
|
void releaseVidPnSources();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "Common/Time.h"
|
#include "Common/Time.h"
|
||||||
#include "Config/Config.h"
|
#include "Config/Config.h"
|
||||||
|
#include "D3dDdi/KernelModeThunks.h"
|
||||||
#include "DDraw/DirectDraw.h"
|
#include "DDraw/DirectDraw.h"
|
||||||
#include "DDraw/DirectDrawSurface.h"
|
#include "DDraw/DirectDrawSurface.h"
|
||||||
#include "DDraw/IReleaseNotifier.h"
|
#include "DDraw/IReleaseNotifier.h"
|
||||||
@ -17,7 +18,6 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void onRelease();
|
void onRelease();
|
||||||
void updateNow(long long qpcNow);
|
|
||||||
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
||||||
|
|
||||||
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
|
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
|
||||||
@ -30,10 +30,11 @@ namespace
|
|||||||
bool g_stopUpdateThread = false;
|
bool g_stopUpdateThread = false;
|
||||||
HANDLE g_updateThread = nullptr;
|
HANDLE g_updateThread = nullptr;
|
||||||
HANDLE g_updateEvent = nullptr;
|
HANDLE g_updateEvent = nullptr;
|
||||||
RECT g_updateRect = {};
|
|
||||||
std::atomic<int> g_disableUpdateCount = 0;
|
std::atomic<int> g_disableUpdateCount = 0;
|
||||||
long long g_qpcMinUpdateInterval = 0;
|
long long g_qpcFlipModeTimeout = 0;
|
||||||
std::atomic<long long> g_qpcNextUpdate = 0;
|
long long g_qpcLastFlip = 0;
|
||||||
|
long long g_qpcNextUpdate = 0;
|
||||||
|
long long g_qpcUpdateInterval = 0;
|
||||||
|
|
||||||
std::atomic<bool> g_isFullScreen(false);
|
std::atomic<bool> g_isFullScreen(false);
|
||||||
|
|
||||||
@ -59,9 +60,7 @@ namespace
|
|||||||
if (paletteConverterDc && primaryDc)
|
if (paletteConverterDc && primaryDc)
|
||||||
{
|
{
|
||||||
result = TRUE == CALL_ORIG_FUNC(BitBlt)(paletteConverterDc,
|
result = TRUE == CALL_ORIG_FUNC(BitBlt)(paletteConverterDc,
|
||||||
g_updateRect.left, g_updateRect.top,
|
0, 0, g_surfaceDesc.dwWidth, g_surfaceDesc.dwHeight, primaryDc, 0, 0, SRCCOPY);
|
||||||
g_updateRect.right - g_updateRect.left, g_updateRect.bottom - g_updateRect.top,
|
|
||||||
primaryDc, g_updateRect.left, g_updateRect.top, SRCCOPY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
primary->ReleaseDC(primary, primaryDc);
|
primary->ReleaseDC(primary, primaryDc);
|
||||||
@ -69,19 +68,13 @@ namespace
|
|||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
result = SUCCEEDED(dest->Blt(&dest, &g_updateRect,
|
result = SUCCEEDED(dest->Blt(
|
||||||
g_paletteConverter, &g_updateRect, DDBLT_WAIT, nullptr));
|
&dest, nullptr, g_paletteConverter, nullptr, DDBLT_WAIT, nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = SUCCEEDED(dest->Blt(&dest, &g_updateRect,
|
result = SUCCEEDED(dest->Blt(&dest, nullptr, primary, nullptr, DDBLT_WAIT, nullptr));
|
||||||
primary, &g_updateRect, DDBLT_WAIT, nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
SetRectEmpty(&g_updateRect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Compat::LogLeave("RealPrimarySurface::compatBlt", dest) << result;
|
Compat::LogLeave("RealPrimarySurface::compatBlt", dest) << result;
|
||||||
@ -120,14 +113,8 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long getNextUpdateQpc(long long qpcNow)
|
template <typename DirectDraw>
|
||||||
{
|
HRESULT init(CompatRef<DirectDraw> dd, CompatPtr<IDirectDrawSurface7> surface)
|
||||||
long long qpcNextUpdate = g_qpcNextUpdate;
|
|
||||||
const long long missedIntervals = (qpcNow - qpcNextUpdate) / g_qpcMinUpdateInterval;
|
|
||||||
return qpcNextUpdate + g_qpcMinUpdateInterval * (missedIntervals + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT init(CompatPtr<IDirectDrawSurface7> surface)
|
|
||||||
{
|
{
|
||||||
DDSURFACEDESC2 desc = {};
|
DDSURFACEDESC2 desc = {};
|
||||||
desc.dwSize = sizeof(desc);
|
desc.dwSize = sizeof(desc);
|
||||||
@ -142,9 +129,19 @@ namespace
|
|||||||
surface->GetAttachedSurface(surface, &backBufferCaps, &backBuffer.getRef());
|
surface->GetAttachedSurface(surface, &backBufferCaps, &backBuffer.getRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
g_qpcMinUpdateInterval = Time::g_qpcFrequency / Config::maxPrimaryUpdateRate;
|
g_qpcFlipModeTimeout = Time::g_qpcFrequency / Config::minExpectedFlipsPerSec;
|
||||||
|
g_qpcLastFlip = Time::queryPerformanceCounter() - g_qpcFlipModeTimeout;
|
||||||
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
||||||
|
|
||||||
|
typename DDraw::Types<DirectDraw>::TSurfaceDesc dm = {};
|
||||||
|
dm.dwSize = sizeof(dm);
|
||||||
|
dd->GetDisplayMode(&dd, &dm);
|
||||||
|
if (dm.dwRefreshRate <= 1 || dm.dwRefreshRate >= 1000)
|
||||||
|
{
|
||||||
|
dm.dwRefreshRate = 60;
|
||||||
|
}
|
||||||
|
g_qpcUpdateInterval = Time::g_qpcFrequency / dm.dwRefreshRate;
|
||||||
|
|
||||||
if (!g_updateEvent)
|
if (!g_updateEvent)
|
||||||
{
|
{
|
||||||
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
@ -159,8 +156,6 @@ namespace
|
|||||||
surface->SetPrivateData(surface, IID_IReleaseNotifier,
|
surface->SetPrivateData(surface, IID_IReleaseNotifier,
|
||||||
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||||
|
|
||||||
timeBeginPeriod(1);
|
|
||||||
|
|
||||||
g_frontBuffer = surface.detach();
|
g_frontBuffer = surface.detach();
|
||||||
g_backBuffer = backBuffer;
|
g_backBuffer = backBuffer;
|
||||||
g_surfaceDesc = desc;
|
g_surfaceDesc = desc;
|
||||||
@ -169,10 +164,21 @@ namespace
|
|||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNextUpdateSignaledAndReady(long long qpcNow)
|
bool isUpdateScheduled()
|
||||||
{
|
{
|
||||||
return Time::qpcToMs(qpcNow - g_qpcNextUpdate) >= 0 &&
|
return WAIT_OBJECT_0 == WaitForSingleObject(g_updateEvent, 0);
|
||||||
WAIT_OBJECT_0 == WaitForSingleObject(g_updateEvent, 0);
|
}
|
||||||
|
|
||||||
|
int msUntilNextUpdate()
|
||||||
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
|
const auto qpcNow = Time::queryPerformanceCounter();
|
||||||
|
const int result = max(0, Time::qpcToMs(g_qpcNextUpdate - qpcNow));
|
||||||
|
if (0 == result && g_isFullScreen && qpcNow - g_qpcLastFlip >= g_qpcFlipModeTimeout)
|
||||||
|
{
|
||||||
|
return D3dDdi::KernelModeThunks::isPresentReady() ? 0 : 2;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRelease()
|
void onRelease()
|
||||||
@ -180,7 +186,6 @@ namespace
|
|||||||
Compat::LogEnter("RealPrimarySurface::onRelease");
|
Compat::LogEnter("RealPrimarySurface::onRelease");
|
||||||
|
|
||||||
ResetEvent(g_updateEvent);
|
ResetEvent(g_updateEvent);
|
||||||
timeEndPeriod(1);
|
|
||||||
g_frontBuffer = nullptr;
|
g_frontBuffer = nullptr;
|
||||||
g_backBuffer = nullptr;
|
g_backBuffer = nullptr;
|
||||||
g_clipper = nullptr;
|
g_clipper = nullptr;
|
||||||
@ -192,18 +197,24 @@ namespace
|
|||||||
Compat::LogLeave("RealPrimarySurface::onRelease");
|
Compat::LogLeave("RealPrimarySurface::onRelease");
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateNow(long long qpcNow)
|
void updateNow()
|
||||||
{
|
{
|
||||||
ResetEvent(g_updateEvent);
|
ResetEvent(g_updateEvent);
|
||||||
|
|
||||||
if (compatBlt(*g_frontBuffer))
|
if (!g_isFullScreen)
|
||||||
{
|
{
|
||||||
long long qpcNextUpdate = getNextUpdateQpc(qpcNow);
|
compatBlt(*g_frontBuffer);
|
||||||
if (Time::qpcToMs(qpcNow - qpcNextUpdate) >= 0)
|
return;
|
||||||
{
|
}
|
||||||
qpcNextUpdate += g_qpcMinUpdateInterval;
|
|
||||||
}
|
if (compatBlt(*g_backBuffer))
|
||||||
g_qpcNextUpdate = qpcNextUpdate;
|
{
|
||||||
|
D3dDdi::KernelModeThunks::overrideFlipInterval(
|
||||||
|
Time::queryPerformanceCounter() - g_qpcLastFlip >= g_qpcFlipModeTimeout
|
||||||
|
? D3DDDI_FLIPINTERVAL_ONE
|
||||||
|
: D3DDDI_FLIPINTERVAL_IMMEDIATE);
|
||||||
|
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT);
|
||||||
|
D3dDdi::KernelModeThunks::overrideFlipInterval(D3DDDI_FLIPINTERVAL_NOOVERRIDE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,20 +229,17 @@ namespace
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const long long qpcTargetNextUpdate = g_qpcNextUpdate;
|
const int waitTime = msUntilNextUpdate();
|
||||||
const int msUntilNextUpdate =
|
if (waitTime > 0)
|
||||||
Time::qpcToMs(qpcTargetNextUpdate - Time::queryPerformanceCounter());
|
|
||||||
if (msUntilNextUpdate > 0)
|
|
||||||
{
|
{
|
||||||
Sleep(msUntilNextUpdate);
|
Sleep(waitTime);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DDraw::ScopedThreadLock lock;
|
DDraw::ScopedThreadLock lock;
|
||||||
const long long qpcNow = Time::queryPerformanceCounter();
|
if (isUpdateScheduled() && msUntilNextUpdate() <= 0)
|
||||||
const bool isTargetUpdateStillNeeded = qpcTargetNextUpdate == g_qpcNextUpdate;
|
|
||||||
if (g_frontBuffer && (isTargetUpdateStillNeeded || isNextUpdateSignaledAndReady(qpcNow)))
|
|
||||||
{
|
{
|
||||||
updateNow(qpcNow);
|
updateNow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,7 +283,7 @@ namespace DDraw
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return init(surface);
|
return init(dd, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw>);
|
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw>);
|
||||||
@ -305,17 +313,10 @@ namespace DDraw
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResetEvent(g_updateEvent);
|
ResetEvent(g_updateEvent);
|
||||||
|
g_qpcLastFlip = Time::queryPerformanceCounter();
|
||||||
invalidate(nullptr);
|
|
||||||
compatBlt(*g_backBuffer);
|
compatBlt(*g_backBuffer);
|
||||||
|
|
||||||
HRESULT result = g_frontBuffer->Flip(g_frontBuffer, nullptr, flags);
|
HRESULT result = g_frontBuffer->Flip(g_frontBuffer, nullptr, flags);
|
||||||
if (SUCCEEDED(result))
|
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
||||||
{
|
|
||||||
g_qpcNextUpdate = getNextUpdateQpc(
|
|
||||||
Time::queryPerformanceCounter() + Time::msToQpc(Config::primaryUpdateDelayAfterFlip));
|
|
||||||
SetRectEmpty(&g_updateRect);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,19 +325,6 @@ namespace DDraw
|
|||||||
return g_frontBuffer;
|
return g_frontBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealPrimarySurface::invalidate(const RECT* rect)
|
|
||||||
{
|
|
||||||
if (rect)
|
|
||||||
{
|
|
||||||
UnionRect(&g_updateRect, &g_updateRect, rect);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto primaryDesc = PrimarySurface::getDesc();
|
|
||||||
SetRect(&g_updateRect, 0, 0, primaryDesc.dwWidth, primaryDesc.dwHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RealPrimarySurface::isFullScreen()
|
bool RealPrimarySurface::isFullScreen()
|
||||||
{
|
{
|
||||||
return g_isFullScreen;
|
return g_isFullScreen;
|
||||||
@ -404,17 +392,23 @@ namespace DDraw
|
|||||||
|
|
||||||
void RealPrimarySurface::update()
|
void RealPrimarySurface::update()
|
||||||
{
|
{
|
||||||
if (!IsRectEmpty(&g_updateRect) && 0 == g_disableUpdateCount && (g_isFullScreen || g_clipper))
|
if (0 == g_disableUpdateCount && (g_isFullScreen || g_clipper))
|
||||||
{
|
{
|
||||||
const long long qpcNow = Time::queryPerformanceCounter();
|
if (!isUpdateScheduled())
|
||||||
if (Time::qpcToMs(qpcNow - g_qpcNextUpdate) >= 0)
|
|
||||||
{
|
|
||||||
updateNow(qpcNow);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
const auto qpcNow = Time::queryPerformanceCounter();
|
||||||
|
const long long missedIntervals = (qpcNow - g_qpcNextUpdate) / g_qpcUpdateInterval;
|
||||||
|
g_qpcNextUpdate += g_qpcUpdateInterval * (missedIntervals + 1);
|
||||||
|
if (Time::qpcToMs(g_qpcNextUpdate - qpcNow) < 2)
|
||||||
|
{
|
||||||
|
g_qpcNextUpdate += g_qpcUpdateInterval;
|
||||||
|
}
|
||||||
SetEvent(g_updateEvent);
|
SetEvent(g_updateEvent);
|
||||||
}
|
}
|
||||||
|
else if (msUntilNextUpdate() <= 0)
|
||||||
|
{
|
||||||
|
updateNow();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +417,6 @@ namespace DDraw
|
|||||||
Gdi::updatePalette(startingEntry, count);
|
Gdi::updatePalette(startingEntry, count);
|
||||||
if (PrimarySurface::s_palette)
|
if (PrimarySurface::s_palette)
|
||||||
{
|
{
|
||||||
invalidate(nullptr);
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ namespace DDraw
|
|||||||
static void enableUpdates();
|
static void enableUpdates();
|
||||||
static HRESULT flip(DWORD flags);
|
static HRESULT flip(DWORD flags);
|
||||||
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
||||||
static void invalidate(const RECT* rect);
|
|
||||||
static bool isFullScreen();
|
static bool isFullScreen();
|
||||||
static bool isLost();
|
static bool isLost();
|
||||||
static void release();
|
static void release();
|
||||||
|
@ -33,7 +33,6 @@ namespace DDraw
|
|||||||
HRESULT result = m_impl.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
HRESULT result = m_impl.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
RealPrimarySurface::invalidate(lpDestRect);
|
|
||||||
RealPrimarySurface::update();
|
RealPrimarySurface::update();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -67,7 +66,6 @@ namespace DDraw
|
|||||||
destRect.right += desc.dwWidth;
|
destRect.right += desc.dwWidth;
|
||||||
destRect.bottom += desc.dwHeight;
|
destRect.bottom += desc.dwHeight;
|
||||||
}
|
}
|
||||||
RealPrimarySurface::invalidate(&destRect);
|
|
||||||
RealPrimarySurface::update();
|
RealPrimarySurface::update();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -144,7 +142,6 @@ namespace DDraw
|
|||||||
HRESULT result = m_impl.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
HRESULT result = m_impl.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
RealPrimarySurface::invalidate(lpDestRect);
|
|
||||||
restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps.dwCaps);
|
restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps.dwCaps);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -167,7 +164,6 @@ namespace DDraw
|
|||||||
HRESULT result = m_impl.ReleaseDC(This, hDC);
|
HRESULT result = m_impl.ReleaseDC(This, hDC);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
RealPrimarySurface::invalidate(nullptr);
|
|
||||||
RealPrimarySurface::update();
|
RealPrimarySurface::update();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <timeapi.h>
|
||||||
#include <Uxtheme.h>
|
#include <Uxtheme.h>
|
||||||
|
|
||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
@ -125,6 +126,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
|
|||||||
const BOOL disablePriorityBoost = TRUE;
|
const BOOL disablePriorityBoost = TRUE;
|
||||||
SetProcessPriorityBoost(GetCurrentProcess(), disablePriorityBoost);
|
SetProcessPriorityBoost(GetCurrentProcess(), disablePriorityBoost);
|
||||||
SetProcessAffinityMask(GetCurrentProcess(), 1);
|
SetProcessAffinityMask(GetCurrentProcess(), 1);
|
||||||
|
timeBeginPeriod(1);
|
||||||
SetThemeAppProperties(0);
|
SetThemeAppProperties(0);
|
||||||
|
|
||||||
Compat::redirectIatHooks("ddraw.dll", "DirectDrawCreate",
|
Compat::redirectIatHooks("ddraw.dll", "DirectDrawCreate",
|
||||||
@ -150,6 +152,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
|
|||||||
FreeLibrary(g_origDInputModule);
|
FreeLibrary(g_origDInputModule);
|
||||||
FreeLibrary(g_origDDrawModule);
|
FreeLibrary(g_origDDrawModule);
|
||||||
Win32::FontSmoothing::setSystemSettingsForced(Win32::FontSmoothing::g_origSystemSettings);
|
Win32::FontSmoothing::setSystemSettingsForced(Win32::FontSmoothing::g_origSystemSettings);
|
||||||
|
timeEndPeriod(1);
|
||||||
Compat::Log() << "DDrawCompat detached successfully";
|
Compat::Log() << "DDrawCompat detached successfully";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,6 @@ namespace
|
|||||||
gdiSurface.get()->lpVtbl->Unlock(gdiSurface, nullptr);
|
gdiSurface.get()->lpVtbl->Unlock(gdiSurface, nullptr);
|
||||||
if (DDLOCK_READONLY != g_ddLockFlags)
|
if (DDLOCK_READONLY != g_ddLockFlags)
|
||||||
{
|
{
|
||||||
DDraw::RealPrimarySurface::invalidate(nullptr);
|
|
||||||
DDraw::RealPrimarySurface::update();
|
DDraw::RealPrimarySurface::update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user