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

Compare commits

..

12 Commits

Author SHA1 Message Date
narzoul
4598013310 Added support for ddrawex
See issue #349.
2024-08-25 22:18:24 +02:00
narzoul
f78a96a334 Improved DPI unaware cursor positioning
See issue #342.
2024-08-25 22:18:24 +02:00
narzoul
16b062d17d Added VSync=wait setting 2024-08-25 22:18:24 +02:00
narzoul
76dfc38645 Added ViewportEdgeFix setting
See issue #344.
2024-08-25 22:17:56 +02:00
narzoul
f1ae0c7147 Added StatsRows=vblankcount, vblankrate, vblanktime settings 2024-08-25 14:07:42 +02:00
narzoul
cc2cc7510d Fixed an occasional deadlock caused by SPI_SETSHOWIMEUI when alt-tabbing 2024-08-25 14:07:42 +02:00
narzoul
2e9f55a2f0 Added ForceD3D9On12=forceoff setting
The default "off" setting no longer replaces D3D9On12 with igd9trinity32.dll.
It was causing issues when used with older driver versions.
Newer drivers use igd9trinity32.dll by default.
2024-08-25 14:01:49 +02:00
narzoul
ae10673b3e Fixed a crash when the driver's WDDM version is higher than the OS supports 2024-08-24 11:09:48 +02:00
narzoul
c8c6bd0ce9 Updated waitForIdle implementation
Fixes performance issues on old versions of igd9trinity32.dll.
2024-08-24 11:09:48 +02:00
narzoul
1c4445717a Fixed vertex shader declaration for VertexFixup=cpu
See issue #340.
2024-08-24 11:09:48 +02:00
narzoul
142b13e032 Fixed graphical artifacts in Nocturne
See issue #336.
2024-08-24 11:09:48 +02:00
narzoul
97249c9b47 Fixed occasional frame drops on NVIDIA GPUs
See issue #298.
2024-08-24 11:09:14 +02:00
33 changed files with 376 additions and 168 deletions

View File

@ -50,6 +50,7 @@
#include <Config/Settings/ThreadPriorityBoost.h>
#include <Config/Settings/VertexBufferMemoryType.h>
#include <Config/Settings/VertexFixup.h>
#include <Config/Settings/ViewportEdgeFix.h>
#include <Config/Settings/VSync.h>
#include <Config/Settings/WinVersionLie.h>
@ -107,6 +108,7 @@ namespace Config
Settings::ThreadPriorityBoost threadPriorityBoost;
Settings::VertexBufferMemoryType vertexBufferMemoryType;
Settings::VertexFixup vertexFixup;
Settings::ViewportEdgeFix viewportEdgeFix;
Settings::VSync vSync;
Settings::WinVersionLie winVersionLie;
}

View File

