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

Added ThreadPriorityBoost setting

This commit is contained in:
narzoul 2021-04-28 23:43:12 +02:00
parent 6f92c8ef22
commit b3b54d5fbd
15 changed files with 336 additions and 79 deletions

View File

@ -0,0 +1,6 @@
#include <Config/Config.h>
namespace Config
{
Settings::ThreadPriorityBoost threadPriorityBoost;
}

View File

@ -1,10 +1,12 @@
#pragma once
#include <Config/Settings/ThreadPriorityBoost.h>
namespace Config
{
const unsigned delayedFlipModeTimeout = 200;
const unsigned evictionTimeout = 200;
const unsigned maxPaletteUpdatesPerMs = 5;
const unsigned maxUserModeDisplayDrivers = 3;
const unsigned threadSwitchCycleTime = 3 * 1000 * 1000;
extern Settings::ThreadPriorityBoost threadPriorityBoost;
}

View File

@ -0,0 +1,35 @@
#include <algorithm>
#include <Config/Parser.h>
#include <Config/EnumSetting.h>
namespace Config
{
EnumSetting::EnumSetting(const std::string& name, unsigned default, const std::vector<std::string>& enumNames)
: Setting(name)
, m_default(default)
, m_value(default)
, m_enumNames(enumNames)
{
}
std::string EnumSetting::getValueStr() const
{
return m_enumNames[m_value];
}
void EnumSetting::resetValue()
{
m_value = m_default;
}
void EnumSetting::setValue(const std::string& value)
{
auto it = std::find(m_enumNames.begin(), m_enumNames.end(), value);
if (it == m_enumNames.end())
{
throw ParsingError("invalid value: '" + value + "'");
}
m_value = it - m_enumNames.begin();
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <vector>
#include <Config/Setting.h>
namespace Config
{
class EnumSetting : public Setting
{
public:
unsigned get() const { return m_value; }
protected:
EnumSetting(const std::string& name, unsigned default, const std::vector<std::string>& enumNames);
private:
std::string getValueStr() const override;
void resetValue() override;
void setValue(const std::string& value) override;
unsigned m_default;
unsigned m_value;
const std::vector<std::string> m_enumNames;
};
}

View File

@ -1,17 +1,27 @@
#include <fstream>
#include <locale>
#include <map>
#include <Common/Log.h>
#include <Common/Path.h>
#include <Config/Parser.h>
#include <Config/Setting.h>
namespace
{
void setConfig(const std::string& name, const std::string& value);
void setConfig(const std::string& name, const std::string& value, const std::string& source);
std::string tolower(const std::string& str);
std::string trim(const std::string& str);
void loadConfigFile(const std::string& type, const std::filesystem::path& path)
auto& getSettings()
{
Compat::Log() << "Loading " << type << " config file: " << path.u8string();
static std::map<std::string, Config::Setting&> settings;
return settings;
}
void loadConfigFile(const std::string& source, const std::filesystem::path& path)
{
Compat::Log() << "Loading " << source << " config file: " << path.u8string();
std::ifstream f(path);
if (!f.is_open())
{
@ -42,7 +52,7 @@ namespace
throw Config::ParsingError("missing '=' separator");
}
setConfig(trim(line.substr(0, pos)), trim(line.substr(pos + 1)));
setConfig(trim(line.substr(0, pos)), trim(line.substr(pos + 1)), source);
}
catch (const Config::ParsingError& error)
{
@ -51,14 +61,38 @@ namespace
}
}
void setConfig(const std::string& name, const std::string& /*value*/)
void setConfig(const std::string& name, const std::string& value, const std::string& source)
{
if (name.empty())
{
throw Config::ParsingError("missing setting name before '='");
}
throw Config::ParsingError("unknown setting: '" + name + "'");
auto it = std::find_if(getSettings().cbegin(), getSettings().cend(), [&](const auto& v) {
return 0 == _stricmp(v.first.c_str(), name.c_str()); });
if (it == getSettings().end())
{
throw Config::ParsingError("unknown setting: '" + name + "'");
}
try
{
it->second.set(tolower(value), source);
}
catch (const Config::ParsingError& error)
{
throw Config::ParsingError(it->second.getName() + ": " + error.what());
}
}
std::string tolower(const std::string& str)
{
std::string result(str);
for (auto& c : result)
{
c = std::tolower(c, std::locale());
}
return result;
}
std::string trim(const std::string& str)
@ -85,6 +119,10 @@ namespace Config
{
void loadAllConfigFiles(const std::filesystem::path& processPath)
{
for (auto& setting : getSettings()) {
setting.second.reset();
}
loadConfigFile("global", Compat::getEnvPath("PROGRAMDATA") / "DDrawCompat" / "DDrawCompat.ini");
loadConfigFile("user", Compat::getEnvPath("LOCALAPPDATA") / "DDrawCompat" / "DDrawCompat.ini");
loadConfigFile("directory", Compat::replaceFilename(processPath, "DDrawCompat.ini"));
@ -96,6 +134,36 @@ namespace Config
}
processConfigPath.replace_filename(L"DDrawCompat-" + processConfigPath.filename().native() + L".ini");
loadConfigFile("process", processConfigPath);
std::size_t maxNameLength = 0;
std::size_t maxSourceLength = 0;
for (const auto& setting : getSettings())
{
if (setting.second.getName().length() > maxNameLength)
{
maxNameLength = setting.second.getName().length();
}
if (setting.second.getSource().length() > maxSourceLength)
{
maxSourceLength = setting.second.getSource().length();
}
}
Compat::Log() << "Final configuration:";
for (const auto& setting : getSettings())
{
std::string name(setting.second.getName());
name.insert(name.end(), maxNameLength - name.length(), ' ');
std::string source(setting.second.getSource());
source.insert(source.end(), maxSourceLength - source.length(), ' ');
Compat::Log() << " [" << source << "] " << name << " = " << setting.second.getValueAsString();
}
}
void registerSetting(Setting& setting)
{
const auto& name = setting.getName();
getSettings().emplace(name, setting);
}
}
}

