1
0
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:
narzoul 2017-05-17 20:41:05 +02:00
parent 640f746633
commit 5c91706b03
8 changed files with 124 additions and 100 deletions

View File

@ -4,8 +4,7 @@ typedef unsigned long DWORD;
namespace Config namespace Config
{ {
const int maxPaletteUpdatesPerMs = 10; const int maxPaletteUpdatesPerMs = 5;
const int maxPrimaryUpdateRate = 60; const int minExpectedFlipsPerSec = 5;
const int primaryUpdateDelayAfterFlip = 100;
const DWORD preallocatedGdiDcCount = 4; const DWORD preallocatedGdiDcCount = 4;
} }

View File

@ -35,6 +35,9 @@ namespace
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr; decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
decltype(D3DKMTSetVidPnSourceOwner1)* g_origD3dKmtSetVidPnSourceOwner1 = nullptr; decltype(D3DKMTSetVidPnSourceOwner1)* g_origD3dKmtSetVidPnSourceOwner1 = nullptr;
D3DDDI_FLIPINTERVAL_TYPE g_overrideFlipInterval = D3DDDI_FLIPINTERVAL_NOOVERRIDE;
UINT g_presentCount = 0;
NTSTATUS APIENTRY createDevice(D3DKMT_CREATEDEVICE* pData) NTSTATUS APIENTRY createDevice(D3DKMT_CREATEDEVICE* pData)
{ {
Compat::LogEnter("D3DKMTCreateDevice", pData); Compat::LogEnter("D3DKMTCreateDevice", pData);
@ -101,19 +104,37 @@ namespace
return result; return result;
} }
bool isPresentReady(D3DKMT_HANDLE device, D3DDDI_VIDEO_PRESENT_SOURCE_ID vidPnSourceId)
{
D3DKMT_GETDEVICESTATE deviceState = {};
deviceState.hDevice = device;
deviceState.StateType = D3DKMT_DEVICESTATE_PRESENT;
deviceState.PresentState.VidPnSourceId = vidPnSourceId;
NTSTATUS stateResult = D3DKMTGetDeviceState(&deviceState);
return FAILED(stateResult) ||
g_presentCount == deviceState.PresentState.PresentStats.PresentCount ||
0 == deviceState.PresentState.PresentStats.PresentCount;
}
NTSTATUS APIENTRY present(D3DKMT_PRESENT* pData) NTSTATUS APIENTRY present(D3DKMT_PRESENT* pData)
{ {
Compat::LogEnter("D3DKMTPresent", pData); Compat::LogEnter("D3DKMTPresent", pData);
static UINT presentCount = 0; if (pData->Flags.Flip && D3DDDI_FLIPINTERVAL_NOOVERRIDE != g_overrideFlipInterval)
++presentCount; {
pData->FlipInterval = g_overrideFlipInterval;
}
++g_presentCount;
pData->Flags.PresentCountValid = 1; pData->Flags.PresentCountValid = 1;
pData->PresentCount = presentCount; pData->PresentCount = g_presentCount;
NTSTATUS result = CALL_ORIG_FUNC(D3DKMTPresent)(pData); NTSTATUS result = CALL_ORIG_FUNC(D3DKMTPresent)(pData);
if (SUCCEEDED(result) && if (SUCCEEDED(result) &&
1 == DDraw::PrimarySurface::getDesc().dwBackBufferCount && 1 == DDraw::PrimarySurface::getDesc().dwBackBufferCount &&
pData->Flags.Flip && pData->FlipInterval != D3DDDI_FLIPINTERVAL_IMMEDIATE) pData->Flags.Flip &&
D3DDDI_FLIPINTERVAL_IMMEDIATE != pData->FlipInterval &&
D3DDDI_FLIPINTERVAL_NOOVERRIDE == g_overrideFlipInterval)
{ {
auto contextIt = g_contexts.find(pData->hContext); auto contextIt = g_contexts.find(pData->hContext);
auto deviceIt = (contextIt != g_contexts.end()) auto deviceIt = (contextIt != g_contexts.end())
@ -126,19 +147,12 @@ namespace
vbEvent.hDevice = deviceIt->first; vbEvent.hDevice = deviceIt->first;
vbEvent.VidPnSourceId = deviceIt->second.vidPnSourceId; vbEvent.VidPnSourceId = deviceIt->second.vidPnSourceId;
D3DKMT_GETDEVICESTATE deviceState = {}; while (!isPresentReady(deviceIt->first, deviceIt->second.vidPnSourceId))
deviceState.hDevice = deviceIt->first;
deviceState.StateType = D3DKMT_DEVICESTATE_PRESENT;
deviceState.PresentState.VidPnSourceId = deviceIt->second.vidPnSourceId;
NTSTATUS stateResult = D3DKMTGetDeviceState(&deviceState);
while (SUCCEEDED(stateResult) &&
presentCount != deviceState.PresentState.PresentStats.PresentCount)
{ {
if (FAILED(D3DKMTWaitForVerticalBlankEvent(&vbEvent))) if (FAILED(D3DKMTWaitForVerticalBlankEvent(&vbEvent)))
{ {
Sleep(1); Sleep(1);
} }
stateResult = D3DKMTGetDeviceState(&deviceState);
} }
} }
} }
@ -220,6 +234,18 @@ namespace D3dDdi
{ {
namespace KernelModeThunks namespace KernelModeThunks
{ {
bool isPresentReady()
{
for (auto it : g_devices)
{
if (D3DDDI_ID_UNINITIALIZED != it.second.vidPnSourceId)
{
return ::isPresentReady(it.first, it.second.vidPnSourceId);
}
}
return true;
}
void installHooks() void installHooks()
{ {
HOOK_FUNCTION(gdi32, D3DKMTCreateContext, createContext); HOOK_FUNCTION(gdi32, D3DKMTCreateContext, createContext);
@ -238,6 +264,11 @@ namespace D3dDdi
reinterpret_cast<void*&>(g_origD3dKmtSetVidPnSourceOwner1), setVidPnSourceOwner1); reinterpret_cast<void*&>(g_origD3dKmtSetVidPnSourceOwner1), setVidPnSourceOwner1);
} }
void overrideFlipInterval(D3DDDI_FLIPINTERVAL_TYPE flipInterval)
{
g_overrideFlipInterval = flipInterval;
}
void releaseVidPnSources() void releaseVidPnSources()
{ {
for (auto it : g_devices) for (auto it : g_devices)

View File

@ -2,11 +2,15 @@
#include "D3dDdi/Log/KernelModeThunksLog.h" #include "D3dDdi/Log/KernelModeThunksLog.h"
static const auto D3DDDI_FLIPINTERVAL_NOOVERRIDE = static_cast<D3DDDI_FLIPINTERVAL_TYPE>(5);
namespace D3dDdi namespace D3dDdi
{ {
namespace KernelModeThunks namespace KernelModeThunks
{ {
void installHooks(); void installHooks();
bool isPresentReady();
void overrideFlipInterval(D3DDDI_FLIPINTERVAL_TYPE flipInterval);
void releaseVidPnSources(); void releaseVidPnSources();
} }
} }

View File

@ -4,6 +4,7 @@
#include "Common/Hook.h" #include "Common/Hook.h"
#include "Common/Time.h" #include "Common/Time.h"
#include "Config/Config.h" #include "Config/Config.h"
#include "D3dDdi/KernelModeThunks.h"
#include "DDraw/DirectDraw.h" #include "DDraw/DirectDraw.h"
#include "DDraw/DirectDrawSurface.h" #include "DDraw/DirectDrawSurface.h"
#include "DDraw/IReleaseNotifier.h" #include "DDraw/IReleaseNotifier.h"
@ -17,7 +18,6 @@
namespace namespace
{ {
void onRelease(); void onRelease();
void updateNow(long long qpcNow);
DWORD WINAPI updateThreadProc(LPVOID lpParameter); DWORD WINAPI updateThreadProc(LPVOID lpParameter);
CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer; CompatWeakPtr<IDirectDrawSurface7> g_frontBuffer;
@ -30,10 +30,11 @@ namespace
bool g_stopUpdateThread = false; bool g_stopUpdateThread = false;
HANDLE g_updateThread = nullptr; HANDLE g_updateThread = nullptr;
HANDLE g_updateEvent = nullptr; HANDLE g_updateEvent = nullptr;
RECT g_updateRect = {};
std::atomic<int> g_disableUpdateCount = 0; std::atomic<int> g_disableUpdateCount = 0;
long long g_qpcMinUpdateInterval = 0; long long g_qpcFlipModeTimeout = 0;
std::atomic<long long> g_qpcNextUpdate = 0; long long g_qpcLastFlip = 0;
long long g_qpcNextUpdate = 0;
long long g_qpcUpdateInterval = 0;
std::atomic<bool> g_isFullScreen(false); std::atomic<bool> g_isFullScreen(false);
@ -59,9 +60,7 @@ namespace
if (paletteConverterDc && primaryDc) if (paletteConverterDc && primaryDc)
{ {
result = TRUE == CALL_ORIG_FUNC(BitBlt)(paletteConverterDc, result = TRUE == CALL_ORIG_FUNC(BitBlt)(paletteConverterDc,
g_updateRect.left, g_updateRect.top, 0, 0, g_surfaceDesc.dwWidth, g_surfaceDesc.dwHeight, primaryDc, 0, 0, SRCCOPY);
g_updateRect.right - g_updateRect.left, g_updateRect.bottom - g_updateRect.top,
primaryDc, g_updateRect.left, g_updateRect.top, SRCCOPY);
} }
primary->ReleaseDC(primary, primaryDc); primary->ReleaseDC(primary, primaryDc);
@ -69,19 +68,13 @@ namespace
if (result) if (result)
{ {
result = SUCCEEDED(dest->Blt(&dest, &g_updateRect, result = SUCCEEDED(dest->Blt(
g_paletteConverter, &g_updateRect, DDBLT_WAIT, nullptr)); &dest, nullptr, g_paletteConverter, nullptr, DDBLT_WAIT, nullptr));
} }
} }
else else
{ {
result = SUCCEEDED(dest->Blt(&dest, &g_updateRect, result = SUCCEEDED(dest->Blt(&dest, nullptr, primary, nullptr, DDBLT_WAIT, nullptr));
primary, &g_updateRect, DDBLT_WAIT, nullptr));
}
if (result)
{
SetRectEmpty(&g_updateRect);
} }
Compat::LogLeave("RealPrimarySurface::compatBlt", dest) << result; Compat::LogLeave("RealPrimarySurface::compatBlt", dest) << result;
@ -120,14 +113,8 @@ namespace
return result; return result;
} }
long long getNextUpdateQpc(long long qpcNow) template <typename DirectDraw>
{ HRESULT init(CompatRef<DirectDraw> dd, CompatPtr<IDirectDrawSurface7> surface)
long long qpcNextUpdate = g_qpcNextUpdate;
const long long missedIntervals = (qpcNow - qpcNextUpdate) / g_qpcMinUpdateInterval;
return qpcNextUpdate + g_qpcMinUpdateInterval * (missedIntervals + 1);
}
HRESULT init(CompatPtr<IDirectDrawSurface7> surface)
{ {
DDSURFACEDESC2 desc = {}; DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc); desc.dwSize = sizeof(desc);
@ -142,9 +129,19 @@ namespace
surface->GetAttachedSurface(surface, &backBufferCaps, &backBuffer.getRef()); surface->GetAttachedSurface(surface, &backBufferCaps, &backBuffer.getRef());
} }
g_qpcMinUpdateInterval = Time::g_qpcFrequency / Config::maxPrimaryUpdateRate; g_qpcFlipModeTimeout = Time::g_qpcFrequency / Config::minExpectedFlipsPerSec;
g_qpcLastFlip = Time::queryPerformanceCounter() - g_qpcFlipModeTimeout;
g_qpcNextUpdate = Time::queryPerformanceCounter(); g_qpcNextUpdate = Time::queryPerformanceCounter();
typename DDraw::Types<DirectDraw>::TSurfaceDesc dm = {};
dm.dwSize = sizeof(dm);
dd->GetDisplayMode(&dd, &dm);
if (dm.dwRefreshRate <= 1 || dm.dwRefreshRate >= 1000)
{
dm.dwRefreshRate = 60;
}
g_qpcUpdateInterval = Time::g_qpcFrequency / dm.dwRefreshRate;
if (!g_updateEvent) if (!g_updateEvent)
{ {
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
@ -159,8 +156,6 @@ namespace
surface->SetPrivateData(surface, IID_IReleaseNotifier, surface->SetPrivateData(surface, IID_IReleaseNotifier,
&g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER); &g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
timeBeginPeriod(1);
g_frontBuffer = surface.detach(); g_frontBuffer = surface.detach();
g_backBuffer = backBuffer; g_backBuffer = backBuffer;
g_surfaceDesc = desc; g_surfaceDesc = desc;
@ -169,10 +164,21 @@ namespace
return DD_OK; return DD_OK;
} }
bool isNextUpdateSignaledAndReady(long long qpcNow) bool isUpdateScheduled()
{ {
return Time::qpcToMs(qpcNow - g_qpcNextUpdate) >= 0 && return WAIT_OBJECT_0 == WaitForSingleObject(g_updateEvent, 0);
WAIT_OBJECT_0 == WaitForSingleObject(g_updateEvent, 0); }
int msUntilNextUpdate()
{
DDraw::ScopedThreadLock lock;
const auto qpcNow = Time::queryPerformanceCounter();
const int result = max(0, Time::qpcToMs(g_qpcNextUpdate - qpcNow));
if (0 == result && g_isFullScreen && qpcNow - g_qpcLastFlip >= g_qpcFlipModeTimeout)
{
return D3dDdi::KernelModeThunks::isPresentReady() ? 0 : 2;
}
return result;
} }
void onRelease() void onRelease()
@ -180,7 +186,6 @@ namespace
Compat::LogEnter("RealPrimarySurface::onRelease"); Compat::LogEnter("RealPrimarySurface::onRelease");
ResetEvent(g_updateEvent); ResetEvent(g_updateEvent);
timeEndPeriod(1);
g_frontBuffer = nullptr; g_frontBuffer = nullptr;
g_backBuffer = nullptr; g_backBuffer = nullptr;
g_clipper = nullptr; g_clipper = nullptr;
@ -192,18 +197,24 @@ namespace
Compat::LogLeave("RealPrimarySurface::onRelease"); Compat::LogLeave("RealPrimarySurface::onRelease");
} }
void updateNow(long long qpcNow) void updateNow()
{ {
ResetEvent(g_updateEvent); ResetEvent(g_updateEvent);
if (compatBlt(*g_frontBuffer)) if (!g_isFullScreen)
{ {
long long qpcNextUpdate = getNextUpdateQpc(qpcNow); compatBlt(*g_frontBuffer);
if (Time::qpcToMs(qpcNow - qpcNextUpdate) >= 0) return;
{ }
qpcNextUpdate += g_qpcMinUpdateInterval;
} if (compatBlt(*g_backBuffer))
g_qpcNextUpdate = qpcNextUpdate; {
D3dDdi::KernelModeThunks::overrideFlipInterval(
Time::queryPerformanceCounter() - g_qpcLastFlip >= g_qpcFlipModeTimeout
? D3DDDI_FLIPINTERVAL_ONE
: D3DDDI_FLIPINTERVAL_IMMEDIATE);
g_frontBuffer->Flip(g_frontBuffer, nullptr, DDFLIP_WAIT);
D3dDdi::KernelModeThunks::overrideFlipInterval(D3DDDI_FLIPINTERVAL_NOOVERRIDE);
} }
} }
@ -218,20 +229,17 @@ namespace
return 0; return 0;
} }
const long long qpcTargetNextUpdate = g_qpcNextUpdate; const int waitTime = msUntilNextUpdate();
const int msUntilNextUpdate = if (waitTime > 0)
Time::qpcToMs(qpcTargetNextUpdate - Time::queryPerformanceCounter());
if (msUntilNextUpdate > 0)
{ {
Sleep(msUntilNextUpdate); Sleep(waitTime);
continue;
} }
DDraw::ScopedThreadLock lock; DDraw::ScopedThreadLock lock;
const long long qpcNow = Time::queryPerformanceCounter(); if (isUpdateScheduled() && msUntilNextUpdate() <= 0)
const bool isTargetUpdateStillNeeded = qpcTargetNextUpdate == g_qpcNextUpdate;
if (g_frontBuffer && (isTargetUpdateStillNeeded || isNextUpdateSignaledAndReady(qpcNow)))
{ {
updateNow(qpcNow); updateNow();
} }
} }
} }
@ -275,7 +283,7 @@ namespace DDraw
return result; return result;
} }
return init(surface); return init(dd, surface);
} }
template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw>); template HRESULT RealPrimarySurface::create(CompatRef<IDirectDraw>);
@ -305,17 +313,10 @@ namespace DDraw
} }
ResetEvent(g_updateEvent); ResetEvent(g_updateEvent);
g_qpcLastFlip = Time::queryPerformanceCounter();
invalidate(nullptr);
compatBlt(*g_backBuffer); compatBlt(*g_backBuffer);
HRESULT result = g_frontBuffer->Flip(g_frontBuffer, nullptr, flags); HRESULT result = g_frontBuffer->Flip(g_frontBuffer, nullptr, flags);
if (SUCCEEDED(result)) g_qpcNextUpdate = Time::queryPerformanceCounter();
{
g_qpcNextUpdate = getNextUpdateQpc(
Time::queryPerformanceCounter() + Time::msToQpc(Config::primaryUpdateDelayAfterFlip));
SetRectEmpty(&g_updateRect);
}
return result; return result;
} }
@ -324,19 +325,6 @@ namespace DDraw
return g_frontBuffer; return g_frontBuffer;
} }
void RealPrimarySurface::invalidate(const RECT* rect)
{
if (rect)
{
UnionRect(&g_updateRect, &g_updateRect, rect);
}
else
{
auto primaryDesc = PrimarySurface::getDesc();
SetRect(&g_updateRect, 0, 0, primaryDesc.dwWidth, primaryDesc.dwHeight);
}
}
bool RealPrimarySurface::isFullScreen() bool RealPrimarySurface::isFullScreen()
{ {
return g_isFullScreen; return g_isFullScreen;
@ -404,17 +392,23 @@ namespace DDraw
void RealPrimarySurface::update() void RealPrimarySurface::update()
{ {
if (!IsRectEmpty(&g_updateRect) && 0 == g_disableUpdateCount && (g_isFullScreen || g_clipper)) if (0 == g_disableUpdateCount && (g_isFullScreen || g_clipper))
{ {
const long long qpcNow = Time::queryPerformanceCounter(); if (!isUpdateScheduled())
if (Time::qpcToMs(qpcNow - g_qpcNextUpdate) >= 0)
{
updateNow(qpcNow);
}
else
{ {
const auto qpcNow = Time::queryPerformanceCounter();
const long long missedIntervals = (qpcNow - g_qpcNextUpdate) / g_qpcUpdateInterval;
g_qpcNextUpdate += g_qpcUpdateInterval * (missedIntervals + 1);
if (Time::qpcToMs(g_qpcNextUpdate - qpcNow) < 2)
{
g_qpcNextUpdate += g_qpcUpdateInterval;
}
SetEvent(g_updateEvent); SetEvent(g_updateEvent);
} }
else if (msUntilNextUpdate() <= 0)
{
updateNow();
}
} }
} }
@ -423,7 +417,6 @@ namespace DDraw
Gdi::updatePalette(startingEntry, count); Gdi::updatePalette(startingEntry, count);
if (PrimarySurface::s_palette) if (PrimarySurface::s_palette)
{ {
invalidate(nullptr);
update(); update();
} }
} }