@ -1,16 +1,18 @@
#pragma once
#include <Config/BoolSetting.h>
#include <Config/EnumSetting.h>
namespace Config
{
namespace Settings
{
class ForceD3D9On12 : public BoolSetting
class ForceD3D9On12 : public EnumSetting
{
public:
enum Values { FORCEOFF, OFF, ON };
ForceD3D9On12()
: BoolSetting("ForceD3D9On12", "off")
: EnumSetting("ForceD3D9On12", "off", { "forceoff", "off", "on" })
{
}
};

View File

@ -23,6 +23,9 @@ namespace Config
LOCKCOUNT,
LOCKRATE,
LOCKTIME,
VBLANKCOUNT,
VBLANKRATE,
VBLANKTIME,
DDIUSAGE,
GDIOBJECTS,
DEBUG,
@ -45,6 +48,9 @@ namespace Config
"lockcount",
"lockrate",
"locktime",
"vblankcount",
"vblankrate",
"vblanktime",
"ddiusage",
"gdiobjects",
"debug"

View File

@ -8,13 +8,13 @@ namespace Config
namespace Settings
{
VSync::VSync()
: EnumSetting("VSync", "app", { "app", "off", "on" })
: EnumSetting("VSync", "app", { "app", "off", "on", "wait"})
{
}
Setting::ParamInfo VSync::getParamInfo() const
{
if (ON == m_value)
if (ON == m_value || WAIT == m_value)
{
return { "Interval", 1, 16, 1 };
}

View File

@ -9,7 +9,7 @@ namespace Config
class VSync : public EnumSetting
{
public:
enum Values { APP, OFF, ON };
enum Values { APP, OFF, ON, WAIT };
VSync();

View File

@ -0,0 +1,32 @@
#pragma once
#include <Config/EnumSetting.h>
namespace Config
{
namespace Settings
{
class ViewportEdgeFix : public EnumSetting
{
public:
enum Values { OFF, SCALE };
ViewportEdgeFix()
: EnumSetting("ViewportEdgeFix", "off", { "off", "scale" })
{
}
virtual ParamInfo getParamInfo() const override
{
switch (m_value)
{
case SCALE:
return { "Gap", 1, 100, 50 };
}
return {};
}
};
}
extern Settings::ViewportEdgeFix viewportEdgeFix;
}

View File

@ -437,7 +437,7 @@ namespace D3dDdi
pCreateData->Interface = origInterface;
if (SUCCEEDED(result))
{
DeviceFuncs::hookVtable(*pCreateData->pDeviceFuncs, m_driverVersion);
DeviceFuncs::hookVtable(*pCreateData->pDeviceFuncs, std::min(m_runtimeVersion, m_driverVersion));
Device::add(*this, pCreateData->hDevice);
}
return result;

View File

@ -586,33 +586,6 @@ namespace D3dDdi
m_state.updateConfig();
}
void Device::waitForIdle()
{
D3dDdi::ScopedCriticalSection lock;
flushPrimitives();
D3DDDIARG_ISSUEQUERY issueQuery = {};
issueQuery.hQuery = m_eventQuery;
issueQuery.Flags.End = 1;
m_origVtable.pfnIssueQuery(m_device, &issueQuery);
if (m_origVtable.pfnFlush1)
{
m_origVtable.pfnFlush1(m_device, 0);
}
else
{
m_origVtable.pfnFlush(m_device);
}
BOOL result = FALSE;
D3DDDIARG_GETQUERYDATA getQueryData = {};
getQueryData.hQuery = m_eventQuery;
getQueryData.pData = &result;
while (S_FALSE == m_origVtable.pfnGetQueryData(m_device, &getQueryData))
{
}
}
std::map<HANDLE, Device> Device::s_devices;
bool Device::s_isFlushEnabled = true;
}

View File

@ -72,7 +72,6 @@ namespace D3dDdi
void setDepthStencil(HANDLE resource);
void setRenderTarget(const D3DDDIARG_SETRENDERTARGET& data);
void updateConfig();
void waitForIdle();
static void add(Adapter& adapter, HANDLE device);
static Device& get(HANDLE device) { return s_devices.find(device)->second; }

View File

@ -16,6 +16,7 @@
#include <D3dDdi/ShaderAssembler.h>
#include <Overlay/Steam.h>
#include <Shaders/VertexFixup.h>
#include <Config/Settings/ViewportEdgeFix.h>
#define LOG_DS LOG_DEBUG << "DeviceState::" << __func__ << ": "
@ -549,10 +550,18 @@ namespace D3dDdi
}
}
HRESULT result = m_device.getOrigVtable().pfnCreateVertexShaderDecl(m_device, data, ve.data());
HRESULT result = m_device.getOrigVtable().pfnCreateVertexShaderDecl(m_device, data, vertexElements);
if (SUCCEEDED(result))
{
m_vertexShaderDecls[data->ShaderHandle] = decl;
if (decl.isTransformed)
{
D3DDDIARG_CREATEVERTEXSHADERDECL d = *data;
d.ShaderHandle = nullptr;
m_device.getOrigVtable().pfnCreateVertexShaderDecl(m_device, &d, ve.data());
decl.untransformedDecl = std::unique_ptr<void, ResourceDeleter>(
d.ShaderHandle, ResourceDeleter(m_device, m_device.getOrigVtable().pfnDeleteVertexShaderDecl));
}
m_vertexShaderDecls.emplace(data->ShaderHandle, std::move(decl));
}
return result;
}
@ -893,7 +902,7 @@ namespace D3dDdi
if (spriteMode != m_spriteMode)
{
m_spriteMode = spriteMode;
m_changedStates |= CS_RENDER_STATE | CS_TEXTURE_STAGE;
m_changedStates |= CS_RENDER_STATE | CS_RENDER_TARGET | CS_TEXTURE_STAGE;
m_changedRenderStates.set(D3DDDIRS_MULTISAMPLEANTIALIAS);
if (Config::Settings::SpriteTexCoord::ROUND == Config::spriteTexCoord.get())
{
@ -1236,15 +1245,17 @@ namespace D3dDdi
void DeviceState::updateShaders()
{
setPixelShader(mapPixelShader(m_app.pixelShader));
setVertexShaderDecl(m_app.vertexShaderDecl);
auto& vertexDecl = getVertexDecl();
if (Config::Settings::VertexFixup::GPU == m_vertexFixupConfig &&
getVertexDecl().isTransformed)
vertexDecl.isTransformed)
{
setVertexShaderDecl(vertexDecl.untransformedDecl.get());
setVertexShaderFunc(getVsVertexFixup());
}
else
{
setVertexShaderDecl(m_app.vertexShaderDecl);
setVertexShaderFunc(m_app.vertexShaderFunc);
}
}
@ -1343,17 +1354,21 @@ namespace D3dDdi
const float apc = Config::alternatePixelCenter.get();
const auto& zr = m_current.zRange;
const float viewportEdgeGap = m_spriteMode ? 0 : (Config::viewportEdgeFix.getParam() / 100.0f);
const float w = width - viewportEdgeGap;
const float h = height - viewportEdgeGap;
m_vertexFixupData.texCoordAdj[2] = stc;
m_vertexFixupData.texCoordAdj[3] = stc;
if (Config::Settings::VertexFixup::GPU == m_vertexFixupConfig)
{
m_vertexFixupData.offset[0] = 0.5f + apc - 0.5f / sx - width / 2;
m_vertexFixupData.offset[1] = 0.5f + apc - 0.5f / sy - height / 2;
m_vertexFixupData.offset[0] = 0.5f + apc - 0.5f / sx - w / 2;
m_vertexFixupData.offset[1] = 0.5f + apc - 0.5f / sy - h / 2;
m_vertexFixupData.offset[2] = -zr.MinZ;
m_vertexFixupData.multiplier[0] = 2.0f / width;
m_vertexFixupData.multiplier[1] = -2.0f / height;
m_vertexFixupData.multiplier[0] = 2.0f / w;
m_vertexFixupData.multiplier[1] = -2.0f / h;
m_vertexFixupData.multiplier[2] = 1.0f / (zr.MaxZ - zr.MinZ);
}
else
@ -1361,8 +1376,8 @@ namespace D3dDdi
m_vertexFixupData.offset[0] = 0.5f + apc - 0.5f / sx;
m_vertexFixupData.offset[1] = 0.5f + apc - 0.5f / sy;
m_vertexFixupData.multiplier[0] = sx;
m_vertexFixupData.multiplier[1] = sy;
m_vertexFixupData.multiplier[0] = sx * width / w;
m_vertexFixupData.multiplier[1] = sy * height / h;
}
m_changedStates |= CS_VERTEX_FIXUP;

