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