1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-22 23:52:10 +01:00
dxvk/src/util/config/config.cpp
Philip Rebohle 2c0ddbd072
[util] Enable D3D11_MAP_FLAG_DO_NOT_WAIT for Anno 1800
Removes a sync point and almost doubles performance as a result.
2019-04-12 10:52:25 +02:00

339 lines
9.1 KiB
C++

#include <fstream>
#include <sstream>
#include <iostream>
#include "config.h"
#include "../log/log.h"
#include "../util_env.h"
namespace dxvk {
const static std::unordered_map<std::string, Config> g_appDefaults = {{
/* Anno 1800 */
{ "Anno1800.exe", {{
{ "d3d11.allowMapFlagNoWait", "True" }
}} },
/* Assassin's Creed Syndicate: amdags issues */
{ "ACS.exe", {{
{ "dxgi.customVendorId", "10de" },
}} },
/* Dishonored 2 */
{ "Dishonored2.exe", {{
{ "d3d11.allowMapFlagNoWait", "True" }
}} },
/* Dissidia Final Fantasy NT Free Edition */
{ "dffnt.exe", {{
{ "dxgi.deferSurfaceCreation", "True" },
}} },
/* Elite Dangerous: Compiles weird shaders *
* when running on AMD hardware */
{ "EliteDangerous64.exe", {{
{ "dxgi.customVendorId", "10de" },
}} },
/* The Vanishing of Ethan Carter Redux */
{ "EthanCarter-Win64-Shipping.exe", {{
{ "dxgi.customVendorId", "10de" },
}} },
/* The Evil Within: Submits command lists *
* multiple times */
{ "EvilWithin.exe", {{
{ "d3d11.dcSingleUseMode", "False" },
}} },
/* The Evil Within Demo */
{ "EvilWithinDemo.exe", {{
{ "d3d11.dcSingleUseMode", "False" },
}} },
/* Far Cry 3: Assumes clear(0.5) on an UNORM *
* format to result in 128 on AMD and 127 on *
* Nvidia. Most Vulkan drivers clear to 127, *
* assuming higher values causes artifacts. */
{ "farcry3_d3d11.exe", {{
{ "dxgi.customVendorId", "10de" },
}} },
{ "fc3_blooddragon_d3d11.exe", {{
{ "dxgi.customVendorId", "10de" },
}} },
/* Far Cry 4: Same as Far Cry 3 */
{ "FarCry4.exe", {{
{ "dxgi.customVendorId", "10de" },
}} },
/* Far Cry 5: Avoid CPU <-> GPU sync */
{ "FarCry5.exe", {{
{ "d3d11.allowMapFlagNoWait", "True" }
}} },
/* Far Cry Primal: Nvidia performance */
{ "FCPrimal.exe", {{
{ "dxgi.nvapiHack", "False" },
} }},
/* Frostpunk: Renders one frame with D3D9 *
* after creating the DXGI swap chain */
{ "Frostpunk.exe", {{
{ "dxgi.deferSurfaceCreation", "True" },
}} },
/* Nioh: See Frostpunk, apparently? */
{ "nioh.exe", {{
{ "dxgi.deferSurfaceCreation", "True" },
}} },
/* Quantum Break: Mever initializes shared *
* memory in one of its compute shaders */
{ "QuantumBreak.exe", {{
{ "d3d11.zeroInitWorkgroupMemory", "True" },
}} },
/* Anno 2205: Random crashes with state cache */
{ "anno2205.exe", {{
{ "dxvk.enableStateCache", "False" },
}} },
/* Fifa '19: Binds typed buffer SRV to shader *
* that expects raw/structured buffer SRV */
{ "FIFA19.exe", {{
{ "dxvk.useRawSsbo", "True" },
}} },
/* Final Fantasy XIV: Fix random black blocks */
{ "ffxiv_dx11.exe", {{
{ "d3d11.strictDivision", "True" },
}} },
/* Fifa '19 Demo */
{ "FIFA19_demo.exe", {{
{ "dxvk.useRawSsbo", "True" },
}} },
/* Resident Evil 2: Improve GPU performance */
{ "re2.exe", {{
{ "d3d11.relaxedBarriers", "True" },
}} },
/* Resident Evil 7 */
{ "re7.exe", {{
{ "d3d11.relaxedBarriers", "True" },
}} },
/* Devil May Cry 5 */
{ "DevilMayCry5.exe", {{
{ "d3d11.relaxedBarriers", "True" },
}} },
/* Call of Duty WW2 */
{ "s2_sp64_ship.exe", {{
{ "dxgi.nvapiHack", "False" },
}} },
/* Need for Speed 2015 */
{ "NFS16.exe", {{
{ "dxgi.nvapiHack", "False" },
}} },
/* Mass Effect Andromeda */
{ "MassEffectAndromeda.exe", {{
{ "dxgi.nvapiHack", "False" },
}} },
/* Star Wars Battlefront (2015) */
{ "starwarsbattlefront.exe", {{
{ "dxgi.nvapiHack", "False" },
}} },
/* Star Wars Battlefront (2015) Trial */
{ "starwarsbattlefronttrial.exe", {{
{ "dxgi.nvapiHack", "False" },
}} },
/* Dark Souls Remastered */
{ "DarkSoulsRemastered.exe", {{
{ "d3d11.constantBufferRangeCheck", "True" },
}} },
/* Grim Dawn */
{ "Grim Dawn.exe", {{
{ "d3d11.constantBufferRangeCheck", "True" },
}} },
}};
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;
}
static void parseUserConfigLine(Config& config, const std::string& line) {
std::stringstream key;
std::stringstream value;
// Extract the key
size_t n = skipWhitespace(line, 0);
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++];
config.setOption(key.str(), value.str());
}
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;
}
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;
}
}
Config Config::getAppConfig(const std::string& appName) {
auto appConfig = g_appDefaults.find(appName);
if (appConfig != g_appDefaults.end()) {
// Inform the user that we loaded a default config
Logger::info(str::format("Found built-in config: ", appName));
return appConfig->second;
}
return Config();
}
Config Config::getUserConfig() {
Config config;
// Load either $DXVK_CONFIG_FILE or $PWD/dxvk.conf
std::string filePath = env::getEnvVar("DXVK_CONFIG_FILE");
if (filePath == "")
filePath = "dxvk.conf";
// Open the file if it exists
std::ifstream stream(filePath);
if (!stream)
return config;
// Inform the user that we loaded a file, might
// help when debugging configuration issues
Logger::info(str::format("Found config file: ", filePath));
// Parse the file line by line
std::string line;
while (std::getline(stream, line))
parseUserConfigLine(config, line);
return config;
}
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));
}
}
}