View File

@ -103,6 +103,7 @@ namespace D3dDdi
struct VertexDecl
{
std::unique_ptr<void, ResourceDeleter> untransformedDecl;
std::vector<D3DDDIVERTEXELEMENT> elements;
std::array<UINT, 8> texCoordOffset;
std::array<UINT, 8> texCoordType;

View File

@ -213,7 +213,7 @@ namespace D3dDdi
bool DrawPrimitive::appendPrimitives(D3DPRIMITIVETYPE primitiveType, INT baseVertexIndex, UINT primitiveCount,
const UINT16* indices, UINT minIndex, UINT maxIndex)
{
if (m_batched.primitiveCount + primitiveCount > D3DMAXNUMPRIMITIVES)
if ((m_batched.primitiveCount + primitiveCount) * 3 > D3DMAXNUMVERTICES)
{
return false;
}

View File

@ -121,7 +121,7 @@ namespace
pOpenData->Interface = origInterface;
if (SUCCEEDED(result))
{
D3dDdi::AdapterFuncs::hookVtable(*pOpenData->pAdapterFuncs, pOpenData->DriverVersion);
D3dDdi::AdapterFuncs::hookVtable(*pOpenData->pAdapterFuncs, std::min(pOpenData->Version, pOpenData->DriverVersion));
D3dDdi::Adapter::add(*pOpenData);
}
return result;

View File

@ -19,8 +19,10 @@
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/GuiThread.h>
#include <Gdi/Palette.h>
#include <Gdi/Window.h>
#include <Overlay/StatsWindow.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
@ -161,7 +163,7 @@ namespace
{
return -1;
}
return data.ScanLine;
return data.InVerticalBlank ? 0 : data.ScanLine;
}
void getVidPnSource(D3DKMT_HANDLE& adapter, UINT& vidPnSourceId)
@ -210,7 +212,7 @@ namespace
switch (pData->Type)
{
case KMTQAITYPE_UMDRIVERNAME:
if (Config::forceD3D9On12.get() &&
if (Config::Settings::ForceD3D9On12::ON == Config::forceD3D9On12.get() &&
KMTUMDVERSION_DX9 == static_cast<D3DKMT_UMDFILENAMEINFO*>(pData->pPrivateDriverData)->Version)
{
return STATUS_INVALID_PARAMETER;
@ -237,7 +239,7 @@ namespace
}
}
}
else if (!Config::forceD3D9On12.get() &&
else if (Config::Settings::ForceD3D9On12::FORCEOFF == Config::forceD3D9On12.get() &&
KMTQAITYPE_UMDRIVERNAME == pData->Type &&
KMTUMDVERSION_DX9 == static_cast<D3DKMT_UMDFILENAMEINFO*>(pData->pPrivateDriverData)->Version)
{
@ -365,6 +367,13 @@ namespace
}
WakeAllConditionVariable(&g_vsyncCounterCv);
auto statsWindow = Gdi::GuiThread::getStatsWindow();
if (statsWindow)
{
statsWindow->m_vblank.add();
}
}
return 0;
}

View File

@ -1851,4 +1851,46 @@ namespace D3dDdi
m_palettizedTexture->m_isPalettizedTextureUpToDate = true;
m_paletteColorKeyIndex = paletteColorKeyIndex;
}
void Resource::waitForIdle(UINT subResourceIndex)
{
m_device.flushPrimitives();
Resource* srcResource = this;
RECT rect = { 0, 0, 1, 1 };
if (m_lockResource)
{
if (m_lockData[subResourceIndex].isMsaaUpToDate ||
m_lockData[subResourceIndex].isMsaaResolvedUpToDate)
{
if (!m_lockData[subResourceIndex].isMsaaResolvedUpToDate)
{
copySubResourceRegion(*m_msaaResolvedSurface.resource, subResourceIndex, rect,
*m_msaaSurface.resource, subResourceIndex, rect);
}
srcResource = m_msaaResolvedSurface.resource;
}
else if (!m_lockData[subResourceIndex].isVidMemUpToDate)
{
return;
}
}
auto& syncSurface = m_device.getRepo().getSyncSurface(srcResource->m_fixedData.Format);
if (!syncSurface.resource)
{
return;
}
copySubResourceRegion(*syncSurface.resource, 0, rect, *srcResource, subResourceIndex, rect);
D3DDDIARG_LOCK lock = {};
lock.hResource = *syncSurface.resource;
lock.Flags.ReadOnly = 1;
m_device.getOrigVtable().pfnLock(m_device, &lock);
D3DDDIARG_UNLOCK unlock = {};
unlock.hResource = *syncSurface.resource;
m_device.getOrigVtable().pfnUnlock(m_device, &unlock);
}
}

View File

@ -66,6 +66,7 @@ namespace D3dDdi
HRESULT unlock(const D3DDDIARG_UNLOCK& data);
void updateConfig();
void updatePalettizedTexture(UINT stage);
void waitForIdle(UINT subResourceIndex);
static void enableConfig(bool enable);
static void setFormatOverride(D3DDDIFORMAT format);

View File

