Configuration simplified

This commit is contained in:
Nekotekina 2017-05-20 14:45:02 +03:00
parent d5107aab47
commit f010b5b235
46 changed files with 1018 additions and 904 deletions

View file

@ -7,7 +7,7 @@ namespace cfg
{
logs::channel cfg("CFG");
entry_base::entry_base(type _type)
_base::_base(type _type)
: m_type(_type)
{
if (_type != type::node)
@ -16,51 +16,36 @@ namespace cfg
}
}
entry_base::entry_base(type _type, node& owner, const std::string& name)
_base::_base(type _type, node* owner, const std::string& name)
: m_type(_type)
{
if (!owner.m_nodes.emplace(name, this).second)
for (const auto& pair : owner->m_nodes)
{
fmt::throw_exception<std::logic_error>("Node already exists: %s" HERE, name);
}
}
entry_base& entry_base::operator[](const std::string& name) const
{
if (m_type == type::node)
{
return *static_cast<const node&>(*this).m_nodes.at(name);
if (pair.first == name)
{
fmt::throw_exception<std::logic_error>("Node already exists: %s" HERE, name);
}
}
fmt::throw_exception<std::logic_error>("Invalid node type" HERE);
owner->m_nodes.emplace_back(name, this);
}
entry_base& entry_base::operator[](const char* name) const
{
if (m_type == type::node)
{
return *static_cast<const node&>(*this).m_nodes.at(name);
}
fmt::throw_exception<std::logic_error>("Invalid node type" HERE);
}
bool entry_base::from_string(const std::string&)
bool _base::from_string(const std::string&)
{
fmt::throw_exception<std::logic_error>("from_string() purecall" HERE);
}
bool entry_base::from_list(std::vector<std::string>&&)
bool _base::from_list(std::vector<std::string>&&)
{
fmt::throw_exception<std::logic_error>("from_list() purecall" HERE);
}
// Emit YAML
static void encode(YAML::Emitter& out, const class entry_base& rhs);
static void encode(YAML::Emitter& out, const class _base& rhs);
// Incrementally load config entries from YAML::Node.
// The config value is preserved if the corresponding YAML node doesn't exist.
static void decode(const YAML::Node& data, class entry_base& rhs);
static void decode(const YAML::Node& data, class _base& rhs);
}
bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
@ -151,7 +136,7 @@ std::vector<std::string> cfg::try_to_enum_list(decltype(&fmt_class_string<int>::
return result;
}
void cfg::encode(YAML::Emitter& out, const cfg::entry_base& rhs)
void cfg::encode(YAML::Emitter& out, const cfg::_base& rhs)
{
switch (rhs.get_type())
{
@ -197,7 +182,7 @@ void cfg::encode(YAML::Emitter& out, const cfg::entry_base& rhs)
out << rhs.to_string();
}
void cfg::decode(const YAML::Node& data, cfg::entry_base& rhs)
void cfg::decode(const YAML::Node& data, cfg::_base& rhs)
{
switch (rhs.get_type())
{
@ -213,15 +198,12 @@ void cfg::decode(const YAML::Node& data, cfg::entry_base& rhs)
if (!pair.first.IsScalar()) continue;
// Find the key among existing nodes
const auto found = static_cast<node&>(rhs).get_nodes().find(pair.first.Scalar());
if (found != static_cast<node&>(rhs).get_nodes().cend())
for (const auto& _pair : static_cast<node&>(rhs).get_nodes())
{
decode(pair.second, *found->second);
}
else
{
// ???
if (_pair.first == pair.first.Scalar())
{
decode(pair.second, *_pair.second);
}
}
}
@ -297,19 +279,18 @@ void cfg::node::from_default()
}
}
void cfg::bool_entry::from_default()
void cfg::_bool::from_default()
{
value = def;
m_value = def;
}
void cfg::string_entry::from_default()
void cfg::string::from_default()
{
*this = def;
m_value = def;
}
void cfg::set_entry::from_default()
{
std::lock_guard<std::mutex> lock(m_mutex);
m_set = {};
}
@ -327,10 +308,3 @@ void cfg::log_entry::from_default()
{
set_map({});
}
cfg::root_node& cfg::get_root()
{
// Magic static
static root_node root;
return root;
}

View file

@ -1,19 +1,14 @@
#pragma once
#include "Utilities/types.h"
#include "Utilities/Atomic.h"
#include "Utilities/StrFmt.h"
#include "Utilities/Log.h"
#include <initializer_list>
#include <exception>
#include <utility>
#include <string>
#include <vector>
#include <set>
#include <unordered_map>
#include <map>
#include <mutex>
namespace cfg
{
@ -30,37 +25,33 @@ namespace cfg
enum class type : uint
{
node = 0, // cfg::node type
boolean, // cfg::bool_entry type
fixed_map, // cfg::map_entry type
enumeration, // cfg::enum_entry type
integer, // cfg::int_entry type
string, // cfg::string_entry type
_bool, // cfg::_bool type
_enum, // cfg::_enum type
_int, // cfg::_int type
string, // cfg::string type
set, // cfg::set_entry type
log,
};
// Config tree entry abstract base class
class entry_base
class _base
{
const type m_type;
protected:
// Ownerless entry constructor
entry_base(type _type);
_base(type _type);
// Owned entry constructor
entry_base(type _type, class node& owner, const std::string& name);
_base(type _type, class node* owner, const std::string& name);
public:
// Disallow copy/move constructors and assignments
entry_base(const entry_base&) = delete;
_base(const _base&) = delete;
// Get type
type get_type() const { return m_type; }
// Access child node (must exist)
entry_base& operator [](const std::string& name) const; entry_base& operator [](const char* name) const;
// Reset defaults
virtual void from_default() = 0;
@ -84,27 +75,27 @@ namespace cfg
};
// Config tree node which contains another nodes
class node : public entry_base
class node : public _base
{
std::map<std::string, entry_base*> m_nodes;
std::vector<std::pair<std::string, _base*>> m_nodes;
friend class entry_base;
friend class _base;
public:
// Root node constructor
node()
: entry_base(type::node)
: _base(type::node)
{
}
// Registered node constructor
node(node& owner, const std::string& name)
: entry_base(type::node, owner, name)
node(node* owner, const std::string& name)
: _base(type::node, owner, name)
{
}
// Get child nodes
const std::map<std::string, entry_base*>& get_nodes() const
const auto& get_nodes() const
{
return m_nodes;
}
@ -119,43 +110,38 @@ namespace cfg
void from_default() override;
};
struct bool_entry final : public entry_base
class _bool final : public _base
{
atomic_t<bool> value;
bool m_value;
public:
const bool def;
bool_entry(node& owner, const std::string& name, bool def = false)
: entry_base(type::boolean, owner, name)
, value(def)
_bool(node* owner, const std::string& name, bool def = false)
: _base(type::_bool, owner, name)
, m_value(def)
, def(def)
{
}
explicit operator bool() const
{
return value.load();
}
bool_entry& operator =(bool value)
{
value = value;
return *this;
return m_value;
}
void from_default() override;
std::string to_string() const override
{
return value.load() ? "true" : "false";
return m_value ? "true" : "false";
}
bool from_string(const std::string& value) override
{
if (value == "false")
this->value = false;
m_value = false;
else if (value == "true")
this->value = true;
m_value = true;
else
return false;
@ -163,116 +149,17 @@ namespace cfg
}
};
// Value node with fixed set of possible values, each maps to a value of type T.
template<typename T>
struct map_entry final : public entry_base
{
using init_type = std::initializer_list<std::pair<std::string, T>>;
using map_type = std::unordered_map<std::string, T>;
using list_type = std::vector<std::string>;
using value_type = typename map_type::value_type;
static map_type make_map(init_type init)
{
map_type map(init.size());
for (const auto& v : init)
{
// Ensure elements are unique
verify(HERE), map.emplace(v.first, v.second).second;
}
return map;
}
static list_type make_list(init_type init)
{
list_type list; list.reserve(init.size());
for (const auto& v : init)
{
list.emplace_back(v.first);
}
return list;
}
public:
const map_type map;
const list_type list; // Element list sorted in original order
const value_type& def; // Pointer to the default value
private:
atomic_t<const value_type*> m_value;
public:
map_entry(node& owner, const std::string& name, const std::string& def, init_type init)
: entry_base(type::fixed_map, owner, name)
, map(make_map(init))
, list(make_list(init))
, def(*map.find(def))
, m_value(&this->def)
{
}
map_entry(node& owner, const std::string& name, std::size_t def_index, init_type init)
: map_entry(owner, name, (init.begin() + (def_index < init.size() ? def_index : 0))->first, init)
{
}
map_entry(node& owner, const std::string& name, init_type init)
: map_entry(owner, name, 0, init)
{
}
const T& get() const
{
return m_value.load()->second;
}
void from_default() override
{
m_value = &def;
}
std::string to_string() const override
{
return m_value.load()->first;
}
bool from_string(const std::string& value) override
{
const auto found = map.find(value);
if (found == map.end())
{
return false;
}
else
{
m_value = &*found;
return true;
}
}
std::vector<std::string> to_list() const override
{
return list;
}
};
// Value node with fixed set of possible values, each maps to an enum value of type T.
template<typename T, bool External = false>
class enum_entry final : public entry_base
template <typename T>
class _enum final : public _base
{
// Value or reference
std::conditional_t<External, atomic_t<T>&, atomic_t<T>> m_value;
T m_value;
public:
const T def;
enum_entry(node& owner, const std::string& name, std::conditional_t<External, atomic_t<T>&, T> value)
: entry_base(type::enumeration, owner, name)
_enum(node* owner, const std::string& name, T value = {})
: _base(type::_enum, owner, name)
, m_value(value)
, def(value)
{
@ -280,13 +167,7 @@ namespace cfg
operator T() const
{
return m_value.load();
}
enum_entry& operator =(T value)
{
m_value = value;
return *this;
return m_value;
}
void from_default() override
@ -322,21 +203,21 @@ namespace cfg
};
// Signed 32/64-bit integer entry with custom Min/Max range.
template<s64 Min, s64 Max>
class int_entry final : public entry_base
template <s64 Min, s64 Max>
class _int final : public _base
{
static_assert(Min < Max, "Invalid cfg::int_entry range");
static_assert(Min < Max, "Invalid cfg::_int range");
// Prefer 32 bit type if possible
using int_type = std::conditional_t<Min >= INT32_MIN && Max <= INT32_MAX, s32, s64>;
atomic_t<int_type> m_value;
int_type m_value;
public:
const int_type def;
int_entry(node& owner, const std::string& name, int_type def = std::min<int_type>(Max, std::max<int_type>(Min, 0)))
: entry_base(type::integer, owner, name)
_int(node* owner, const std::string& name, int_type def = std::min<int_type>(Max, std::max<int_type>(Min, 0)))
: _base(type::_int, owner, name)
, m_value(def)
, def(def)
{
@ -344,18 +225,7 @@ namespace cfg
operator int_type() const
{
return m_value.load();
}
int_entry& operator =(int_type value)
{
if (value < Min || value > Max)
{
fmt::throw_exception("Value out of the valid range: %lld" HERE, s64{ value });
}
m_value = value;
return *this;
return m_value;
}
void from_default() override
@ -365,7 +235,7 @@ namespace cfg
std::string to_string() const override
{
return std::to_string(m_value.load());
return std::to_string(m_value);
}
bool from_string(const std::string& value) override
@ -382,22 +252,21 @@ namespace cfg
};
// Alias for 32 bit int
using int32_entry = int_entry<INT32_MIN, INT32_MAX>;
using int32 = _int<INT32_MIN, INT32_MAX>;
// Alias for 64 bit int
using int64_entry = int_entry<INT64_MIN, INT64_MAX>;
using int64 = _int<INT64_MIN, INT64_MAX>;
// Simple string entry with mutex
class string_entry final : public entry_base
class string final : public _base
{
mutable std::mutex m_mutex;
std::string m_value;
public:
const std::string def;
string_entry(node& owner, const std::string& name, const std::string& def = {})
: entry_base(type::string, owner, name)
string(node* owner, const std::string& name, const std::string& def = {})
: _base(type::string, owner, name)
, m_value(def)
, def(def)
{
@ -405,25 +274,16 @@ namespace cfg
operator std::string() const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_value;
}
std::string get() const
const std::string& get() const
{
return *this;
}
string_entry& operator =(const std::string& value)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_value = value;
return *this;
return m_value;
}
std::size_t size() const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_value.size();
}
@ -431,41 +291,35 @@ namespace cfg
std::string to_string() const override
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_value;
}
bool from_string(const std::string& value) override
{
*this = value;
m_value = value;
return true;
}
};
// Simple set entry with mutex (TODO: template for various types)
class set_entry final : public entry_base
class set_entry final : public _base
{
mutable std::mutex m_mutex;
std::set<std::string> m_set;
public:
// Default value is empty list in current implementation
set_entry(node& owner, const std::string& name)
: entry_base(type::set, owner, name)
set_entry(node* owner, const std::string& name)
: _base(type::set, owner, name)
{
}
std::set<std::string> get_set() const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_set;
}
void set_set(std::set<std::string>&& set)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_set = std::move(set);
}
@ -473,27 +327,24 @@ namespace cfg
std::vector<std::string> to_list() const override
{
std::lock_guard<std::mutex> lock(m_mutex);
return{ m_set.begin(), m_set.end() };
}
bool from_list(std::vector<std::string>&& list) override
{
std::lock_guard<std::mutex> lock(m_mutex);
m_set = { std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()) };
return true;
}
};
class log_entry final : public entry_base
class log_entry final : public _base
{
std::map<std::string, logs::level> m_map;
public:
log_entry(node& owner, const std::string& name)
: entry_base(type::log, owner, name)
log_entry(node* owner, const std::string& name)
: _base(type::log, owner, name)
{
}
@ -506,25 +357,4 @@ namespace cfg
void from_default() override;
};
// Root type with some predefined nodes. Don't change it, this is not mandatory for adding nodes.
struct root_node : node
{
node core {*this, "Core"};
node vfs {*this, "VFS"};
node video {*this, "Video"};
node audio {*this, "Audio"};
node io {*this, "Input/Output"};
node sys {*this, "System"};
node net {*this, "Net"};
node misc {*this, "Miscellaneous"};
log_entry log{*this, "Log"};
};
// Get global configuration root instance
extern root_node& get_root();
// Global configuration root instance (cached reference)
static root_node& root = get_root();
}

View file

@ -3,7 +3,6 @@
#include "GDBDebugServer.h"
#include "Log.h"
#include "Config.h"
#include <algorithm>
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
@ -65,8 +64,6 @@ bool check_errno_again() {
#endif
}
cfg::int_entry<1, 65535> g_cfg_gdb_server_port(cfg::root.misc, "Port", 2345);
std::string u32_to_hex(u32 i) {
return fmt::format("%" HEX_U32, i);
}
@ -119,7 +116,7 @@ void GDBDebugServer::start_server()
sockaddr_in server_saddr;
server_saddr.sin_family = AF_INET;
int port = g_cfg_gdb_server_port;
int port = g_cfg.misc.gdb_server_port;
server_saddr.sin_port = htons(port);
server_saddr.sin_addr.s_addr = htonl(INADDR_ANY);

View file