View File

@ -11,8 +11,11 @@ namespace Config
ParsingError(const std::string& error) : runtime_error(error) {}
};
class Setting;
namespace Parser
{
void loadAllConfigFiles(const std::filesystem::path& processPath);
void registerSetting(Setting& setting);
}
}

View File

@ -0,0 +1,30 @@
#include <Config/Parser.h>
#include <Config/Setting.h>
namespace Config
{
Setting::Setting(const std::string& name)
: m_name(name)
{
Parser::registerSetting(*this);
}
void Setting::reset()
{
resetValue();
m_source = "default";
}
void Setting::set(const std::string& value, const std::string& source)
{
if ("default" == value)
{
resetValue();
}
else
{
setValue(value);
}
m_source = source;
}
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <string>
namespace Config
{
class Setting
{
public:
Setting(const std::string& name);
Setting(const Setting&) = delete;
Setting(Setting&&) = delete;
Setting& operator=(const Setting&) = delete;
Setting& operator=(Setting&&) = delete;
const std::string& getName() const { return m_name; }
const std::string& getSource() const { return m_source; }
std::string getValueAsString() const { return getValueStr(); }
void reset();
void set(const std::string& value, const std::string& source);
private:
virtual std::string getValueStr() const = 0;
virtual void resetValue() = 0;
virtual void setValue(const std::string& value) = 0;
std::string m_name;
std::string m_source;
};
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <Config/EnumSetting.h>
namespace Config
{
namespace Settings
{
class ThreadPriorityBoost : public EnumSetting
{
public:
enum Value { OFF, ON, MAIN, APP };
ThreadPriorityBoost()
: EnumSetting("ThreadPriorityBoost", OFF, { "off", "on", "main", "app" })
{
}
};
}
}

View File

@ -178,7 +178,10 @@
<ClInclude Include="Common\ScopedCriticalSection.h" />
<ClInclude Include="Common\Time.h" />
<ClInclude Include="Config\Config.h" />
<ClInclude Include="Config\EnumSetting.h" />
<ClInclude Include="Config\Parser.h" />
<ClInclude Include="Config\Setting.h" />
<ClInclude Include="Config\Settings\ThreadPriorityBoost.h" />
<ClInclude Include="D3dDdi\Adapter.h" />
<ClInclude Include="D3dDdi\AdapterCallbacks.h" />
<ClInclude Include="D3dDdi\AdapterFuncs.h" />
@ -265,14 +268,17 @@
<ClInclude Include="Win32\MemoryManagement.h" />
<ClInclude Include="Win32\MsgHooks.h" />
<ClInclude Include="Win32\Registry.h" />
<ClInclude Include="Win32\WaitFunctions.h" />
<ClInclude Include="Win32\Thread.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Common\Log.cpp" />
<ClCompile Include="Common\Hook.cpp" />
<ClCompile Include="Common\Path.cpp" />
<ClCompile Include="Common\Time.cpp" />
<ClCompile Include="Config\Config.cpp" />
<ClCompile Include="Config\EnumSetting.cpp" />
<ClCompile Include="Config\Parser.cpp" />
<ClCompile Include="Config\Setting.cpp" />
<ClCompile Include="D3dDdi\Adapter.cpp" />
<ClCompile Include="D3dDdi\AdapterCallbacks.cpp" />
<ClCompile Include="D3dDdi\AdapterFuncs.cpp" />
@ -341,7 +347,7 @@
<ClCompile Include="Win32\MemoryManagement.cpp" />
<ClCompile Include="Win32\MsgHooks.cpp" />
<ClCompile Include="Win32\Registry.cpp" />
<ClCompile Include="Win32\WaitFunctions.cpp" />
<ClCompile Include="Win32\Thread.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DDrawCompat.rc" />

View File

@ -82,6 +82,9 @@
<Filter Include="Source Files\Config">
<UniqueIdentifier>{9d313de7-b8ca-49d0-84d2-217f2818d9d3}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Config\Settings">
<UniqueIdentifier>{bdde0d15-27ab-43a7-9c0a-294df6a52bad}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Gdi\Gdi.h">
@ -327,9 +330,6 @@
<ClInclude Include="DDraw\Log.h">
<Filter>Header Files\DDraw</Filter>
</ClInclude>
<ClInclude Include="Win32\WaitFunctions.h">
<Filter>Header Files\Win32</Filter>
</ClInclude>
<ClInclude Include="Direct3d\Direct3dMaterial.h">
<Filter>Header Files\Direct3d</Filter>
</ClInclude>
@ -396,6 +396,18 @@
<ClInclude Include="Config\Parser.h">
<Filter>Header Files\Config</Filter>
</ClInclude>
<ClInclude Include="Config\Setting.h">
<Filter>Header Files\Config</Filter>
</ClInclude>
<ClInclude Include="Config\EnumSetting.h">
<Filter>Header Files\Config</Filter>
</ClInclude>
<ClInclude Include="Config\Settings\ThreadPriorityBoost.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
<ClInclude Include="Win32\Thread.h">
<Filter>Header Files\Win32</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -563,9 +575,6 @@
<ClCompile Include="DDraw\Log.cpp">
<Filter>Source Files\DDraw</Filter>
</ClCompile>
<ClCompile Include="Win32\WaitFunctions.cpp">
<Filter>Source Files\Win32</Filter>
</ClCompile>
<ClCompile Include="Direct3d\Direct3dMaterial.cpp">
<Filter>Source Files\Direct3d</Filter>
</ClCompile>
@ -620,6 +629,18 @@
<ClCompile Include="Config\Parser.cpp">
<Filter>Source Files\Config</Filter>
</ClCompile>
<ClCompile Include="Config\Config.cpp">
<Filter>Source Files\Config</Filter>
</ClCompile>
<ClCompile Include="Config\Setting.cpp">
<Filter>Source Files\Config</Filter>
</ClCompile>
<ClCompile Include="Config\EnumSetting.cpp">
<Filter>Source Files\Config</Filter>
</ClCompile>
<ClCompile Include="Win32\Thread.cpp">
<Filter>Source Files\Win32</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DDrawCompat.rc">

View File

@ -9,6 +9,7 @@
#include <Common/Log.h>
#include <Common/Path.h>
#include <Common/Time.h>
#include <Config/Config.h>
#include <Config/Parser.h>
#include <D3dDdi/Hooks.h>
#include <DDraw/DirectDraw.h>
@ -22,7 +23,7 @@
#include <Win32/MemoryManagement.h>
#include <Win32/MsgHooks.h>
#include <Win32/Registry.h>
#include <Win32/WaitFunctions.h>
#include <Win32/Thread.h>
HRESULT WINAPI SetAppCompatData(DWORD, DWORD);
@ -60,8 +61,6 @@ namespace
Win32::Registry::installHooks();
Compat::Log() << "Installing Direct3D driver hooks";
D3dDdi::installHooks();
Compat::Log() << "Installing Win32 hooks";
Win32::WaitFunctions::installHooks();
Gdi::VirtualScreen::init();
CompatPtr<IDirectDraw> dd;
@ -206,19 +205,19 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Dll::g_jmpTargetProcs = Dll::g_origProcs;
VISIT_PUBLIC_DDRAW_PROCS(HOOK_DDRAW_PROC)
VISIT_PUBLIC_DDRAW_PROCS(HOOK_DDRAW_PROC);
Win32::MemoryManagement::installHooks();
Win32::MsgHooks::installHooks();
Win32::Thread::installHooks();
Compat::closeDbgEng();
const BOOL disablePriorityBoost = TRUE;
SetProcessPriorityBoost(GetCurrentProcess(), disablePriorityBoost);
SetProcessAffinityMask(GetCurrentProcess(), 1);
timeBeginPeriod(1);
setDpiAwareness();
SetThemeAppProperties(0);
Win32::MemoryManagement::installHooks();
Win32::MsgHooks::installHooks();
Time::init();
Compat::closeDbgEng();
Win32::Thread::applyConfig();
const DWORD disableMaxWindowedMode = 12;
CALL_ORIG_PROC(SetAppCompatData)(disableMaxWindowedMode, 0);

View File

@ -0,0 +1,60 @@
#include <Windows.h>
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Config/Config.h>
#include <Win32/Thread.h>
namespace
{
BOOL WINAPI setProcessPriorityBoost(HANDLE hProcess, BOOL bDisablePriorityBoost)
{
LOG_FUNC("SetProcessPriorityBoost", hProcess, bDisablePriorityBoost);
if (Config::Settings::ThreadPriorityBoost::APP != Config::threadPriorityBoost.get())
{
return LOG_RESULT(TRUE);
}
return LOG_RESULT(CALL_ORIG_FUNC(SetProcessPriorityBoost)(hProcess, bDisablePriorityBoost));
}
BOOL WINAPI setThreadPriorityBoost(HANDLE hThread, BOOL bDisablePriorityBoost)
{
LOG_FUNC("SetThreadPriorityBoost", hThread, bDisablePriorityBoost);
if (Config::Settings::ThreadPriorityBoost::APP != Config::threadPriorityBoost.get())
{
return LOG_RESULT(TRUE);
}
return LOG_RESULT(CALL_ORIG_FUNC(SetThreadPriorityBoost)(hThread, bDisablePriorityBoost));
}
}
namespace Win32
{
namespace Thread
{
void applyConfig()
{
switch (Config::threadPriorityBoost.get())
{
case Config::Settings::ThreadPriorityBoost::OFF:
CALL_ORIG_FUNC(SetProcessPriorityBoost)(GetCurrentProcess(), TRUE);
break;
case Config::Settings::ThreadPriorityBoost::ON:
CALL_ORIG_FUNC(SetProcessPriorityBoost)(GetCurrentProcess(), FALSE);
break;
case Config::Settings::ThreadPriorityBoost::MAIN:
CALL_ORIG_FUNC(SetProcessPriorityBoost)(GetCurrentProcess(), TRUE);
CALL_ORIG_FUNC(SetThreadPriorityBoost)(GetCurrentThread(), FALSE);
break;
}
}
void installHooks()
{
HOOK_FUNCTION(kernel32, SetProcessPriorityBoost, setProcessPriorityBoost);
HOOK_FUNCTION(kernel32, SetThreadPriorityBoost, setThreadPriorityBoost);
}
}
}

View File

@ -2,8 +2,9 @@
namespace Win32
{
namespace WaitFunctions
namespace Thread
{
void applyConfig();
void installHooks();
}
}

View File

@ -1,52 +0,0 @@
#include <Windows.h>
#include <timeapi.h>
#include <Common/Hook.h>
#include <Common/Time.h>
#include <Config/Config.h>
#include <Win32/WaitFunctions.h>
namespace
{
void mitigateBusyWaiting()
{
thread_local ULONG64 ctLastThreadSwitch = Time::queryThreadCycleTime();
ULONG64 ctNow = Time::queryThreadCycleTime();
if (ctNow - ctLastThreadSwitch >= Config::threadSwitchCycleTime)
{
Sleep(0);
ctLastThreadSwitch = ctNow;
}
}
template <auto func, typename Result, typename... Params>
Result WINAPI mitigatedBusyWaitingFunc(Params... params)
{
mitigateBusyWaiting();
return Compat::g_origFuncPtr<func>(params...);
}
}
#define MITIGATE_BUSY_WAITING(module, func) \
Compat::hookFunction<&func>(#module, #func, &mitigatedBusyWaitingFunc<&func>)
namespace Win32
{
namespace WaitFunctions
{
void installHooks()
{
MITIGATE_BUSY_WAITING(user32, GetMessageA);
MITIGATE_BUSY_WAITING(user32, GetMessageW);
MITIGATE_BUSY_WAITING(kernel32, GetTickCount);
MITIGATE_BUSY_WAITING(user32, MsgWaitForMultipleObjects);
MITIGATE_BUSY_WAITING(user32, MsgWaitForMultipleObjectsEx);
MITIGATE_BUSY_WAITING(user32, PeekMessageA);
MITIGATE_BUSY_WAITING(user32, PeekMessageW);
MITIGATE_BUSY_WAITING(kernel32, SignalObjectAndWait);
MITIGATE_BUSY_WAITING(winmm, timeGetTime);
MITIGATE_BUSY_WAITING(kernel32, WaitForSingleObjectEx);
MITIGATE_BUSY_WAITING(kernel32, WaitForMultipleObjectsEx);
}
}
}