@ -333,6 +333,11 @@ namespace D3dDdi
return surface;
}
SurfaceRepository::Surface& SurfaceRepository::getSyncSurface(D3DDDIFORMAT format)
{
return getSurface(m_syncSurface[format], 16, 16, format, DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY);
}
SurfaceRepository::Surface& SurfaceRepository::getTempSurface(Surface& surface, DWORD width, DWORD height,
D3DDDIFORMAT format, DWORD caps, UINT surfaceCount)
{

View File

@ -49,6 +49,7 @@ namespace D3dDdi
const Resource* currentSrcRt = nullptr, const Resource* currentDstRt = nullptr);
Surface& getSurface(Surface& surface, DWORD width, DWORD height,
D3DDDIFORMAT format, DWORD caps, UINT surfaceCount = 1, DWORD caps2 = 0);
Surface& getSyncSurface(D3DDDIFORMAT format);
Surface& getTempSysMemSurface(DWORD width, DWORD height);
Surface& getTempSurface(Surface& surface, DWORD width, DWORD height,
D3DDDIFORMAT format, DWORD caps, UINT surfaceCount = 1);
@ -89,6 +90,7 @@ namespace D3dDdi
std::array<Surface, 3> m_hqRenderTargets;
std::map<D3DDDIFORMAT, Surface> m_textures;
std::vector<Surface> m_releasedSurfaces;
std::map<D3DDDIFORMAT, Surface> m_syncSurface;
Surface m_sysMemSurface;
Surface m_windowedBackBuffer;
CompatPtr<IDirectDrawSurface7> m_windowedPrimary;

View File

@ -99,10 +99,13 @@ namespace
UINT getFlipInterval(DWORD flags)
{
auto vSync = Config::vSync.get();
if (Config::Settings::VSync::APP != vSync)
switch (Config::vSync.get())
{
return Config::Settings::VSync::OFF == vSync ? 0 : Config::vSync.getParam();
case Config::Settings::VSync::OFF:
case Config::Settings::VSync::WAIT:
return 0;
case Config::Settings::VSync::ON:
return Config::vSync.getParam();
}
if (flags & DDFLIP_NOVSYNC)
@ -509,10 +512,9 @@ namespace DDraw
return DD_OK;
}
HRESULT RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
void RealPrimarySurface::flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags)
{
const DWORD flipInterval = getFlipInterval(flags);
PrimarySurface::waitForIdle();
Compat::ScopedCriticalSection lock(g_presentCs);
scheduleUpdate();
@ -527,8 +529,6 @@ namespace DDraw
{
g_lastFlipSurface = nullptr;
}
return DD_OK;
}
int RealPrimarySurface::flush()
@ -737,12 +737,17 @@ namespace DDraw
return true;
}
bool isUpdateReady = g_isUpdateReady;
auto qpcStart = Time::queryPerformanceCounter();
auto vsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
while (static_cast<int>(vsyncCount - g_flipEndVsyncCount) < 0)
{
++vsyncCount;
D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCount);
if (isUpdateReady)
{
flush();
}
}
Compat::ScopedCriticalSection lock(g_presentCs);
@ -767,10 +772,10 @@ namespace DDraw
g_qpcPrevWaitEnd = qpcWaitEnd;
Compat::ScopedThreadPriority prio(THREAD_PRIORITY_TIME_CRITICAL);
auto qpcStart = Time::queryPerformanceCounter();
while (Time::qpcToMs(qpcWaitEnd - qpcNow) > 0)
{
Time::waitForNextTick();
flush();
qpcNow = Time::queryPerformanceCounter();
}
@ -778,12 +783,5 @@ namespace DDraw
{
qpcNow = Time::queryPerformanceCounter();
}
Compat::ScopedCriticalSection lock(g_presentCs);
auto qpcEnd = Time::queryPerformanceCounter();
if (g_isUpdatePending)
{
g_qpcUpdateStart += qpcEnd - qpcStart;
}
}
}

View File