@ -1,12 +1,8 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "OpenALThread.h"
extern cfg::bool_entry g_cfg_audio_convert_to_u16;
extern cfg::bool_entry g_cfg_audio_downmix_to_2ch;
#ifdef _MSC_VER
#pragma comment(lib, "OpenAL32.lib")
#endif
@ -46,13 +42,13 @@ OpenALThread::OpenALThread()
alcMakeContextCurrent(m_context);
checkForAlcError("alcMakeContextCurrent");
if (g_cfg_audio_downmix_to_2ch)
if (g_cfg.audio.downmix_to_2ch)
{
m_format = g_cfg_audio_convert_to_u16 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
m_format = g_cfg.audio.convert_to_u16 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
}
else
{
m_format = g_cfg_audio_convert_to_u16 ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32;
m_format = g_cfg.audio.convert_to_u16 ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32;
}
}

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Utilities/GSL.h"
#include "Emu/System.h"
@ -9,10 +8,7 @@
#include <alsa/asoundlib.h>
extern cfg::bool_entry g_cfg_audio_convert_to_u16;
extern cfg::bool_entry g_cfg_audio_downmix_to_2ch;
thread_local static snd_pcm_t* s_tls_handle{nullptr};
static thread_local snd_pcm_t* s_tls_handle{nullptr};
static void error(int err, const char* reason)
{
@ -54,13 +50,13 @@ ALSAThread::ALSAThread()
if (!check(snd_pcm_hw_params_set_access(s_tls_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
return;
if (!check(snd_pcm_hw_params_set_format(s_tls_handle, hw_params, g_cfg_audio_convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
if (!check(snd_pcm_hw_params_set_format(s_tls_handle, hw_params, g_cfg.audio.convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
return;
if (!check(snd_pcm_hw_params_set_rate(s_tls_handle, hw_params, 48000, 0), "snd_pcm_hw_params_set_rate_near"))
return;
if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, hw_params, g_cfg_audio_downmix_to_2ch ? 2 : 8), "snd_pcm_hw_params_set_channels"))
if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, hw_params, g_cfg.audio.downmix_to_2ch ? 2 : 8), "snd_pcm_hw_params_set_channels"))
return;
if (!check(snd_pcm_hw_params_set_buffer_size(s_tls_handle, hw_params, 8 * 256), "snd_pcm_hw_params_set_buffer_size"))
@ -106,8 +102,8 @@ void ALSAThread::Open(const void* src, int size)
void ALSAThread::AddData(const void* src, int size)
{
size /= g_cfg_audio_convert_to_u16 ? 2 : 4;
size /= g_cfg_audio_downmix_to_2ch ? 2 : 8;
size /= g_cfg.audio.convert_to_u16 ? 2 : 4;
size /= g_cfg.audio.downmix_to_2ch ? 2 : 8;
int res;

View file

@ -2,15 +2,11 @@
#include "Utilities/Log.h"
#include "Utilities/StrFmt.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "XAudio2Thread.h"
#include "3rdparty/XAudio2_7/XAudio2.h"
extern cfg::bool_entry g_cfg_audio_convert_to_u16;
extern cfg::bool_entry g_cfg_audio_downmix_to_2ch;
static thread_local HMODULE s_tls_xaudio2_lib{};
static thread_local IXAudio2* s_tls_xaudio2_instance{};
static thread_local IXAudio2MasteringVoice* s_tls_master_voice{};
@ -38,7 +34,7 @@ void XAudio2Thread::xa27_init(void* lib2_7)
return;
}
hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg_audio_downmix_to_2ch ? 2 : 8, 48000);
hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
if (FAILED(hr))
{
LOG_ERROR(GENERAL, "XAudio2Thread : CreateMasteringVoice() failed(0x%08x)", (u32)hr);
@ -105,11 +101,11 @@ void XAudio2Thread::xa27_open()
{
HRESULT hr;
WORD sample_size = g_cfg_audio_convert_to_u16 ? sizeof(u16) : sizeof(float);
WORD channels = g_cfg_audio_downmix_to_2ch ? 2 : 8;
WORD sample_size = g_cfg.audio.convert_to_u16 ? sizeof(u16) : sizeof(float);
WORD channels = g_cfg.audio.downmix_to_2ch ? 2 : 8;
WAVEFORMATEX waveformatex;
waveformatex.wFormatTag = g_cfg_audio_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = channels;
waveformatex.nSamplesPerSec = 48000;
waveformatex.nAvgBytesPerSec = 48000 * (DWORD)channels * (DWORD)sample_size;
@ -125,7 +121,7 @@ void XAudio2Thread::xa27_open()
return;
}
s_tls_source_voice->SetVolume(g_cfg_audio_downmix_to_2ch ? 1.0 : 4.0);
s_tls_source_voice->SetVolume(g_cfg.audio.downmix_to_2ch ? 1.0 : 4.0);
}
void XAudio2Thread::xa27_add(const void* src, int size)

View file

@ -2,15 +2,11 @@
#include "Utilities/Log.h"
#include "Utilities/StrFmt.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "XAudio2Thread.h"
#include "3rdparty/minidx12/Include/xaudio2.h"
extern cfg::bool_entry g_cfg_audio_convert_to_u16;
extern cfg::bool_entry g_cfg_audio_downmix_to_2ch;
static thread_local HMODULE s_tls_xaudio2_lib{};
static thread_local IXAudio2* s_tls_xaudio2_instance{};
static thread_local IXAudio2MasteringVoice* s_tls_master_voice{};
@ -40,7 +36,7 @@ void XAudio2Thread::xa28_init(void* lib)
return;
}
hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg_audio_downmix_to_2ch ? 2 : 8, 48000);
hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
if (FAILED(hr))
{
LOG_ERROR(GENERAL, "XAudio2Thread : CreateMasteringVoice() failed(0x%08x)", (u32)hr);
@ -107,11 +103,11 @@ void XAudio2Thread::xa28_open()
{
HRESULT hr;
WORD sample_size = g_cfg_audio_convert_to_u16 ? sizeof(u16) : sizeof(float);
WORD channels = g_cfg_audio_downmix_to_2ch ? 2 : 8;
WORD sample_size = g_cfg.audio.convert_to_u16 ? sizeof(u16) : sizeof(float);
WORD channels = g_cfg.audio.downmix_to_2ch ? 2 : 8;
WAVEFORMATEX waveformatex;
waveformatex.wFormatTag = g_cfg_audio_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = channels;
waveformatex.nSamplesPerSec = 48000;
waveformatex.nAvgBytesPerSec = 48000 * (DWORD)channels * (DWORD)sample_size;
@ -127,7 +123,7 @@ void XAudio2Thread::xa28_open()
return;
}
s_tls_source_voice->SetVolume(g_cfg_audio_downmix_to_2ch ? 1.0 : 4.0);
s_tls_source_voice->SetVolume(g_cfg.audio.downmix_to_2ch ? 1.0 : 4.0);
}
void XAudio2Thread::xa28_add(const void* src, int size)

View file

@ -4,7 +4,6 @@
#include "CPUThread.h"
#include "Emu/IdManager.h"
#include "Utilities/GDBDebugServer.h"
#include "Utilities/Config.h"
#ifdef _WIN32
#include <Windows.h>

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
@ -13,10 +12,6 @@
logs::channel cellAudio("cellAudio");
cfg::bool_entry g_cfg_audio_dump_to_file(cfg::root.audio, "Dump to file");
cfg::bool_entry g_cfg_audio_convert_to_u16(cfg::root.audio, "Convert to 16 bit");
cfg::bool_entry g_cfg_audio_downmix_to_2ch(cfg::root.audio, "Downmix to Stereo", true);
void audio_config::on_init(const std::shared_ptr<void>& _this)
{
m_buffer.set(vm::alloc(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, vm::main));
@ -34,12 +29,12 @@ void audio_config::on_init(const std::shared_ptr<void>& _this)
void audio_config::on_task()
{
AudioDumper m_dump(g_cfg_audio_dump_to_file ? 2 : 0); // Init AudioDumper for 2 channels if enabled
AudioDumper m_dump(g_cfg.audio.dump_to_file ? 2 : 0); // Init AudioDumper for 2 channels if enabled
float buf2ch[2 * BUFFER_SIZE]{}; // intermediate buffer for 2 channels
float buf8ch[8 * BUFFER_SIZE]{}; // intermediate buffer for 8 channels
const u32 buf_sz = BUFFER_SIZE * (g_cfg_audio_convert_to_u16 ? 2 : 4) * (g_cfg_audio_downmix_to_2ch ? 2 : 8);
const u32 buf_sz = BUFFER_SIZE * (g_cfg.audio.convert_to_u16 ? 2 : 4) * (g_cfg.audio.downmix_to_2ch ? 2 : 8);
std::unique_ptr<float[]> out_buffer[BUFFER_NUM];
@ -227,7 +222,7 @@ void audio_config::on_task()
if (!first_mix)
{
// Copy output data (2ch or 8ch)
if (g_cfg_audio_downmix_to_2ch)
if (g_cfg.audio.downmix_to_2ch)
{
for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++)
{
@ -250,7 +245,7 @@ void audio_config::on_task()
std::memset(out_buffer[out_pos].get(), 0, 8 * BUFFER_SIZE * sizeof(float));
}
if (g_cfg_audio_convert_to_u16)
if (g_cfg.audio.convert_to_u16)
{
// convert the data from float to u16 with clipping:
// 2x MULPS

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
@ -8,19 +7,37 @@
logs::channel cellCamera("cellCamera");
cfg::map_entry<bool> g_cfg_camera(cfg::root.io, "Camera",
template <>
void fmt_class_string<camera_handler>::format(std::string& out, u64 arg)
{
{ "Null", false },
{ "Fake", true },
});
format_enum(out, arg, [](auto value)
{
switch (value)
{
case camera_handler::null: return "Null";
case camera_handler::fake: return "Fake";
}
cfg::map_entry<CellCameraType> g_cfg_camera_type(cfg::root.io, "Camera type",
return unknown;
});
}
template <>
void fmt_class_string<fake_camera_type>::format(std::string& out, u64 arg)
{
{ "Unknown", CELL_CAMERA_TYPE_UNKNOWN },
{ "EyeToy", CELL_CAMERA_EYETOY },
{ "PS Eye", CELL_CAMERA_EYETOY2 },
{ "UVC 1.1", CELL_CAMERA_USBVIDEOCLASS },
});
format_enum(out, arg, [](auto value)
{
switch (value)
{
case fake_camera_type::unknown: return "Unknown";
case fake_camera_type::eyetoy: return "EyeToy";
case fake_camera_type::eyetoy2: return "PS Eye";
case fake_camera_type::uvc1_1: return "UVC 1.1";
}
return unknown;
});
}
static const char* get_camera_attr_name(s32 value)
{
@ -95,7 +112,7 @@ s32 cellCameraInit()
{
cellCamera.warning("cellCameraInit()");
if (!g_cfg_camera.get())
if (g_cfg.io.camera == camera_handler::null)
{
return CELL_CAMERA_ERROR_DEVICE_NOT_FOUND;
}
@ -107,9 +124,9 @@ s32 cellCameraInit()
return CELL_CAMERA_ERROR_ALREADY_INIT;
}
switch (g_cfg_camera_type.get())
switch (g_cfg.io.camera_type)
{
case CELL_CAMERA_EYETOY:
case fake_camera_type::eyetoy:
{
camera->attr[CELL_CAMERA_SATURATION] = { 164 };
camera->attr[CELL_CAMERA_BRIGHTNESS] = { 96 };
@ -125,10 +142,10 @@ s32 cellCameraInit()
camera->attr[CELL_CAMERA_MIRRORFLAG] = { 1 };
camera->attr[CELL_CAMERA_422FLAG] = { 1 };
camera->attr[CELL_CAMERA_USBLOAD] = { 4 };
break;
}
break;
case CELL_CAMERA_EYETOY2:
case fake_camera_type::eyetoy2:
{
camera->attr[CELL_CAMERA_SATURATION] = { 64 };
camera->attr[CELL_CAMERA_BRIGHTNESS] = { 8 };
@ -145,11 +162,8 @@ s32 cellCameraInit()
camera->attr[CELL_CAMERA_PIXELOUTLIERFILTER] = { 1 };
camera->attr[CELL_CAMERA_AGCLOW] = { 48 };
camera->attr[CELL_CAMERA_AGCHIGH] = { 64 };
break;
}
break;
default: break;
}
// TODO: Some other default attributes? Need to check the actual behaviour on a real PS3.
@ -204,7 +218,14 @@ s32 cellCameraGetType(s32 dev_num, vm::ptr<s32> type)
return CELL_CAMERA_ERROR_NOT_INIT;
}
*type = g_cfg_camera_type.get();
switch (g_cfg.io.camera_type)
{
case fake_camera_type::unknown: *type = CELL_CAMERA_TYPE_UNKNOWN; break;
case fake_camera_type::eyetoy: *type = CELL_CAMERA_EYETOY; break;
case fake_camera_type::eyetoy2: *type = CELL_CAMERA_EYETOY2; break;
case fake_camera_type::uvc1_1: *type = CELL_CAMERA_USBVIDEOCLASS; break;
}
return CELL_OK;
}
@ -218,7 +239,7 @@ s32 cellCameraIsAttached(s32 dev_num)
{
cellCamera.warning("cellCameraIsAttached(dev_num=%d)", dev_num);
if (g_cfg_camera.get())
if (g_cfg.io.camera == camera_handler::fake)
{
return 1;
}

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
@ -11,7 +10,7 @@
logs::channel cellNetCtl("cellNetCtl");
template<>
template <>
void fmt_class_string<CellNetCtlError>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](auto error)
@ -69,15 +68,22 @@ void fmt_class_string<CellNetCtlError>::format(std::string& out, u64 arg)
});
}
cfg::map_entry<s32> g_cfg_net_status(cfg::root.net, "Connection status",
template <>
void fmt_class_string<CellNetCtlState>::format(std::string& out, u64 arg)
{
{ "Disconnected", CELL_NET_CTL_STATE_Disconnected },
{ "Connecting", CELL_NET_CTL_STATE_Connecting },
{ "Obtaining IP", CELL_NET_CTL_STATE_IPObtaining },
{ "IP Obtained", CELL_NET_CTL_STATE_IPObtained },
});
format_enum(out, arg, [](CellNetCtlState value)
{
switch (value)
{
case CELL_NET_CTL_STATE_Disconnected: return "Disconnected";
case CELL_NET_CTL_STATE_Connecting: return "Connecting";
case CELL_NET_CTL_STATE_IPObtaining: return "Obtaining IP";
case CELL_NET_CTL_STATE_IPObtained: return "IP Obtained";
}
cfg::string_entry g_cfg_net_ip_address(cfg::root.net, "IP address", "192.168.1.1");
return unknown;
});
}
error_code cellNetCtlInit()
{
@ -97,7 +103,7 @@ error_code cellNetCtlGetState(vm::ptr<u32> state)
{
cellNetCtl.trace("cellNetCtlGetState(state=*0x%x)", state);
*state = g_cfg_net_status.get();
*state = g_cfg.net.net_status;
return CELL_OK;
}
@ -125,7 +131,7 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
}
else if (code == CELL_NET_CTL_INFO_LINK)
{
if (g_cfg_net_status.get() != CELL_NET_CTL_STATE_Disconnected)
if (g_cfg.net.net_status != CELL_NET_CTL_STATE_Disconnected)
{
info->link = CELL_NET_CTL_LINK_CONNECTED;
}
@ -136,14 +142,14 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
}
else if (code == CELL_NET_CTL_INFO_IP_ADDRESS)
{
if (g_cfg_net_status.get() != CELL_NET_CTL_STATE_IPObtained)
if (g_cfg.net.net_status != CELL_NET_CTL_STATE_IPObtained)
{
// 0.0.0.0 seems to be the default address when no ethernet cables are connected to the PS3
strcpy_trunc(info->ip_address, "0.0.0.0");
}
else
{
strcpy_trunc(info->ip_address, g_cfg_net_ip_address);
strcpy_trunc(info->ip_address, g_cfg.net.ip_address);
}
}
else if (code == CELL_NET_CTL_INFO_NETMASK)

View file

