2018-08-07 16:58:16 +02:00
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
2019-08-17 11:46:56 +02:00
|
|
|
#include <regex>
|
2018-08-07 16:58:16 +02:00
|
|
|
|
2018-08-07 14:13:57 +02:00
|
|
|
#include "config.h"
|
|
|
|
|
2018-08-07 16:58:16 +02:00
|
|
|
#include "../log/log.h"
|
|
|
|
|
|
|
|
#include "../util_env.h"
|
|
|
|
|
2018-08-07 14:13:57 +02:00
|
|
|
namespace dxvk {
|
|
|
|
|
2019-08-17 11:46:56 +02:00
|
|
|
const static std::vector<std::pair<const char*, Config>> g_appDefaults = {{
|
2019-04-12 10:51:07 +02:00
|
|
|
/* Anno 1800 */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\Anno1800\.exe$)", {{
|
2019-04-12 10:51:07 +02:00
|
|
|
{ "d3d11.allowMapFlagNoWait", "True" }
|
|
|
|
}} },
|
2019-01-19 17:45:26 +01:00
|
|
|
/* Assassin's Creed Syndicate: amdags issues */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\ACS\.exe$)", {{
|
2018-09-09 13:46:57 +02:00
|
|
|
{ "dxgi.customVendorId", "10de" },
|
2018-09-12 14:10:49 +02:00
|
|
|
}} },
|
2018-08-10 12:50:31 +02:00
|
|
|
/* Dishonored 2 */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\Dishonored2\.exe$)", {{
|
2018-08-07 16:58:16 +02:00
|
|
|
{ "d3d11.allowMapFlagNoWait", "True" }
|
|
|
|
}} },
|
2019-03-30 21:05:39 +01:00
|
|
|
/* Dissidia Final Fantasy NT Free Edition */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\dffnt\.exe$)", {{
|
2019-03-30 21:05:39 +01:00
|
|
|
{ "dxgi.deferSurfaceCreation", "True" },
|
|
|
|
}} },
|
2019-01-19 17:45:26 +01:00
|
|
|
/* Elite Dangerous: Compiles weird shaders *
|
|
|
|
* when running on AMD hardware */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\EliteDangerous64\.exe$)", {{
|
2018-11-06 17:03:01 +01:00
|
|
|
{ "dxgi.customVendorId", "10de" },
|
|
|
|
}} },
|
2018-10-25 17:49:42 +02:00
|
|
|
/* The Vanishing of Ethan Carter Redux */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\EthanCarter-Win64-Shipping\.exe$)", {{
|
2018-10-25 17:49:42 +02:00
|
|
|
{ "dxgi.customVendorId", "10de" },
|
|
|
|
}} },
|
2019-01-19 17:45:26 +01:00
|
|
|
/* The Evil Within: Submits command lists *
|
|
|
|
* multiple times */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\EvilWithin(Demo)?\.exe$)", {{
|
2018-11-20 10:51:09 +01:00
|
|
|
{ "d3d11.dcSingleUseMode", "False" },
|
2018-10-09 16:29:50 +02:00
|
|
|
}} },
|
2019-02-18 18:02:39 +01:00
|
|
|
/* Far Cry 3: Assumes clear(0.5) on an UNORM *
|
|
|
|
* format to result in 128 on AMD and 127 on *
|
2019-06-12 12:32:30 +02:00
|
|
|
* Nvidia. We assume that the Vulkan drivers *
|
|
|
|
* match the clear behaviour of D3D11. */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\(farcry3|fc3_blooddragon)_d3d11\.exe$)", {{
|
2019-06-12 12:32:30 +02:00
|
|
|
{ "dxgi.nvapiHack", "False" },
|
2019-02-18 18:02:39 +01:00
|
|
|
}} },
|
|
|
|
/* Far Cry 4: Same as Far Cry 3 */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\FarCry4\.exe$)", {{
|
2019-06-12 12:32:30 +02:00
|
|
|
{ "dxgi.nvapiHack", "False" },
|
2019-02-18 18:02:39 +01:00
|
|
|
}} },
|
|
|
|
/* Far Cry 5: Avoid CPU <-> GPU sync */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\FarCry5\.exe$)", {{
|
2018-08-07 16:58:16 +02:00
|
|
|
{ "d3d11.allowMapFlagNoWait", "True" }
|
|
|
|
}} },
|
2019-02-18 18:02:39 +01:00
|
|
|
/* Far Cry Primal: Nvidia performance */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\FCPrimal\.exe$)", {{
|
2019-02-18 18:02:39 +01:00
|
|
|
{ "dxgi.nvapiHack", "False" },
|
|
|
|
} }},
|
2019-01-19 17:45:26 +01:00
|
|
|
/* Frostpunk: Renders one frame with D3D9 *
|
|
|
|
* after creating the DXGI swap chain */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\Frostpunk\.exe$)", {{
|
2018-08-07 16:58:16 +02:00
|
|
|
{ "dxgi.deferSurfaceCreation", "True" },
|
|
|
|
}} },
|
2019-03-29 08:48:52 +01:00
|
|
|
/* Nioh: See Frostpunk, apparently? */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\nioh\.exe$)", {{
|
2019-03-29 08:48:52 +01:00
|
|
|
{ "dxgi.deferSurfaceCreation", "True" },
|
|
|
|
}} },
|
2019-01-19 17:45:26 +01:00
|
|
|
/* Quantum Break: Mever initializes shared *
|
|
|
|
* memory in one of its compute shaders */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\QuantumBreak\.exe$)", {{
|
2018-11-23 16:12:09 +01:00
|
|
|
{ "d3d11.zeroInitWorkgroupMemory", "True" },
|
|
|
|
}} },
|
2019-01-19 17:45:26 +01:00
|
|
|
/* Anno 2205: Random crashes with state cache */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\anno2205\.exe$)", {{
|
2018-11-24 20:04:21 +01:00
|
|
|
{ "dxvk.enableStateCache", "False" },
|
|
|
|
}} },
|
2019-01-19 17:45:26 +01:00
|
|
|
/* Fifa '19: Binds typed buffer SRV to shader *
|
|
|
|
* that expects raw/structured buffer SRV */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\FIFA19(_demo)?\.exe$)", {{
|
2019-01-08 21:01:57 +01:00
|
|
|
{ "dxvk.useRawSsbo", "True" },
|
|
|
|
}} },
|
2019-02-05 20:01:52 +01:00
|
|
|
/* Final Fantasy XIV: Fix random black blocks */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\ffxiv_dx11\.exe$)", {{
|
2019-02-05 20:01:52 +01:00
|
|
|
{ "d3d11.strictDivision", "True" },
|
|
|
|
}} },
|
2019-02-08 01:38:03 +01:00
|
|
|
/* Resident Evil 2: Improve GPU performance */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\re2\.exe$)", {{
|
2019-02-15 20:59:18 +01:00
|
|
|
{ "d3d11.relaxedBarriers", "True" },
|
|
|
|
}} },
|
|
|
|
/* Resident Evil 7 */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\re7\.exe$)", {{
|
2019-02-08 01:38:03 +01:00
|
|
|
{ "d3d11.relaxedBarriers", "True" },
|
|
|
|
}} },
|
2019-03-11 18:35:39 +01:00
|
|
|
/* Devil May Cry 5 */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\DevilMayCry5\.exe$)", {{
|
2019-03-11 18:35:39 +01:00
|
|
|
{ "d3d11.relaxedBarriers", "True" },
|
|
|
|
}} },
|
2019-01-10 11:57:39 +01:00
|
|
|
/* Call of Duty WW2 */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\s2_sp64_ship\.exe$)", {{
|
2019-01-10 11:57:39 +01:00
|
|
|
{ "dxgi.nvapiHack", "False" },
|
|
|
|
}} },
|
|
|
|
/* Need for Speed 2015 */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\NFS16\.exe$)", {{
|
2019-01-10 11:57:39 +01:00
|
|
|
{ "dxgi.nvapiHack", "False" },
|
|
|
|
}} },
|
2019-01-26 18:38:58 +01:00
|
|
|
/* Mass Effect Andromeda */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\MassEffectAndromeda\.exe$)", {{
|
2019-01-26 18:38:58 +01:00
|
|
|
{ "dxgi.nvapiHack", "False" },
|
|
|
|
}} },
|
2019-05-17 11:40:35 +02:00
|
|
|
/* Mirror`s Edge Catalyst: Crashes on AMD */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\MirrorsEdgeCatalyst(Trial)?\.exe$)", {{
|
2019-05-17 11:40:35 +02:00
|
|
|
{ "dxgi.customVendorId", "10de" },
|
2019-05-07 22:19:03 +03:00
|
|
|
}} },
|
2019-03-14 16:33:35 +01:00
|
|
|
/* Star Wars Battlefront (2015) */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\starwarsbattlefront(trial)?\.exe$)", {{
|
2019-03-14 16:33:35 +01:00
|
|
|
{ "dxgi.nvapiHack", "False" },
|
|
|
|
}} },
|
2019-04-05 20:26:57 +02:00
|
|
|
/* Dark Souls Remastered */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\DarkSoulsRemastered\.exe$)", {{
|
2019-04-05 20:26:57 +02:00
|
|
|
{ "d3d11.constantBufferRangeCheck", "True" },
|
|
|
|
}} },
|
|
|
|
/* Grim Dawn */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\Grim Dawn\.exe$)", {{
|
2019-04-05 20:26:57 +02:00
|
|
|
{ "d3d11.constantBufferRangeCheck", "True" },
|
|
|
|
}} },
|
2019-04-25 09:42:45 -07:00
|
|
|
/* NieR:Automata */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\NieRAutomata\.exe$)", {{
|
2019-04-25 09:42:45 -07:00
|
|
|
{ "d3d11.constantBufferRangeCheck", "True" },
|
|
|
|
}} },
|
2019-04-20 15:49:33 +02:00
|
|
|
/* The Surge */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\TheSurge\.exe$)", {{
|
2019-04-20 15:49:33 +02:00
|
|
|
{ "d3d11.allowMapFlagNoWait", "True" },
|
2019-08-10 11:18:26 +02:00
|
|
|
}} },
|
|
|
|
/* SteamVR performance test */
|
2019-08-24 18:38:41 +01:00
|
|
|
{ R"(\\vr\.exe$)", {{
|
2019-08-10 11:18:26 +02:00
|
|
|
{ "d3d11.dcSingleUseMode", "False" },
|
|
|
|
}} },
|
2019-09-08 10:35:57 +02:00
|
|
|
/* Control */
|
|
|
|
{ R"(\\Control_DX11\.exe$)", {{
|
|
|
|
{ "d3d11.allowMapFlagNoWait", "True" }
|
|
|
|
}} },
|
2018-08-07 16:58:16 +02:00
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
|
|
static bool isWhitespace(char ch) {
|
|
|
|
return ch == ' ' || ch == '\x9' || ch == '\r';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool isValidKeyChar(char ch) {
|
|
|
|
return (ch >= '0' && ch <= '9')
|
|
|
|
|| (ch >= 'A' && ch <= 'Z')
|
|
|
|
|| (ch >= 'a' && ch <= 'z')
|
|
|
|
|| (ch == '.' || ch == '_');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static size_t skipWhitespace(const std::string& line, size_t n) {
|
|
|
|
while (n < line.size() && isWhitespace(line[n]))
|
|
|
|
n += 1;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-26 19:17:32 +02:00
|
|
|
struct ConfigContext {
|
|
|
|
bool active;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void parseUserConfigLine(Config& config, ConfigContext& ctx, const std::string& line) {
|
2018-08-07 16:58:16 +02:00
|
|
|
std::stringstream key;
|
|
|
|
std::stringstream value;
|
|
|
|
|
|
|
|
// Extract the key
|
|
|
|
size_t n = skipWhitespace(line, 0);
|
2019-04-26 19:17:32 +02:00
|
|
|
|
|
|
|
if (n < line.size() && line[n] == '[') {
|
|
|
|
n += 1;
|
|
|
|
|
|
|
|
size_t e = line.size() - 1;
|
|
|
|
while (e > n && line[e] != ']')
|
|
|
|
e -= 1;
|
|
|
|
|
|
|
|
while (n < e)
|
|
|
|
key << line[n++];
|
|
|
|
|
|
|
|
ctx.active = key.str() == env::getExeName();
|
|
|
|
} else {
|
|
|
|
while (n < line.size() && isValidKeyChar(line[n]))
|
|
|
|
key << line[n++];
|
|
|
|
|
|
|
|
// Check whether the next char is a '='
|
|
|
|
n = skipWhitespace(line, n);
|
|
|
|
if (n >= line.size() || line[n] != '=')
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Extract the value
|
|
|
|
n = skipWhitespace(line, n + 1);
|
|
|
|
while (n < line.size() && !isWhitespace(line[n]))
|
|
|
|
value << line[n++];
|
|
|
|
|
|
|
|
if (ctx.active)
|
|
|
|
config.setOption(key.str(), value.str());
|
|
|
|
}
|
2018-08-07 16:58:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-07 14:13:57 +02:00
|
|
|
Config::Config() { }
|
|
|
|
Config::~Config() { }
|
|
|
|
|
|
|
|
|
|
|
|
Config::Config(OptionMap&& options)
|
|
|
|
: m_options(std::move(options)) { }
|
|
|
|
|
|
|
|
|
|
|
|
void Config::merge(const Config& other) {
|
|
|
|
for (auto& pair : other.m_options)
|
|
|
|
m_options.insert(pair);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Config::setOption(const std::string& key, const std::string& value) {
|
|
|
|
m_options.insert_or_assign(key, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string Config::getOptionValue(const char* option) const {
|
|
|
|
auto iter = m_options.find(option);
|
|
|
|
|
|
|
|
return iter != m_options.end()
|
|
|
|
? iter->second : std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Config::parseOptionValue(
|
|
|
|
const std::string& value,
|
|
|
|
std::string& result) {
|
|
|
|
result = value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Config::parseOptionValue(
|
|
|
|
const std::string& value,
|
|
|
|
bool& result) {
|
|
|
|
if (value == "True") {
|
|
|
|
result = true;
|
|
|
|
return true;
|
|
|
|
} else if (value == "False") {
|
|
|
|
result = false;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Config::parseOptionValue(
|
|
|
|
const std::string& value,
|
|
|
|
int32_t& result) {
|
|
|
|
if (value.size() == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Parse sign, don't allow '+'
|
|
|
|
int32_t sign = 1;
|
|
|
|
size_t start = 0;
|
|
|
|
|
|
|
|
if (value[0] == '-') {
|
|
|
|
sign = -1;
|
|
|
|
start = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse absolute number
|
|
|
|
int32_t intval = 0;
|
|
|
|
|
|
|
|
for (size_t i = start; i < value.size(); i++) {
|
|
|
|
if (value[i] < '0' || value[i] > '9')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
intval *= 10;
|
|
|
|
intval += value[i] - '0';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply sign and return
|
|
|
|
result = sign * intval;
|
|
|
|
return true;
|
|
|
|
}
|
2019-01-08 20:57:38 +01:00
|
|
|
|
|
|
|
|
|
|
|
bool Config::parseOptionValue(
|
|
|
|
const std::string& value,
|
|
|
|
Tristate& result) {
|
|
|
|
if (value == "True") {
|
|
|
|
result = Tristate::True;
|
|
|
|
return true;
|
|
|
|
} else if (value == "False") {
|
|
|
|
result = Tristate::False;
|
|
|
|
return true;
|
|
|
|
} else if (value == "Auto") {
|
|
|
|
result = Tristate::Auto;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2018-08-07 14:13:57 +02:00
|
|
|
|
2018-08-07 16:58:16 +02:00
|
|
|
|
|
|
|
Config Config::getAppConfig(const std::string& appName) {
|
2019-08-17 11:46:56 +02:00
|
|
|
auto appConfig = std::find_if(g_appDefaults.begin(), g_appDefaults.end(),
|
|
|
|
[&appName] (const std::pair<const char*, Config>& pair) {
|
|
|
|
std::regex expr(pair.first, std::regex::extended | std::regex::icase);
|
|
|
|
return std::regex_search(appName, expr);
|
|
|
|
});
|
|
|
|
|
2018-09-09 13:46:57 +02:00
|
|
|
if (appConfig != g_appDefaults.end()) {
|
|
|
|
// Inform the user that we loaded a default config
|
2019-08-17 11:46:56 +02:00
|
|
|
Logger::info(str::format("Found built-in config:"));
|
2018-08-07 16:58:16 +02:00
|
|
|
return appConfig->second;
|
2018-09-09 13:46:57 +02:00
|
|
|
}
|
|
|
|
|
2018-08-07 16:58:16 +02:00
|
|
|
return Config();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Config Config::getUserConfig() {
|
|
|
|
Config config;
|
|
|
|
|
|
|
|
// Load either $DXVK_CONFIG_FILE or $PWD/dxvk.conf
|
2018-11-15 17:12:09 -05:00
|
|
|
std::string filePath = env::getEnvVar("DXVK_CONFIG_FILE");
|
2018-08-07 16:58:16 +02:00
|
|
|
|
|
|
|
if (filePath == "")
|
|
|
|
filePath = "dxvk.conf";
|
|
|
|
|
|
|
|
// Open the file if it exists
|
|
|
|
std::ifstream stream(filePath);
|
|
|
|
|
|
|
|
if (!stream)
|
|
|
|
return config;
|
2018-08-17 19:42:32 +02:00
|
|
|
|
|
|
|
// Inform the user that we loaded a file, might
|
|
|
|
// help when debugging configuration issues
|
|
|
|
Logger::info(str::format("Found config file: ", filePath));
|
2018-08-07 16:58:16 +02:00
|
|
|
|
2019-04-26 19:17:32 +02:00
|
|
|
// Initialize parser context
|
|
|
|
ConfigContext ctx;
|
|
|
|
ctx.active = true;
|
|
|
|
|
2018-08-07 16:58:16 +02:00
|
|
|
// Parse the file line by line
|
|
|
|
std::string line;
|
|
|
|
|
|
|
|
while (std::getline(stream, line))
|
2019-04-26 19:17:32 +02:00
|
|
|
parseUserConfigLine(config, ctx, line);
|
2018-08-07 16:58:16 +02:00
|
|
|
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
2018-09-09 13:46:57 +02:00
|
|
|
|
|
|
|
void Config::logOptions() const {
|
|
|
|
if (!m_options.empty()) {
|
|
|
|
Logger::info("Effective configuration:");
|
|
|
|
|
|
|
|
for (auto& pair : m_options)
|
|
|
|
Logger::info(str::format(" ", pair.first, " = ", pair.second));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-08 12:46:21 +02:00
|
|
|
}
|