@ -13,7 +13,7 @@ namespace DDraw
{
public:
static HRESULT create(CompatRef<IDirectDraw> dd);
static HRESULT flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
static void flip(CompatPtr<IDirectDrawSurface7> surfaceTargetOverride, DWORD flags);
static int flush();
static HRESULT getGammaRamp(DDGAMMARAMP* rampData);
static HWND getPresentationWindow();

View File

@ -3,6 +3,7 @@
#include <D3dDdi/Device.h>
#include <D3dDdi/KernelModeThunks.h>
#include <D3dDdi/Resource.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <D3dDdi/SurfaceRepository.h>
#include <DDraw/DirectDraw.h>
#include <DDraw/DirectDrawSurface.h>
@ -17,10 +18,10 @@
namespace
{
CompatWeakPtr<IDirectDrawSurface7> g_primarySurface;
D3dDdi::Device* g_device = nullptr;
HANDLE g_gdiDriverResource = nullptr;
HANDLE g_gdiRuntimeResource = nullptr;
HANDLE g_frontResource = nullptr;
D3dDdi::Resource* g_frontResource = nullptr;
UINT g_frontResourceIndex = 0;
DWORD g_origCaps = 0;
HWND g_deviceWindow = nullptr;
HPALETTE g_palette = nullptr;
@ -34,10 +35,10 @@ namespace DDraw
{
LOG_FUNC("PrimarySurface::~PrimarySurface");
g_device = nullptr;
g_gdiRuntimeResource = nullptr;
g_gdiDriverResource = nullptr;
g_frontResource = nullptr;
g_frontResourceIndex = 0;
g_primarySurface = nullptr;
g_origCaps = 0;
g_deviceWindow = nullptr;
@ -111,7 +112,6 @@ namespace DDraw
ResizePalette(g_palette, 256);
}
g_device = D3dDdi::Device::findDeviceByResource(DirectDrawSurface::getDriverResourceHandle(*surface));
data->restore();
D3dDdi::Device::updateAllConfig();
return LOG_RESULT(DD_OK);
@ -215,7 +215,7 @@ namespace DDraw
HANDLE PrimarySurface::getFrontResource()
{
return g_frontResource;
return *g_frontResource;
}
HANDLE PrimarySurface::getGdiResource()
@ -260,7 +260,7 @@ namespace DDraw
g_gdiRuntimeResource = DirectDrawSurface::getRuntimeResourceHandle(*g_primarySurface);
updateFrontResource();
g_gdiDriverResource = g_frontResource;
g_gdiDriverResource = *g_frontResource;
D3dDdi::Device::setGdiResourceHandle(g_gdiDriverResource);
DDSCAPS2 caps = {};
@ -324,7 +324,8 @@ namespace DDraw
void PrimarySurface::updateFrontResource()
{
g_frontResource = DirectDrawSurface::getDriverResourceHandle(*g_primarySurface);
g_frontResource = D3dDdi::Device::findResource(DirectDrawSurface::getDriverResourceHandle(*g_primarySurface));
g_frontResourceIndex = DirectDrawSurface::getSubResourceIndex(*g_primarySurface);
}
void PrimarySurface::updatePalette()
@ -360,10 +361,8 @@ namespace DDraw
void PrimarySurface::waitForIdle()
{
if (g_device)
{
g_device->waitForIdle();
}
D3dDdi::ScopedCriticalSection lock;
g_frontResource->waitForIdle(g_frontResourceIndex);
}
CompatWeakPtr<IDirectDrawPalette> PrimarySurface::s_palette;

View File

@ -1,5 +1,6 @@
#include <Common/CompatPtr.h>
#include <Config/Settings/FpsLimiter.h>
#include <Config/Settings/VSync.h>
#include <D3dDdi/KernelModeThunks.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/DirectDrawClipper.h>
@ -177,18 +178,22 @@ namespace DDraw
caps.dwCaps = DDSCAPS_BACKBUFFER;
getOrigVtable(This).GetAttachedSurface(This, &caps, &surfaceTargetOverride.getRef());
}
HRESULT result = Blt(This, nullptr, surfaceTargetOverride.get(), nullptr, DDBLT_WAIT, nullptr);
if (SUCCEEDED(result) && Config::Settings::FpsLimiter::FLIPEND == Config::fpsLimiter.get())
{
RealPrimarySurface::waitForFlipFpsLimit();
}
return result;
}
HRESULT result = SurfaceImpl::Flip(This, surfaceTargetOverride, DDFLIP_WAIT);
if (FAILED(result))
HRESULT result = SurfaceImpl::Blt(This, nullptr, surfaceTargetOverride.get(), nullptr, DDBLT_WAIT, nullptr);
if (FAILED(result))
{
return result;
}
dwFlags = DDFLIP_NOVSYNC;
}
else
{
return result;
HRESULT result = SurfaceImpl::Flip(This, surfaceTargetOverride, DDFLIP_WAIT);
if (FAILED(result))
{
return result;
}
}
auto statsWindow = Gdi::GuiThread::getStatsWindow();
@ -198,13 +203,41 @@ namespace DDraw
}
PrimarySurface::updateFrontResource();
result = RealPrimarySurface::flip(surfaceTargetOverride, dwFlags);
if (SUCCEEDED(result) && Config::Settings::FpsLimiter::FLIPEND == Config::fpsLimiter.get())
RealPrimarySurface::flip(surfaceTargetOverride, dwFlags);
if (Config::Settings::VSync::WAIT == Config::vSync.get())
{
static UINT lastFlipEnd = 0;
lastFlipEnd += Config::vSync.getParam();
UINT vsyncCount = D3dDdi::KernelModeThunks::getVsyncCounter();
if (static_cast<INT>(vsyncCount - lastFlipEnd) > 0)
{
lastFlipEnd = vsyncCount;
}
RealPrimarySurface::setUpdateReady();
if (0 != RealPrimarySurface::flush())
{
PrimarySurface::waitForIdle();
}
while (static_cast<INT>(vsyncCount - lastFlipEnd) < 0)
{
++vsyncCount;
D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCount);
RealPrimarySurface::flush();
}
}
else
{
PrimarySurface::waitForIdle();
}
if (Config::Settings::FpsLimiter::FLIPEND == Config::fpsLimiter.get())
{
DDraw::RealPrimarySurface::waitForFlip(m_data->getDDS());
RealPrimarySurface::waitForFlipFpsLimit();
}
return result;
return DD_OK;
}
template <typename TSurface>

View File

@ -72,7 +72,7 @@
<AdditionalIncludeDirectories>$(ProjectDir);$(IntDir)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;version.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
@ -110,7 +110,7 @@
<AdditionalIncludeDirectories>$(ProjectDir);$(IntDir)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dwmapi.lib;dxguid.lib;imm32.lib;msimg32.lib;oleacc.lib;uxtheme.lib;version.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
@ -216,6 +216,7 @@
<ClInclude Include="Config\Settings\ThreadPriorityBoost.h" />
<ClInclude Include="Config\Settings\VertexBufferMemoryType.h" />
<ClInclude Include="Config\Settings\VertexFixup.h" />
<ClInclude Include="Config\Settings\ViewportEdgeFix.h" />
<ClInclude Include="Config\Settings\VSync.h" />
<ClInclude Include="Config\Settings\WinVersionLie.h" />
<ClInclude Include="D3dDdi\Adapter.h" />