@ -53,7 +53,7 @@ enum CellNetCtlError : u32
};
// Network connection states
enum
enum CellNetCtlState : s32
{
CELL_NET_CTL_STATE_Disconnected = 0,
CELL_NET_CTL_STATE_Connecting = 1,

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
@ -68,34 +67,43 @@ extern void sysutil_send_system_cmd(u64 status, u64 param)
}
}
cfg::map_entry<s32> g_cfg_sys_language(cfg::root.sys, "Language",
template <>
void fmt_class_string<CellSysutilLang>::format(std::string& out, u64 arg)
{
{ "Japanese", CELL_SYSUTIL_LANG_JAPANESE },
{ "English (US)", CELL_SYSUTIL_LANG_ENGLISH_US },
{ "French", CELL_SYSUTIL_LANG_FRENCH },
{ "Spanish", CELL_SYSUTIL_LANG_SPANISH },
{ "German", CELL_SYSUTIL_LANG_GERMAN },
{ "Italian", CELL_SYSUTIL_LANG_ITALIAN },
{ "Dutch", CELL_SYSUTIL_LANG_DUTCH },
{ "Portuguese (PT)", CELL_SYSUTIL_LANG_PORTUGUESE_PT },
{ "Russian", CELL_SYSUTIL_LANG_RUSSIAN },
{ "Korean", CELL_SYSUTIL_LANG_KOREAN },
{ "Chinese (Trad.)", CELL_SYSUTIL_LANG_CHINESE_T },
{ "Chinese (Simp.)", CELL_SYSUTIL_LANG_CHINESE_S },
{ "Finnish", CELL_SYSUTIL_LANG_FINNISH },
{ "Swedish", CELL_SYSUTIL_LANG_SWEDISH },
{ "Danish", CELL_SYSUTIL_LANG_DANISH },
{ "Norwegian", CELL_SYSUTIL_LANG_NORWEGIAN },
{ "Polish", CELL_SYSUTIL_LANG_POLISH },
{ "English (UK)", CELL_SYSUTIL_LANG_ENGLISH_GB },
{ "Portuguese (BR)", CELL_SYSUTIL_LANG_PORTUGUESE_BR },
{ "Turkish", CELL_SYSUTIL_LANG_TURKISH },
});
format_enum(out, arg, [](CellSysutilLang value)
{
switch (value)
{
case CELL_SYSUTIL_LANG_JAPANESE: return "Japanese";
case CELL_SYSUTIL_LANG_ENGLISH_US: return "English (US)";
case CELL_SYSUTIL_LANG_FRENCH: return "French";
case CELL_SYSUTIL_LANG_SPANISH: return "Spanish";
case CELL_SYSUTIL_LANG_GERMAN: return "German";
case CELL_SYSUTIL_LANG_ITALIAN: return "Italian";
case CELL_SYSUTIL_LANG_DUTCH: return "Dutch";
case CELL_SYSUTIL_LANG_PORTUGUESE_PT: return "Portuguese (PT)";
case CELL_SYSUTIL_LANG_RUSSIAN: return "Russian";
case CELL_SYSUTIL_LANG_KOREAN: return "Korean";
case CELL_SYSUTIL_LANG_CHINESE_T: return "Chinese (Trad.)";
case CELL_SYSUTIL_LANG_CHINESE_S: return "Chinese (Simp.)";
case CELL_SYSUTIL_LANG_FINNISH: return "Finnish";
case CELL_SYSUTIL_LANG_SWEDISH: return "Swedish";
case CELL_SYSUTIL_LANG_DANISH: return "Danish";
case CELL_SYSUTIL_LANG_NORWEGIAN: return "Norwegian";
case CELL_SYSUTIL_LANG_POLISH: return "Polish";
case CELL_SYSUTIL_LANG_ENGLISH_GB: return "English (UK)";
case CELL_SYSUTIL_LANG_PORTUGUESE_BR: return "Portuguese (BR)";
case CELL_SYSUTIL_LANG_TURKISH: return "Turkish";
}
return unknown;
});
}
// For test
enum systemparam_id_name : s32 {};
template<>
template <>
void fmt_class_string<systemparam_id_name>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](auto value)
@ -134,7 +142,7 @@ s32 cellSysutilGetSystemParamInt(systemparam_id_name id, vm::ptr<s32> value)
switch(id)
{
case CELL_SYSUTIL_SYSTEMPARAM_ID_LANG:
*value = g_cfg_sys_language.get();
*value = g_cfg.sys.language;
break;
case CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN:

View file

@ -38,7 +38,7 @@ enum
CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USERNAME = 0x0131,
};
enum
enum CellSysutilLang : s32
{
CELL_SYSUTIL_LANG_JAPANESE = 0,
CELL_SYSUTIL_LANG_ENGLISH_US = 1,

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
@ -7,34 +6,35 @@
extern logs::channel cellSysutil;
cfg::map_entry<u8> g_cfg_video_out_resolution(cfg::root.video, "Resolution", "1280x720",
const extern std::unordered_map<video_resolution, std::pair<int, int>, value_hash<video_resolution>> g_video_out_resolution_map
{
{ "1920x1080", CELL_VIDEO_OUT_RESOLUTION_1080 },
{ "1280x720", CELL_VIDEO_OUT_RESOLUTION_720 },
{ "720x480", CELL_VIDEO_OUT_RESOLUTION_480 },
{ "720x576", CELL_VIDEO_OUT_RESOLUTION_576 },
{ "1600x1080", CELL_VIDEO_OUT_RESOLUTION_1600x1080 },
{ "1440x1080", CELL_VIDEO_OUT_RESOLUTION_1440x1080 },
{ "1280x1080", CELL_VIDEO_OUT_RESOLUTION_1280x1080 },
{ "960x1080", CELL_VIDEO_OUT_RESOLUTION_960x1080 },
});
{ video_resolution::_1080, { 1920, 1080 } },
{ video_resolution::_720, { 1280, 720 } },
{ video_resolution::_480, { 720, 480 } },
{ video_resolution::_576, { 720, 576 } },
{ video_resolution::_1600x1080, { 1600, 1080 } },
{ video_resolution::_1440x1080, { 1440, 1080 } },
{ video_resolution::_1280x1080, { 1280, 1080 } },
{ video_resolution::_960x1080, { 960, 1080 } },
};
cfg::map_entry<u8> g_cfg_video_out_aspect_ratio(cfg::root.video, "Aspect ratio", "16x9",
const extern std::unordered_map<video_resolution, CellVideoOutResolutionId, value_hash<video_resolution>> g_video_out_resolution_id
{
{ "4x3", CELL_VIDEO_OUT_ASPECT_4_3 },
{ "16x9", CELL_VIDEO_OUT_ASPECT_16_9 },
});
{ video_resolution::_1080, CELL_VIDEO_OUT_RESOLUTION_1080 },
{ video_resolution::_720, CELL_VIDEO_OUT_RESOLUTION_720 },
{ video_resolution::_480, CELL_VIDEO_OUT_RESOLUTION_480 },
{ video_resolution::_576, CELL_VIDEO_OUT_RESOLUTION_576 },
{ video_resolution::_1600x1080, CELL_VIDEO_OUT_RESOLUTION_1600x1080 },
{ video_resolution::_1440x1080, CELL_VIDEO_OUT_RESOLUTION_1440x1080 },
{ video_resolution::_1280x1080, CELL_VIDEO_OUT_RESOLUTION_1280x1080 },
{ video_resolution::_960x1080, CELL_VIDEO_OUT_RESOLUTION_960x1080 },
};
const extern std::unordered_map<u8, std::pair<int, int>> g_video_out_resolution_map
const extern std::unordered_map<video_aspect, CellVideoOutDisplayAspect, value_hash<video_aspect>> g_video_out_aspect_id
{
{ CELL_VIDEO_OUT_RESOLUTION_1080, { 1920, 1080 } },
{ CELL_VIDEO_OUT_RESOLUTION_720, { 1280, 720 } },
{ CELL_VIDEO_OUT_RESOLUTION_480, { 720, 480 } },
{ CELL_VIDEO_OUT_RESOLUTION_576, { 720, 576 } },
{ CELL_VIDEO_OUT_RESOLUTION_1600x1080, { 1600, 1080 } },
{ CELL_VIDEO_OUT_RESOLUTION_1440x1080, { 1440, 1080 } },
{ CELL_VIDEO_OUT_RESOLUTION_1280x1080, { 1280, 1080 } },
{ CELL_VIDEO_OUT_RESOLUTION_960x1080, { 960, 1080 } },
{ video_aspect::_auto, CELL_VIDEO_OUT_ASPECT_AUTO },
{ video_aspect::_16_9, CELL_VIDEO_OUT_ASPECT_16_9 },
{ video_aspect::_4_3, CELL_VIDEO_OUT_ASPECT_4_3 },
};
template<>
@ -70,10 +70,10 @@ error_code cellVideoOutGetState(u32 videoOut, u32 deviceIndex, vm::ptr<CellVideo
case CELL_VIDEO_OUT_PRIMARY:
state->state = CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED;
state->colorSpace = CELL_VIDEO_OUT_COLOR_SPACE_RGB;
state->displayMode.resolutionId = g_cfg_video_out_resolution.get(); // TODO
state->displayMode.resolutionId = g_video_out_resolution_id.at(g_cfg.video.resolution); // TODO
state->displayMode.scanMode = CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE;
state->displayMode.conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE;
state->displayMode.aspect = g_cfg_video_out_aspect_ratio.get(); // TODO
state->displayMode.aspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio); // TODO
state->displayMode.refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ;
return CELL_OK;
@ -133,11 +133,11 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptr<CellVideoOutConfiguration
switch (videoOut)
{
case CELL_VIDEO_OUT_PRIMARY:
if (config->resolutionId != g_cfg_video_out_resolution.get()
if (config->resolutionId != g_video_out_resolution_id.at(g_cfg.video.resolution)
|| (config->format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8 &&
config->format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8 &&
config->format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT)
|| (config->aspect != CELL_VIDEO_OUT_ASPECT_AUTO && config->aspect != g_cfg_video_out_aspect_ratio.get()))
|| (config->aspect != CELL_VIDEO_OUT_ASPECT_AUTO && config->aspect != g_video_out_aspect_id.at(g_cfg.video.aspect_ratio)))
{
return CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION;
}
@ -160,10 +160,10 @@ error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutConfig
switch (videoOut)
{
case CELL_VIDEO_OUT_PRIMARY:
config->resolutionId = g_cfg_video_out_resolution.get();
config->resolutionId = g_video_out_resolution_id.at(g_cfg.video.resolution);
config->format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
config->aspect = g_cfg_video_out_aspect_ratio.get();
config->pitch = 4 * g_video_out_resolution_map.at(g_cfg_video_out_resolution.get()).first;
config->aspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio);
config->pitch = 4 * g_video_out_resolution_map.at(g_cfg.video.resolution).first;
return CELL_OK;
@ -197,10 +197,10 @@ error_code cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr<Cell
info->colorInfo.whiteX = 0xFFFF;
info->colorInfo.whiteY = 0xFFFF;
info->colorInfo.gamma = 100;
info->availableModes[0].aspect = g_cfg_video_out_aspect_ratio.get();
info->availableModes[0].aspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio);
info->availableModes[0].conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE;
info->availableModes[0].refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_60HZ;
info->availableModes[0].resolutionId = g_cfg_video_out_resolution.get();
info->availableModes[0].resolutionId = g_video_out_resolution_id.at(g_cfg.video.resolution);
info->availableModes[0].scanMode = CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE;
return CELL_OK;
}
@ -225,8 +225,8 @@ error_code cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId,
switch (videoOut)
{
case CELL_VIDEO_OUT_PRIMARY: return not_an_error(
resolutionId == g_cfg_video_out_resolution.get()
&& (aspect == CELL_VIDEO_OUT_ASPECT_AUTO || aspect == g_cfg_video_out_aspect_ratio.get())
resolutionId == g_video_out_resolution_id.at(g_cfg.video.resolution)
&& (aspect == CELL_VIDEO_OUT_ASPECT_AUTO || aspect == g_video_out_aspect_id.at(g_cfg.video.aspect_ratio))
);
case CELL_VIDEO_OUT_SECONDARY: return not_an_error(0);
}

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Utilities/VirtualMemory.h"
#include "Crypto/sha1.h"
#include "Crypto/unself.h"
@ -19,28 +18,6 @@
namespace vm { using namespace ps3; }
enum class lib_loader_mode
{
automatic,
manual,
both,
liblv2only
};
cfg::map_entry<lib_loader_mode> g_cfg_lib_loader(cfg::root.core, "Lib Loader", 3,
{
{ "Automatically load required libraries", lib_loader_mode::automatic },
{ "Manually load selected libraries", lib_loader_mode::manual },
{ "Load automatic and manual selection", lib_loader_mode::both },
{ "Load liblv2.sprx only", lib_loader_mode::liblv2only },
});
cfg::bool_entry g_cfg_hook_ppu_funcs(cfg::root.core, "Hook static functions");
cfg::set_entry g_cfg_load_libs(cfg::root.core, "Load libraries");
extern cfg::map_entry<ppu_decoder_type> g_cfg_ppu_decoder;
extern void ppu_initialize_syscalls();
extern std::string ppu_get_function_name(const std::string& module, u32 fnid);
extern std::string ppu_get_variable_name(const std::string& module, u32 vnid);
@ -56,6 +33,23 @@ extern u32 g_ps3_sdk_version;
// HLE function name cache
std::vector<std::string> g_ppu_function_names;
template <>
void fmt_class_string<lib_loading_type>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](lib_loading_type value)
{
switch (value)
{
case lib_loading_type::automatic: return "Automatically load required libraries";
case lib_loading_type::manual: return "Manually load selected libraries";
case lib_loading_type::both: return "Load automatic and manual selection";
case lib_loading_type::liblv2only: return "Load liblv2.sprx only";
}
return unknown;
});
}
extern u32 ppu_generate_id(const char* name)
{
// Symbol name suffix
@ -627,7 +621,7 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& name)
{
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm && name == "libfiber.sprx")
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm && name == "libfiber.sprx")
{
LOG_FATAL(PPU, "libfiber.sprx is not compatible with PPU LLVM Recompiler. Use PPU Interpreter.");
Emu.Pause();
@ -833,7 +827,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
void ppu_load_exec(const ppu_exec_object& elf)
{
if (g_cfg_hook_ppu_funcs)
if (g_cfg.core.hook_functions)
{
LOG_TODO(LOADER, "'Hook static functions' option deactivated");
}
@ -1014,17 +1008,18 @@ void ppu_load_exec(const ppu_exec_object& elf)
// Get LLE module list
std::set<std::string> load_libs;
if (g_cfg_lib_loader.get() == lib_loader_mode::manual || g_cfg_lib_loader.get() == lib_loader_mode::both)
if (g_cfg.core.lib_loading == lib_loading_type::manual || g_cfg.core.lib_loading == lib_loading_type::both)
{
// Load required set of modules
load_libs = g_cfg_load_libs.get_set();
load_libs = g_cfg.core.load_libraries.get_set();
}
else if (g_cfg_lib_loader.get() == lib_loader_mode::liblv2only)
else if (g_cfg.core.lib_loading == lib_loading_type::liblv2only)
{
// Load only liblv2.sprx
load_libs.emplace("liblv2.sprx");
}
if (g_cfg_lib_loader.get() == lib_loader_mode::automatic || g_cfg_lib_loader.get() == lib_loader_mode::both)
if (g_cfg.core.lib_loading == lib_loading_type::automatic || g_cfg.core.lib_loading == lib_loading_type::both)
{
// Load recommended set of modules: Module name -> SPRX
std::unordered_multimap<std::string, std::string> sprx_map
@ -1228,7 +1223,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
// TODO: adjust for liblv2 loading option
u32 entry = static_cast<u32>(elf.header.e_entry);
if (g_cfg_lib_loader.get() != lib_loader_mode::liblv2only)
if (g_cfg.core.lib_loading != lib_loading_type::liblv2only)
{
// Set TLS args, call sys_initialize_tls
ppu->cmd_list

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Utilities/VirtualMemory.h"
#include "Crypto/sha1.h"
#include "Emu/Memory/Memory.h"
@ -82,18 +81,21 @@ void fmt_class_string<join_status>::format(std::string& out, u64 arg)
});
}
cfg::map_entry<ppu_decoder_type> g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder", 1,
template <>
void fmt_class_string<ppu_decoder_type>::format(std::string& out, u64 arg)
{
{ "Interpreter (precise)", ppu_decoder_type::precise },
{ "Interpreter (fast)", ppu_decoder_type::fast },
{ "Recompiler (LLVM)", ppu_decoder_type::llvm },
});
format_enum(out, arg, [](ppu_decoder_type type)
{
switch (type)
{
case ppu_decoder_type::precise: return "Interpreter (precise)";
case ppu_decoder_type::fast: return "Interpreter (fast)";
case ppu_decoder_type::llvm: return "Recompiler (LLVM)";
}
cfg::bool_entry g_cfg_ppu_debug(cfg::root.core, "PPU Debug");
cfg::bool_entry g_cfg_llvm_logs(cfg::root.core, "Save LLVM logs");
cfg::string_entry g_cfg_llvm_cpu(cfg::root.core, "Use LLVM CPU");
return unknown;
});
}
const ppu_decoder<ppu_interpreter_precise> s_ppu_interpreter_precise;
const ppu_decoder<ppu_interpreter_fast> s_ppu_interpreter_fast;
@ -113,8 +115,8 @@ static u32 ppu_cache(u32 addr)
{
// Select opcode table
const auto& table = *(
g_cfg_ppu_decoder.get() == ppu_decoder_type::precise ? &s_ppu_interpreter_precise.get_table() :
g_cfg_ppu_decoder.get() == ppu_decoder_type::fast ? &s_ppu_interpreter_fast.get_table() :
g_cfg.core.ppu_decoder == ppu_decoder_type::precise ? &s_ppu_interpreter_precise.get_table() :
g_cfg.core.ppu_decoder == ppu_decoder_type::fast ? &s_ppu_interpreter_fast.get_table() :
(fmt::throw_exception<std::logic_error>("Invalid PPU decoder"), nullptr));
return ::narrow<u32>(reinterpret_cast<std::uintptr_t>(table[ppu_decode(vm::read32(addr))]));
@ -122,14 +124,14 @@ static u32 ppu_cache(u32 addr)
static bool ppu_fallback(ppu_thread& ppu, ppu_opcode_t op)
{
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)
{
fmt::throw_exception("Unregistered PPU function");
}
ppu_ref(ppu.cia) = ppu_cache(ppu.cia);
if (g_cfg_ppu_debug)
if (g_cfg.core.ppu_debug)
{
LOG_ERROR(PPU, "Unregistered instruction: 0x%08x", op.opcode);
}
@ -196,7 +198,7 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr)
if (!size)
{
if (g_cfg_ppu_debug)
if (g_cfg.core.ppu_debug)
{
LOG_ERROR(PPU, "ppu_register_function_at(0x%x): empty range", addr);
}
@ -204,7 +206,7 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr)
return;
}
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)
{
return;
}
@ -249,7 +251,7 @@ static bool ppu_break(ppu_thread& ppu, ppu_opcode_t op)
// Set or remove breakpoint
extern void ppu_breakpoint(u32 addr)
{
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)
{
return;
}
@ -292,7 +294,7 @@ void ppu_thread::on_init(const std::shared_ptr<void>& _this)
//sets breakpoint, does nothing if there is a breakpoint there already
extern void ppu_set_breakpoint(u32 addr)
{
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)
{
return;
}
@ -308,7 +310,7 @@ extern void ppu_set_breakpoint(u32 addr)
//removes breakpoint, does nothing if there is no breakpoint at location
extern void ppu_remove_breakpoint(u32 addr)
{
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)
{
return;
}
@ -369,7 +371,7 @@ std::string ppu_thread::dump() const
fmt::append(ret, "XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", xer.ca, xer.ov, xer.so, xer.cnt);
fmt::append(ret, "VSCR = [SAT=%u | NJ=%u]\n", sat, nj);
fmt::append(ret, "FPSCR = [FL=%u | FG=%u | FE=%u | FU=%u]\n", fpscr.fl, fpscr.fg, fpscr.fe, fpscr.fu);
fmt::append(ret, "\nCall stack:\n=========\n0x%08x (0x0) called\n", g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm ? 0 : cia);
fmt::append(ret, "\nCall stack:\n=========\n0x%08x (0x0) called\n", g_cfg.core.ppu_decoder == ppu_decoder_type::llvm ? 0 : cia);
// Determine stack range
u32 stack_ptr = static_cast<u32>(gpr[1]);
@ -470,7 +472,7 @@ void ppu_thread::cpu_task()
void ppu_thread::exec_task()
{
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)
{
reinterpret_cast<ppu_function_t>(static_cast<std::uintptr_t>(ppu_ref(cia)))(*this);
return;
@ -912,7 +914,7 @@ extern void ppu_initialize()
extern void ppu_initialize(const ppu_module& info)
{
if (g_cfg_ppu_decoder.get() != ppu_decoder_type::llvm)
if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm)
{
// Temporarily
s_ppu_toc = fxm::get_always<std::unordered_map<u32, u32>>().get();
@ -924,7 +926,7 @@ extern void ppu_initialize(const ppu_module& info)
ppu_register_function_at(block.first, block.second, nullptr);
}
if (g_cfg_ppu_debug && func.size && func.toc != -1)
if (g_cfg.core.ppu_debug && func.size && func.toc != -1)
{
s_ppu_toc->emplace(func.addr, func.toc);
ppu_ref(func.addr) = ::narrow<u32>(reinterpret_cast<std::uintptr_t>(&ppu_check_toc));
@ -1009,7 +1011,7 @@ extern void ppu_initialize(const ppu_module& info)
}
}
const auto jit = fxm::make<jit_compiler>(std::move(link_table), g_cfg_llvm_cpu.get());
const auto jit = fxm::make<jit_compiler>(std::move(link_table), g_cfg.core.llvm_cpu);
LOG_SUCCESS(PPU, "LLVM: JIT initialized (%s)", jit->cpu());
}
@ -1210,7 +1212,7 @@ extern void ppu_initialize(const ppu_module& info)
std::string result;
raw_string_ostream out(result);
if (g_cfg_llvm_logs)
if (g_cfg.core.llvm_logs)
{
out << *module; // print IR
fs::file(Emu.GetCachePath() + obj_name + ".log", fs::rewrite).write(out.str());

View file

@ -18,13 +18,6 @@ enum class ppu_cmd : u32
sleep,
};
enum class ppu_decoder_type
{
precise,
fast,
llvm,
};
class ppu_thread : public cpu_thread
{
public:

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
@ -24,14 +23,12 @@
const spu_decoder<spu_interpreter_fast> s_spu_interpreter; // TODO: remove
const spu_decoder<spu_recompiler> s_spu_decoder;
extern cfg::bool_entry g_cfg_spu_debug;
spu_recompiler::spu_recompiler()
: m_jit(std::make_shared<asmjit::JitRuntime>())
{
LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created...");
if (g_cfg_spu_debug)
if (g_cfg.core.spu_debug)
{
fs::file log(Emu.GetCachePath() + "SPUJIT.log", fs::rewrite);
log.write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str()));
@ -63,7 +60,7 @@ void spu_recompiler::compile(spu_function_t& f)
std::string log;
if (g_cfg_spu_debug)
if (g_cfg.core.spu_debug)
{
fmt::append(log, "========== SPU FUNCTION 0x%05x - 0x%05x ==========\n\n", f.addr, f.addr + f.size);
}
@ -77,7 +74,7 @@ void spu_recompiler::compile(spu_function_t& f)
X86Compiler compiler(&code);
this->c = &compiler;
if (g_cfg_spu_debug)
if (g_cfg.core.spu_debug)
{
// Set logger
codeHolder->setLogger(&logger);
@ -163,7 +160,7 @@ void spu_recompiler::compile(spu_function_t& f)
}
}
if (g_cfg_spu_debug)
if (g_cfg.core.spu_debug)
{
// Disasm
dis_asm.dump_pc = m_pos;
@ -190,7 +187,7 @@ void spu_recompiler::compile(spu_function_t& f)
m_pos += 4;
}
if (g_cfg_spu_debug)
if (g_cfg.core.spu_debug)
{
log += '\n';
}
@ -240,7 +237,7 @@ void spu_recompiler::compile(spu_function_t& f)
f.compiled = asmjit::Internal::ptr_cast<decltype(f.compiled)>(fn);
if (g_cfg_spu_debug)
if (g_cfg.core.spu_debug)
{
// Add ASMJIT logs
log += logger.getString();

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Utilities/lockless.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
@ -34,31 +33,28 @@ extern u64 get_timebased_time();
extern thread_local u64 g_tls_fault_spu;
enum class spu_decoder_type
{
precise,
fast,
asmjit,
llvm,
};
cfg::map_entry<spu_decoder_type> g_cfg_spu_decoder(cfg::root.core, "SPU Decoder", 2,
{
{ "Interpreter (precise)", spu_decoder_type::precise },
{ "Interpreter (fast)", spu_decoder_type::fast },
{ "Recompiler (ASMJIT)", spu_decoder_type::asmjit },
{ "Recompiler (LLVM)", spu_decoder_type::llvm },
});
cfg::bool_entry g_cfg_spu_debug(cfg::root.core, "SPU Debug");
cfg::bool_entry g_cfg_core_bind_spu_cores(cfg::root.core, "Bind SPU threads to secondary cores");
cfg::bool_entry g_cfg_core_lower_spu_priority(cfg::root.core, "Lower SPU thread priority");
const spu_decoder<spu_interpreter_precise> s_spu_interpreter_precise;
const spu_decoder<spu_interpreter_fast> s_spu_interpreter_fast;
std::atomic<u64> g_num_spu_threads = { 0ull };
template <>
void fmt_class_string<spu_decoder_type>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](spu_decoder_type type)
{
switch (type)
{
case spu_decoder_type::precise: return "Interpreter (precise)";
case spu_decoder_type::fast: return "Interpreter (fast)";
case spu_decoder_type::asmjit: return "Recompiler (ASMJIT)";
case spu_decoder_type::llvm: return "Recompiler (LLVM)";
}
return unknown;
});
}
void spu_int_ctrl_t::set(u64 ints)
{
// leave only enabled interrupts
@ -142,7 +138,7 @@ spu_imm_table_t::spu_imm_table_t()
void SPUThread::on_spawn()
{
if (g_cfg_core_bind_spu_cores)
if (g_cfg.core.bind_spu_cores)
{
//Get next secondary core number
auto core_count = std::thread::hardware_concurrency();
@ -155,7 +151,7 @@ void SPUThread::on_spawn()
}
}
if (g_cfg_core_lower_spu_priority)
if (g_cfg.core.lower_spu_priority)
{
set_native_priority(-1);
}
@ -238,7 +234,7 @@ void SPUThread::cpu_task()
{
std::fesetround(FE_TOWARDZERO);
if (g_cfg_spu_decoder.get() == spu_decoder_type::asmjit)
if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit)
{
if (!spu_db) spu_db = fxm::get_always<SPUDatabase>();
return spu_recompiler_base::enter(*this);
@ -253,8 +249,8 @@ void SPUThread::cpu_task()
// Select opcode table
const auto& table = *(
g_cfg_spu_decoder.get() == spu_decoder_type::precise ? &s_spu_interpreter_precise.get_table() :
g_cfg_spu_decoder.get() == spu_decoder_type::fast ? &s_spu_interpreter_fast.get_table() :
g_cfg.core.spu_decoder == spu_decoder_type::precise ? &s_spu_interpreter_precise.get_table() :
g_cfg.core.spu_decoder == spu_decoder_type::fast ? &s_spu_interpreter_fast.get_table() :
(fmt::throw_exception<std::logic_error>("Invalid SPU decoder"), nullptr));
// LS base address

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUFunction.h"
@ -1005,9 +1004,6 @@ DECLARE(lv2_obj::g_ppu);
DECLARE(lv2_obj::g_pending);
DECLARE(lv2_obj::g_waiting);
// Amount of PPU threads running simultaneously (must be 2)
cfg::int_entry<1, 16> g_cfg_ppu_threads(cfg::root.core, "PPU Threads", 2);
void lv2_obj::sleep_timeout(named_thread& thread, u64 timeout)
{
semaphore_lock lock(g_mutex);
@ -1132,7 +1128,7 @@ void lv2_obj::awake(cpu_thread& cpu, u32 prio)
}
// Suspend threads if necessary
for (std::size_t i = g_cfg_ppu_threads; i < g_ppu.size(); i++)
for (std::size_t i = g_cfg.core.ppu_threads; i < g_ppu.size(); i++)
{
const auto target = g_ppu[i];
@ -1158,7 +1154,7 @@ void lv2_obj::schedule_all()
if (g_pending.empty())
{
// Wake up threads
for (std::size_t i = 0, x = std::min<std::size_t>(g_cfg_ppu_threads, g_ppu.size()); i < x; i++)
for (std::size_t i = 0, x = std::min<std::size_t>(g_cfg.core.ppu_threads, g_ppu.size()); i < x; i++)
{
const auto target = g_ppu[i];

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Loader/ELF.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"

View file

@ -1,8 +1,8 @@
#ifdef _MSC_VER
#include "stdafx.h"
#include "stdafx_d3d12.h"
#include "Utilities/Config.h"
#include "D3D12GSRender.h"
#include "Emu/System.h"
#include <wrl/client.h>
#include <dxgi1_4.h>
#include <thread>
@ -15,14 +15,6 @@
#include "D3D12Formats.h"
#include "../rsx_methods.h"
extern cfg::bool_entry g_cfg_rsx_vsync;
extern cfg::bool_entry g_cfg_rsx_debug_output;
extern cfg::bool_entry g_cfg_rsx_overlay;
static cfg::node s_cfg_d3d12(cfg::root.video, "D3D12");
cfg::string_entry g_cfg_d3d12_adapter(s_cfg_d3d12, "Adapter");
PFN_D3D12_CREATE_DEVICE wrapD3D12CreateDevice;
PFN_D3D12_GET_DEBUG_INTERFACE wrapD3D12GetDebugInterface;
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE wrapD3D12SerializeRootSignature;
@ -141,11 +133,11 @@ namespace
}
D3D12GSRender::D3D12GSRender()
: GSRender(frame_type::DX12)
: GSRender()
, m_d3d12_lib()
, m_current_pso({})
{
if (g_cfg_rsx_debug_output)
if (g_cfg.video.debug_output)
{
Microsoft::WRL::ComPtr<ID3D12Debug> debugInterface;
wrapD3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface));
@ -157,7 +149,7 @@ D3D12GSRender::D3D12GSRender()
// Create adapter
ComPtr<IDXGIAdapter> adapter;
const std::wstring& adapter_name = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(g_cfg_d3d12_adapter);
const std::wstring adapter_name = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(g_cfg.video.d3d12.adapter);
for (UINT id = 0; dxgi_factory->EnumAdapters(id, adapter.ReleaseAndGetAddressOf()) != DXGI_ERROR_NOT_FOUND; id++)
{
@ -179,7 +171,7 @@ D3D12GSRender::D3D12GSRender()
if (FAILED(wrapD3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device))))
{
LOG_ERROR(RSX, "Failed to initialize D3D device on adapter '%s', falling back to first available GPU", g_cfg_d3d12_adapter.to_string().c_str());
LOG_ERROR(RSX, "Failed to initialize D3D device on adapter '%s', falling back to first available GPU", g_cfg.video.d3d12.adapter.get());
//Try to create a device on the first available device
if (FAILED(wrapD3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device))))
@ -267,7 +259,7 @@ D3D12GSRender::D3D12GSRender()
)
);
if (g_cfg_rsx_overlay)
if (g_cfg.video.overlay)
init_d2d_structures();
}
@ -381,7 +373,7 @@ void D3D12GSRender::end()
.Offset((INT)currentDescriptorIndex + vertex_buffer_count, m_descriptor_stride_srv_cbv_uav)
);
if (m_transform_constants_dirty && !g_cfg_rsx_debug_output)
if (m_transform_constants_dirty && !g_cfg.video.debug_output)
{
m_current_transform_constants_buffer_descriptor_id = (u32)currentDescriptorIndex + 1 + vertex_buffer_count;
upload_and_bind_vertex_shader_constants(currentDescriptorIndex + 1 + vertex_buffer_count);
@ -478,7 +470,7 @@ void D3D12GSRender::end()
m_timers.draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
m_timers.draw_calls_count++;
if (g_cfg_rsx_debug_output)
if (g_cfg.video.debug_output)
{
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
@ -646,21 +638,21 @@ void D3D12GSRender::flip(int buffer)
if (resource_to_flip)
get_current_resource_storage().command_list->DrawInstanced(4, 1, 0, 0);
if (!g_cfg_rsx_overlay)
if (!g_cfg.video.overlay)
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
if (is_flip_surface_in_global_memory(rsx::method_registers.surface_color_target()) && resource_to_flip != nullptr)
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(resource_to_flip, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET));
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
if (g_cfg_rsx_overlay)
if (g_cfg.video.overlay)
render_overlay();
reset_timer();
std::chrono::time_point<steady_clock> flip_start = steady_clock::now();
CHECK_HRESULT(m_swap_chain->Present(g_cfg_rsx_vsync ? 1 : 0, 0));
CHECK_HRESULT(m_swap_chain->Present(g_cfg.video.vsync ? 1 : 0, 0));
// Add an event signaling queue completion
resource_storage &storage = get_non_current_resource_storage();

View file

@ -1,7 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h"
#include "stdafx_d3d12.h"
#include "Utilities/Config.h"
#include "D3D12PipelineState.h"
#include "D3D12GSRender.h"
#include "D3D12Formats.h"
@ -10,8 +9,6 @@
#define TO_STRING(x) #x
extern cfg::bool_entry g_cfg_rsx_debug_output;
extern pD3DCompile wrapD3DCompile;
void Shader::Compile(const std::string &code, SHADER_TYPE st)
@ -20,7 +17,7 @@ void Shader::Compile(const std::string &code, SHADER_TYPE st)
HRESULT hr;
ComPtr<ID3DBlob> errorBlob;
UINT compileFlags;
if (g_cfg_rsx_debug_output)
if (g_cfg.video.debug_output)
compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
else
compileFlags = 0;

View file

@ -1,7 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h"
#include "stdafx_d3d12.h"
#include "Utilities/Config.h"
#include "D3D12RenderTargetSets.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
@ -12,10 +11,6 @@
#include "D3D12GSRender.h"
#include "D3D12Formats.h"
extern cfg::bool_entry g_cfg_rsx_debug_output;
extern cfg::bool_entry g_cfg_rsx_write_color_buffers;
extern cfg::bool_entry g_cfg_rsx_write_depth_buffer;
namespace
{
u32 get_max_depth_value(rsx::surface_depth_format format)
@ -158,7 +153,7 @@ void D3D12GSRender::clear_surface(u32 arg)
m_timers.draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
m_timers.draw_calls_count++;
if (g_cfg_rsx_debug_output)
if (g_cfg.video.debug_output)
{
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
@ -311,7 +306,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
bool need_transfer = false;
if (rsx::method_registers.surface_z_dma() && g_cfg_rsx_write_depth_buffer)
if (rsx::method_registers.surface_z_dma() && g_cfg.video.write_depth_buffer)
{
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.get_heap(), { depth_buffer_offset_in_heap,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)depth_row_pitch } }), 0, 0, 0,
@ -323,7 +318,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
}
size_t color_buffer_offset_in_heap[4];
if (g_cfg_rsx_write_color_buffers)
if (g_cfg.video.write_color_buffers)
{
for (u8 i : get_rtt_indexes(rsx::method_registers.surface_color_target()))
{
@ -344,7 +339,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
//Wait for result
wait_for_command_queue(m_device.Get(), m_command_queue.Get());
if (address_z && g_cfg_rsx_write_depth_buffer)
if (address_z && g_cfg.video.write_depth_buffer)
{
auto ptr = vm::base(address_z);
char *depth_buffer = (char*)ptr;
@ -364,7 +359,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
m_readback_resources.unmap();
}
if (g_cfg_rsx_write_color_buffers)
if (g_cfg.video.write_color_buffers)
{
size_t srcPitch = get_aligned_pitch(rsx::method_registers.surface_color(), clip_w);
size_t dstPitch = get_packed_pitch(rsx::method_registers.surface_color(), clip_w);

View file

@ -1,16 +1,12 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "GLGSRender.h"
#include "GLVertexProgram.h"
#include "../rsx_methods.h"
#include "../Common/BufferUtils.h"
#include "../rsx_utils.h"
extern cfg::bool_entry g_cfg_rsx_debug_output;
extern cfg::bool_entry g_cfg_rsx_overlay;
extern cfg::bool_entry g_cfg_rsx_gl_legacy_buffers;
#define DUMP_VERTEX_DATA 0
namespace
@ -26,7 +22,7 @@ namespace
}
}
GLGSRender::GLGSRender() : GSRender(frame_type::OpenGL)
GLGSRender::GLGSRender() : GSRender()
{
shaders_cache.load(rsx::old_shaders_cache::shader_language::glsl);
}
@ -413,7 +409,7 @@ void GLGSRender::end()
std::chrono::time_point<steady_clock> draw_start = steady_clock::now();
if (g_cfg_rsx_debug_output)
if (g_cfg.video.debug_output)
{
m_program->validate();
}
@ -477,7 +473,7 @@ void GLGSRender::on_init_thread()
gl::init();
if (g_cfg_rsx_debug_output)
if (g_cfg.video.debug_output)
gl::enable_debugging();
LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_VERSION));
@ -520,10 +516,11 @@ void GLGSRender::on_init_thread()
if (!gl_caps.ARB_buffer_storage_supported)
{
LOG_WARNING(RSX, "Forcing use of legacy OpenGL buffers because ARB_buffer_storage is not supported");
g_cfg_rsx_gl_legacy_buffers = true;
// TODO: do not modify config options
g_cfg.video.gl_legacy_buffers.from_string("true");
}
if (g_cfg_rsx_gl_legacy_buffers)
if (g_cfg.video.gl_legacy_buffers)
{
LOG_WARNING(RSX, "Using legacy openGL buffers.");
manually_flush_ring_buffers = true;
@ -551,7 +548,7 @@ void GLGSRender::on_init_thread()
m_vao.element_array_buffer = *m_index_ring_buffer;
if (g_cfg_rsx_overlay)
if (g_cfg.video.overlay)
{
if (gl_caps.ARB_shader_draw_parameters_supported)
{
@ -908,7 +905,7 @@ void GLGSRender::flip(int buffer)
__glcheck flip_fbo->blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical(), gl::buffers::color, gl::filter::linear);
if (g_cfg_rsx_overlay)
if (g_cfg.video.overlay)
{
gl::screen.bind();
glViewport(0, 0, m_frame->client_width(), m_frame->client_height());

View file

@ -1,12 +1,7 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "../rsx_methods.h"
#include "GLGSRender.h"
extern cfg::bool_entry g_cfg_rsx_write_color_buffers;
extern cfg::bool_entry g_cfg_rsx_write_depth_buffer;
extern cfg::bool_entry g_cfg_rsx_read_color_buffers;
extern cfg::bool_entry g_cfg_rsx_read_depth_buffer;
#include "Emu/System.h"
color_format rsx::internals::surface_color_format_to_gl(rsx::surface_color_format color_format)
{
@ -274,7 +269,7 @@ void GLGSRender::init_buffers(bool skip_reading)
}
//Mark buffer regions as NO_ACCESS on Cell visible side
if (g_cfg_rsx_write_color_buffers)
if (g_cfg.video.write_color_buffers)
{
auto color_format = rsx::internals::surface_color_format_to_gl(surface_format);
@ -288,7 +283,7 @@ void GLGSRender::init_buffers(bool skip_reading)
}
}
if (g_cfg_rsx_write_depth_buffer)
if (g_cfg.video.write_depth_buffer)
{
if (depth_surface_info.address && depth_surface_info.pitch)
{
@ -330,7 +325,7 @@ void GLGSRender::read_buffers()
glDisable(GL_STENCIL_TEST);
if (g_cfg_rsx_read_color_buffers)
if (g_cfg.video.read_color_buffers)
{
auto color_format = rsx::internals::surface_color_format_to_gl(rsx::method_registers.surface_color());
@ -405,7 +400,7 @@ void GLGSRender::read_buffers()
}
}
if (g_cfg_rsx_read_depth_buffer)
if (g_cfg.video.read_depth_buffer)
{
//TODO: use pitch
u32 pitch = depth_surface_info.pitch;
@ -459,7 +454,7 @@ void GLGSRender::write_buffers()
if (!draw_fbo)
return;
if (g_cfg_rsx_write_color_buffers)
if (g_cfg.video.write_color_buffers)
{
auto write_color_buffers = [&](int index, int count)
{
@ -481,7 +476,7 @@ void GLGSRender::write_buffers()
write_color_buffers(0, 4);
}
if (g_cfg_rsx_write_depth_buffer)
if (g_cfg.video.write_depth_buffer)
{
//TODO: use pitch
if (depth_surface_info.pitch == 0) return;

View file

@ -14,15 +14,11 @@
#include "GLRenderTargets.h"
#include "../Common/TextureUtils.h"
#include "../../Memory/vm.h"
#include "Utilities/Config.h"
#include "../rsx_utils.h"
class GLGSRender;
extern cfg::bool_entry g_cfg_rsx_write_color_buffers;
extern cfg::bool_entry g_cfg_rsx_write_depth_buffer;
namespace gl
{
class texture_cache

View file

@ -1,14 +1,9 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "GSRender.h"
// temporarily (u8 value is really CellVideoOutResolutionId, but HLE declarations shouldn't be available for the rest of emu, even indirectly)
extern cfg::map_entry<u8> g_cfg_video_out_resolution;
extern const std::unordered_map<u8, std::pair<int, int>> g_video_out_resolution_map;
draw_context_t GSFrameBase::new_context()
{
if (void* context = make_context())
@ -19,10 +14,9 @@ draw_context_t GSFrameBase::new_context()
return nullptr;
}
GSRender::GSRender(frame_type type)
GSRender::GSRender()
{
const auto size = g_video_out_resolution_map.at(g_cfg_video_out_resolution.get());
m_frame = Emu.GetCallbacks().get_gs_frame(type, size.first, size.second).release();
m_frame = Emu.GetCallbacks().get_gs_frame().release();
}
GSRender::~GSRender()

View file

@ -47,14 +47,6 @@ protected:
virtual void* make_context() = 0;
};
enum class frame_type
{
Null,
OpenGL,
DX12,
Vulkan
};
class GSRender : public rsx::thread
{
protected:
@ -62,7 +54,7 @@ protected:
draw_context_t m_context;
public:
GSRender(frame_type type);
GSRender();
virtual ~GSRender();
void on_init_rsx() override;

View file

@ -2,7 +2,7 @@
#include "NullGSRender.h"
#include "Emu/System.h"
NullGSRender::NullGSRender() : GSRender(frame_type::Null)
NullGSRender::NullGSRender() : GSRender()
{
}

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
@ -19,17 +18,6 @@ class GSRender;
#define CMD_DEBUG 0
cfg::bool_entry g_cfg_rsx_write_color_buffers(cfg::root.video, "Write Color Buffers");
cfg::bool_entry g_cfg_rsx_write_depth_buffer(cfg::root.video, "Write Depth Buffer");
cfg::bool_entry g_cfg_rsx_read_color_buffers(cfg::root.video, "Read Color Buffers");
cfg::bool_entry g_cfg_rsx_read_depth_buffer(cfg::root.video, "Read Depth Buffer");
cfg::bool_entry g_cfg_rsx_log_programs(cfg::root.video, "Log shader programs");
cfg::bool_entry g_cfg_rsx_vsync(cfg::root.video, "VSync");
cfg::bool_entry g_cfg_rsx_debug_output(cfg::root.video, "Debug output");
cfg::bool_entry g_cfg_rsx_overlay(cfg::root.video, "Debug overlay");
cfg::bool_entry g_cfg_rsx_gl_legacy_buffers(cfg::root.video, "Use Legacy OpenGL Buffers (Debug)");
cfg::bool_entry g_cfg_rsx_use_gpu_texture_scaling(cfg::root.video, "Use GPU texture scaling", true);
bool user_asked_for_frame_capture = false;
rsx::frame_capture_data frame_debug;

View file

@ -7,10 +7,6 @@
#include "../Common/BufferUtils.h"
#include "VKFormats.h"
extern cfg::bool_entry g_cfg_rsx_overlay;
extern cfg::bool_entry g_cfg_rsx_write_color_buffers;
extern cfg::bool_entry g_cfg_rsx_write_depth_buffer;
namespace
{
u32 get_max_depth_value(rsx::surface_depth_format format)
@ -451,7 +447,7 @@ namespace
}
}
VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan)
VKGSRender::VKGSRender() : GSRender()
{
shaders_cache.load(rsx::old_shaders_cache::shader_language::glsl);
@ -556,7 +552,7 @@ VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan)
vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &m_present_semaphore);
if (g_cfg_rsx_overlay)
if (g_cfg.video.overlay)
{
size_t idx = vk::get_render_pass_location( m_swap_chain->get_surface_format(), VK_FORMAT_UNDEFINED, 1);
m_text_writer.reset(new vk::text_writer());
@ -644,7 +640,7 @@ bool VKGSRender::on_access_violation(u32 address, bool is_writing)
return m_texture_cache.invalidate_address(address);
else
{
if (g_cfg_rsx_write_color_buffers || g_cfg_rsx_write_depth_buffer)
if (g_cfg.video.write_color_buffers || g_cfg.video.write_depth_buffer)
{
bool flushable, synchronized;
std::tie(flushable, synchronized) = m_texture_cache.address_is_flushable(address);
@ -1066,7 +1062,7 @@ void VKGSRender::copy_render_targets_to_dma_location()
if (!m_flush_draw_buffers)
return;
if (!g_cfg_rsx_write_color_buffers && !g_cfg_rsx_write_depth_buffer)
if (!g_cfg.video.write_color_buffers && !g_cfg.video.write_depth_buffer)
return;
//TODO: Make this asynchronous. Should be similar to a glFlush() but in this case its similar to glFinish
@ -1075,7 +1071,7 @@ void VKGSRender::copy_render_targets_to_dma_location()
vk::enter_uninterruptible();
if (g_cfg_rsx_write_color_buffers)
if (g_cfg.video.write_color_buffers)
{
for (u8 index = 0; index < rsx::limits::color_buffers_count; index++)
{
@ -1087,7 +1083,7 @@ void VKGSRender::copy_render_targets_to_dma_location()
}
}
if (g_cfg_rsx_write_depth_buffer)
if (g_cfg.video.write_depth_buffer)
{
if (m_depth_surface_info.pitch)
{
@ -1192,7 +1188,7 @@ void VKGSRender::process_swap_request()
m_sampler_to_clean.clear();
m_framebuffer_to_clean.clear();
if (g_cfg_rsx_overlay)
if (g_cfg.video.overlay)
{
m_text_writer->reset_descriptors();
}
@ -1609,7 +1605,7 @@ void VKGSRender::prepare_rtts()
m_depth_surface_info.pitch = 0;
}
if (g_cfg_rsx_write_color_buffers)
if (g_cfg.video.write_color_buffers)
{
for (u8 index : draw_buffers)
{
@ -1621,7 +1617,7 @@ void VKGSRender::prepare_rtts()
}
}
if (g_cfg_rsx_write_depth_buffer)
if (g_cfg.video.write_depth_buffer)
{
if (m_depth_surface_info.address && m_depth_surface_info.pitch)
{
@ -1717,7 +1713,7 @@ void VKGSRender::flip(int buffer)
std::unique_ptr<vk::framebuffer> direct_fbo;
std::vector<std::unique_ptr<vk::image_view>> swap_image_view;
if (g_cfg_rsx_overlay)
if (g_cfg.video.overlay)
{
//Change the image layout whilst setting up a dependency on waiting for the blit op to finish before we start writing
auto subres = vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT);

View file

@ -8,7 +8,7 @@
#include <memory>
#include <unordered_map>
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "VulkanAPI.h"
#include "../GCM.h"
#include "../Common/TextureUtils.h"
@ -23,8 +23,6 @@
#define TEXTURES_FIRST_BIND_SLOT 19
#define VERTEX_TEXTURES_FIRST_BIND_SLOT 35 //19+16
extern cfg::bool_entry g_cfg_rsx_debug_output;
namespace rsx
{
class fragment_texture;
@ -184,7 +182,7 @@ namespace vk
std::vector<const char *> layers;
if (g_cfg_rsx_debug_output)
if (g_cfg.video.debug_output)
layers.push_back("VK_LAYER_LUNARG_standard_validation");
VkDeviceCreateInfo device = {};
@ -1090,7 +1088,7 @@ namespace vk
std::vector<const char *> layers;
if (g_cfg_rsx_debug_output)
if (g_cfg.video.debug_output)
layers.push_back("VK_LAYER_LUNARG_standard_validation");
VkInstanceCreateInfo instance_info = {};
@ -1374,4 +1372,4 @@ namespace vk
void copy_mipmaped_image_using_buffer(VkCommandBuffer cmd, VkImage dst_image,
const std::vector<rsx_subresource_layout> subresource_layout, int format, bool is_swizzled, u16 mipmap_count,
vk::vk_data_heap &upload_heap, vk::buffer* upload_buffer);
}
}

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "rsx_methods.h"
#include "RSXThread.h"
#include "Emu/Memory/Memory.h"
@ -13,17 +12,24 @@
#include <thread>
cfg::map_entry<double> g_cfg_rsx_frame_limit(cfg::root.video, "Frame limit",
template <>
void fmt_class_string<frame_limit_type>::format(std::string& out, u64 arg)
{
{ "Off", 0. },
{ "59.94", 59.94 },
{ "50", 50. },
{ "60", 60. },
{ "30", 30. },
{ "Auto", -1. },
});
format_enum(out, arg, [](frame_limit_type value)
{
switch (value)
{
case frame_limit_type::none: return "Off";
case frame_limit_type::_59_94: return "59.94";
case frame_limit_type::_50: return "50";
case frame_limit_type::_60: return "60";
case frame_limit_type::_30: return "30";
case frame_limit_type::_auto: return "Auto";
}
extern cfg::bool_entry g_cfg_rsx_use_gpu_texture_scaling;
return unknown;
});
}
namespace rsx
{
@ -575,7 +581,7 @@ namespace rsx
}
}
if (g_cfg_rsx_use_gpu_texture_scaling && dst_dma == CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER)
if (g_cfg.video.use_gpu_texture_scaling && dst_dma == CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER)
{
//For now, only use this for actual scaled images, there are use cases that should not go through 3d engine, e.g program ucode transfer
//TODO: Figure out more instances where we can use this without problems
@ -811,10 +817,18 @@ namespace rsx
Emu.Pause();
}
if (double limit = g_cfg_rsx_frame_limit.get())
double limit = 0.;
switch (g_cfg.video.frame_limit)
{
case frame_limit_type::none: limit = 0.; break;
case frame_limit_type::_59_94: limit = 59.94; break;
case frame_limit_type::_50: limit = 50.; break;
case frame_limit_type::_60: limit = 60.; break;
case frame_limit_type::_30: limit = 30.; break;
case frame_limit_type::_auto: limit = rsx->fps_limit; break; // TODO
}
if (limit)
{
if (limit < 0) limit = rsx->fps_limit; // TODO
std::this_thread::sleep_for(std::chrono::milliseconds((s64)(1000.0 / limit - rsx->timer_sync.GetElapsedTimeInMilliSec())));
rsx->timer_sync.Start();
}

View file

@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Utilities/event.h"
#include "Utilities/bin_patch.h"
#include "Emu/Memory/Memory.h"
@ -27,21 +26,10 @@
#include "Utilities/GDBDebugServer.h"
cfg_root g_cfg;
system_type g_system;
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot", true);
cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes");
cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_config_dir()
cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/");
cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/");
cfg::string_entry g_cfg_vfs_dev_flash(cfg::root.vfs, "/dev_flash/", "$(EmulatorDir)dev_flash/");
cfg::string_entry g_cfg_vfs_dev_usb000(cfg::root.vfs, "/dev_usb000/", "$(EmulatorDir)dev_usb000/");
cfg::string_entry g_cfg_vfs_dev_bdvd(cfg::root.vfs, "/dev_bdvd/"); // Not mounted
cfg::string_entry g_cfg_vfs_app_home(cfg::root.vfs, "/app_home/"); // Not mounted
cfg::bool_entry g_cfg_vfs_allow_host_root(cfg::root.vfs, "Enable /host_root/");
std::string g_cfg_defaults;
extern atomic_t<u32> g_thread_count;
@ -55,6 +43,136 @@ extern std::shared_ptr<struct lv2_prx> ppu_load_prx(const ppu_prx_object&, const
fs::file g_tty;
template <>
void fmt_class_string<keyboard_handler>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](keyboard_handler value)
{
switch (value)
{
case keyboard_handler::null: return "Null";
case keyboard_handler::basic: return "Basic";
}
return unknown;
});
}
template <>
void fmt_class_string<mouse_handler>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](mouse_handler value)
{
switch (value)
{
case mouse_handler::null: return "Null";
case mouse_handler::basic: return "Basic";
}
return unknown;
});
}
template <>
void fmt_class_string<pad_handler>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](pad_handler value)
{
switch (value)
{
case pad_handler::null: return "Null";
case pad_handler::keyboard: return "Keyboard";
case pad_handler::ds4: return "DualShock 4";
#ifdef _MSC_VER
case pad_handler::xinput: return "XInput";
#endif
#ifdef _WIN32
case pad_handler::mm: return "MMJoystick";
#endif
}
return unknown;
});
}
template <>
void fmt_class_string<video_renderer>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](video_renderer value)
{
switch (value)
{
case video_renderer::null: return "Null";
case video_renderer::opengl: return "OpenGL";
#ifdef _WIN32
case video_renderer::vulkan: return "Vulkan";
#endif
#ifdef _MSC_VER
case video_renderer::dx12: return "D3D12";
#endif
}
return unknown;
});
}
template <>
void fmt_class_string<audio_renderer>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](audio_renderer value)
{
switch (value)
{
case audio_renderer::null: return "Null";
#ifdef _WIN32
case audio_renderer::xaudio: return "XAudio2";
#elif __linux__
case audio_renderer::alsa: return "ALSA";
#endif
case audio_renderer::openal: return "OpenAL";
}
return unknown;
});
}
template <>
void fmt_class_string<video_resolution>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](video_resolution value)
{
switch (value)
{
case video_resolution::_1080: return "1920x1080";
case video_resolution::_720: return "1280x720";
case video_resolution::_480: return "720x480";
case video_resolution::_576: return "720x576";
case video_resolution::_1600x1080: return "1600x1080";
case video_resolution::_1440x1080: return "1440x1080";
case video_resolution::_1280x1080: return "1280x1080";
case video_resolution::_960x1080: return "960x1080";
}
return unknown;
});
}
template <>
void fmt_class_string<video_aspect>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](video_aspect value)
{
switch (value)
{
case video_aspect::_auto: return "Auto";
case video_aspect::_4_3: return "4:3";
case video_aspect::_16_9: return "16:9";
}
return unknown;
});
}
namespace rpcs3
{
event<void>& on_run() { static event<void> on_run; return on_run; }
@ -74,18 +192,18 @@ void Emulator::Init()
fxm::init();
// Reset defaults, cache them
cfg::root.from_default();
g_cfg_defaults = cfg::root.to_string();
g_cfg.from_default();
g_cfg_defaults = g_cfg.to_string();
// Reload global configuration
cfg::root.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string());
g_cfg.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string());
// Create directories
const std::string emu_dir_ = g_cfg_vfs_emulator_dir;
const std::string emu_dir_ = g_cfg.vfs.emulator_dir;
const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
const std::string dev_hdd0 = fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir);
const std::string dev_hdd1 = fmt::replace_all(g_cfg_vfs_dev_hdd1, "$(EmulatorDir)", emu_dir);
const std::string dev_usb = fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir);
const std::string dev_hdd0 = fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir);
const std::string dev_hdd1 = fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir);
const std::string dev_usb = fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir);
fs::create_path(dev_hdd0);
fs::create_dir(dev_hdd0 + "game/");
@ -151,18 +269,18 @@ bool Emulator::BootGame(const std::string& path, bool direct)
std::string Emulator::GetGameDir()
{
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
const std::string& emu_dir_ = g_cfg.vfs.emulator_dir;
const std::string& emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
return fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir) + "game/";
return fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir) + "game/";
}
std::string Emulator::GetLibDir()
{
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
const std::string& emu_dir_ = g_cfg.vfs.emulator_dir;
const std::string& emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
return fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir) + "sys/external/";
return fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir) + "sys/external/";
}
void Emulator::Load()
@ -204,40 +322,40 @@ void Emulator::Load()
if (fs::file cfg_file{m_cache_path + "/config.yml"})
{
LOG_NOTICE(LOADER, "Applying custom config: %s/config.yml", m_cache_path);
cfg::root.from_string(cfg_file.to_string());
g_cfg.from_string(cfg_file.to_string());
}
// Load custom config-1
if (fs::file cfg_file{fs::get_config_dir() + "data/" + m_title_id + "/config.yml"})
{
LOG_NOTICE(LOADER, "Applying custom config: data/%s/config.yml", m_title_id);
cfg::root.from_string(cfg_file.to_string());
g_cfg.from_string(cfg_file.to_string());
}
// Load custom config-2
if (fs::file cfg_file{m_path + ".yml"})
{
LOG_NOTICE(LOADER, "Applying custom config: %s.yml", m_path);
cfg::root.from_string(cfg_file.to_string());
g_cfg.from_string(cfg_file.to_string());
}
LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string());
LOG_NOTICE(LOADER, "Used configuration:\n%s\n", g_cfg.to_string());
// Load patches from different locations
fxm::check_unlocked<patch_engine>()->append(fs::get_config_dir() + "data/" + m_title_id + "/patch.yml");
fxm::check_unlocked<patch_engine>()->append(m_cache_path + "/patch.yml");
// Mount all devices
const std::string emu_dir_ = g_cfg_vfs_emulator_dir;
const std::string emu_dir_ = g_cfg.vfs.emulator_dir;
const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
const std::string home_dir = g_cfg_vfs_app_home;
std::string bdvd_dir = g_cfg_vfs_dev_bdvd;
const std::string home_dir = g_cfg.vfs.app_home;
std::string bdvd_dir = g_cfg.vfs.dev_bdvd;
vfs::mount("dev_hdd0", fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_hdd1", fmt::replace_all(g_cfg_vfs_dev_hdd1, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_flash", fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_usb", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_usb000", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_hdd0", fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_hdd1", fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_flash", fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_usb", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_usb000", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));
// Mount /dev_bdvd/ if necessary
@ -256,7 +374,7 @@ void Emulator::Load()
}
// Mount /host_root/ if necessary
if (g_cfg_vfs_allow_host_root)
if (g_cfg.vfs.host_root)
{
vfs::mount("host_root", {});
}
@ -306,7 +424,7 @@ void Emulator::Load()
{
// PS3 executable
g_system = system_type::ps3;
m_status = Ready;
m_state = system_state::ready;
vm::ps3::init();
if (m_elf_path.empty())
@ -323,7 +441,7 @@ void Emulator::Load()
{
// PPU PRX (experimental)
g_system = system_type::ps3;
m_status = Ready;
m_state = system_state::ready;
vm::ps3::init();
ppu_load_prx(ppu_prx, "");
}
@ -331,7 +449,7 @@ void Emulator::Load()
{
// SPU executable (experimental)
g_system = system_type::ps3;
m_status = Ready;
m_state = system_state::ready;
vm::ps3::init();
spu_load_exec(spu_exec);
}
@ -339,7 +457,7 @@ void Emulator::Load()
{
// ARMv7 executable
g_system = system_type::psv;
m_status = Ready;
m_state = system_state::ready;
vm::psv::init();
if (m_elf_path.empty())
@ -361,13 +479,13 @@ void Emulator::Load()
return;
}
if (g_cfg_autostart && IsReady())
if (g_cfg.misc.autostart && IsReady())
{
Run();
}
else if (IsPaused())
{
m_status = Ready;
m_state = system_state::ready;
}
}
catch (const std::exception& e)
@ -397,7 +515,7 @@ void Emulator::Run()
m_pause_start_time = 0;
m_pause_amend_time = 0;
m_status = Running;
m_state = system_state::running;
auto on_select = [](u32, cpu_thread& cpu)
{
@ -415,9 +533,9 @@ bool Emulator::Pause()
const u64 start = get_system_time();
// Try to pause
if (!m_status.compare_and_swap_test(Running, Paused))
if (!m_state.compare_and_swap_test(system_state::running, system_state::paused))
{
return m_status.compare_and_swap_test(Ready, Paused);
return m_state.compare_and_swap_test(system_state::ready, system_state::paused);
}
rpcs3::on_pause()();
@ -458,7 +576,7 @@ void Emulator::Resume()
}
// Try to resume
if (!m_status.compare_and_swap_test(Paused, Running))
if (!m_state.compare_and_swap_test(system_state::paused, system_state::running))
{
return;
}
@ -489,7 +607,7 @@ void Emulator::Resume()
void Emulator::Stop()
{
if (m_status.exchange(Stopped) == Stopped)
if (m_state.exchange(system_state::stopped) == system_state::stopped)
{
return;
}
@ -542,7 +660,7 @@ void Emulator::Stop()
RSXIOMem.Clear();
vm::close();
if (g_cfg_autoexit)
if (g_cfg.misc.autoexit)
{
GetCallbacks().exit();
}

View file

@ -1,6 +1,11 @@
#pragma once
#include "VFS.h"
#include "Utilities/Atomic.h"
#include "Utilities/Config.h"
#include <functional>
#include <memory>
#include <string>
enum class system_type
{
@ -9,11 +14,134 @@ enum class system_type
//psp, // Hypothetical
};
enum class system_state
{
running,
paused,
stopped,
ready,
};
enum class ppu_decoder_type
{
precise,
fast,
llvm,
};
enum class spu_decoder_type
{
precise,
fast,
asmjit,
llvm,
};
enum class lib_loading_type
{
automatic,
manual,
both,
liblv2only
};
enum class keyboard_handler
{
null,
basic,
};
enum class mouse_handler
{
null,
basic,
};
enum class pad_handler
{
null,
keyboard,
ds4,
#ifdef _MSC_VER
xinput,
#endif
#ifdef _WIN32
mm,
#endif
};
enum class video_renderer
{
null,
opengl,
#ifdef _WIN32
vulkan,
#endif
#ifdef _MSC_VER
dx12,
#endif
};
enum class audio_renderer
{
null,
#ifdef _WIN32
xaudio,
#elif __linux__
alsa,
#endif
openal,
};
enum class camera_handler
{
null,
fake,
};
enum class fake_camera_type
{
unknown,
eyetoy,
eyetoy2,
uvc1_1,
};
enum class video_resolution
{
_1080,
_720,
_480,
_576,
_1600x1080,
_1440x1080,
_1280x1080,
_960x1080,
};
enum class video_aspect
{
_auto,
_4_3,
_16_9,
};
enum class frame_limit_type
{
none,
_59_94,
_50,
_60,
_30,
_auto,
};
enum CellNetCtlState : s32;
enum CellSysutilLang : s32;
// Current process type
extern system_type g_system;
enum class frame_type;
struct EmuCallbacks
{
std::function<void(std::function<void()>)> call_after;
@ -22,24 +150,16 @@ struct EmuCallbacks
std::function<std::shared_ptr<class KeyboardHandlerBase>()> get_kb_handler;
std::function<std::shared_ptr<class MouseHandlerBase>()> get_mouse_handler;
std::function<std::shared_ptr<class PadHandlerBase>()> get_pad_handler;
std::function<std::unique_ptr<class GSFrameBase>(frame_type, int, int)> get_gs_frame;
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame;
std::function<std::shared_ptr<class GSRender>()> get_gs_render;
std::function<std::shared_ptr<class AudioThread>()> get_audio;
std::function<std::shared_ptr<class MsgDialogBase>()> get_msg_dialog;
std::function<std::unique_ptr<class SaveDialogBase>()> get_save_dialog;
};
enum Status : u32
{
Running,
Paused,
Stopped,
Ready,
};
class Emulator final
{
atomic_t<u32> m_status{Stopped};
atomic_t<system_state> m_state{system_state::stopped};
EmuCallbacks m_cb;
@ -76,7 +196,7 @@ public:
*/
void SetTestMode()
{
m_status = Running;
m_state = system_state::running;
}
void Init();
@ -118,11 +238,137 @@ public:
void Resume();
void Stop();
bool IsRunning() const { return m_status == Running; }
bool IsPaused() const { return m_status == Paused; }
bool IsStopped() const { return m_status == Stopped; }
bool IsReady() const { return m_status == Ready; }
auto GetStatus() const { return m_status.load(); }
bool IsRunning() const { return m_state == system_state::running; }
bool IsPaused() const { return m_state == system_state::paused; }
bool IsStopped() const { return m_state == system_state::stopped; }
bool IsReady() const { return m_state == system_state::ready; }
auto GetStatus() const { return m_state.load(); }
};
extern Emulator Emu;
struct cfg_root : cfg::node
{
struct node_core : cfg::node
{
node_core(cfg::node* _this) : cfg::node(_this, "Core") {}
cfg::_enum<ppu_decoder_type> ppu_decoder{this, "PPU Decoder", ppu_decoder_type::fast};
cfg::_int<1, 16> ppu_threads{this, "PPU Threads", 2}; // Amount of PPU threads running simultaneously (must be 2)
cfg::_bool ppu_debug{this, "PPU Debug"};
cfg::_bool llvm_logs{this, "Save LLVM logs"};
cfg::string llvm_cpu{this, "Use LLVM CPU"};
cfg::_enum<spu_decoder_type> spu_decoder{this, "SPU Decoder", spu_decoder_type::asmjit};
cfg::_bool bind_spu_cores{this, "Bind SPU threads to secondary cores"};
cfg::_bool lower_spu_priority{this, "Lower SPU thread priority"};
cfg::_bool spu_debug{this, "SPU Debug"};
cfg::_enum<lib_loading_type> lib_loading{this, "Lib Loader", lib_loading_type::automatic};
cfg::_bool hook_functions{this, "Hook static functions"};
cfg::set_entry load_libraries{this, "Load libraries"};
} core{this};
struct node_vfs : cfg::node
{
node_vfs(cfg::node* _this) : cfg::node(_this, "VFS") {}
cfg::string emulator_dir{this, "$(EmulatorDir)"}; // Default (empty): taken from fs::get_config_dir()
cfg::string dev_hdd0{this, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/"};
cfg::string dev_hdd1{this, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/"};
cfg::string dev_flash{this, "/dev_flash/", "$(EmulatorDir)dev_flash/"};
cfg::string dev_usb000{this, "/dev_usb000/", "$(EmulatorDir)dev_usb000/"};
cfg::string dev_bdvd{this, "/dev_bdvd/"}; // Not mounted
cfg::string app_home{this, "/app_home/"}; // Not mounted
cfg::_bool host_root{this, "Enable /host_root/"};
} vfs{this};
struct node_video : cfg::node
{
node_video(cfg::node* _this) : cfg::node(_this, "Video") {}
cfg::_enum<video_renderer> renderer{this, "Renderer", video_renderer::opengl};
cfg::_enum<video_resolution> resolution{this, "Resolution", video_resolution::_720};
cfg::_enum<video_aspect> aspect_ratio{this, "Aspect ratio", video_aspect::_16_9};
cfg::_enum<frame_limit_type> frame_limit{this, "Frame limit", frame_limit_type::none};
cfg::_bool write_color_buffers{this, "Write Color Buffers"};
cfg::_bool write_depth_buffer{this, "Write Depth Buffer"};
cfg::_bool read_color_buffers{this, "Read Color Buffers"};
cfg::_bool read_depth_buffer{this, "Read Depth Buffer"};
cfg::_bool log_programs{this, "Log shader programs"};
cfg::_bool vsync{this, "VSync"};
cfg::_bool debug_output{this, "Debug output"};
cfg::_bool overlay{this, "Debug overlay"};
cfg::_bool gl_legacy_buffers{this, "Use Legacy OpenGL Buffers (Debug)"};
cfg::_bool use_gpu_texture_scaling{this, "Use GPU texture scaling", true};
struct node_d3d12 : cfg::node
{
node_d3d12(cfg::node* _this) : cfg::node(_this, "D3D12") {}
cfg::string adapter{this, "Adapter"};
} d3d12{this};
} video{this};
struct node_audio : cfg::node
{
node_audio(cfg::node* _this) : cfg::node(_this, "Audio") {}
cfg::_enum<audio_renderer> renderer{this, "Renderer", static_cast<audio_renderer>(1)};
cfg::_bool dump_to_file{this, "Dump to file"};
cfg::_bool convert_to_u16{this, "Convert to 16 bit"};
cfg::_bool downmix_to_2ch{this, "Downmix to Stereo", true};
} audio{this};
struct node_io : cfg::node
{
node_io(cfg::node* _this) : cfg::node(_this, "Input/Output") {}
cfg::_enum<keyboard_handler> keyboard{this, "Keyboard", keyboard_handler::null};
cfg::_enum<mouse_handler> mouse{this, "Mouse", mouse_handler::basic};
cfg::_enum<pad_handler> pad{this, "Pad", pad_handler::keyboard};
cfg::_enum<camera_handler> camera{this, "Camera", camera_handler::null};
cfg::_enum<fake_camera_type> camera_type{this, "Camera type", fake_camera_type::unknown};
} io{this};
struct node_sys : cfg::node
{
node_sys(cfg::node* _this) : cfg::node(_this, "System") {}
cfg::_enum<CellSysutilLang> language{this, "Language"};
} sys{this};
struct node_net : cfg::node
{
node_net(cfg::node* _this) : cfg::node(_this, "Net") {}
cfg::_enum<CellNetCtlState> net_status{this, "Connection status"};
cfg::string ip_address{this, "IP address", "192.168.1.1"};
} net{this};
struct node_misc : cfg::node
{
node_misc(cfg::node* _this) : cfg::node(_this, "Miscellaneous") {}
cfg::_bool autostart{this, "Always start after boot", true};
cfg::_bool autoexit{this, "Exit RPCS3 when process finishes"};
cfg::_int<1, 65535> gdb_server_port{this, "Port", 2345};
} misc{this};
cfg::log_entry log{this, "Log"};
};
extern cfg_root g_cfg;

View file

@ -16,7 +16,7 @@ class DbgEmuPanel : public wxPanel
wxButton* m_btn_stop;
wxButton* m_btn_restart;
wxButton* m_btn_capture_frame;
u32 m_last_status = Ready;
system_state m_last_status = system_state::ready;
public:
DbgEmuPanel(wxWindow* parent) : wxPanel(parent)
@ -54,10 +54,10 @@ public:
{
m_last_status = status;
m_btn_run->Enable(status != Stopped);
m_btn_stop->Enable(status != Stopped);
m_btn_run->Enable(status != system_state::stopped);
m_btn_stop->Enable(status != system_state::stopped);
m_btn_restart->Enable(!Emu.GetPath().empty());
m_btn_run->SetLabel(status == Paused ? "Resume" : status == Running ? "Pause" : "Run");
m_btn_run->SetLabel(status == system_state::paused ? "Resume" : status == system_state::running ? "Pause" : "Run");
}
}

View file

@ -1,11 +1,9 @@
#include "stdafx.h"
#include "stdafx_gui.h"
#include "Utilities/Config.h"
#include "Emu/System.h"
#include "GLGSFrame.h"
#include <wx/version.h>
extern cfg::bool_entry g_cfg_rsx_debug_output;
GLGSFrame::GLGSFrame(int w, int h)
: GSFrame("OpenGL", w, h)
{
@ -19,7 +17,7 @@ GLGSFrame::GLGSFrame(int w, int h)
WX_GL_MINOR_VERSION, 3,
WX_GL_CORE_PROFILE,
#if !defined(CMAKE_BUILD)
g_cfg_rsx_debug_output ? WX_GL_DEBUG : 0,
g_cfg.video.debug_output ? WX_GL_DEBUG : 0,
#endif
#endif
0

View file

@ -252,43 +252,50 @@ void PADManager::OnKeyDown(wxKeyEvent &keyEvent)
{
m_key_pressed = true;
cfg::int32* entry = nullptr;
switch (m_button_id)
{
case id_pad_lstick_left: g_kbpad_config.left_stick_left = keyEvent.GetKeyCode(); break;
case id_pad_lstick_down: g_kbpad_config.left_stick_down = keyEvent.GetKeyCode(); break;
case id_pad_lstick_right: g_kbpad_config.left_stick_right = keyEvent.GetKeyCode(); break;
case id_pad_lstick_up: g_kbpad_config.left_stick_up = keyEvent.GetKeyCode(); break;
case id_pad_lstick_left: entry = &g_kbpad_config.left_stick_left; break;
case id_pad_lstick_down: entry = &g_kbpad_config.left_stick_down; break;
case id_pad_lstick_right: entry = &g_kbpad_config.left_stick_right; break;
case id_pad_lstick_up: entry = &g_kbpad_config.left_stick_up; break;
case id_pad_left: g_kbpad_config.left = keyEvent.GetKeyCode(); break;
case id_pad_down: g_kbpad_config.down = keyEvent.GetKeyCode(); break;
case id_pad_right: g_kbpad_config.right = keyEvent.GetKeyCode(); break;
case id_pad_up: g_kbpad_config.up = keyEvent.GetKeyCode(); break;
case id_pad_left: entry = &g_kbpad_config.left; break;
case id_pad_down: entry = &g_kbpad_config.down; break;
case id_pad_right: entry = &g_kbpad_config.right; break;
case id_pad_up: entry = &g_kbpad_config.up; break;
case id_pad_l1: g_kbpad_config.l1 = keyEvent.GetKeyCode(); break;
case id_pad_l2: g_kbpad_config.l2 = keyEvent.GetKeyCode(); break;
case id_pad_l3: g_kbpad_config.l3 = keyEvent.GetKeyCode(); break;
case id_pad_l1: entry = &g_kbpad_config.l1; break;
case id_pad_l2: entry = &g_kbpad_config.l2; break;
case id_pad_l3: entry = &g_kbpad_config.l3; break;
case id_pad_start: g_kbpad_config.start = keyEvent.GetKeyCode(); break;
case id_pad_select: g_kbpad_config.select = keyEvent.GetKeyCode(); break;
case id_pad_start: entry = &g_kbpad_config.start; break;
case id_pad_select: entry = &g_kbpad_config.select; break;
case id_pad_r1: g_kbpad_config.r1 = keyEvent.GetKeyCode(); break;
case id_pad_r2: g_kbpad_config.r2 = keyEvent.GetKeyCode(); break;
case id_pad_r3: g_kbpad_config.r3 = keyEvent.GetKeyCode(); break;
case id_pad_r1: entry = &g_kbpad_config.r1; break;
case id_pad_r2: entry = &g_kbpad_config.r2; break;
case id_pad_r3: entry = &g_kbpad_config.r3; break;
case id_pad_square: g_kbpad_config.square = keyEvent.GetKeyCode(); break;
case id_pad_cross: g_kbpad_config.cross = keyEvent.GetKeyCode(); break;
case id_pad_circle: g_kbpad_config.circle = keyEvent.GetKeyCode(); break;
case id_pad_triangle: g_kbpad_config.triangle = keyEvent.GetKeyCode(); break;
case id_pad_square: entry = &g_kbpad_config.square; break;
case id_pad_cross: entry = &g_kbpad_config.cross; break;
case id_pad_circle: entry = &g_kbpad_config.circle; break;
case id_pad_triangle: entry = &g_kbpad_config.triangle; break;
case id_pad_rstick_left: g_kbpad_config.right_stick_left = keyEvent.GetKeyCode(); break;
case id_pad_rstick_down: g_kbpad_config.right_stick_down = keyEvent.GetKeyCode(); break;
case id_pad_rstick_right: g_kbpad_config.right_stick_right = keyEvent.GetKeyCode(); break;
case id_pad_rstick_up: g_kbpad_config.right_stick_up = keyEvent.GetKeyCode(); break;
case id_pad_rstick_left: entry = &g_kbpad_config.right_stick_left; break;
case id_pad_rstick_down: entry = &g_kbpad_config.right_stick_down; break;
case id_pad_rstick_right: entry = &g_kbpad_config.right_stick_right; break;
case id_pad_rstick_up: entry = &g_kbpad_config.right_stick_up; break;
case 0: break;
default: LOG_ERROR(HLE, "Unknown button ID: %d", m_button_id); break;
}
if (entry)
{
// TODO: do not modify config
entry->from_string(std::to_string(keyEvent.GetKeyCode()));
}
UpdateLabel();
keyEvent.Skip();
}
@ -316,7 +323,7 @@ void PADManager::OnButtonClicked(wxCommandEvent &event)
{
switch (event.GetId())
{
case id_reset_parameters: ResetParameters(); UpdateLabel(); break;
case id_reset_parameters: g_kbpad_config.from_default(); UpdateLabel(); break;
case wxID_OK: g_kbpad_config.save(); break;
case wxID_CANCEL: break;
@ -437,40 +444,6 @@ void PADManager::UpdateLabel()
b_right_rstick->SetLabel(GetKeyName(g_kbpad_config.right_stick_right));
}
void PADManager::ResetParameters()
{
g_kbpad_config.left_stick_up = g_kbpad_config.left_stick_up.def;
g_kbpad_config.left_stick_down = g_kbpad_config.left_stick_down.def;
g_kbpad_config.left_stick_left = g_kbpad_config.left_stick_left.def;
g_kbpad_config.left_stick_right = g_kbpad_config.left_stick_right.def;
g_kbpad_config.up = g_kbpad_config.up.def;
g_kbpad_config.down = g_kbpad_config.down.def;
g_kbpad_config.left = g_kbpad_config.left.def;
g_kbpad_config.right = g_kbpad_config.right.def;
g_kbpad_config.l1 = g_kbpad_config.l1.def;
g_kbpad_config.l2 = g_kbpad_config.l2.def;
g_kbpad_config.l3 = g_kbpad_config.l3.def;
g_kbpad_config.start = g_kbpad_config.start.def;
g_kbpad_config.select = g_kbpad_config.select.def;
g_kbpad_config.r1 = g_kbpad_config.r1.def;
g_kbpad_config.r2 = g_kbpad_config.r2.def;
g_kbpad_config.r3 = g_kbpad_config.r3.def;
g_kbpad_config.square = g_kbpad_config.square.def;
g_kbpad_config.cross = g_kbpad_config.cross.def;
g_kbpad_config.circle = g_kbpad_config.circle.def;
g_kbpad_config.triangle = g_kbpad_config.triangle.def;
g_kbpad_config.right_stick_up = g_kbpad_config.right_stick_up.def;
g_kbpad_config.right_stick_down = g_kbpad_config.right_stick_down.def;
g_kbpad_config.right_stick_left = g_kbpad_config.right_stick_left.def;
g_kbpad_config.right_stick_right = g_kbpad_config.right_stick_right.def;
}
void PADManager::UpdateTimerLabel(const u32 id)
{
switch (id)

View file

@ -89,7 +89,6 @@ public:
void OnKeyUp(wxKeyEvent &keyEvent);
void OnButtonClicked(wxCommandEvent &event);
void UpdateLabel();
void ResetParameters();
void UpdateTimerLabel(const u32 id);
void SwitchButtons(const bool IsEnabled);
const wxString GetKeyName(const u32 keyCode);

View file

@ -75,9 +75,25 @@ struct cfg_adapter
{
}
static cfg::entry_base& get_cfg(cfg::entry_base& root, cfg_location::const_iterator begin, cfg_location::const_iterator end)
static cfg::_base& get_cfg(cfg::_base& root, const std::string& name)
{
return begin == end ? root : get_cfg(root[*begin], begin + 1, end);
if (root.get_type() == cfg::type::node)
{
for (const auto& pair : static_cast<cfg::node&>(root).get_nodes())
{
if (pair.first == name)
{
return *pair.second;
}
}
}
fmt::throw_exception("Node not found: %s", name);
}
static cfg::_base& get_cfg(cfg::_base& root, cfg_location::const_iterator begin, cfg_location::const_iterator end)
{
return begin == end ? root : get_cfg(get_cfg(root, *begin), begin + 1, end);
}
static YAML::Node get_node(YAML::Node node, cfg_location::const_iterator begin, cfg_location::const_iterator end)
@ -85,9 +101,9 @@ struct cfg_adapter
return begin == end ? node : get_node(node[*begin], begin + 1, end); // TODO
}
cfg::entry_base& get_cfg() const
cfg::_base& get_cfg() const
{
return get_cfg(cfg::root, location.cbegin(), location.cend());
return get_cfg(g_cfg, location.cbegin(), location.cend());
}
YAML::Node get_node(YAML::Node root) const
@ -106,7 +122,7 @@ struct radiobox_pad_helper
radiobox_pad_helper(cfg_location&& _loc)
: location(std::move(_loc))
{
for (const auto& v : cfg_adapter::get_cfg(cfg::root, location.cbegin(), location.cend()).to_list())
for (const auto& v : cfg_adapter::get_cfg(g_cfg, location.cbegin(), location.cend()).to_list())
{
values.Add(fmt::FromUTF8(v));
}

View file

@ -7,30 +7,30 @@ struct KeyboardPadConfig final : cfg::node
{
const std::string cfg_name = fs::get_config_dir() + "/config_kbpad.yml";
cfg::int32_entry left_stick_left{ *this, "Left Analog Stick Left", static_cast<int>('A') };
cfg::int32_entry left_stick_down{ *this, "Left Analog Stick Down", static_cast<int>('S') };
cfg::int32_entry left_stick_right{ *this, "Left Analog Stick Right", static_cast<int>('D') };
cfg::int32_entry left_stick_up{ *this, "Left Analog Stick Up", static_cast<int>('W') };
cfg::int32_entry right_stick_left{ *this, "Right Analog Stick Left", 313 };
cfg::int32_entry right_stick_down{ *this, "Right Analog Stick Down", 367 };
cfg::int32_entry right_stick_right{ *this, "Right Analog Stick Right", 312 };
cfg::int32_entry right_stick_up{ *this, "Right Analog Stick Up", 366 };
cfg::int32_entry start{ *this, "Start", 13 };
cfg::int32_entry select{ *this, "Select", 32 };
cfg::int32_entry square{ *this, "Square", static_cast<int>('Z') };
cfg::int32_entry cross{ *this, "Cross", static_cast<int>('X') };
cfg::int32_entry circle{ *this, "Circle", static_cast<int>('C') };
cfg::int32_entry triangle{ *this, "Triangle", static_cast<int>('V') };
cfg::int32_entry left{ *this, "Left", 314 };
cfg::int32_entry down{ *this, "Down", 317 };
cfg::int32_entry right{ *this, "Right", 316 };
cfg::int32_entry up{ *this, "Up", 315 };
cfg::int32_entry r1{ *this, "R1", static_cast<int>('E') };
cfg::int32_entry r2{ *this, "R2", static_cast<int>('T') };
cfg::int32_entry r3{ *this, "R3", static_cast<int>('G') };
cfg::int32_entry l1{ *this, "L1", static_cast<int>('Q') };
cfg::int32_entry l2{ *this, "L2", static_cast<int>('R') };
cfg::int32_entry l3{ *this, "L3", static_cast<int>('F') };
cfg::int32 left_stick_left{this, "Left Analog Stick Left", static_cast<int>('A')};
cfg::int32 left_stick_down{this, "Left Analog Stick Down", static_cast<int>('S')};
cfg::int32 left_stick_right{this, "Left Analog Stick Right", static_cast<int>('D')};
cfg::int32 left_stick_up{this, "Left Analog Stick Up", static_cast<int>('W')};
cfg::int32 right_stick_left{this, "Right Analog Stick Left", 313};
cfg::int32 right_stick_down{this, "Right Analog Stick Down", 367};
cfg::int32 right_stick_right{this, "Right Analog Stick Right", 312};
cfg::int32 right_stick_up{this, "Right Analog Stick Up", 366};
cfg::int32 start{this, "Start", 13};
cfg::int32 select{this, "Select", 32};
cfg::int32 square{this, "Square", static_cast<int>('Z')};
cfg::int32 cross{this, "Cross", static_cast<int>('X')};
cfg::int32 circle{this, "Circle", static_cast<int>('C')};
cfg::int32 triangle{this, "Triangle", static_cast<int>('V')};
cfg::int32 left{this, "Left", 314};
cfg::int32 down{this, "Down", 317};
cfg::int32 right{this, "Right", 316};
cfg::int32 up{this, "Up", 315};
cfg::int32 r1{this, "R1", static_cast<int>('E')};
cfg::int32 r2{this, "R2", static_cast<int>('T')};
cfg::int32 r3{this, "R3", static_cast<int>('G')};
cfg::int32 l1{this, "L1", static_cast<int>('Q')};
cfg::int32 l2{this, "L2", static_cast<int>('R')};
cfg::int32 l3{this, "L3", static_cast<int>('F')};
bool load()
{

View file

@ -1,6 +1,6 @@
#include "stdafx.h"
#include "stdafx_gui.h"
#ifdef _MSC_VER
#ifdef _WIN32
#include "MMJoystickHandler.h"
MMJoystickConfig g_mmjoystick_config;

View file

@ -8,30 +8,30 @@ struct MMJoystickConfig final : cfg::node
{
const std::string cfg_name = fs::get_config_dir() + "/config_mmjoystick.yml";
//cfg::int32_entry left_stick_left{ *this, "Left Analog Stick Left", static_cast<int>('A') };
//cfg::int32_entry left_stick_down{ *this, "Left Analog Stick Down", static_cast<int>('S') };
//cfg::int32_entry left_stick_right{ *this, "Left Analog Stick Right", static_cast<int>('D') };
//cfg::int32_entry left_stick_up{ *this, "Left Analog Stick Up", static_cast<int>('W') };
//cfg::int32_entry right_stick_left{ *this, "Right Analog Stick Left", 313 };
//cfg::int32_entry right_stick_down{ *this, "Right Analog Stick Down", 367 };
//cfg::int32_entry right_stick_right{ *this, "Right Analog Stick Right", 312 };
//cfg::int32_entry right_stick_up{ *this, "Right Analog Stick Up", 366 };
cfg::int32_entry start{ *this, "Start", JOY_BUTTON9 };
cfg::int32_entry select{ *this, "Select", JOY_BUTTON10 };
cfg::int32_entry square{ *this, "Square", JOY_BUTTON4 };
cfg::int32_entry cross{ *this, "Cross", JOY_BUTTON3 };
cfg::int32_entry circle{ *this, "Circle", JOY_BUTTON2 };
cfg::int32_entry triangle{ *this, "Triangle", JOY_BUTTON1 };
//cfg::int32_entry left{ *this, "Left", 314 };
//cfg::int32_entry down{ *this, "Down", 317 };
//cfg::int32_entry right{ *this, "Right", 316 };
//cfg::int32_entry up{ *this, "Up", 315 };
cfg::int32_entry r1{ *this, "R1", JOY_BUTTON8 };
cfg::int32_entry r2{ *this, "R2", JOY_BUTTON6 };
cfg::int32_entry r3{ *this, "R3", JOY_BUTTON12 };
cfg::int32_entry l1{ *this, "L1", JOY_BUTTON7 };
cfg::int32_entry l2{ *this, "L2", JOY_BUTTON5 };
cfg::int32_entry l3{ *this, "L3", JOY_BUTTON11 };
//cfg::int32 left_stick_left{this, "Left Analog Stick Left", static_cast<int>('A')};
//cfg::int32 left_stick_down{this, "Left Analog Stick Down", static_cast<int>('S')};
//cfg::int32 left_stick_right{this, "Left Analog Stick Right", static_cast<int>('D')};
//cfg::int32 left_stick_up{this, "Left Analog Stick Up", static_cast<int>('W')};
//cfg::int32 right_stick_left{this, "Right Analog Stick Left", 313};
//cfg::int32 right_stick_down{this, "Right Analog Stick Down", 367};
//cfg::int32 right_stick_right{this, "Right Analog Stick Right", 312};
//cfg::int32 right_stick_up{this, "Right Analog Stick Up", 366};
cfg::int32 start{this, "Start", JOY_BUTTON9};
cfg::int32 select{this, "Select", JOY_BUTTON10};
cfg::int32 square{this, "Square", JOY_BUTTON4};
cfg::int32 cross{this, "Cross", JOY_BUTTON3};
cfg::int32 circle{this, "Circle", JOY_BUTTON2};
cfg::int32 triangle{this, "Triangle", JOY_BUTTON1};
//cfg::int32 left{this, "Left", 314};
//cfg::int32 down{this, "Down", 317};
//cfg::int32 right{this, "Right", 316};
//cfg::int32 up{this, "Up", 315};
cfg::int32 r1{this, "R1", JOY_BUTTON8};
cfg::int32 r2{this, "R2", JOY_BUTTON6};
cfg::int32 r3{this, "R3", JOY_BUTTON12};
cfg::int32 l1{this, "L1", JOY_BUTTON7};
cfg::int32 l2{this, "L2", JOY_BUTTON5};
cfg::int32 l3{this, "L3", JOY_BUTTON11};
bool load()
{

View file

@ -20,6 +20,8 @@
#include "DS4PadHandler.h"
#ifdef _MSC_VER
#include "XInputPadHandler.h"
#endif
#ifdef _WIN32
#include "MMJoystickHandler.h"
#endif
@ -72,55 +74,6 @@ void save_gui_cfg()
IMPLEMENT_APP(Rpcs3App)
Rpcs3App* TheApp;
cfg::map_entry<std::function<std::shared_ptr<KeyboardHandlerBase>()>> g_cfg_kb_handler(cfg::root.io, "Keyboard",
{
{ "Null", &std::make_shared<NullKeyboardHandler> },
{ "Basic", &std::make_shared<BasicKeyboardHandler> },
});
cfg::map_entry<std::function<std::shared_ptr<MouseHandlerBase>()>> g_cfg_mouse_handler(cfg::root.io, "Mouse",
{
{ "Null", &std::make_shared<NullMouseHandler> },
{ "Basic", &std::make_shared<BasicMouseHandler> },
});
cfg::map_entry<std::function<std::shared_ptr<PadHandlerBase>()>> g_cfg_pad_handler(cfg::root.io, "Pad", "Keyboard",
{
{ "Null", &std::make_shared<NullPadHandler> },
{ "Keyboard", &std::make_shared<KeyboardPadHandler> },
{ "DualShock 4", &std::make_shared<DS4PadHandler> },
#ifdef _MSC_VER
{ "XInput", &std::make_shared<XInputPadHandler> },
{ "MMJoystick", &std::make_shared<MMJoystickHandler>},
#endif
});
cfg::map_entry<std::function<std::shared_ptr<GSRender>()>> g_cfg_gs_render(cfg::root.video, "Renderer", "OpenGL",
{
{ "Null", &std::make_shared<NullGSRender> },
{ "OpenGL", &std::make_shared<GLGSRender> },
#ifdef _MSC_VER
{ "D3D12", &std::make_shared<D3D12GSRender> },
#endif
#ifdef _WIN32
{ "Vulkan", &std::make_shared<VKGSRender> },
#endif
});
cfg::map_entry<std::function<std::shared_ptr<AudioThread>()>> g_cfg_audio_render(cfg::root.audio, "Renderer", 1,
{
{ "Null", &std::make_shared<NullAudioThread> },
#ifdef _WIN32
{ "XAudio2", &std::make_shared<XAudio2Thread> },
#elif __linux__
{ "ALSA", &std::make_shared<ALSAThread> },
#endif
{ "OpenAL", &std::make_shared<OpenALThread> },
});
extern cfg::bool_entry g_cfg_autostart;
extern cfg::bool_entry g_cfg_autoexit;
bool Rpcs3App::OnInit()
{
static const wxCmdLineEntryDesc desc[]
@ -161,28 +114,93 @@ bool Rpcs3App::OnInit()
wxGetApp().Exit();
};
callbacks.get_kb_handler = []{ return g_cfg_kb_handler.get()(); };
callbacks.get_mouse_handler = []{ return g_cfg_mouse_handler.get()(); };
callbacks.get_pad_handler = []{ return g_cfg_pad_handler.get()(); };
callbacks.get_gs_frame = [](frame_type type, int w, int h) -> std::unique_ptr<GSFrameBase>
callbacks.get_kb_handler = []() -> std::shared_ptr<KeyboardHandlerBase>
{
switch (type)
switch (keyboard_handler type = g_cfg.io.keyboard)
{
case frame_type::OpenGL: return std::make_unique<GLGSFrame>(w, h);
case frame_type::DX12: return std::make_unique<GSFrame>("DirectX 12", w, h);
case frame_type::Null: return std::make_unique<GSFrame>("Null", w, h);
case frame_type::Vulkan: return std::make_unique<GSFrame>("Vulkan", w, h);
case keyboard_handler::null: return std::make_shared<NullKeyboardHandler>();
case keyboard_handler::basic: return std::make_shared<BasicKeyboardHandler>();
default: fmt::throw_exception("Invalid keyboard handler: %s", type);
}
fmt::throw_exception("Invalid frame type (0x%x)" HERE, (int)type);
};
callbacks.get_gs_render = []{ return g_cfg_gs_render.get()(); };
callbacks.get_mouse_handler = []() -> std::shared_ptr<MouseHandlerBase>
{
switch (mouse_handler type = g_cfg.io.mouse)
{
case mouse_handler::null: return std::make_shared<NullMouseHandler>();
case mouse_handler::basic: return std::make_shared<BasicMouseHandler>();
default: fmt::throw_exception("Invalid mouse handler: %s", type);
}
};
callbacks.get_audio = []{ return g_cfg_audio_render.get()(); };
callbacks.get_pad_handler = []() -> std::shared_ptr<PadHandlerBase>
{
switch (pad_handler type = g_cfg.io.pad)
{
case pad_handler::null: return std::make_shared<NullPadHandler>();
case pad_handler::keyboard: return std::make_shared<KeyboardPadHandler>();
case pad_handler::ds4: return std::make_shared<DS4PadHandler>();
#ifdef _MSC_VER
case pad_handler::xinput: return std::make_shared<XInputPadHandler>();
#endif
#ifdef _WIN32
case pad_handler::mm: return std::make_shared<MMJoystickHandler>();
#endif
default: fmt::throw_exception("Invalid pad handler: %s", type);
}
};
callbacks.get_gs_frame = []() -> std::unique_ptr<GSFrameBase>
{
extern const std::unordered_map<video_resolution, std::pair<int, int>, value_hash<video_resolution>> g_video_out_resolution_map;
const auto size = g_video_out_resolution_map.at(g_cfg.video.resolution);
switch (video_renderer type = g_cfg.video.renderer)
{
case video_renderer::null: return std::make_unique<GSFrame>("Null", size.first, size.second);
case video_renderer::opengl: return std::make_unique<GLGSFrame>(size.first, size.second);
#ifdef _WIN32
case video_renderer::vulkan: return std::make_unique<GSFrame>("Vulkan", size.first, size.second);
#endif
#ifdef _MSC_VER
case video_renderer::dx12: return std::make_unique<GSFrame>("DirectX 12", size.first, size.second);
#endif
default: fmt::throw_exception("Invalid video renderer: %s" HERE, type);
}
};
callbacks.get_gs_render = []() -> std::shared_ptr<GSRender>
{
switch (video_renderer type = g_cfg.video.renderer)
{
case video_renderer::null: return std::make_shared<NullGSRender>();
case video_renderer::opengl: return std::make_shared<GLGSRender>();
#ifdef _WIN32
case video_renderer::vulkan: return std::make_shared<VKGSRender>();
#endif
#ifdef _MSC_VER
case video_renderer::dx12: return std::make_shared<D3D12GSRender>();
#endif
default: fmt::throw_exception("Invalid video renderer: %s" HERE, type);
}
};
callbacks.get_audio = []() -> std::shared_ptr<AudioThread>
{
switch (audio_renderer type = g_cfg.audio.renderer)
{
case audio_renderer::null: return std::make_shared<NullAudioThread>();
#ifdef _WIN32
case audio_renderer::xaudio: return std::make_shared<XAudio2Thread>();
#elif __linux__
case audio_renderer::alsa: return std::make_shared<ALSAThread>();
#endif
case audio_renderer::openal: return std::make_shared<OpenALThread>();
default: fmt::throw_exception("Invalid audio renderer: %s" HERE, type);
}
};
callbacks.get_msg_dialog = []() -> std::shared_ptr<MsgDialogBase>
{
@ -227,8 +245,8 @@ void Rpcs3App::OnArguments(const wxCmdLineParser& parser)
}
// TODO: clean implementation
g_cfg_autostart = true;
g_cfg_autoexit = true;
g_cfg.misc.autostart.from_string("true");
g_cfg.misc.autoexit.from_string("true");
}
if (parser.GetParamCount() > 0)