View File

@ -19,7 +19,6 @@ namespace DDraw
static void enableUpdates(); static void enableUpdates();
static HRESULT flip(DWORD flags); static HRESULT flip(DWORD flags);
static CompatWeakPtr<IDirectDrawSurface7> getSurface(); static CompatWeakPtr<IDirectDrawSurface7> getSurface();
static void invalidate(const RECT* rect);
static bool isFullScreen(); static bool isFullScreen();
static bool isLost(); static bool isLost();
static void release(); static void release();

View File

@ -33,7 +33,6 @@ namespace DDraw
HRESULT result = m_impl.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); HRESULT result = m_impl.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
RealPrimarySurface::invalidate(lpDestRect);
RealPrimarySurface::update(); RealPrimarySurface::update();
} }
return result; return result;
@ -67,7 +66,6 @@ namespace DDraw
destRect.right += desc.dwWidth; destRect.right += desc.dwWidth;
destRect.bottom += desc.dwHeight; destRect.bottom += desc.dwHeight;
} }
RealPrimarySurface::invalidate(&destRect);
RealPrimarySurface::update(); RealPrimarySurface::update();
} }
return result; return result;
@ -144,7 +142,6 @@ namespace DDraw
HRESULT result = m_impl.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent); HRESULT result = m_impl.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
RealPrimarySurface::invalidate(lpDestRect);
restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps.dwCaps); restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps.dwCaps);
} }
return result; return result;
@ -167,7 +164,6 @@ namespace DDraw
HRESULT result = m_impl.ReleaseDC(This, hDC); HRESULT result = m_impl.ReleaseDC(This, hDC);
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
RealPrimarySurface::invalidate(nullptr);
RealPrimarySurface::update(); RealPrimarySurface::update();
} }
return result; return result;

