mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-07 16:00:18 +02:00
Instead of having the configuration being loaded and stored in to a frontend system. First moves the backing store of the configuration in to FEXCore. Each layer that is constructed then loads its particular configuration. After the layers are loaded, then a meta layer is constructed that merges the layers flat. This means we will no longer hit the problem where a configuration is stored in the "main" configuration file, then environment and arguments passed manage to overwrite it. The order of the layers going from inner most layer to outer most, with outermost overwriting previous layer configurations is as follows: Main < Global application < Local application < Arguments < Environment One step that needs to be changed in the future is that FEXCore can then just load its configuration from the layers directly since the data is in FEXCore now. This will be reserved for a future change so we are less disruptive.
268 lines
8.0 KiB
C++
268 lines
8.0 KiB
C++
#include "Common/StringConv.h"
|
|
|
|
#include <FEXCore/Utils/LogManager.h>
|
|
#include "Interface/Context/Context.h"
|
|
|
|
#include <FEXCore/Config/Config.h>
|
|
|
|
namespace FEXCore::Config {
|
|
void SetConfig(FEXCore::Context::Context *CTX, ConfigOption Option, uint64_t Config) {
|
|
switch (Option) {
|
|
case FEXCore::Config::CONFIG_MULTIBLOCK:
|
|
CTX->Config.Multiblock = Config != 0;
|
|
break;
|
|
case FEXCore::Config::CONFIG_MAXBLOCKINST:
|
|
CTX->Config.MaxInstPerBlock = Config;
|
|
break;
|
|
case FEXCore::Config::CONFIG_DEFAULTCORE:
|
|
CTX->Config.Core = static_cast<FEXCore::Config::ConfigCore>(Config);
|
|
break;
|
|
case FEXCore::Config::CONFIG_VIRTUALMEMSIZE:
|
|
CTX->Config.VirtualMemSize = Config;
|
|
break;
|
|
case FEXCore::Config::CONFIG_SINGLESTEP:
|
|
CTX->Config.RunningMode = Config != 0 ? FEXCore::Context::CoreRunningMode::MODE_SINGLESTEP : FEXCore::Context::CoreRunningMode::MODE_RUN;
|
|
break;
|
|
case FEXCore::Config::CONFIG_GDBSERVER:
|
|
Config != 0 ? CTX->StartGdbServer() : CTX->StopGdbServer();
|
|
break;
|
|
case FEXCore::Config::CONFIG_UNIFIED_MEMORY:
|
|
CTX->Config.UnifiedMemory = Config != 0;
|
|
break;
|
|
case FEXCore::Config::CONFIG_IS64BIT_MODE:
|
|
CTX->Config.Is64BitMode = Config != 0;
|
|
break;
|
|
case FEXCore::Config::CONFIG_EMULATED_CPU_CORES:
|
|
CTX->Config.EmulatedCPUCores = std::max(1UL, Config);
|
|
break;
|
|
case FEXCore::Config::CONFIG_TSO_ENABLED:
|
|
CTX->Config.TSOEnabled = Config != 0;
|
|
break;
|
|
case FEXCore::Config::CONFIG_SMC_CHECKS:
|
|
CTX->Config.SMCChecks = Config != 0;
|
|
break;
|
|
case FEXCore::Config::CONFIG_ABI_LOCAL_FLAGS:
|
|
CTX->Config.ABILocalFlags = Config != 0;
|
|
break;
|
|
case FEXCore::Config::CONFIG_ABI_NO_PF:
|
|
CTX->Config.ABINoPF = Config != 0;
|
|
break;
|
|
default: LogMan::Msg::A("Unknown configuration option");
|
|
}
|
|
}
|
|
|
|
void SetConfig(FEXCore::Context::Context *CTX, ConfigOption Option, std::string const &Config) {
|
|
switch (Option) {
|
|
case CONFIG_ROOTFSPATH:
|
|
CTX->Config.RootFSPath = Config;
|
|
break;
|
|
case CONFIG_THUNKLIBSPATH:
|
|
CTX->Config.ThunkLibsPath = Config;
|
|
break;
|
|
case FEXCore::Config::CONFIG_DUMPIR:
|
|
CTX->Config.DumpIR = Config;
|
|
break;
|
|
default: LogMan::Msg::A("Unknown configuration option");
|
|
}
|
|
}
|
|
|
|
uint64_t GetConfig(FEXCore::Context::Context *CTX, ConfigOption Option) {
|
|
switch (Option) {
|
|
case FEXCore::Config::CONFIG_MULTIBLOCK:
|
|
return CTX->Config.Multiblock;
|
|
break;
|
|
case FEXCore::Config::CONFIG_MAXBLOCKINST:
|
|
return CTX->Config.MaxInstPerBlock;
|
|
break;
|
|
case FEXCore::Config::CONFIG_DEFAULTCORE:
|
|
return CTX->Config.Core;
|
|
break;
|
|
case FEXCore::Config::CONFIG_VIRTUALMEMSIZE:
|
|
return CTX->Config.VirtualMemSize;
|
|
break;
|
|
case FEXCore::Config::CONFIG_SINGLESTEP:
|
|
return CTX->Config.RunningMode == FEXCore::Context::CoreRunningMode::MODE_SINGLESTEP ? 1 : 0;
|
|
case FEXCore::Config::CONFIG_GDBSERVER:
|
|
return CTX->GetGdbServerStatus();
|
|
break;
|
|
case FEXCore::Config::CONFIG_UNIFIED_MEMORY:
|
|
return CTX->Config.UnifiedMemory;
|
|
break;
|
|
case FEXCore::Config::CONFIG_IS64BIT_MODE:
|
|
return CTX->Config.Is64BitMode;
|
|
break;
|
|
case FEXCore::Config::CONFIG_EMULATED_CPU_CORES:
|
|
return CTX->Config.EmulatedCPUCores;
|
|
break;
|
|
case FEXCore::Config::CONFIG_TSO_ENABLED:
|
|
return CTX->Config.TSOEnabled;
|
|
break;
|
|
case FEXCore::Config::CONFIG_SMC_CHECKS:
|
|
return CTX->Config.SMCChecks;
|
|
break;
|
|
case FEXCore::Config::CONFIG_ABI_LOCAL_FLAGS:
|
|
return CTX->Config.ABILocalFlags;
|
|
break;
|
|
case FEXCore::Config::CONFIG_ABI_NO_PF:
|
|
return CTX->Config.ABINoPF;
|
|
break;
|
|
default: LogMan::Msg::A("Unknown configuration option");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static std::map<FEXCore::Config::LayerType, std::unique_ptr<FEXCore::Config::Layer>> ConfigLayers;
|
|
static FEXCore::Config::Layer *Meta{};
|
|
|
|
constexpr std::array<FEXCore::Config::LayerType, 6> LoadOrder = {
|
|
FEXCore::Config::LayerType::LAYER_MAIN,
|
|
FEXCore::Config::LayerType::LAYER_GLOBAL_APP,
|
|
FEXCore::Config::LayerType::LAYER_LOCAL_APP,
|
|
FEXCore::Config::LayerType::LAYER_ARGUMENTS,
|
|
FEXCore::Config::LayerType::LAYER_ENVIRONMENT,
|
|
FEXCore::Config::LayerType::LAYER_TOP
|
|
};
|
|
|
|
Layer::Layer(const LayerType _Type)
|
|
: Type {_Type} {
|
|
}
|
|
|
|
Layer::~Layer() {
|
|
}
|
|
|
|
class MetaLayer final : public FEXCore::Config::Layer {
|
|
public:
|
|
MetaLayer(const LayerType _Type)
|
|
: FEXCore::Config::Layer (_Type) {
|
|
}
|
|
~MetaLayer() {
|
|
}
|
|
void Load();
|
|
|
|
private:
|
|
void MergeConfigMap(const LayerOptions &Options);
|
|
};
|
|
|
|
void MetaLayer::Load() {
|
|
OptionMap.clear();
|
|
|
|
for (auto CurrentLayer = LoadOrder.begin(); CurrentLayer != LoadOrder.end(); ++CurrentLayer) {
|
|
auto it = ConfigLayers.find(*CurrentLayer);
|
|
if (it != ConfigLayers.end() && *CurrentLayer != Type) {
|
|
// Merge this layer's options to this layer
|
|
MergeConfigMap(it->second->GetOptionMap());
|
|
}
|
|
}
|
|
}
|
|
|
|
void MetaLayer::MergeConfigMap(const LayerOptions &Options) {
|
|
// Insert this layer's options, overlaying previous options that exist here
|
|
for (auto &it : Options) {
|
|
OptionMap.insert_or_assign(it.first, it.second);
|
|
}
|
|
}
|
|
|
|
void Initialize() {
|
|
AddLayer(std::make_unique<MetaLayer>(FEXCore::Config::LayerType::LAYER_TOP));
|
|
Meta = ConfigLayers.begin()->second.get();
|
|
}
|
|
|
|
void Shutdown() {
|
|
ConfigLayers.clear();
|
|
Meta = nullptr;
|
|
}
|
|
|
|
void Load() {
|
|
for (auto CurrentLayer = LoadOrder.begin(); CurrentLayer != LoadOrder.end(); ++CurrentLayer) {
|
|
auto it = ConfigLayers.find(*CurrentLayer);
|
|
if (it != ConfigLayers.end()) {
|
|
it->second->Load();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReloadMetaLayer() {
|
|
Meta->Load();
|
|
}
|
|
|
|
void AddLayer(std::unique_ptr<FEXCore::Config::Layer> _Layer) {
|
|
ConfigLayers.emplace(_Layer->GetLayerType(), std::move(_Layer));
|
|
}
|
|
|
|
bool Exists(ConfigOption Option) {
|
|
return Meta->OptionExists(Option);
|
|
}
|
|
|
|
std::optional<LayerValue*> All(ConfigOption Option) {
|
|
return Meta->All(Option);
|
|
}
|
|
|
|
std::optional<std::string*> Get(ConfigOption Option) {
|
|
return Meta->Get(Option);
|
|
}
|
|
|
|
void Set(ConfigOption Option, std::string Data) {
|
|
Meta->Set(Option, Data);
|
|
}
|
|
|
|
void EraseSet(ConfigOption Option, std::string Data) {
|
|
Meta->EraseSet(Option, Data);
|
|
}
|
|
|
|
template<typename T>
|
|
T Value<T>::Get(FEXCore::Config::ConfigOption Option) {
|
|
T Result;
|
|
auto Value = FEXCore::Config::Get(Option);
|
|
|
|
if (!FEXCore::StrConv::Conv(**Value, &Result)) {
|
|
assert(0 && "Attempted to convert invalid value");
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
template<typename T>
|
|
T Value<T>::GetIfExists(FEXCore::Config::ConfigOption Option, T Default) {
|
|
T Result;
|
|
auto Value = FEXCore::Config::Get(Option);
|
|
|
|
if (Value && FEXCore::StrConv::Conv(**Value, &Result)) {
|
|
return Result;
|
|
}
|
|
else {
|
|
return Default;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
std::string Value<std::string>::GetIfExists(FEXCore::Config::ConfigOption Option, std::string Default) {
|
|
auto Value = FEXCore::Config::Get(Option);
|
|
if (Value) {
|
|
return **Value;
|
|
}
|
|
else {
|
|
return Default;
|
|
}
|
|
}
|
|
|
|
template bool Value<bool>::GetIfExists(FEXCore::Config::ConfigOption Option, bool Default);
|
|
template uint8_t Value<uint8_t>::GetIfExists(FEXCore::Config::ConfigOption Option, uint8_t Default);
|
|
template uint64_t Value<uint64_t>::GetIfExists(FEXCore::Config::ConfigOption Option, uint64_t Default);
|
|
|
|
// Constructor
|
|
template Value<std::string>::Value(FEXCore::Config::ConfigOption _Option, std::string Default);
|
|
template Value<bool>::Value(FEXCore::Config::ConfigOption _Option, bool Default);
|
|
template Value<uint8_t>::Value(FEXCore::Config::ConfigOption _Option, uint8_t Default);
|
|
template Value<uint64_t>::Value(FEXCore::Config::ConfigOption _Option, uint64_t Default);
|
|
|
|
template<typename T>
|
|
void Value<T>::GetListIfExists(FEXCore::Config::ConfigOption Option, std::list<std::string> *List) {
|
|
auto Value = FEXCore::Config::All(Option);
|
|
List->clear();
|
|
if (Value) {
|
|
*List = **Value;
|
|
}
|
|
}
|
|
}
|
|
|