View File

@ -723,6 +723,9 @@
<ClInclude Include="Config\Settings\GdiStretchBltMode.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
<ClInclude Include="Config\Settings\ViewportEdgeFix.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">

View File

@ -215,7 +215,7 @@ namespace Gdi
POINT pos = {};
CALL_ORIG_FUNC(GetCursorPos)(&pos);
CALL_ORIG_FUNC(SetCursorPos)(pos.x, pos.y);
SetCursorPos(pos.x, pos.y);
}
void setMonitorClipRect(const RECT& rect)

View File

@ -23,6 +23,8 @@ namespace
case SPI_SETFONTSMOOTHING:
g_isFontSmoothingEnabled = 0 != uiParam;
return TRUE;
case SPI_SETSHOWIMEUI:
return TRUE;
}
return LOG_RESULT(origSystemParametersInfo(uiAction, uiParam, pvParam, fWinIni));
}

View File

@ -21,6 +21,7 @@
#include <Overlay/Steam.h>
#include <Overlay/Window.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace
{
@ -29,7 +30,6 @@ namespace
HOOKPROC origHookProc;
LPARAM origHookStruct;
MSLLHOOKSTRUCT hookStruct;
DWORD dpiScale;
};
struct HotKeyData
@ -43,7 +43,6 @@ namespace
SIZE g_bmpArrowSize = {};
Overlay::Control* g_capture = nullptr;
POINT g_cursorPos = {};
POINT g_origCursorPos = { MAXLONG, MAXLONG };
HWND g_cursorWindow = nullptr;
std::map<Input::HotKey, HotKeyData> g_hotKeys;
RECT g_monitorRect = {};
@ -56,7 +55,7 @@ namespace
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);
POINT physicalToLogicalPoint(POINT pt, DWORD dpiScale);
POINT physicalToLogicalPoint(POINT pt);
LRESULT CALLBACK cursorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
@ -106,7 +105,22 @@ namespace
if (WM_MOUSEMOVE == wParam)
{
data.hookStruct.pt = physicalToLogicalPoint(data.hookStruct.pt, data.dpiScale);
if (Win32::DpiAwareness::isMixedModeSupported())
{
POINT logicalCursorPos = {};
GetCursorPos(&logicalCursorPos);
Win32::ScopedDpiAwareness dpiAwareness;
POINT physicalCursorPos = {};
GetCursorPos(&physicalCursorPos);
data.hookStruct.pt.x = logicalCursorPos.x + data.hookStruct.pt.x - physicalCursorPos.x;
data.hookStruct.pt.y = logicalCursorPos.y + data.hookStruct.pt.y - physicalCursorPos.y;
}
else
{
data.hookStruct.pt = physicalToLogicalPoint(data.hookStruct.pt);
}
}
else
{
@ -118,13 +132,6 @@ namespace
return g_dinputMouseHookData.origHookProc(nCode, wParam, lParam);
}
DWORD getDpiScaleForCursorPos()
{
POINT cp = {};
CALL_ORIG_FUNC(GetCursorPos)(&cp);
return Win32::DisplayMode::getMonitorInfo(cp).dpiScale;
}
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (HC_ACTION == nCode &&
@ -178,25 +185,23 @@ namespace
if (WM_MOUSEMOVE == wParam)
{
if (MAXLONG == g_origCursorPos.y)
POINT origCursorPos = {};
POINT newCursorPos = llHook.pt;
if (Win32::DpiAwareness::isMixedModeSupported())
{
if (llHook.flags & LLMHF_INJECTED)
{
if (MAXLONG == g_origCursorPos.x)
{
g_origCursorPos.x = llHook.pt.x;
}
else
{
g_origCursorPos.y = llHook.pt.y;
}
}
return 1;
Win32::ScopedDpiAwareness dpiAwareness;
CALL_ORIG_FUNC(GetCursorPos)(&origCursorPos);
llHook.pt = {};
}
else
{
CALL_ORIG_FUNC(GetCursorPos)(&origCursorPos);
newCursorPos = physicalToLogicalPoint(llHook.pt);
}
POINT cp = g_cursorPos;
cp.x += llHook.pt.x - g_origCursorPos.x;
cp.y += llHook.pt.y - g_origCursorPos.y;
cp.x += newCursorPos.x - origCursorPos.x;
cp.y += newCursorPos.y - origCursorPos.y;
cp.x = std::min(std::max(g_monitorRect.left, cp.x), g_monitorRect.right);
cp.y = std::min(std::max(g_monitorRect.top, cp.y), g_monitorRect.bottom);
g_cursorPos = cp;
@ -240,13 +245,14 @@ namespace
TerminateProcess(GetCurrentProcess(), 0);
}
POINT physicalToLogicalPoint(POINT pt, DWORD dpiScale)
POINT physicalToLogicalPoint(POINT pt)
{
if (g_physicalToLogicalPointForPerMonitorDPI)
{
g_physicalToLogicalPointForPerMonitorDPI(nullptr, &pt);
return pt;
}
auto dpiScale = Win32::DisplayMode::getMonitorInfo(pt).dpiScale;
return { MulDiv(pt.x, 100, dpiScale), MulDiv(pt.y, 100, dpiScale) };
}
@ -287,46 +293,28 @@ namespace
});
}
void resetMouseHookFunc()
{
if (g_mouseHook)
{
UnhookWindowsHookEx(g_mouseHook);
}
g_origCursorPos = { MAXLONG, MAXLONG };
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_origDDrawModule, 0);
if (g_mouseHook)
{
INPUT inputs[2] = {};
inputs[0].mi.dy = 1;
inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE;
inputs[1].mi.dx = 1;
inputs[1].mi.dwFlags = MOUSEEVENTF_MOVE;
SendInput(2, inputs, sizeof(INPUT));
}
else
{
LOG_ONCE("ERROR: Failed to install low level mouse hook, error code: " << GetLastError());
}
}
void resetMouseHook()
{
Gdi::GuiThread::executeAsyncFunc(resetMouseHookFunc);
}
Gdi::GuiThread::execute([]()
{
if (!g_capture)
{
return;
}
BOOL WINAPI setCursorPos(int X, int Y)
{
LOG_FUNC("SetCursorPos", X, Y);
auto result = CALL_ORIG_FUNC(SetCursorPos)(X, Y);
if (result && g_mouseHook)
{
resetMouseHook();
}
return LOG_RESULT(result);
if (g_mouseHook)
{
UnhookWindowsHookEx(g_mouseHook);
}
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_origDDrawModule, 0);
if (!g_mouseHook)
{
LOG_ONCE("ERROR: Failed to install low level mouse hook, error code: " << GetLastError());
}
});
}
HHOOK setWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId,
@ -345,11 +333,6 @@ namespace
(0 == _stricmp(moduleName.c_str(), "dinput") || 0 == _stricmp(moduleName.c_str(), "dinput8")))
{
g_dinputMouseHookData.origHookProc = lpfn;
if (!g_physicalToLogicalPointForPerMonitorDPI)
{
g_dinputMouseHookData.dpiScale = getDpiScaleForCursorPos();
}
lpfn = dinputLowLevelMouseProc;
Compat::hookIatFunction(hmod, "CallNextHookEx", dinputCallNextHookEx);
}
@ -441,7 +424,6 @@ namespace Input
GetProcAddress(GetModuleHandle("user32"), "PhysicalToLogicalPointForPerMonitorDPI"));
HOOK_FUNCTION(user32, RegisterRawInputDevices, registerRawInputDevices);
HOOK_FUNCTION(user32, SetCursorPos, setCursorPos);
HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA);
HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW);