View File

@ -3,6 +3,7 @@
#include <string> #include <string>
#include <Windows.h> #include <Windows.h>
#include <timeapi.h>
#include <Uxtheme.h> #include <Uxtheme.h>
#include "Common/Hook.h" #include "Common/Hook.h"
@ -125,6 +126,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
const BOOL disablePriorityBoost = TRUE; const BOOL disablePriorityBoost = TRUE;
SetProcessPriorityBoost(GetCurrentProcess(), disablePriorityBoost); SetProcessPriorityBoost(GetCurrentProcess(), disablePriorityBoost);
SetProcessAffinityMask(GetCurrentProcess(), 1); SetProcessAffinityMask(GetCurrentProcess(), 1);
timeBeginPeriod(1);
SetThemeAppProperties(0); SetThemeAppProperties(0);
Compat::redirectIatHooks("ddraw.dll", "DirectDrawCreate", Compat::redirectIatHooks("ddraw.dll", "DirectDrawCreate",
@ -150,6 +152,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
FreeLibrary(g_origDInputModule); FreeLibrary(g_origDInputModule);
FreeLibrary(g_origDDrawModule); FreeLibrary(g_origDDrawModule);
Win32::FontSmoothing::setSystemSettingsForced(Win32::FontSmoothing::g_origSystemSettings); Win32::FontSmoothing::setSystemSettingsForced(Win32::FontSmoothing::g_origSystemSettings);
timeEndPeriod(1);
Compat::Log() << "DDrawCompat detached successfully"; Compat::Log() << "DDrawCompat detached successfully";
} }

View File

@ -61,7 +61,6 @@ namespace
gdiSurface.get()->lpVtbl->Unlock(gdiSurface, nullptr); gdiSurface.get()->lpVtbl->Unlock(gdiSurface, nullptr);
if (DDLOCK_READONLY != g_ddLockFlags) if (DDLOCK_READONLY != g_ddLockFlags)
{ {
DDraw::RealPrimarySurface::invalidate(nullptr);
DDraw::RealPrimarySurface::update(); DDraw::RealPrimarySurface::update();
} }
} }