mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Improved presentation scheduling
Fixes cursor flickering issues in Siege of Avalon (issue #34) and multimon flip issues on Windows 8.1 (issue #28).
This commit is contained in:
parent
e69b5e312c
commit
537ef9c595
@ -10,14 +10,14 @@ namespace Time
|
|||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
inline long long msToQpc(int ms)
|
inline long long msToQpc(long long ms)
|
||||||
{
|
{
|
||||||
return static_cast<long long>(ms) * g_qpcFrequency / 1000;
|
return static_cast<long long>(ms) * g_qpcFrequency / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int qpcToMs(long long qpc)
|
inline long long qpcToMs(long long qpc)
|
||||||
{
|
{
|
||||||
return static_cast<int>(qpc * 1000 / g_qpcFrequency);
|
return qpc * 1000 / g_qpcFrequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline long long queryPerformanceCounter()
|
inline long long queryPerformanceCounter()
|
||||||
|
@ -4,6 +4,7 @@ typedef unsigned long DWORD;
|
|||||||
|
|
||||||
namespace Config
|
namespace Config
|
||||||
{
|
{
|
||||||
|
const int delayedFlipModeTimeout = 200;
|
||||||
const int maxPaletteUpdatesPerMs = 5;
|
const int maxPaletteUpdatesPerMs = 5;
|
||||||
const int minExpectedFlipsPerSec = 5;
|
const int minExpectedFlipsPerSec = 5;
|
||||||
const DWORD primarySurfaceExtraRows = 2;
|
const DWORD primarySurfaceExtraRows = 2;
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
#include <d3d.h>
|
||||||
|
#include <../km/d3dkmthk.h>
|
||||||
|
|
||||||
#include "D3dDdi/AdapterFuncs.h"
|
#include "D3dDdi/AdapterFuncs.h"
|
||||||
#include "D3dDdi/Device.h"
|
#include "D3dDdi/Device.h"
|
||||||
#include "D3dDdi/DeviceFuncs.h"
|
#include "D3dDdi/DeviceFuncs.h"
|
||||||
@ -208,7 +211,7 @@ namespace D3dDdi
|
|||||||
{
|
{
|
||||||
if (resource == m_sharedPrimary)
|
if (resource == m_sharedPrimary)
|
||||||
{
|
{
|
||||||
KernelModeThunks::releaseVidPnSources();
|
D3DKMTReleaseProcessVidPnSourceOwners(GetCurrentProcess());
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT result = m_origVtable->pfnDestroyResource(m_device, resource);
|
HRESULT result = m_origVtable->pfnDestroyResource(m_device, resource);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <atomic>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <d3d.h>
|
#include <d3d.h>
|
||||||
@ -6,12 +7,23 @@
|
|||||||
|
|
||||||
#include "Common/Log.h"
|
#include "Common/Log.h"
|
||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
|
#include "Common/ScopedCriticalSection.h"
|
||||||
|
#include "Common/Time.h"
|
||||||
#include "D3dDdi/Hooks.h"
|
#include "D3dDdi/Hooks.h"
|
||||||
#include "D3dDdi/KernelModeThunks.h"
|
#include "D3dDdi/KernelModeThunks.h"
|
||||||
|
#include "D3dDdi/Log/KernelModeThunksLog.h"
|
||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
|
#include "Win32/DisplayMode.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
struct AdapterInfo
|
||||||
|
{
|
||||||
|
UINT adapter;
|
||||||
|
UINT vidPnSourceId;
|
||||||
|
RECT monitorRect;
|
||||||
|
};
|
||||||
|
|
||||||
struct ContextInfo
|
struct ContextInfo
|
||||||
{
|
{
|
||||||
D3DKMT_HANDLE device;
|
D3DKMT_HANDLE device;
|
||||||
@ -19,40 +31,26 @@ namespace
|
|||||||
ContextInfo() : device(0) {}
|
ContextInfo() : device(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DeviceInfo
|
|
||||||
{
|
|
||||||
D3DKMT_HANDLE adapter;
|
|
||||||
D3DDDI_VIDEO_PRESENT_SOURCE_ID vidPnSourceId;
|
|
||||||
|
|
||||||
DeviceInfo() : adapter(0), vidPnSourceId(D3DDDI_ID_UNINITIALIZED) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<D3DKMT_HANDLE, ContextInfo> g_contexts;
|
std::map<D3DKMT_HANDLE, ContextInfo> g_contexts;
|
||||||
std::map<D3DKMT_HANDLE, DeviceInfo> g_devices;
|
AdapterInfo g_gdiAdapterInfo = {};
|
||||||
HMONITOR g_lastOpenAdapterMonitor = nullptr;
|
AdapterInfo g_lastOpenAdapterInfo = {};
|
||||||
|
UINT g_lastFlipInterval = 0;
|
||||||
|
UINT g_flipIntervalOverride = 0;
|
||||||
|
D3DKMT_HANDLE g_lastPresentContext = 0;
|
||||||
|
UINT g_presentCount = 0;
|
||||||
|
std::atomic<long long> g_qpcLastVerticalBlank = 0;
|
||||||
|
CRITICAL_SECTION g_vblankCs = {};
|
||||||
|
|
||||||
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
|
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
|
||||||
decltype(D3DKMTSetVidPnSourceOwner1)* g_origD3dKmtSetVidPnSourceOwner1 = nullptr;
|
|
||||||
|
|
||||||
D3DDDI_FLIPINTERVAL_TYPE g_overrideFlipInterval = D3DDDI_FLIPINTERVAL_NOOVERRIDE;
|
NTSTATUS APIENTRY closeAdapter(const D3DKMT_CLOSEADAPTER* pData)
|
||||||
UINT g_presentCount = 0;
|
|
||||||
|
|
||||||
NTSTATUS APIENTRY createDevice(D3DKMT_CREATEDEVICE* pData)
|
|
||||||
{
|
{
|
||||||
Compat::LogEnter("D3DKMTCreateDevice", pData);
|
Compat::ScopedCriticalSection lock(g_vblankCs);
|
||||||
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTCreateDevice)(pData);
|
if (pData && pData->hAdapter == g_lastOpenAdapterInfo.adapter)
|
||||||
if (SUCCEEDED(result))
|
|
||||||
{
|
{
|
||||||
g_devices[pData->hDevice].adapter = pData->hAdapter;
|
g_lastOpenAdapterInfo = {};
|
||||||
|
|
||||||
D3DKMT_SETQUEUEDLIMIT limit = {};
|
|
||||||
limit.hDevice = pData->hDevice;
|
|
||||||
limit.Type = D3DKMT_SET_QUEUEDLIMIT_PRESENT;
|
|
||||||
limit.QueuedPresentLimit = 1;
|
|
||||||
CALL_ORIG_FUNC(D3DKMTSetQueuedLimit)(&limit);
|
|
||||||
}
|
}
|
||||||
Compat::LogLeave("D3DKMTCreateDevice", pData) << result;
|
return CALL_ORIG_FUNC(D3DKMTCloseAdapter)(pData);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS APIENTRY createContext(D3DKMT_CREATECONTEXT* pData)
|
NTSTATUS APIENTRY createContext(D3DKMT_CREATECONTEXT* pData)
|
||||||
@ -98,6 +96,22 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS APIENTRY createDevice(D3DKMT_CREATEDEVICE* pData)
|
||||||
|
{
|
||||||
|
Compat::LogEnter("D3DKMTCreateDevice", pData);
|
||||||
|
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTCreateDevice)(pData);
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
D3DKMT_SETQUEUEDLIMIT limit = {};
|
||||||
|
limit.hDevice = pData->hDevice;
|
||||||
|
limit.Type = D3DKMT_SET_QUEUEDLIMIT_PRESENT;
|
||||||
|
limit.QueuedPresentLimit = 2;
|
||||||
|
CALL_ORIG_FUNC(D3DKMTSetQueuedLimit)(&limit);
|
||||||
|
}
|
||||||
|
Compat::LogLeave("D3DKMTCreateDevice", pData) << result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS APIENTRY destroyContext(const D3DKMT_DESTROYCONTEXT* pData)
|
NTSTATUS APIENTRY destroyContext(const D3DKMT_DESTROYCONTEXT* pData)
|
||||||
{
|
{
|
||||||
Compat::LogEnter("D3DKMTDestroyContext", pData);
|
Compat::LogEnter("D3DKMTDestroyContext", pData);
|
||||||
@ -105,89 +119,71 @@ namespace
|
|||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
g_contexts.erase(pData->hContext);
|
g_contexts.erase(pData->hContext);
|
||||||
|
if (g_lastPresentContext == pData->hContext)
|
||||||
|
{
|
||||||
|
g_lastPresentContext = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Compat::LogLeave("D3DKMTDestroyContext", pData) << result;
|
Compat::LogLeave("D3DKMTDestroyContext", pData) << result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS APIENTRY destroyDevice(const D3DKMT_DESTROYDEVICE* pData)
|
AdapterInfo getAdapterInfo(const D3DKMT_OPENADAPTERFROMHDC& data)
|
||||||
{
|
{
|
||||||
Compat::LogEnter("D3DKMTDestroyDevice", pData);
|
AdapterInfo adapterInfo = {};
|
||||||
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTDestroyDevice)(pData);
|
adapterInfo.adapter = data.hAdapter;
|
||||||
if (SUCCEEDED(result))
|
adapterInfo.vidPnSourceId = data.VidPnSourceId;
|
||||||
{
|
|
||||||
g_devices.erase(pData->hDevice);
|
POINT p = {};
|
||||||
}
|
GetDCOrgEx(data.hDc, &p);
|
||||||
Compat::LogLeave("D3DKMTDestroyDevice", pData) << result;
|
MONITORINFO mi = {};
|
||||||
return result;
|
mi.cbSize = sizeof(mi);
|
||||||
|
GetMonitorInfo(MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY), &mi);
|
||||||
|
adapterInfo.monitorRect = mi.rcMonitor;
|
||||||
|
|
||||||
|
return adapterInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS APIENTRY openAdapterFromHdc(D3DKMT_OPENADAPTERFROMHDC* pData)
|
NTSTATUS APIENTRY openAdapterFromHdc(D3DKMT_OPENADAPTERFROMHDC* pData)
|
||||||
{
|
{
|
||||||
Compat::LogEnter("D3DKMTOpenAdapterFromHdc", pData);
|
Compat::LogEnter("D3DKMTOpenAdapterFromHdc", pData);
|
||||||
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTOpenAdapterFromHdc)(pData);
|
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTOpenAdapterFromHdc)(pData);
|
||||||
if (pData)
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
POINT p = {};
|
Compat::ScopedCriticalSection lock(g_vblankCs);
|
||||||
GetDCOrgEx(pData->hDc, &p);
|
g_lastOpenAdapterInfo = getAdapterInfo(*pData);
|
||||||
g_lastOpenAdapterMonitor = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
|
|
||||||
}
|
}
|
||||||
Compat::LogLeave("D3DKMTOpenAdapterFromHdc", pData) << result;
|
Compat::LogLeave("D3DKMTOpenAdapterFromHdc", pData) << result;
|
||||||
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);
|
||||||
|
|
||||||
if (pData->Flags.Flip && D3DDDI_FLIPINTERVAL_NOOVERRIDE != g_overrideFlipInterval)
|
if (pData->Flags.Flip)
|
||||||
{
|
{
|
||||||
pData->FlipInterval = g_overrideFlipInterval;
|
g_lastFlipInterval = pData->FlipInterval;
|
||||||
}
|
g_lastPresentContext = pData->hContext;
|
||||||
|
|
||||||
++g_presentCount;
|
if (UINT_MAX == g_flipIntervalOverride)
|
||||||
pData->Flags.PresentCountValid = 1;
|
{
|
||||||
pData->PresentCount = g_presentCount;
|
Compat::LogLeave("D3DKMTPresent", pData) << S_OK;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
++g_presentCount;
|
||||||
|
if (0 == g_presentCount)
|
||||||
|
{
|
||||||
|
g_presentCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pData->PresentCount = g_presentCount;
|
||||||
|
pData->Flags.PresentCountValid = 1;
|
||||||
|
pData->FlipInterval = static_cast<D3DDDI_FLIPINTERVAL_TYPE>(g_flipIntervalOverride);
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTPresent)(pData);
|
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTPresent)(pData);
|
||||||
if (SUCCEEDED(result) &&
|
|
||||||
1 == DDraw::PrimarySurface::getDesc().dwBackBufferCount &&
|
|
||||||
pData->Flags.Flip &&
|
|
||||||
D3DDDI_FLIPINTERVAL_IMMEDIATE != pData->FlipInterval &&
|
|
||||||
D3DDDI_FLIPINTERVAL_NOOVERRIDE == g_overrideFlipInterval)
|
|
||||||
{
|
|
||||||
auto contextIt = g_contexts.find(pData->hContext);
|
|
||||||
auto deviceIt = (contextIt != g_contexts.end())
|
|
||||||
? g_devices.find(contextIt->second.device)
|
|
||||||
: g_devices.find(pData->hDevice);
|
|
||||||
if (deviceIt != g_devices.end())
|
|
||||||
{
|
|
||||||
D3DKMT_WAITFORVERTICALBLANKEVENT vbEvent = {};
|
|
||||||
vbEvent.hAdapter = deviceIt->second.adapter;
|
|
||||||
vbEvent.hDevice = deviceIt->first;
|
|
||||||
vbEvent.VidPnSourceId = deviceIt->second.vidPnSourceId;
|
|
||||||
|
|
||||||
while (!isPresentReady(deviceIt->first, deviceIt->second.vidPnSourceId))
|
|
||||||
{
|
|
||||||
if (FAILED(D3DKMTWaitForVerticalBlankEvent(&vbEvent)))
|
|
||||||
{
|
|
||||||
Sleep(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Compat::LogLeave("D3DKMTPresent", pData) << result;
|
Compat::LogLeave("D3DKMTPresent", pData) << result;
|
||||||
return result;
|
return result;
|
||||||
@ -212,7 +208,7 @@ namespace
|
|||||||
if (D3DKMT_SET_QUEUEDLIMIT_PRESENT == pData->Type)
|
if (D3DKMT_SET_QUEUEDLIMIT_PRESENT == pData->Type)
|
||||||
{
|
{
|
||||||
const UINT origLimit = pData->QueuedPresentLimit;
|
const UINT origLimit = pData->QueuedPresentLimit;
|
||||||
const_cast<D3DKMT_SETQUEUEDLIMIT*>(pData)->QueuedPresentLimit = 1;
|
const_cast<D3DKMT_SETQUEUEDLIMIT*>(pData)->QueuedPresentLimit = 2;
|
||||||
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTSetQueuedLimit)(pData);
|
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTSetQueuedLimit)(pData);
|
||||||
const_cast<D3DKMT_SETQUEUEDLIMIT*>(pData)->QueuedPresentLimit = origLimit;
|
const_cast<D3DKMT_SETQUEUEDLIMIT*>(pData)->QueuedPresentLimit = origLimit;
|
||||||
Compat::LogLeave("D3DKMTSetQueuedLimit", pData) << result;
|
Compat::LogLeave("D3DKMTSetQueuedLimit", pData) << result;
|
||||||
@ -223,42 +219,30 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void processSetVidPnSourceOwner(const D3DKMT_SETVIDPNSOURCEOWNER* pData)
|
void updateGdiAdapterInfo()
|
||||||
{
|
{
|
||||||
auto& vidPnSourceId = g_devices[pData->hDevice].vidPnSourceId;
|
static auto lastDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
|
||||||
for (UINT i = 0; i < pData->VidPnSourceCount; ++i)
|
const auto currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness();
|
||||||
|
if (currentDisplaySettingsUniqueness != lastDisplaySettingsUniqueness)
|
||||||
{
|
{
|
||||||
if (D3DKMT_VIDPNSOURCEOWNER_UNOWNED != pData->pType[i])
|
if (g_gdiAdapterInfo.adapter)
|
||||||
{
|
{
|
||||||
vidPnSourceId = pData->pVidPnSourceId[i];
|
D3DKMT_CLOSEADAPTER data = {};
|
||||||
return;
|
data.hAdapter = g_gdiAdapterInfo.adapter;
|
||||||
|
CALL_ORIG_FUNC(D3DKMTCloseAdapter)(&data);
|
||||||
|
g_gdiAdapterInfo = {};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
vidPnSourceId = D3DDDI_ID_UNINITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS APIENTRY setVidPnSourceOwner(const D3DKMT_SETVIDPNSOURCEOWNER* pData)
|
D3DKMT_OPENADAPTERFROMHDC data = {};
|
||||||
{
|
data.hDc = GetDC(nullptr);
|
||||||
Compat::LogEnter("D3DKMTSetVidPnSourceOwner", pData);
|
if (SUCCEEDED(CALL_ORIG_FUNC(D3DKMTOpenAdapterFromHdc)(&data)))
|
||||||
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTSetVidPnSourceOwner)(pData);
|
{
|
||||||
if (SUCCEEDED(result))
|
g_gdiAdapterInfo = getAdapterInfo(data);
|
||||||
{
|
}
|
||||||
processSetVidPnSourceOwner(pData);
|
ReleaseDC(nullptr, data.hDc);
|
||||||
}
|
|
||||||
Compat::LogLeave("D3DKMTSetVidPnSourceOwner", pData) << result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS APIENTRY setVidPnSourceOwner1(const D3DKMT_SETVIDPNSOURCEOWNER1* pData)
|
lastDisplaySettingsUniqueness = currentDisplaySettingsUniqueness;
|
||||||
{
|
|
||||||
Compat::LogEnter("D3DKMTSetVidPnSourceOwner1", pData);
|
|
||||||
NTSTATUS result = g_origD3dKmtSetVidPnSourceOwner1(pData);
|
|
||||||
if (SUCCEEDED(result))
|
|
||||||
{
|
|
||||||
processSetVidPnSourceOwner(&pData->Version0);
|
|
||||||
}
|
}
|
||||||
Compat::LogLeave("D3DKMTSetVidPnSourceOwner1", pData) << result;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,58 +250,113 @@ namespace D3dDdi
|
|||||||
{
|
{
|
||||||
namespace KernelModeThunks
|
namespace KernelModeThunks
|
||||||
{
|
{
|
||||||
HMONITOR getLastOpenAdapterMonitor()
|
UINT getLastFlipInterval()
|
||||||
{
|
{
|
||||||
return g_lastOpenAdapterMonitor;
|
return g_lastFlipInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPresentReady()
|
UINT getLastDisplayedFrameCount()
|
||||||
{
|
{
|
||||||
for (auto it : g_devices)
|
auto contextIter = g_contexts.find(g_lastPresentContext);
|
||||||
|
if (contextIter == g_contexts.end())
|
||||||
{
|
{
|
||||||
if (D3DDDI_ID_UNINITIALIZED != it.second.vidPnSourceId)
|
return g_presentCount;
|
||||||
{
|
|
||||||
return ::isPresentReady(it.first, it.second.vidPnSourceId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
D3DKMT_GETDEVICESTATE data = {};
|
||||||
|
data.hDevice = contextIter->second.device;
|
||||||
|
data.StateType = D3DKMT_DEVICESTATE_PRESENT;
|
||||||
|
data.PresentState.VidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
|
||||||
|
D3DKMTGetDeviceState(&data);
|
||||||
|
|
||||||
|
if (0 == data.PresentState.PresentStats.PresentCount)
|
||||||
|
{
|
||||||
|
return g_presentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.PresentState.PresentStats.PresentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT getLastSubmittedFrameCount()
|
||||||
|
{
|
||||||
|
return g_presentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT getMonitorRect()
|
||||||
|
{
|
||||||
|
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||||
|
if (!primary)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto lastDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
|
||||||
|
const auto currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness();
|
||||||
|
if (currentDisplaySettingsUniqueness != lastDisplaySettingsUniqueness)
|
||||||
|
{
|
||||||
|
lastDisplaySettingsUniqueness = currentDisplaySettingsUniqueness;
|
||||||
|
CompatPtr<IUnknown> ddUnk;
|
||||||
|
primary->GetDDInterface(primary, reinterpret_cast<void**>(&ddUnk.getRef()));
|
||||||
|
CompatPtr<IDirectDraw7> dd7(ddUnk);
|
||||||
|
|
||||||
|
DDDEVICEIDENTIFIER2 di = {};
|
||||||
|
dd7->GetDeviceIdentifier(dd7, &di, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_lastOpenAdapterInfo.monitorRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long getQpcLastVerticalBlank()
|
||||||
|
{
|
||||||
|
return g_qpcLastVerticalBlank;
|
||||||
}
|
}
|
||||||
|
|
||||||
void installHooks()
|
void installHooks()
|
||||||
{
|
{
|
||||||
|
InitializeCriticalSection(&g_vblankCs);
|
||||||
|
HOOK_FUNCTION(gdi32, D3DKMTCloseAdapter, closeAdapter);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTCreateContext, createContext);
|
HOOK_FUNCTION(gdi32, D3DKMTCreateContext, createContext);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTCreateDevice, createDevice);
|
HOOK_FUNCTION(gdi32, D3DKMTCreateDevice, createDevice);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTCreateDCFromMemory, createDcFromMemory);
|
HOOK_FUNCTION(gdi32, D3DKMTCreateDCFromMemory, createDcFromMemory);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTDestroyContext, destroyContext);
|
HOOK_FUNCTION(gdi32, D3DKMTDestroyContext, destroyContext);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTDestroyDevice, destroyDevice);
|
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTOpenAdapterFromHdc, openAdapterFromHdc);
|
HOOK_FUNCTION(gdi32, D3DKMTOpenAdapterFromHdc, openAdapterFromHdc);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTQueryAdapterInfo, queryAdapterInfo);
|
HOOK_FUNCTION(gdi32, D3DKMTQueryAdapterInfo, queryAdapterInfo);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTPresent, present);
|
HOOK_FUNCTION(gdi32, D3DKMTPresent, present);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTSetQueuedLimit, setQueuedLimit);
|
HOOK_FUNCTION(gdi32, D3DKMTSetQueuedLimit, setQueuedLimit);
|
||||||
HOOK_FUNCTION(gdi32, D3DKMTSetVidPnSourceOwner, setVidPnSourceOwner);
|
|
||||||
|
|
||||||
// Functions not available in Windows Vista
|
// Functions not available in Windows Vista
|
||||||
Compat::hookFunction("gdi32", "D3DKMTCreateContextVirtual",
|
Compat::hookFunction("gdi32", "D3DKMTCreateContextVirtual",
|
||||||
reinterpret_cast<void*&>(g_origD3dKmtCreateContextVirtual), createContextVirtual);
|
reinterpret_cast<void*&>(g_origD3dKmtCreateContextVirtual), createContextVirtual);
|
||||||
Compat::hookFunction("gdi32", "D3DKMTSetVidPnSourceOwner1",
|
|
||||||
reinterpret_cast<void*&>(g_origD3dKmtSetVidPnSourceOwner1), setVidPnSourceOwner1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void overrideFlipInterval(D3DDDI_FLIPINTERVAL_TYPE flipInterval)
|
void setFlipIntervalOverride(UINT flipInterval)
|
||||||
{
|
{
|
||||||
g_overrideFlipInterval = flipInterval;
|
g_flipIntervalOverride = flipInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void releaseVidPnSources()
|
void waitForVerticalBlank()
|
||||||
{
|
{
|
||||||
for (auto it : g_devices)
|
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};
|
||||||
|
|
||||||
{
|
{
|
||||||
if (D3DDDI_ID_UNINITIALIZED != it.second.vidPnSourceId)
|
Compat::ScopedCriticalSection lock(g_vblankCs);
|
||||||
|
if (g_lastOpenAdapterInfo.adapter)
|
||||||
{
|
{
|
||||||
D3DKMT_SETVIDPNSOURCEOWNER vidPnSourceOwner = {};
|
data.hAdapter = g_lastOpenAdapterInfo.adapter;
|
||||||
vidPnSourceOwner.hDevice = it.first;
|
data.VidPnSourceId = g_lastOpenAdapterInfo.vidPnSourceId;
|
||||||
D3DKMTSetVidPnSourceOwner(&vidPnSourceOwner);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateGdiAdapterInfo();
|
||||||
|
data.hAdapter = g_gdiAdapterInfo.adapter;
|
||||||
|
data.VidPnSourceId = g_gdiAdapterInfo.vidPnSourceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.hAdapter)
|
||||||
|
{
|
||||||
|
D3DKMTWaitForVerticalBlankEvent(&data);
|
||||||
|
g_qpcLastVerticalBlank = Time::queryPerformanceCounter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <d3d.h>
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <d3dumddi.h>
|
|
||||||
#include <../km/d3dkmthk.h>
|
|
||||||
#include <Windows.h>
|
#include <Windows.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
|
||||||
{
|
{
|
||||||
HMONITOR getLastOpenAdapterMonitor();
|
UINT getLastFlipInterval();
|
||||||
|
UINT getLastDisplayedFrameCount();
|
||||||
|
UINT getLastSubmittedFrameCount();
|
||||||
|
RECT getMonitorRect();
|
||||||
|
long long getQpcLastVerticalBlank();
|
||||||
void installHooks();
|
void installHooks();
|
||||||
bool isPresentReady();
|
void setFlipIntervalOverride(UINT flipInterval);
|
||||||
void overrideFlipInterval(D3DDDI_FLIPINTERVAL_TYPE flipInterval);
|
void waitForVerticalBlank();
|
||||||
void releaseVidPnSources();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Common/CompatPtr.h"
|
#include "Common/CompatPtr.h"
|
||||||
|
#include "D3dDdi/KernelModeThunks.h"
|
||||||
#include "DDraw/ActivateAppHandler.h"
|
#include "DDraw/ActivateAppHandler.h"
|
||||||
#include "DDraw/DirectDraw.h"
|
#include "DDraw/DirectDraw.h"
|
||||||
#include "DDraw/Repository.h"
|
#include "DDraw/Repository.h"
|
||||||
@ -117,6 +118,7 @@ namespace DDraw
|
|||||||
vtable.GetGDISurface = &GetGDISurface;
|
vtable.GetGDISurface = &GetGDISurface;
|
||||||
vtable.SetCooperativeLevel = &SetCooperativeLevel;
|
vtable.SetCooperativeLevel = &SetCooperativeLevel;
|
||||||
vtable.SetDisplayMode = &SetDisplayMode;
|
vtable.SetDisplayMode = &SetDisplayMode;
|
||||||
|
vtable.WaitForVerticalBlank = &WaitForVerticalBlank;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDirectDraw>
|
template <typename TDirectDraw>
|
||||||
@ -206,6 +208,30 @@ namespace DDraw
|
|||||||
return setDisplayMode(This, dwWidth, dwHeight, dwBPP, params...);
|
return setDisplayMode(This, dwWidth, dwHeight, dwBPP, params...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
HRESULT STDMETHODCALLTYPE DirectDraw<TDirectDraw>::WaitForVerticalBlank(
|
||||||
|
TDirectDraw* This, DWORD dwFlags, HANDLE hEvent)
|
||||||
|
{
|
||||||
|
if (!This || (DDWAITVB_BLOCKBEGIN != dwFlags && DDWAITVB_BLOCKEND != dwFlags))
|
||||||
|
{
|
||||||
|
return s_origVtable.WaitForVerticalBlank(This, dwFlags, hEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD scanLine = 0;
|
||||||
|
if (DDERR_VERTICALBLANKINPROGRESS != s_origVtable.GetScanLine(This, &scanLine))
|
||||||
|
{
|
||||||
|
D3dDdi::KernelModeThunks::waitForVerticalBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DDWAITVB_BLOCKEND == dwFlags)
|
||||||
|
{
|
||||||
|
while (DDERR_VERTICALBLANKINPROGRESS == s_origVtable.GetScanLine(This, &scanLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
return DD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template DirectDraw<IDirectDraw>;
|
template DirectDraw<IDirectDraw>;
|
||||||
template DirectDraw<IDirectDraw2>;
|
template DirectDraw<IDirectDraw2>;
|
||||||
template DirectDraw<IDirectDraw4>;
|
template DirectDraw<IDirectDraw4>;
|
||||||
|
@ -46,6 +46,8 @@ namespace DDraw
|
|||||||
DWORD dwHeight,
|
DWORD dwHeight,
|
||||||
DWORD dwBPP,
|
DWORD dwBPP,
|
||||||
Params... params);
|
Params... params);
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE WaitForVerticalBlank(TDirectDraw* This, DWORD dwFlags, HANDLE hEvent);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,8 +32,10 @@ namespace DDraw
|
|||||||
SET_COMPAT_METHOD(Blt);
|
SET_COMPAT_METHOD(Blt);
|
||||||
SET_COMPAT_METHOD(BltFast);
|
SET_COMPAT_METHOD(BltFast);
|
||||||
SET_COMPAT_METHOD(Flip);
|
SET_COMPAT_METHOD(Flip);
|
||||||
|
SET_COMPAT_METHOD(GetBltStatus);
|
||||||
SET_COMPAT_METHOD(GetCaps);
|
SET_COMPAT_METHOD(GetCaps);
|
||||||
SET_COMPAT_METHOD(GetDC);
|
SET_COMPAT_METHOD(GetDC);
|
||||||
|
SET_COMPAT_METHOD(GetFlipStatus);
|
||||||
SET_COMPAT_METHOD(GetSurfaceDesc);
|
SET_COMPAT_METHOD(GetSurfaceDesc);
|
||||||
SET_COMPAT_METHOD(IsLost);
|
SET_COMPAT_METHOD(IsLost);
|
||||||
SET_COMPAT_METHOD(Lock);
|
SET_COMPAT_METHOD(Lock);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#include <atomic>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -39,7 +38,6 @@ namespace
|
|||||||
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
||||||
|
|
||||||
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
|
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
|
||||||
CompatWeakPtr<IDirectDrawSurface7> g_backBuffer;
|
|
||||||
CompatWeakPtr<IDirectDrawSurface7> g_paletteConverter;
|
CompatWeakPtr<IDirectDrawSurface7> g_paletteConverter;
|
||||||
CompatWeakPtr<IDirectDrawClipper> g_clipper;
|
CompatWeakPtr<IDirectDrawClipper> g_clipper;
|
||||||
DDSURFACEDESC2 g_surfaceDesc = {};
|
DDSURFACEDESC2 g_surfaceDesc = {};
|
||||||
@ -47,15 +45,19 @@ namespace
|
|||||||
|
|
||||||
bool g_stopUpdateThread = false;
|
bool g_stopUpdateThread = false;
|
||||||
HANDLE g_updateThread = nullptr;
|
HANDLE g_updateThread = nullptr;
|
||||||
HANDLE g_updateEvent = nullptr;
|
unsigned int g_disableUpdateCount = 0;
|
||||||
std::atomic<int> g_disableUpdateCount = 0;
|
bool g_isFlipPending = false;
|
||||||
bool g_isUpdateSuspended = false;
|
bool g_isPresentPending = false;
|
||||||
long long g_qpcFlipModeTimeout = 0;
|
bool g_isUpdatePending = false;
|
||||||
long long g_qpcLastFlip = 0;
|
bool g_isFullScreen = false;
|
||||||
long long g_qpcNextUpdate = 0;
|
bool g_waitingForPrimaryUnlock = false;
|
||||||
long long g_qpcUpdateInterval = 0;
|
UINT g_flipIntervalDriverOverride = UINT_MAX;
|
||||||
|
UINT g_lastFlipFrameCount = 0;
|
||||||
|
DDraw::Surface* g_lastFlipSurface = nullptr;
|
||||||
|
long long g_qpcLastUpdate = 0;
|
||||||
|
|
||||||
std::atomic<bool> g_isFullScreen(false);
|
CompatPtr<IDirectDrawSurface7> getBackBuffer();
|
||||||
|
CompatPtr<IDirectDrawSurface7> getLastSurface();
|
||||||
|
|
||||||
BOOL CALLBACK addVisibleLayeredWindowToVector(HWND hwnd, LPARAM lParam)
|
BOOL CALLBACK addVisibleLayeredWindowToVector(HWND hwnd, LPARAM lParam)
|
||||||
{
|
{
|
||||||
@ -140,8 +142,14 @@ namespace
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto backBuffer(getBackBuffer());
|
||||||
|
if (!backBuffer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
HDC backBufferDc = nullptr;
|
HDC backBufferDc = nullptr;
|
||||||
g_backBuffer->GetDC(g_backBuffer, &backBufferDc);
|
backBuffer->GetDC(backBuffer, &backBufferDc);
|
||||||
|
|
||||||
for (auto it = visibleLayeredWindows.rbegin(); it != visibleLayeredWindows.rend(); ++it)
|
for (auto it = visibleLayeredWindows.rbegin(); it != visibleLayeredWindows.rend(); ++it)
|
||||||
{
|
{
|
||||||
@ -159,76 +167,22 @@ namespace
|
|||||||
ReleaseDC(*it, windowDc);
|
ReleaseDC(*it, windowDc);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_backBuffer->ReleaseDC(g_backBuffer, backBufferDc);
|
backBuffer->ReleaseDC(backBuffer, backBufferDc);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT bltToPrimaryChain(CompatRef<IDirectDrawSurface7> src)
|
void bltToPrimaryChain(CompatRef<IDirectDrawSurface7> src)
|
||||||
{
|
{
|
||||||
if (g_isFullScreen)
|
if (!g_isFullScreen)
|
||||||
{
|
{
|
||||||
return g_backBuffer->Blt(g_backBuffer, nullptr, &src, nullptr, DDBLT_WAIT, nullptr);
|
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindow, reinterpret_cast<LPARAM>(&src));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindow, reinterpret_cast<LPARAM>(&src));
|
auto backBuffer(getBackBuffer());
|
||||||
return DD_OK;
|
if (backBuffer)
|
||||||
}
|
|
||||||
|
|
||||||
bool compatBlt()
|
|
||||||
{
|
|
||||||
Compat::LogEnter("RealPrimarySurface::compatBlt");
|
|
||||||
|
|
||||||
BltToWindowViaGdiArgs bltToWindowViaGdiArgs;
|
|
||||||
if (!g_frontBuffer || (!g_isFullScreen && DDraw::RealPrimarySurface::isLost()))
|
|
||||||
{
|
{
|
||||||
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
|
backBuffer->Blt(backBuffer, nullptr, &src, nullptr, DDBLT_WAIT, nullptr);
|
||||||
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
|
|
||||||
Compat::LogLeave("RealPrimarySurface::compatBlt") << false;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Gdi::Region primaryRegion(DDraw::PrimarySurface::getMonitorRect());
|
|
||||||
bltToWindowViaGdiArgs.primaryRegion = &primaryRegion;
|
|
||||||
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
|
|
||||||
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
|
|
||||||
|
|
||||||
bool result = false;
|
|
||||||
auto primary(DDraw::PrimarySurface::getPrimary());
|
|
||||||
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, DDraw::PrimarySurface::isGdiSurface(primary.get()));
|
|
||||||
if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8)
|
|
||||||
{
|
|
||||||
HDC paletteConverterDc = nullptr;
|
|
||||||
g_paletteConverter->GetDC(g_paletteConverter, &paletteConverterDc);
|
|
||||||
HDC primaryDc = nullptr;
|
|
||||||
D3dDdi::Device::setReadOnlyGdiLock(true);
|
|
||||||
primary->GetDC(primary, &primaryDc);
|
|
||||||
D3dDdi::Device::setReadOnlyGdiLock(false);
|
|
||||||
|
|
||||||
if (paletteConverterDc && primaryDc)
|
|
||||||
{
|
|
||||||
result = TRUE == CALL_ORIG_FUNC(BitBlt)(paletteConverterDc,
|
|
||||||
0, 0, g_surfaceDesc.dwWidth, g_surfaceDesc.dwHeight, primaryDc, 0, 0, SRCCOPY);
|
|
||||||
}
|
|
||||||
|
|
||||||
primary->ReleaseDC(primary, primaryDc);
|
|
||||||
g_paletteConverter->ReleaseDC(g_paletteConverter, paletteConverterDc);
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
result = SUCCEEDED(bltToPrimaryChain(*g_paletteConverter));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = SUCCEEDED(bltToPrimaryChain(*primary));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result && g_isFullScreen && primary == DDraw::PrimarySurface::getGdiSurface())
|
|
||||||
{
|
|
||||||
bltVisibleLayeredWindowsToBackBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
Compat::LogLeave("RealPrimarySurface::compatBlt") << result;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDirectDraw>
|
template <typename TDirectDraw>
|
||||||
@ -263,124 +217,278 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DirectDraw>
|
CompatPtr<IDirectDrawSurface7> getBackBuffer()
|
||||||
HRESULT init(CompatRef<DirectDraw> dd, CompatPtr<IDirectDrawSurface7> surface)
|
|
||||||
{
|
{
|
||||||
DDSURFACEDESC2 desc = {};
|
DDSCAPS2 caps = {};
|
||||||
desc.dwSize = sizeof(desc);
|
caps.dwCaps = DDSCAPS_BACKBUFFER;
|
||||||
surface->GetSurfaceDesc(surface, &desc);
|
|
||||||
|
|
||||||
const bool isFlippable = 0 != (desc.ddsCaps.dwCaps & DDSCAPS_FLIP);
|
|
||||||
CompatPtr<IDirectDrawSurface7> backBuffer;
|
CompatPtr<IDirectDrawSurface7> backBuffer;
|
||||||
if (isFlippable)
|
if (g_frontBuffer)
|
||||||
{
|
{
|
||||||
DDSCAPS2 backBufferCaps = {};
|
g_frontBuffer->GetAttachedSurface(g_frontBuffer, &caps, &backBuffer.getRef());
|
||||||
backBufferCaps.dwCaps = DDSCAPS_BACKBUFFER;
|
|
||||||
surface->GetAttachedSurface(surface, &backBufferCaps, &backBuffer.getRef());
|
|
||||||
}
|
}
|
||||||
else
|
return backBuffer;
|
||||||
{
|
|
||||||
CALL_ORIG_PROC(DirectDrawCreateClipper, 0, &g_clipper.getRef(), nullptr);
|
|
||||||
surface->SetClipper(surface, g_clipper);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_qpcLastFlip = Time::queryPerformanceCounter() - g_qpcFlipModeTimeout;
|
|
||||||
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;
|
|
||||||
|
|
||||||
surface->SetPrivateData(surface, IID_IReleaseNotifier,
|
|
||||||
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
|
||||||
|
|
||||||
g_frontBuffer = surface.detach();
|
|
||||||
g_backBuffer = backBuffer;
|
|
||||||
g_surfaceDesc = desc;
|
|
||||||
g_isFullScreen = isFlippable;
|
|
||||||
|
|
||||||
return DD_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isUpdateScheduled()
|
CompatPtr<IDirectDrawSurface7> getLastSurface()
|
||||||
{
|
{
|
||||||
return WAIT_OBJECT_0 == WaitForSingleObject(g_updateEvent, 0);
|
DDSCAPS2 caps = {};
|
||||||
|
caps.dwCaps = DDSCAPS_FLIP;;
|
||||||
|
CompatPtr<IDirectDrawSurface7> backBuffer(getBackBuffer());
|
||||||
|
CompatPtr<IDirectDrawSurface7> lastSurface;
|
||||||
|
if (backBuffer)
|
||||||
|
{
|
||||||
|
backBuffer->GetAttachedSurface(backBuffer, &caps, &lastSurface.getRef());
|
||||||
|
}
|
||||||
|
return lastSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
int msUntilNextUpdate()
|
UINT getFlipIntervalFromFlags(DWORD flags)
|
||||||
{
|
{
|
||||||
DDraw::ScopedThreadLock lock;
|
if (flags & DDFLIP_NOVSYNC)
|
||||||
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 0;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
if (flags & (DDFLIP_INTERVAL2 | DDFLIP_INTERVAL3 | DDFLIP_INTERVAL4))
|
||||||
|
{
|
||||||
|
UINT flipInterval = (flags & (DDFLIP_INTERVAL2 | DDFLIP_INTERVAL3 | DDFLIP_INTERVAL4)) >> 24;
|
||||||
|
if (flipInterval < 2 || flipInterval > 4)
|
||||||
|
{
|
||||||
|
flipInterval = 1;
|
||||||
|
}
|
||||||
|
return flipInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT getFlipInterval(DWORD flags)
|
||||||
|
{
|
||||||
|
if (0 == g_flipIntervalDriverOverride)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT flipInterval = getFlipIntervalFromFlags(flags);
|
||||||
|
if (UINT_MAX != g_flipIntervalDriverOverride)
|
||||||
|
{
|
||||||
|
return max(flipInterval, g_flipIntervalDriverOverride);
|
||||||
|
}
|
||||||
|
return flipInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFlipPending()
|
||||||
|
{
|
||||||
|
if (g_isFlipPending)
|
||||||
|
{
|
||||||
|
g_isFlipPending = static_cast<int>(D3dDdi::KernelModeThunks::getLastDisplayedFrameCount() -
|
||||||
|
g_lastFlipFrameCount) < 0;
|
||||||
|
}
|
||||||
|
return g_isFlipPending;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPresentPending()
|
||||||
|
{
|
||||||
|
if (g_isPresentPending)
|
||||||
|
{
|
||||||
|
g_isPresentPending = static_cast<int>(D3dDdi::KernelModeThunks::getLastDisplayedFrameCount() -
|
||||||
|
D3dDdi::KernelModeThunks::getLastSubmittedFrameCount()) < 0;
|
||||||
|
}
|
||||||
|
return g_isPresentPending;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRelease()
|
void onRelease()
|
||||||
{
|
{
|
||||||
Compat::LogEnter("RealPrimarySurface::onRelease");
|
Compat::LogEnter("RealPrimarySurface::onRelease");
|
||||||
|
|
||||||
ResetEvent(g_updateEvent);
|
|
||||||
g_frontBuffer = nullptr;
|
g_frontBuffer = nullptr;
|
||||||
g_backBuffer = nullptr;
|
|
||||||
g_clipper.release();
|
g_clipper.release();
|
||||||
g_isFullScreen = false;
|
g_isFullScreen = false;
|
||||||
|
g_isFlipPending = false;
|
||||||
|
g_isPresentPending = false;
|
||||||
|
g_waitingForPrimaryUnlock = false;
|
||||||
g_paletteConverter.release();
|
g_paletteConverter.release();
|
||||||
g_qpcUpdateInterval = Time::g_qpcFrequency / 60;
|
g_surfaceDesc = {};
|
||||||
|
|
||||||
ZeroMemory(&g_surfaceDesc, sizeof(g_surfaceDesc));
|
|
||||||
|
|
||||||
Compat::LogLeave("RealPrimarySurface::onRelease");
|
Compat::LogLeave("RealPrimarySurface::onRelease");
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateNow()
|
void onRestore()
|
||||||
{
|
{
|
||||||
ResetEvent(g_updateEvent);
|
DDSURFACEDESC2 desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
g_frontBuffer->GetSurfaceDesc(g_frontBuffer, &desc);
|
||||||
|
|
||||||
|
g_clipper.release();
|
||||||
|
|
||||||
|
const bool isFlippable = 0 != (desc.ddsCaps.dwCaps & DDSCAPS_FLIP);
|
||||||
|
if (!isFlippable)
|
||||||
|
{
|
||||||
|
CALL_ORIG_PROC(DirectDrawCreateClipper, 0, &g_clipper.getRef(), nullptr);
|
||||||
|
g_frontBuffer->SetClipper(g_frontBuffer, g_clipper);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_surfaceDesc = desc;
|
||||||
|
g_isFullScreen = isFlippable;
|
||||||
|
g_flipIntervalDriverOverride = UINT_MAX;
|
||||||
|
g_isFlipPending = false;
|
||||||
|
g_isPresentPending = false;
|
||||||
|
g_isUpdatePending = false;
|
||||||
|
g_qpcLastUpdate = Time::queryPerformanceCounter() - Time::msToQpc(Config::delayedFlipModeTimeout);
|
||||||
|
|
||||||
|
if (isFlippable)
|
||||||
|
{
|
||||||
|
D3dDdi::KernelModeThunks::setFlipIntervalOverride(UINT_MAX);
|
||||||
|
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT | DDFLIP_NOVSYNC);
|
||||||
|
g_flipIntervalDriverOverride = D3dDdi::KernelModeThunks::getLastFlipInterval();
|
||||||
|
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT);
|
||||||
|
if (0 == g_flipIntervalDriverOverride)
|
||||||
|
{
|
||||||
|
g_flipIntervalDriverOverride = D3dDdi::KernelModeThunks::getLastFlipInterval();
|
||||||
|
if (1 == g_flipIntervalDriverOverride)
|
||||||
|
{
|
||||||
|
g_flipIntervalDriverOverride = UINT_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT);
|
||||||
|
D3dDdi::KernelModeThunks::setFlipIntervalOverride(0);
|
||||||
|
g_lastFlipFrameCount = D3dDdi::KernelModeThunks::getLastSubmittedFrameCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
D3dDdi::KernelModeThunks::waitForVerticalBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
void presentToPrimaryChain(CompatWeakPtr<IDirectDrawSurface7> src)
|
||||||
|
{
|
||||||
|
Compat::LogEnter("RealPrimarySurface::presentToPrimaryChain", src.get());
|
||||||
|
|
||||||
Gdi::VirtualScreen::update();
|
Gdi::VirtualScreen::update();
|
||||||
if (compatBlt() && g_isFullScreen)
|
|
||||||
|
BltToWindowViaGdiArgs bltToWindowViaGdiArgs;
|
||||||
|
if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost())
|
||||||
{
|
{
|
||||||
D3dDdi::KernelModeThunks::overrideFlipInterval(
|
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
|
||||||
Time::queryPerformanceCounter() - g_qpcLastFlip >= g_qpcFlipModeTimeout
|
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
|
||||||
? D3DDDI_FLIPINTERVAL_ONE
|
Compat::LogLeave("RealPrimarySurface::presentToPrimaryChain", src.get()) << false;
|
||||||
: D3DDDI_FLIPINTERVAL_IMMEDIATE);
|
return;
|
||||||
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT);
|
}
|
||||||
D3dDdi::KernelModeThunks::overrideFlipInterval(D3DDDI_FLIPINTERVAL_NOOVERRIDE);
|
|
||||||
|
Gdi::Region primaryRegion(D3dDdi::KernelModeThunks::getMonitorRect());
|
||||||
|
bltToWindowViaGdiArgs.primaryRegion = &primaryRegion;
|
||||||
|
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
|
||||||
|
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
|
||||||
|
|
||||||
|
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, DDraw::PrimarySurface::isGdiSurface(src.get()));
|
||||||
|
if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8)
|
||||||
|
{
|
||||||
|
HDC paletteConverterDc = nullptr;
|
||||||
|
g_paletteConverter->GetDC(g_paletteConverter, &paletteConverterDc);
|
||||||
|
HDC srcDc = nullptr;
|
||||||
|
D3dDdi::Device::setReadOnlyGdiLock(true);
|
||||||
|
src->GetDC(src, &srcDc);
|
||||||
|
D3dDdi::Device::setReadOnlyGdiLock(false);
|
||||||
|
|
||||||
|
if (paletteConverterDc && srcDc)
|
||||||
|
{
|
||||||
|
CALL_ORIG_FUNC(BitBlt)(paletteConverterDc,
|
||||||
|
0, 0, g_surfaceDesc.dwWidth, g_surfaceDesc.dwHeight, srcDc, 0, 0, SRCCOPY);
|
||||||
|
}
|
||||||
|
|
||||||
|
src->ReleaseDC(src, srcDc);
|
||||||
|
g_paletteConverter->ReleaseDC(g_paletteConverter, paletteConverterDc);
|
||||||
|
|
||||||
|
bltToPrimaryChain(*g_paletteConverter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bltToPrimaryChain(*src);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_isFullScreen && src == DDraw::PrimarySurface::getGdiSurface())
|
||||||
|
{
|
||||||
|
bltVisibleLayeredWindowsToBackBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat::LogLeave("RealPrimarySurface::presentToPrimaryChain", src.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateNow(CompatWeakPtr<IDirectDrawSurface7> src, UINT flipInterval)
|
||||||
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
|
if (flipInterval <= 1 && isPresentPending())
|
||||||
|
{
|
||||||
|
g_isUpdatePending = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
presentToPrimaryChain(src);
|
||||||
|
g_isUpdatePending = false;
|
||||||
|
|
||||||
|
if (!g_isFullScreen)
|
||||||
|
{
|
||||||
|
g_isPresentPending = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flipInterval > 1 && isPresentPending())
|
||||||
|
{
|
||||||
|
--flipInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3dDdi::KernelModeThunks::setFlipIntervalOverride(flipInterval);
|
||||||
|
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT);
|
||||||
|
|
||||||
|
// Workaround for Windows 8 multimon display glitches when presenting from GDI shared primary surface
|
||||||
|
D3dDdi::KernelModeThunks::setFlipIntervalOverride(UINT_MAX);
|
||||||
|
g_frontBuffer->Flip(g_frontBuffer, getLastSurface(), DDFLIP_WAIT);
|
||||||
|
D3dDdi::KernelModeThunks::setFlipIntervalOverride(0);
|
||||||
|
|
||||||
|
g_isPresentPending = 0 != flipInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 && DDERR_SURFACELOST != result)
|
||||||
|
{
|
||||||
|
const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate);
|
||||||
|
updateNow(primary, msSinceLastUpdate > Config::delayedFlipModeTimeout ? 0 : 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI updateThreadProc(LPVOID /*lpParameter*/)
|
DWORD WINAPI updateThreadProc(LPVOID /*lpParameter*/)
|
||||||
{
|
{
|
||||||
while (true)
|
const int msPresentDelayAfterVBlank = 1;
|
||||||
|
bool waitForVBlank = true;
|
||||||
|
|
||||||
|
while (!g_stopUpdateThread)
|
||||||
{
|
{
|
||||||
WaitForSingleObject(g_updateEvent, INFINITE);
|
if (waitForVBlank)
|
||||||
|
|
||||||
if (g_stopUpdateThread)
|
|
||||||
{
|
{
|
||||||
return 0;
|
D3dDdi::KernelModeThunks::waitForVerticalBlank();
|
||||||
|
if (!g_isFullScreen)
|
||||||
|
{
|
||||||
|
g_isPresentPending = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int waitTime = msUntilNextUpdate();
|
Sleep(msPresentDelayAfterVBlank);
|
||||||
if (waitTime > 0)
|
|
||||||
{
|
|
||||||
Sleep(waitTime);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DDraw::ScopedThreadLock lock;
|
DDraw::ScopedThreadLock lock;
|
||||||
if (isUpdateScheduled() && msUntilNextUpdate() <= 0)
|
waitForVBlank = Time::qpcToMs(Time::queryPerformanceCounter() -
|
||||||
|
D3dDdi::KernelModeThunks::getQpcLastVerticalBlank()) >= msPresentDelayAfterVBlank;
|
||||||
|
|
||||||
|
if (waitForVBlank && g_isUpdatePending && 0 == g_disableUpdateCount && !isPresentPending())
|
||||||
{
|
{
|
||||||
updateNow();
|
updateNowIfNotBusy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,6 +497,7 @@ namespace DDraw
|
|||||||
template <typename DirectDraw>
|
template <typename DirectDraw>
|
||||||
HRESULT RealPrimarySurface::create(CompatRef<DirectDraw> dd)
|
HRESULT RealPrimarySurface::create(CompatRef<DirectDraw> dd)
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
HRESULT result = createPaletteConverter(dd);
|
HRESULT result = createPaletteConverter(dd);
|
||||||
if (FAILED(result))
|
if (FAILED(result))
|
||||||
{
|
{
|
||||||
@ -400,7 +509,7 @@ namespace DDraw
|
|||||||
desc.dwSize = sizeof(desc);
|
desc.dwSize = sizeof(desc);
|
||||||
desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
||||||
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
|
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
|
||||||
desc.dwBackBufferCount = 1;
|
desc.dwBackBufferCount = 2;
|
||||||
|
|
||||||
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);
|
||||||
@ -420,7 +529,12 @@ namespace DDraw
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ::init(dd, surface);
|
g_frontBuffer = CompatPtr<IDirectDrawSurface7>::from(surface.get()).detach();
|
||||||
|
g_frontBuffer->SetPrivateData(g_frontBuffer, IID_IReleaseNotifier,
|
||||||
|
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||||
|
onRestore();
|
||||||
|
|
||||||
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw>);
|
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw>);
|
||||||
@ -430,41 +544,73 @@ namespace DDraw
|
|||||||
|
|
||||||
void RealPrimarySurface::disableUpdates()
|
void RealPrimarySurface::disableUpdates()
|
||||||
{
|
{
|
||||||
if (0 == g_disableUpdateCount++ && isUpdateScheduled())
|
DDraw::ScopedThreadLock lock;
|
||||||
{
|
--g_disableUpdateCount;
|
||||||
ResetEvent(g_updateEvent);
|
|
||||||
g_isUpdateSuspended = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealPrimarySurface::enableUpdates()
|
void RealPrimarySurface::enableUpdates()
|
||||||
{
|
{
|
||||||
if (0 == --g_disableUpdateCount && g_isUpdateSuspended)
|
DDraw::ScopedThreadLock lock;
|
||||||
{
|
++g_disableUpdateCount;
|
||||||
SetEvent(g_updateEvent);
|
|
||||||
g_isUpdateSuspended = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT RealPrimarySurface::flip(DWORD flags)
|
HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
|
||||||
{
|
{
|
||||||
if (!g_isFullScreen)
|
DDraw::ScopedThreadLock lock;
|
||||||
|
|
||||||
|
auto primary(PrimarySurface::getPrimary());
|
||||||
|
const bool isFlipEmulated = 0 != (PrimarySurface::getOrigCaps() & DDSCAPS_SYSTEMMEMORY);
|
||||||
|
if (isFlipEmulated && !surfaceTargetOverride)
|
||||||
{
|
{
|
||||||
return DDERR_NOTFLIPPABLE;
|
surfaceTargetOverride = PrimarySurface::getBackBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResetEvent(g_updateEvent);
|
HRESULT result = primary->Flip(primary, surfaceTargetOverride, DDFLIP_WAIT);
|
||||||
g_isUpdateSuspended = false;
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
g_qpcLastFlip = Time::queryPerformanceCounter();
|
DWORD flipInterval = getFlipInterval(flags);
|
||||||
compatBlt();
|
const auto msSinceLastUpdate = Time::qpcToMs(Time::queryPerformanceCounter() - g_qpcLastUpdate);
|
||||||
HRESULT result = g_frontBuffer->Flip(g_frontBuffer, nullptr, flags);
|
const bool isFlipDelayed = msSinceLastUpdate >= 0 && msSinceLastUpdate <= Config::delayedFlipModeTimeout;
|
||||||
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
if (isFlipDelayed)
|
||||||
return result;
|
{
|
||||||
|
CompatPtr<IDirectDrawSurface7> prevPrimarySurface(
|
||||||
|
surfaceTargetOverride ? surfaceTargetOverride : PrimarySurface::getLastSurface());
|
||||||
|
updateNow(prevPrimarySurface, flipInterval);
|
||||||
|
g_isUpdatePending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFlipEmulated)
|
||||||
|
{
|
||||||
|
surfaceTargetOverride->Blt(surfaceTargetOverride, nullptr, primary, nullptr, DDBLT_WAIT, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isFlipDelayed)
|
||||||
|
{
|
||||||
|
updateNow(primary, flipInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != flipInterval)
|
||||||
|
{
|
||||||
|
g_isFlipPending = true;
|
||||||
|
g_lastFlipFrameCount = D3dDdi::KernelModeThunks::getLastSubmittedFrameCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_lastFlipSurface = nullptr;
|
||||||
|
if (g_isFlipPending && !isFlipEmulated)
|
||||||
|
{
|
||||||
|
g_lastFlipSurface = Surface::getSurface(
|
||||||
|
surfaceTargetOverride ? *surfaceTargetOverride : *PrimarySurface::getLastSurface());
|
||||||
|
}
|
||||||
|
|
||||||
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT RealPrimarySurface::getGammaRamp(DDGAMMARAMP* rampData)
|
HRESULT RealPrimarySurface::getGammaRamp(DDGAMMARAMP* rampData)
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
auto gammaControl(CompatPtr<IDirectDrawGammaControl>::from(g_frontBuffer.get()));
|
auto gammaControl(CompatPtr<IDirectDrawGammaControl>::from(g_frontBuffer.get()));
|
||||||
if (!gammaControl)
|
if (!gammaControl)
|
||||||
{
|
{
|
||||||
@ -481,11 +627,6 @@ namespace DDraw
|
|||||||
|
|
||||||
void RealPrimarySurface::init()
|
void RealPrimarySurface::init()
|
||||||
{
|
{
|
||||||
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
|
||||||
g_qpcUpdateInterval = Time::g_qpcFrequency / 60;
|
|
||||||
g_qpcFlipModeTimeout = Time::g_qpcFrequency / Config::minExpectedFlipsPerSec;
|
|
||||||
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
|
||||||
|
|
||||||
g_updateThread = CreateThread(nullptr, 0, &updateThreadProc, nullptr, 0, nullptr);
|
g_updateThread = CreateThread(nullptr, 0, &updateThreadProc, nullptr, 0, nullptr);
|
||||||
SetThreadPriority(g_updateThread, THREAD_PRIORITY_TIME_CRITICAL);
|
SetThreadPriority(g_updateThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||||
}
|
}
|
||||||
@ -497,11 +638,13 @@ namespace DDraw
|
|||||||
|
|
||||||
bool RealPrimarySurface::isLost()
|
bool RealPrimarySurface::isLost()
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
return g_frontBuffer && DDERR_SURFACELOST == g_frontBuffer->IsLost(g_frontBuffer);
|
return g_frontBuffer && DDERR_SURFACELOST == g_frontBuffer->IsLost(g_frontBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealPrimarySurface::release()
|
void RealPrimarySurface::release()
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
g_frontBuffer.release();
|
g_frontBuffer.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,24 +656,28 @@ namespace DDraw
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_stopUpdateThread = true;
|
g_stopUpdateThread = true;
|
||||||
SetEvent(g_updateEvent);
|
|
||||||
if (WAIT_OBJECT_0 != WaitForSingleObject(g_updateThread, 1000))
|
if (WAIT_OBJECT_0 != WaitForSingleObject(g_updateThread, 1000))
|
||||||
{
|
{
|
||||||
TerminateThread(g_updateThread, 0);
|
TerminateThread(g_updateThread, 0);
|
||||||
Compat::Log() << "The update thread was terminated forcefully";
|
Compat::Log() << "The update thread was terminated forcefully";
|
||||||
}
|
}
|
||||||
ResetEvent(g_updateEvent);
|
|
||||||
g_stopUpdateThread = false;
|
|
||||||
g_updateThread = nullptr;
|
g_updateThread = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT RealPrimarySurface::restore()
|
HRESULT RealPrimarySurface::restore()
|
||||||
{
|
{
|
||||||
return g_frontBuffer->Restore(g_frontBuffer);
|
DDraw::ScopedThreadLock lock;
|
||||||
|
HRESULT result = g_frontBuffer->Restore(g_frontBuffer);
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
onRestore();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData)
|
HRESULT RealPrimarySurface::setGammaRamp(DDGAMMARAMP* rampData)
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
auto gammaControl(CompatPtr<IDirectDrawGammaControl>::from(g_frontBuffer.get()));
|
auto gammaControl(CompatPtr<IDirectDrawGammaControl>::from(g_frontBuffer.get()));
|
||||||
if (!gammaControl)
|
if (!gammaControl)
|
||||||
{
|
{
|
||||||
@ -542,6 +689,7 @@ namespace DDraw
|
|||||||
|
|
||||||
void RealPrimarySurface::setPalette()
|
void RealPrimarySurface::setPalette()
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
if (g_surfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8)
|
if (g_surfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8)
|
||||||
{
|
{
|
||||||
g_frontBuffer->SetPalette(g_frontBuffer, PrimarySurface::s_palette);
|
g_frontBuffer->SetPalette(g_frontBuffer, PrimarySurface::s_palette);
|
||||||
@ -552,41 +700,44 @@ namespace DDraw
|
|||||||
|
|
||||||
void RealPrimarySurface::update()
|
void RealPrimarySurface::update()
|
||||||
{
|
{
|
||||||
if (g_isUpdateSuspended)
|
DDraw::ScopedThreadLock lock;
|
||||||
|
g_qpcLastUpdate = Time::queryPerformanceCounter();
|
||||||
|
g_isUpdatePending = true;
|
||||||
|
if (g_waitingForPrimaryUnlock)
|
||||||
{
|
{
|
||||||
return;
|
updateNowIfNotBusy();
|
||||||
}
|
|
||||||
|
|
||||||
if (!isUpdateScheduled())
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_disableUpdateCount <= 0)
|
|
||||||
{
|
|
||||||
SetEvent(g_updateEvent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_isUpdateSuspended = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (msUntilNextUpdate() <= 0)
|
|
||||||
{
|
|
||||||
updateNow();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealPrimarySurface::updatePalette()
|
void RealPrimarySurface::updatePalette()
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
if (PrimarySurface::s_palette)
|
if (PrimarySurface::s_palette)
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RealPrimarySurface::waitForFlip(Surface* surface, bool wait)
|
||||||
|
{
|
||||||
|
auto primary(DDraw::PrimarySurface::getPrimary());
|
||||||
|
if (!surface || !primary ||
|
||||||
|
surface != g_lastFlipSurface &&
|
||||||
|
surface != Surface::getSurface(*DDraw::PrimarySurface::getPrimary()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wait)
|
||||||
|
{
|
||||||
|
return !isFlipPending();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isFlipPending())
|
||||||
|
{
|
||||||
|
D3dDdi::KernelModeThunks::waitForVerticalBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
#include <ddraw.h>
|
#include <ddraw.h>
|
||||||
|
|
||||||
#include "Common/CompatWeakPtr.h"
|
#include "Common/CompatPtr.h"
|
||||||
#include "Common/CompatRef.h"
|
#include "Common/CompatRef.h"
|
||||||
|
|
||||||
namespace DDraw
|
namespace DDraw
|
||||||
{
|
{
|
||||||
|
class Surface;
|
||||||
|
|
||||||
class RealPrimarySurface
|
class RealPrimarySurface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -15,7 +17,7 @@ namespace DDraw
|
|||||||
|
|
||||||
static void disableUpdates();
|
static void disableUpdates();
|
||||||
static void enableUpdates();
|
static void enableUpdates();
|
||||||
static HRESULT flip(DWORD flags);
|
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
|
||||||
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
|
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
|
||||||
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
static CompatWeakPtr<IDirectDrawSurface7> getSurface();
|
||||||
static void init();
|
static void init();
|
||||||
@ -28,5 +30,6 @@ namespace DDraw
|
|||||||
static void setPalette();
|
static void setPalette();
|
||||||
static void update();
|
static void update();
|
||||||
static void updatePalette();
|
static void updatePalette();
|
||||||
|
static bool waitForFlip(Surface* surface, bool wait = true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#include <ddraw.h>
|
|
||||||
|
|
||||||
#include "Common/CompatPtr.h"
|
#include "Common/CompatPtr.h"
|
||||||
#include "Common/CompatRef.h"
|
#include "Common/CompatRef.h"
|
||||||
#include "Config/Config.h"
|
#include "Config/Config.h"
|
||||||
@ -16,24 +14,6 @@ namespace
|
|||||||
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
|
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
|
||||||
HANDLE g_gdiResourceHandle = nullptr;
|
HANDLE g_gdiResourceHandle = nullptr;
|
||||||
DWORD g_origCaps = 0;
|
DWORD g_origCaps = 0;
|
||||||
RECT g_monitorRect = {};
|
|
||||||
|
|
||||||
RECT getDdMonitorRect(CompatRef<IDirectDraw7> dd)
|
|
||||||
{
|
|
||||||
DDDEVICEIDENTIFIER2 di = {};
|
|
||||||
dd->GetDeviceIdentifier(&dd, &di, 0); // Calls D3DKMTOpenAdapterFromHdc, which updates last monitor below
|
|
||||||
|
|
||||||
HMONITOR monitor = D3dDdi::KernelModeThunks::getLastOpenAdapterMonitor();
|
|
||||||
if (!monitor)
|
|
||||||
{
|
|
||||||
monitor = MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY);
|
|
||||||
}
|
|
||||||
|
|
||||||
MONITORINFO mi = {};
|
|
||||||
mi.cbSize = sizeof(mi);
|
|
||||||
GetMonitorInfo(monitor, &mi);
|
|
||||||
return mi.rcMonitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
HANDLE getResourceHandle(TSurface& surface)
|
HANDLE getResourceHandle(TSurface& surface)
|
||||||
@ -56,7 +36,6 @@ namespace DDraw
|
|||||||
g_gdiResourceHandle = nullptr;
|
g_gdiResourceHandle = nullptr;
|
||||||
g_primarySurface = nullptr;
|
g_primarySurface = nullptr;
|
||||||
g_origCaps = 0;
|
g_origCaps = 0;
|
||||||
g_monitorRect = {};
|
|
||||||
s_palette = nullptr;
|
s_palette = nullptr;
|
||||||
s_surfaceBuffers.clear();
|
s_surfaceBuffers.clear();
|
||||||
ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries));
|
ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries));
|
||||||
@ -100,19 +79,8 @@ namespace DDraw
|
|||||||
|
|
||||||
g_primarySurface = surface7;
|
g_primarySurface = surface7;
|
||||||
g_origCaps = origCaps;
|
g_origCaps = origCaps;
|
||||||
g_monitorRect = getDdMonitorRect(*CompatPtr<IDirectDraw7>::from(&dd));
|
|
||||||
|
|
||||||
ZeroMemory(&g_primarySurfaceDesc, sizeof(g_primarySurfaceDesc));
|
onRestore();
|
||||||
g_primarySurfaceDesc.dwSize = sizeof(g_primarySurfaceDesc);
|
|
||||||
CompatVtable<IDirectDrawSurface7Vtbl>::s_origVtable.GetSurfaceDesc(surface7, &g_primarySurfaceDesc);
|
|
||||||
|
|
||||||
if (g_primarySurfaceDesc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
||||||
{
|
|
||||||
resizeBuffers(*surface7);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_gdiResourceHandle = getResourceHandle(*surface7);
|
|
||||||
D3dDdi::Device::setGdiResourceHandle(*reinterpret_cast<HANDLE*>(g_gdiResourceHandle));
|
|
||||||
|
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
@ -178,9 +146,29 @@ namespace DDraw
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RECT PrimarySurface::getMonitorRect()
|
CompatPtr<IDirectDrawSurface7> PrimarySurface::getBackBuffer()
|
||||||
{
|
{
|
||||||
return g_monitorRect;
|
DDSCAPS2 caps = {};
|
||||||
|
caps.dwCaps = DDSCAPS_BACKBUFFER;
|
||||||
|
CompatPtr<IDirectDrawSurface7> backBuffer;
|
||||||
|
g_primarySurface->GetAttachedSurface(g_primarySurface, &caps, &backBuffer.getRef());
|
||||||
|
return backBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompatPtr<IDirectDrawSurface7> PrimarySurface::getLastSurface()
|
||||||
|
{
|
||||||
|
DDSCAPS2 caps = {};
|
||||||
|
caps.dwCaps = DDSCAPS_FLIP;
|
||||||
|
auto surface(CompatPtr<IDirectDrawSurface7>::from(g_primarySurface.get()));
|
||||||
|
CompatPtr<IDirectDrawSurface7> nextSurface;
|
||||||
|
|
||||||
|
while (SUCCEEDED(surface->GetAttachedSurface(surface, &caps, &nextSurface.getRef())) &&
|
||||||
|
nextSurface != g_primarySurface)
|
||||||
|
{
|
||||||
|
surface = nextSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
|
CompatWeakPtr<IDirectDrawSurface7> PrimarySurface::getPrimary()
|
||||||
@ -207,14 +195,20 @@ namespace DDraw
|
|||||||
|
|
||||||
void PrimarySurface::onRestore()
|
void PrimarySurface::onRestore()
|
||||||
{
|
{
|
||||||
CompatPtr<IUnknown> ddUnk;
|
g_primarySurfaceDesc = {};
|
||||||
g_primarySurface.get()->lpVtbl->GetDDInterface(
|
g_primarySurfaceDesc.dwSize = sizeof(g_primarySurfaceDesc);
|
||||||
g_primarySurface, reinterpret_cast<void**>(&ddUnk.getRef()));
|
g_primarySurface->GetSurfaceDesc(g_primarySurface, &g_primarySurfaceDesc);
|
||||||
CompatPtr<IDirectDraw7> dd7(ddUnk);
|
|
||||||
g_monitorRect = getDdMonitorRect(*dd7);
|
if (g_primarySurfaceDesc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
||||||
|
{
|
||||||
|
resizeBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_gdiResourceHandle = getResourceHandle(*g_primarySurface);
|
||||||
|
D3dDdi::Device::setGdiResourceHandle(*reinterpret_cast<HANDLE*>(g_gdiResourceHandle));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrimarySurface::resizeBuffers(CompatRef<IDirectDrawSurface7> surface)
|
void PrimarySurface::resizeBuffers()
|
||||||
{
|
{
|
||||||
DDSCAPS2 flipCaps = {};
|
DDSCAPS2 flipCaps = {};
|
||||||
flipCaps.dwCaps = DDSCAPS_FLIP;
|
flipCaps.dwCaps = DDSCAPS_FLIP;
|
||||||
@ -226,7 +220,7 @@ namespace DDraw
|
|||||||
const DWORD newBufferSize = g_primarySurfaceDesc.lPitch *
|
const DWORD newBufferSize = g_primarySurfaceDesc.lPitch *
|
||||||
(g_primarySurfaceDesc.dwHeight + Config::primarySurfaceExtraRows);
|
(g_primarySurfaceDesc.dwHeight + Config::primarySurfaceExtraRows);
|
||||||
|
|
||||||
auto surfacePtr(CompatPtr<IDirectDrawSurface7>::from(&surface));
|
auto surfacePtr(CompatPtr<IDirectDrawSurface7>::from(g_primarySurface.get()));
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
s_surfaceBuffers.push_back(std::vector<unsigned char>(newBufferSize));
|
s_surfaceBuffers.push_back(std::vector<unsigned char>(newBufferSize));
|
||||||
@ -236,7 +230,7 @@ namespace DDraw
|
|||||||
CompatPtr<IDirectDrawSurface7> nextSurface;
|
CompatPtr<IDirectDrawSurface7> nextSurface;
|
||||||
surfacePtr->GetAttachedSurface(surfacePtr, &flipCaps, &nextSurface.getRef());
|
surfacePtr->GetAttachedSurface(surfacePtr, &flipCaps, &nextSurface.getRef());
|
||||||
surfacePtr.swap(nextSurface);
|
surfacePtr.swap(nextSurface);
|
||||||
} while (surfacePtr && surfacePtr != &surface);
|
} while (surfacePtr && surfacePtr != g_primarySurface.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
CompatWeakPtr<IDirectDrawPalette> PrimarySurface::s_palette;
|
CompatWeakPtr<IDirectDrawPalette> PrimarySurface::s_palette;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <ddraw.h>
|
||||||
|
|
||||||
#include "Common/CompatPtr.h"
|
#include "Common/CompatPtr.h"
|
||||||
#include "Common/CompatRef.h"
|
#include "Common/CompatRef.h"
|
||||||
#include "DDraw/Surfaces/Surface.h"
|
#include "DDraw/Surfaces/Surface.h"
|
||||||
@ -19,7 +21,8 @@ namespace DDraw
|
|||||||
static HRESULT flipToGdiSurface();
|
static HRESULT flipToGdiSurface();
|
||||||
static const DDSURFACEDESC2& getDesc();
|
static const DDSURFACEDESC2& getDesc();
|
||||||
static CompatPtr<IDirectDrawSurface7> getGdiSurface();
|
static CompatPtr<IDirectDrawSurface7> getGdiSurface();
|
||||||
static RECT getMonitorRect();
|
static CompatPtr<IDirectDrawSurface7> getBackBuffer();
|
||||||
|
static CompatPtr<IDirectDrawSurface7> getLastSurface();
|
||||||
static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
|
static CompatWeakPtr<IDirectDrawSurface7> getPrimary();
|
||||||
static DWORD getOrigCaps();
|
static DWORD getOrigCaps();
|
||||||
static void onRestore();
|
static void onRestore();
|
||||||
@ -35,7 +38,7 @@ namespace DDraw
|
|||||||
|
|
||||||
virtual void createImpl() override;
|
virtual void createImpl() override;
|
||||||
|
|
||||||
static void resizeBuffers(CompatRef<IDirectDrawSurface7> surface);
|
static void resizeBuffers();
|
||||||
|
|
||||||
std::unique_ptr<Surface> m_surface;
|
std::unique_ptr<Surface> m_surface;
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "DDraw/DirectDrawPalette.h"
|
#include "DDraw/DirectDrawPalette.h"
|
||||||
|
#include "DDraw/DirectDrawSurface.h"
|
||||||
#include "DDraw/RealPrimarySurface.h"
|
#include "DDraw/RealPrimarySurface.h"
|
||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
#include "DDraw/Surfaces/PrimarySurfaceImpl.h"
|
#include "DDraw/Surfaces/PrimarySurfaceImpl.h"
|
||||||
@ -65,44 +66,14 @@ namespace DDraw
|
|||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
HRESULT PrimarySurfaceImpl<TSurface>::Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags)
|
HRESULT PrimarySurfaceImpl<TSurface>::Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
if (RealPrimarySurface::isLost())
|
const bool wait = (dwFlags & DDFLIP_WAIT) || !(dwFlags & DDFLIP_DONOTWAIT) &&
|
||||||
|
CompatVtable<IDirectDrawSurface7Vtbl>::s_origVtablePtr == static_cast<void*>(This->lpVtbl);
|
||||||
|
if (!DDraw::RealPrimarySurface::waitForFlip(Surface::getSurface(*This), wait))
|
||||||
{
|
{
|
||||||
return DDERR_SURFACELOST;
|
return DDERR_WASSTILLDRAWING;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT result = m_impl.Flip(This, lpDDSurfaceTargetOverride, dwFlags);
|
return RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7>::from(lpDDSurfaceTargetOverride), dwFlags);
|
||||||
if (FAILED(result))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool isFlipEmulated = 0 != (PrimarySurface::getOrigCaps() & DDSCAPS_SYSTEMMEMORY);
|
|
||||||
result = RealPrimarySurface::flip(dwFlags);
|
|
||||||
if (SUCCEEDED(result) && !isFlipEmulated)
|
|
||||||
{
|
|
||||||
return DD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
undoFlip(This, lpDDSurfaceTargetOverride);
|
|
||||||
|
|
||||||
if (SUCCEEDED(result) && isFlipEmulated)
|
|
||||||
{
|
|
||||||
if (lpDDSurfaceTargetOverride)
|
|
||||||
{
|
|
||||||
s_origVtable.BltFast(This, 0, 0, lpDDSurfaceTargetOverride, nullptr, DDBLTFAST_WAIT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TDdsCaps caps = {};
|
|
||||||
caps.dwCaps = DDSCAPS_BACKBUFFER;
|
|
||||||
CompatPtr<TSurface> backBuffer;
|
|
||||||
s_origVtable.GetAttachedSurface(This, &caps, &backBuffer.getRef());
|
|
||||||
|
|
||||||
s_origVtable.BltFast(This, 0, 0, backBuffer, nullptr, DDBLTFAST_WAIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "Common/CompatRef.h"
|
#include "Common/CompatRef.h"
|
||||||
|
#include "DDraw/RealPrimarySurface.h"
|
||||||
#include "DDraw/Repository.h"
|
#include "DDraw/Repository.h"
|
||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
#include "DDraw/Surfaces/Surface.h"
|
#include "DDraw/Surfaces/Surface.h"
|
||||||
@ -28,6 +29,20 @@ namespace
|
|||||||
dst->SetColorKey(&dst, ckFlag, &ck);
|
dst->SetColorKey(&dst, ckFlag, &ck);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
bool waitForFlip(TSurface* This, DWORD flags, DWORD waitFlag, DWORD doNotWaitFlag)
|
||||||
|
{
|
||||||
|
if (!This)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool wait = (flags & waitFlag) || !(flags & doNotWaitFlag) &&
|
||||||
|
CompatVtable<IDirectDrawSurface7Vtbl>::s_origVtablePtr == static_cast<void*>(This->lpVtbl);
|
||||||
|
|
||||||
|
return DDraw::RealPrimarySurface::waitForFlip(DDraw::Surface::getSurface(*This), wait);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace DDraw
|
namespace DDraw
|
||||||
@ -136,31 +151,16 @@ namespace DDraw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSurface>
|
|
||||||
void SurfaceImpl<TSurface>::undoFlip(TSurface* This, TSurface* targetOverride)
|
|
||||||
{
|
|
||||||
if (targetOverride)
|
|
||||||
{
|
|
||||||
SurfaceImpl::Flip(This, targetOverride, DDFLIP_WAIT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TSurfaceDesc desc = {};
|
|
||||||
desc.dwSize = sizeof(desc);
|
|
||||||
s_origVtable.GetSurfaceDesc(This, &desc);
|
|
||||||
|
|
||||||
for (DWORD i = 0; i < desc.dwBackBufferCount; ++i)
|
|
||||||
{
|
|
||||||
SurfaceImpl::Flip(This, nullptr, DDFLIP_WAIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
HRESULT SurfaceImpl<TSurface>::Blt(
|
HRESULT SurfaceImpl<TSurface>::Blt(
|
||||||
TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,
|
TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,
|
||||||
DWORD dwFlags, LPDDBLTFX lpDDBltFx)
|
DWORD dwFlags, LPDDBLTFX lpDDBltFx)
|
||||||
{
|
{
|
||||||
|
if (!waitForFlip(This, dwFlags, DDBLT_WAIT, DDBLT_DONOTWAIT))
|
||||||
|
{
|
||||||
|
return DDERR_WASSTILLDRAWING;
|
||||||
|
}
|
||||||
|
|
||||||
Gdi::DDrawAccessGuard dstAccessGuard(Gdi::ACCESS_WRITE, PrimarySurface::isGdiSurface(This));
|
Gdi::DDrawAccessGuard dstAccessGuard(Gdi::ACCESS_WRITE, PrimarySurface::isGdiSurface(This));
|
||||||
Gdi::DDrawAccessGuard srcAccessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(lpDDSrcSurface));
|
Gdi::DDrawAccessGuard srcAccessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(lpDDSrcSurface));
|
||||||
HRESULT result = s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
HRESULT result = s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
||||||
@ -182,6 +182,11 @@ namespace DDraw
|
|||||||
HRESULT SurfaceImpl<TSurface>::BltFast(
|
HRESULT SurfaceImpl<TSurface>::BltFast(
|
||||||
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
|
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
|
||||||
{
|
{
|
||||||
|
if (!waitForFlip(This, dwTrans, DDBLTFAST_WAIT, DDBLTFAST_DONOTWAIT))
|
||||||
|
{
|
||||||
|
return DDERR_WASSTILLDRAWING;
|
||||||
|
}
|
||||||
|
|
||||||
Gdi::DDrawAccessGuard dstAccessGuard(Gdi::ACCESS_WRITE, PrimarySurface::isGdiSurface(This));
|
Gdi::DDrawAccessGuard dstAccessGuard(Gdi::ACCESS_WRITE, PrimarySurface::isGdiSurface(This));
|
||||||
Gdi::DDrawAccessGuard srcAccessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(lpDDSrcSurface));
|
Gdi::DDrawAccessGuard srcAccessGuard(Gdi::ACCESS_READ, PrimarySurface::isGdiSurface(lpDDSrcSurface));
|
||||||
HRESULT result = s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
HRESULT result = s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||||
@ -221,6 +226,21 @@ namespace DDraw
|
|||||||
return s_origVtable.Flip(This, lpDDSurfaceTargetOverride, dwFlags);
|
return s_origVtable.Flip(This, lpDDSurfaceTargetOverride, dwFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT SurfaceImpl<TSurface>::GetBltStatus(TSurface* This, DWORD dwFlags)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.GetBltStatus(This, dwFlags);
|
||||||
|
if (SUCCEEDED(result) && (dwFlags & DDGBS_CANBLT))
|
||||||
|
{
|
||||||
|
const bool wait = false;
|
||||||
|
if (!RealPrimarySurface::waitForFlip(Surface::getSurface(*This), wait))
|
||||||
|
{
|
||||||
|
return DDERR_WASSTILLDRAWING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
HRESULT SurfaceImpl<TSurface>::GetCaps(TSurface* This, TDdsCaps* lpDDSCaps)
|
HRESULT SurfaceImpl<TSurface>::GetCaps(TSurface* This, TDdsCaps* lpDDSCaps)
|
||||||
{
|
{
|
||||||
@ -230,8 +250,19 @@ namespace DDraw
|
|||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
HRESULT SurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC)
|
HRESULT SurfaceImpl<TSurface>::GetDC(TSurface* This, HDC* lphDC)
|
||||||
{
|
{
|
||||||
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
HRESULT result = DD_OK;
|
||||||
return s_origVtable.GetDC(This, lphDC);
|
|
||||||
|
{
|
||||||
|
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||||
|
result = s_origVtable.GetDC(This, lphDC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
RealPrimarySurface::waitForFlip(Surface::getSurface(*This));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
@ -246,6 +277,21 @@ namespace DDraw
|
|||||||
reinterpret_cast<IDirectDraw*>(&dd), m_data->m_ddId, lplpDD);
|
reinterpret_cast<IDirectDraw*>(&dd), m_data->m_ddId, lplpDD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT SurfaceImpl<TSurface>::GetFlipStatus(TSurface* This, DWORD dwFlags)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.GetFlipStatus(This, dwFlags);
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
const bool wait = false;
|
||||||
|
if (!RealPrimarySurface::waitForFlip(Surface::getSurface(*This), wait))
|
||||||
|
{
|
||||||
|
return DDERR_WASSTILLDRAWING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TSurface>
|
template <typename TSurface>
|
||||||
HRESULT SurfaceImpl<TSurface>::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc)
|
HRESULT SurfaceImpl<TSurface>::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc)
|
||||||
{
|
{
|
||||||
@ -263,6 +309,11 @@ namespace DDraw
|
|||||||
TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
||||||
DWORD dwFlags, HANDLE hEvent)
|
DWORD dwFlags, HANDLE hEvent)
|
||||||
{
|
{
|
||||||
|
if (!waitForFlip(This, dwFlags, DDLOCK_WAIT, DDLOCK_DONOTWAIT))
|
||||||
|
{
|
||||||
|
return DDERR_WASSTILLDRAWING;
|
||||||
|
}
|
||||||
|
|
||||||
Gdi::DDrawAccessGuard accessGuard((dwFlags & DDLOCK_READONLY) ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE,
|
Gdi::DDrawAccessGuard accessGuard((dwFlags & DDLOCK_READONLY) ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE,
|
||||||
PrimarySurface::isGdiSurface(This));
|
PrimarySurface::isGdiSurface(This));
|
||||||
HRESULT result = s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
HRESULT result = s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
||||||
|
@ -40,8 +40,10 @@ namespace DDraw
|
|||||||
virtual HRESULT BltFast(TSurface* This, DWORD dwX, DWORD dwY,
|
virtual HRESULT BltFast(TSurface* This, DWORD dwX, DWORD dwY,
|
||||||
TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans);
|
TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans);
|
||||||
virtual HRESULT Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags);
|
virtual HRESULT Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags);
|
||||||
|
virtual HRESULT GetBltStatus(TSurface* This, DWORD dwFlags);
|
||||||
virtual HRESULT GetCaps(TSurface* This, TDdsCaps* lpDDSCaps);
|
virtual HRESULT GetCaps(TSurface* This, TDdsCaps* lpDDSCaps);
|
||||||
virtual HRESULT GetDC(TSurface* This, HDC* lphDC);
|
virtual HRESULT GetDC(TSurface* This, HDC* lphDC);
|
||||||
|
virtual HRESULT GetFlipStatus(TSurface* This, DWORD dwFlags);
|
||||||
virtual HRESULT GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc);
|
virtual HRESULT GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc);
|
||||||
virtual HRESULT IsLost(TSurface* This);
|
virtual HRESULT IsLost(TSurface* This);
|
||||||
virtual HRESULT Lock(TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
virtual HRESULT Lock(TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
|
||||||
@ -52,8 +54,6 @@ namespace DDraw
|
|||||||
virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect);
|
virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void undoFlip(TSurface* This, TSurface* targetOverride);
|
|
||||||
|
|
||||||
static const Vtable<TSurface>& s_origVtable;
|
static const Vtable<TSurface>& s_origVtable;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include "D3dDdi/KernelModeThunks.h"
|
||||||
#include "DDraw/RealPrimarySurface.h"
|
#include "DDraw/RealPrimarySurface.h"
|
||||||
#include "DDraw/ScopedThreadLock.h"
|
#include "DDraw/ScopedThreadLock.h"
|
||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
@ -83,7 +84,7 @@ namespace
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto gdiSurface(Gdi::VirtualScreen::createSurface(DDraw::PrimarySurface::getMonitorRect()));
|
auto gdiSurface(Gdi::VirtualScreen::createSurface(D3dDdi::KernelModeThunks::getMonitorRect()));
|
||||||
if (!gdiSurface)
|
if (!gdiSurface)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -96,8 +97,8 @@ namespace
|
|||||||
CompatPtr<IDirectDrawClipper> clipper;
|
CompatPtr<IDirectDrawClipper> clipper;
|
||||||
ddrawSurface->GetClipper(ddrawSurface, &clipper.getRef());
|
ddrawSurface->GetClipper(ddrawSurface, &clipper.getRef());
|
||||||
ddrawSurface->SetClipper(ddrawSurface, nullptr);
|
ddrawSurface->SetClipper(ddrawSurface, nullptr);
|
||||||
result = SUCCEEDED(ddrawSurface->BltFast(
|
result = SUCCEEDED(ddrawSurface->Blt(
|
||||||
ddrawSurface, 0, 0, gdiSurface, nullptr, DDBLTFAST_WAIT));
|
ddrawSurface, nullptr, gdiSurface, nullptr, DDBLT_WAIT, nullptr));
|
||||||
ddrawSurface->SetClipper(ddrawSurface, clipper);
|
ddrawSurface->SetClipper(ddrawSurface, clipper);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user