View File

@ -27,6 +27,7 @@
#include <Config/Settings/StatsTransparency.h>
#include <Config/Settings/TextureFilter.h>
#include <Config/Settings/VertexFixup.h>
#include <Config/Settings/ViewportEdgeFix.h>
#include <Config/Settings/VSync.h>
#include <D3dDdi/Device.h>
#include <Gdi/Gdi.h>
@ -71,6 +72,7 @@ namespace
{ &Config::statsTransparency, [&]() { Gdi::GuiThread::getStatsWindow()->setAlpha(Config::statsTransparency.get()); }},
{ &Config::textureFilter, &D3dDdi::Device::updateAllConfig },
{ &Config::vertexFixup, &D3dDdi::Device::updateAllConfig },
{ &Config::viewportEdgeFix },
{ &Config::vSync }
};
}

View File

@ -110,6 +110,9 @@ namespace Overlay
m_statsRows.push_back({ "Lock count", UpdateStats(m_lock.m_count), &m_lock.m_count });
m_statsRows.push_back({ "Lock rate", UpdateStats(m_lock.m_rate), &m_lock.m_rate });
m_statsRows.push_back({ "Lock time", UpdateStats(m_lock.m_time), &m_lock.m_time });
m_statsRows.push_back({ "VBlank count", UpdateStats(m_vblank.m_count), &m_vblank.m_count });
m_statsRows.push_back({ "VBlank rate", UpdateStats(m_vblank.m_rate), &m_vblank.m_rate });
m_statsRows.push_back({ "VBlank time", UpdateStats(m_vblank.m_time), &m_vblank.m_time });
m_statsRows.push_back({ "DDI usage", UpdateStats(m_ddiUsage), &m_ddiUsage });
m_statsRows.push_back({ "GDI objects", UpdateStats(m_gdiObjects), &m_gdiObjects });
m_statsRows.push_back({ "", &getDebugInfo, nullptr, WS_VISIBLE | WS_GROUP });
@ -135,6 +138,7 @@ namespace Overlay
m_flip.enable();
m_blit.enable();
m_lock.enable();
m_vblank.enable();
}
StatsControl& StatsWindow::addControl(const std::string& name, StatsControl::UpdateFunc updateFunc, DWORD style)

View File

@ -28,6 +28,7 @@ namespace Overlay
StatsEventGroup m_flip;
StatsEventGroup m_blit;
StatsEventGroup m_lock;
StatsEventGroup m_vblank;
StatsTimer m_ddiUsage;
StatsQueue m_gdiObjects;

View File

@ -318,7 +318,7 @@ namespace
LSTATUS WINAPI regEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpValueName, LPDWORD lpcchValueName,
LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
{
LOG_FUNC("RegEnumValueW", hKey, dwIndex, lpValueName, lpcchValueName, lpReserved, lpType, lpData, lpcbData);
LOG_FUNC("RegEnumValueW", hKey, dwIndex, Compat::out(lpValueName), lpcchValueName, lpReserved, lpType, lpData, lpcbData);
if (lpValueName && lpcchValueName && !lpReserved && !lpType && !lpData && !lpcbData)
{
auto keyName(getKeyName(hKey));

View File

@ -2,7 +2,9 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Common/Path.h>
#include <Config/Settings/WinVersionLie.h>
#include <Dll/Dll.h>
#include <Win32/Version.h>
@ -10,6 +12,55 @@
namespace
{
DWORD getModuleFileName(HMODULE mod, char* filename, DWORD size)
{
return GetModuleFileNameA(mod, filename, size);
}
DWORD getModuleFileName(HMODULE mod, wchar_t* filename, DWORD size)
{
return GetModuleFileNameW(mod, filename, size);
}
HMODULE getModuleHandle(const char* moduleName)
{
return GetModuleHandleA(moduleName);
}
HMODULE getModuleHandle(const wchar_t* moduleName)
{
return GetModuleHandleW(moduleName);
}
template <typename Char>
void fixVersionInfoFileName(const Char*& filename)
{
if (getModuleHandle(filename) == Dll::g_currentModule)
{
static Char path[MAX_PATH];
if (0 != getModuleFileName(Dll::g_origDDrawModule, path, MAX_PATH))
{
filename = path;
}
}
}
template <auto func, typename Result, typename Char, typename... Params>
Result WINAPI getFileVersionInfoFunc(const Char* filename ,Params... params)
{
LOG_FUNC(Compat::g_origFuncName<func>.c_str(), filename, params...);
fixVersionInfoFileName(filename);
return LOG_RESULT(CALL_ORIG_FUNC(func)(filename, params...));
}
template <auto func, typename Result, typename Char, typename... Params>
Result WINAPI getFileVersionInfoFunc(DWORD flags, const Char* filename, Params... params)
{
LOG_FUNC(Compat::g_origFuncName<func>.c_str(), filename, params...);
fixVersionInfoFileName(filename);
return LOG_RESULT(CALL_ORIG_FUNC(func)(flags, filename, params...));
}
DWORD WINAPI getVersion()
{
LOG_FUNC("GetVersion");
@ -64,14 +115,53 @@ namespace
{
return getVersionInfo<OSVERSIONINFOEXW>(lpVersionInformation, CALL_ORIG_FUNC(GetVersionExW), "GetVersionExW");
}
template <auto origFunc>
bool hookVersionInfoFunc(const char* moduleName, const char* funcName)
{
HMODULE mod = GetModuleHandle(moduleName);
if (mod)
{
FARPROC func = Compat::getProcAddress(mod, funcName);
if (func)
{
Compat::hookFunction<origFunc>(moduleName, funcName, getFileVersionInfoFunc<origFunc>);
return true;
}
}
return false;
}
template <auto origFunc>
void hookVersionInfoFunc(const char* funcName)
{
hookVersionInfoFunc<origFunc>("kernelbase", funcName) || hookVersionInfoFunc<origFunc>("version", funcName);
}
}
namespace Compat
{
template<> decltype(&GetFileVersionInfoExA) g_origFuncPtr<GetFileVersionInfoExA> = nullptr;
template<> decltype(&GetFileVersionInfoSizeExA) g_origFuncPtr<GetFileVersionInfoSizeExA> = nullptr;
}
#define HOOK_VERSION_INFO_FUNCTION(func) hookVersionInfoFunc<func>(#func)
namespace Win32
{
namespace Version
{
void installHooks()
{
HOOK_VERSION_INFO_FUNCTION(GetFileVersionInfoA);
HOOK_VERSION_INFO_FUNCTION(GetFileVersionInfoW);
HOOK_VERSION_INFO_FUNCTION(GetFileVersionInfoExA);
HOOK_VERSION_INFO_FUNCTION(GetFileVersionInfoExW);
HOOK_VERSION_INFO_FUNCTION(GetFileVersionInfoSizeA);
HOOK_VERSION_INFO_FUNCTION(GetFileVersionInfoSizeW);
HOOK_VERSION_INFO_FUNCTION(GetFileVersionInfoSizeExA);
HOOK_VERSION_INFO_FUNCTION(GetFileVersionInfoSizeExW);
HOOK_FUNCTION(kernel32, GetVersion, getVersion);
HOOK_FUNCTION(kernel32, GetVersionExA, getVersionExA);
HOOK_FUNCTION(kernel32, GetVersionExW, getVersionExW);

View File

@ -22,10 +22,11 @@
# ForceD3D9On12 = off
# FpsLimiter = off
# FullscreenMode = borderless
# GdiStretchBltMode = app
# LogLevel = info
# PalettizedTextures = off
# RemoveBorders = off
# RenderColorDepth = appd8
# RenderColorDepth = 32
# ResolutionScale = app(1)
# ResolutionScaleFilter = point
# SoftwareDevice = rgb
@ -37,15 +38,18 @@
# StatsHotKey = shift+f12
# StatsPosX = right
# StatsPosY = top
# StatsRows = label, presentrate, fliprate, blitcount, lockcount, ddiusage
# StatsRows = label, presentrate, fliprate, blitcount, lockcount
# StatsTransparency = alpha(75)
# StatsUpdateRate = 5
# SupportedDepthFormats = all
# SupportedResolutions = native, 640x480, 800x600, 1024x768
# SupportedTextureFormats = all
# SurfacePatches = none
# TerminateHotKey = ctrl+alt+end
# TextureFilter = app
# ThreadPriorityBoost = off
# VSync = app
# VertexBufferMemoryType = sysmem
# VertexFixup = gpu
# ViewportEdgeFix = off
# WinVersionLie = off