diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index ebf966f2ad..74a571db55 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -208,6 +208,16 @@ std::vector fmt::split(const std::string& source, std::initializer_ return std::move(result); } +std::string fmt::trim(const std::string& source, const std::string& values) +{ + std::size_t begin = source.find_first_not_of(values); + + if (begin == source.npos) + return{}; + + return source.substr(begin, source.find_last_not_of(values) + 1); +} + std::string fmt::tolower(std::string source) { std::transform(source.begin(), source.end(), source.begin(), ::tolower); diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 02111b9db2..5f1376860c 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -300,6 +300,7 @@ namespace fmt std::vector rSplit(const std::string& source, const std::string& delim); std::vector split(const std::string& source, std::initializer_list separators, bool is_skip_empty = true); + std::string trim(const std::string& source, const std::string& values = " \t"); template std::string merge(const T& source, const std::string& separator) diff --git a/Utilities/config_context.cpp b/Utilities/config_context.cpp new file mode 100644 index 0000000000..685328f79a --- /dev/null +++ b/Utilities/config_context.cpp @@ -0,0 +1,146 @@ +#include "stdafx.h" +#include "config_context.h" +#include "convert.h" +#include "StrFmt.h" +#include +#include + +void config_context_t::group::init() +{ + m_cfg->m_groups[full_name()] = this; +} + +config_context_t::group::group(config_context_t* cfg, const std::string& name) + : m_cfg(cfg) + , m_name(name) + , m_parent(nullptr) +{ + init(); +} + +config_context_t::group::group(group* parent, const std::string& name) + : m_cfg(parent->m_cfg) + , m_name(name) + , m_parent(parent) +{ + init(); +} + +void config_context_t::group::set_parent(config_context_t* cfg) +{ + m_cfg = cfg; + init(); +} + +std::string config_context_t::group::name() const +{ + return m_name; +} + +std::string config_context_t::group::full_name() const +{ + if (m_parent) + return m_parent->full_name() + "/" + m_name; + + return m_name; +} + +void config_context_t::assign(const config_context_t& rhs) +{ + for (auto &rhs_g : rhs.m_groups) + { + auto g = m_groups.at(rhs_g.first); + + for (auto rhs_e : rhs_g.second->entries) + { + g->entries[rhs_e.first]->value_from(rhs_e.second); + } + } +} + +void config_context_t::deserialize(std::istream& stream) +{ + set_defaults(); + + uint line_index = 0; + std::string line; + group *current_group = nullptr; + + while (std::getline(stream, line)) + { + ++line_index; + line = fmt::trim(line); + + if (line.empty()) + continue; + + if (line.front() == '[' && line.back() == ']') + { + std::string group_name = line.substr(1, line.length() - 2); + + auto found = m_groups.find(group_name); + + if (found == m_groups.end()) + { + std::cerr << line_index << ": group '" << group_name << "' not exists. ignored" << std::endl; + current_group = nullptr; + continue; + } + + current_group = found->second; + continue; + } + + if (current_group == nullptr) + { + std::cerr << line_index << ": line '" << line << "' ignored, no group." << std::endl; + continue; + } + + auto name_value = fmt::split(line, { "=" }); + switch (name_value.size()) + { + case 1: current_group->entries[fmt::trim(name_value[0])]->string_value({}); break; + + default: + std::cerr << line_index << ": line '" << line << "' has more than one symbol '='. used only first" << std::endl; + case 2: current_group->entries[fmt::trim(name_value[0])]->string_value(fmt::trim(name_value[1])); break; + + } + } +} + +void config_context_t::serialize(std::ostream& stream) const +{ + for (auto &g : m_groups) + { + stream << "[" + g.first + "]" << std::endl; + + for (auto &e : g.second->entries) + { + stream << e.first << "=" << e.second->string_value() << std::endl; + } + + stream << std::endl; + } +} + +void config_context_t::set_defaults() +{ + for (auto &g : m_groups) + { + for (auto &e : g.second->entries) + { + e.second->to_default(); + } + } +} + +std::string config_context_t::to_string() const +{ + std::ostringstream result; + + serialize(result); + + return result.str(); +} \ No newline at end of file diff --git a/Utilities/config_context.h b/Utilities/config_context.h new file mode 100644 index 0000000000..ebc0eaca7f --- /dev/null +++ b/Utilities/config_context.h @@ -0,0 +1,127 @@ +#pragma once +#include +#include + +class config_context_t +{ +public: + class entry_base; + +protected: + class group + { + group* m_parent; + config_context_t* m_cfg; + std::string m_name; + + void init(); + + public: + std::unordered_map entries; + + group(config_context_t* cfg, const std::string& name); + group(group* parent, const std::string& name); + void set_parent(config_context_t* cfg); + + std::string name() const; + std::string full_name() const; + + friend config_context_t; + }; + +public: + class entry_base + { + public: + virtual std::string name() = 0; + virtual void to_default() = 0; + virtual std::string string_value() = 0; + virtual void string_value(const std::string& value) = 0; + virtual void value_from(const entry_base* rhs) = 0; + }; + + template + class entry : public entry_base + { + T m_default_value; + T m_value; + group* m_parent; + std::string m_name; + + public: + entry(group* parent, const std::string& name, const T& default_value) + : m_parent(parent) + , m_name(name) + , m_default_value(default_value) + , m_value(default_value) + { + parent->entries[name] = this; + } + + T default_value() const + { + return m_default_value; + } + + T value() const + { + return m_value; + } + + void value(const T& new_value) + { + m_value = new_value; + } + + std::string name() override + { + return m_name; + } + + void to_default() override + { + value(default_value()); + } + + std::string string_value() override + { + return convert::to(value()); + } + + void string_value(const std::string &new_value) override + { + value(convert::to(new_value)); + } + + void value_from(const entry_base* rhs) + { + value(static_cast(rhs)->value()); + } + + entry& operator = (const T& new_value) + { + value(new_value); + return *this; + } + + explicit operator const T&() const + { + return m_value; + } + }; + +private: + std::unordered_map m_groups; + +public: + config_context_t() = default; + + void assign(const config_context_t& rhs); + + void serialize(std::ostream& stream) const; + void deserialize(std::istream& stream); + + void set_defaults(); + + std::string to_string() const; +}; \ No newline at end of file diff --git a/Utilities/convert.h b/Utilities/convert.h new file mode 100644 index 0000000000..0a782c0347 --- /dev/null +++ b/Utilities/convert.h @@ -0,0 +1,240 @@ +#pragma once +#include + +namespace convert +{ + template + struct to_impl_t; + + template + struct to_impl_t + { + static Type func(const Type& value) + { + return value; + } + }; + + template<> + struct to_impl_t + { + static std::string func(bool value) + { + return value ? "true" : "false"; + } + }; + + template<> + struct to_impl_t + { + static bool func(const std::string& value) + { + return value == "true" ? true : false; + } + }; + + template<> + struct to_impl_t + { + static std::string func(char value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(unsigned char value) + { + return std::to_string(value); + } + }; + + + template<> + struct to_impl_t + { + static std::string func(short value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(unsigned short value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(int value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(unsigned int value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(long value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(unsigned long value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(long long value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(unsigned long long value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(float value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(double value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static std::string func(long double value) + { + return std::to_string(value); + } + }; + + template<> + struct to_impl_t + { + static int func(const std::string& value) + { + return std::stoi(value); + } + }; + + template<> + struct to_impl_t + { + static unsigned int func(const std::string& value) + { + return (unsigned long)std::stoul(value); + } + }; + + template<> + struct to_impl_t + { + static long func(const std::string& value) + { + return std::stol(value); + } + }; + + template<> + struct to_impl_t + { + static unsigned long func(const std::string& value) + { + return std::stoul(value); + } + }; + + template<> + struct to_impl_t + { + static long long func(const std::string& value) + { + return std::stoll(value); + } + }; + + template<> + struct to_impl_t + { + static unsigned long long func(const std::string& value) + { + return std::stoull(value); + } + }; + + template<> + struct to_impl_t + { + static float func(const std::string& value) + { + return std::stof(value); + } + }; + + template<> + struct to_impl_t + { + static double func(const std::string& value) + { + return std::stod(value); + } + }; + + template<> + struct to_impl_t + { + static long double func(const std::string& value) + { + return std::stold(value); + } + }; + + template + ReturnType to(FromType value) + { + return to_impl_t, std::remove_all_extents_t>::func(value); + } +} \ No newline at end of file diff --git a/Utilities/event.h b/Utilities/event.h new file mode 100644 index 0000000000..8078bfccf3 --- /dev/null +++ b/Utilities/event.h @@ -0,0 +1,420 @@ +#pragma once +#include +#include +#include + +enum class event_result +{ + skip, + handled +}; + +class events_queue +{ + std::deque> m_queue; + +public: + /*template + events_queue& operator += (event &evt) + { + evt.set_queue(this); + return *this; + } +*/ + void invoke(std::function function) + { + m_queue.push_back(function); + } + + void flush() + { + while (!m_queue.empty()) + { + std::function function = m_queue.front(); + function(); + m_queue.pop_front(); + } + } +}; + +template +class event +{ + using func_t = std::function; + using entry_t = typename std::list::iterator; + + std::list handlers; + events_queue& m_queue; + +public: + event(events_queue* queue = nullptr) : m_queue(*queue) + { + } + + void invoke(AT... args) + { + m_queue.invoke(std::bind([&](AT... eargs) + { + for (auto &&handler : handlers) + { + if (handler(eargs...) == event_result::handled) + break; + } + }, args...)); + } + + void operator()(AT... args) + { + invoke(args...); + } + + entry_t bind(func_t func) + { + handlers.push_front(func); + return handlers.begin(); + } + + template + entry_t bind(T *caller, event_result(T::*callback)(AT...)) + { + return bind([=](AT... args) { return (caller->*callback)(args...); }); + } + + template + entry_t bind(T *caller, void(T::*callback)(AT...)) + { + return bind([=](AT... args) { (caller->*callback)(args...); return event_result::skip; }); + } + + void unbind(entry_t entry) + { + handlers.erase(entry); + } + + entry_t operator +=(func_t func) + { + return bind(func); + } + + void operator -=(entry_t what) + { + return unbind(what); + } +}; + +template<> +class event +{ + using func_t = std::function; + using entry_t = std::list::iterator; + + std::list m_listeners; + events_queue* m_queue; + + void invoke_listeners() + { + for (auto &&listener : m_listeners) + { + if (listener() == event_result::handled) + break; + } + } + +public: + event(events_queue* queue = nullptr) : m_queue(queue) + { + } + + void invoke() + { + if (m_queue) + m_queue->invoke([=]() { invoke_listeners(); }); + else + invoke_listeners(); + } + + void operator()() + { + invoke(); + } + + entry_t bind(func_t func) + { + m_listeners.push_front(func); + return m_listeners.begin(); + } + + template + entry_t bind(T *caller, event_result(T::*callback)()) + { + return bind([=]() { return (caller->*callback)(); }); + } + + template + entry_t bind(T *caller, void(T::*callback)()) + { + return bind([=]() { (caller->*callback)(); return event_result::skip; }); + } + + void unbind(entry_t what) + { + m_listeners.erase(what); + } + + entry_t operator +=(func_t func) + { + return bind(func); + } + + void operator -=(entry_t what) + { + return unbind(what); + } +}; + +class event_binder_t +{ + template + class binder_impl_t + { + event_binder_t *m_binder; + event *m_event; + + public: + binder_impl_t(event_binder_t *binder, event *evt) + : m_binder(binder) + , m_event(evt) + { + } + }; + +public: + template + binder_impl_t operator()(event& evt) const + { + return{ this, &evt }; + } +}; + +template +class combined_data; + +template +class local_data +{ +public: + using type = T; + +protected: + type m_data; + + void set(type value) + { + m_data = value; + } + + type get() const + { + return m_data; + } + + bool equals(T value) const + { + return get() == value; + } + + bool invoke_event(type value) + { + return false; + } + + friend combined_data; +}; + +template +class combined_data +{ +public: + using type = T; + +protected: + local_data m_local_data; + std::function m_invoke_event_function; + std::function m_get_function; + + bool invoke_event(type value) + { + if (m_invoke_event_function) + { + m_invoke_event_function(value); + return true; + } + + return false; + } + + void set(type value) + { + m_local_data.set(value); + } + + type get() const + { + if (m_get_function) + { + return m_get_function(); + } + + return m_local_data.get(); + } + + type get_local() const + { + return m_local_data.get(); + } + + bool equals(T value) const + { + return get_local() == value; + } + +public: + void invoke_event_function(std::function function) + { + m_invoke_event_function = function; + } + + void get_function(std::function function) + { + m_get_function = function; + } +}; + +template> +class data_event : public base_type_ +{ +public: + using type = T; + using base_type = base_type_; + +protected: + event_result dochange(type new_value) + { + auto old_value = get(); + base_type::set(new_value); + onchanged(old_value); + return event_result::handled; + } + +public: + event onchange; + event onchanged; + + data_event(events_queue *queue = nullptr) + : onchange(queue) + , onchanged(queue) + { + onchange.bind(this, &data_event::dochange); + base_type::set({}); + } + + type get() const + { + return base_type::get(); + } + + type operator()() const + { + return get(); + } + + void change(type value, bool use_custom_invoke_event = true) + { + if (!base_type::equals(value)) + { + if (!use_custom_invoke_event || !base_type::invoke_event(value)) + { + onchange(value); + } + } + } + + operator const type() const + { + return get(); + } + + operator type() + { + return get(); + } + + data_event& operator = (type value) + { + change(value); + return *this; + } + + template auto operator + (aType value) const { return get() + value; } + template auto operator - (aType value) const { return get() - value; } + template auto operator * (aType value) const { return get() * value; } + template auto operator / (aType value) const { return get() / value; } + template auto operator % (aType value) const { return get() % value; } + template auto operator & (aType value) const { return get() & value; } + template auto operator | (aType value) const { return get() | value; } + template auto operator ^ (aType value) const { return get() ^ value; } + + template data_event& operator += (aType value) { return *this = get() + value; } + template data_event& operator -= (aType value) { return *this = get() - value; } + template data_event& operator *= (aType value) { return *this = get() * value; } + template data_event& operator /= (aType value) { return *this = get() / value; } + template data_event& operator %= (aType value) { return *this = get() % value; } + template data_event& operator &= (aType value) { return *this = get() & value; } + template data_event& operator |= (aType value) { return *this = get() | value; } + template data_event& operator ^= (aType value) { return *this = get() ^ value; } + + data_event& operator ++() + { + type value = get(); + return *this = ++value; + } + + type operator ++(int) + { + type value = get(); + type result = value; + *this = value++; + return result; + } + + data_event& operator --() + { + type value = get(); + return *this = --value; + } + + type operator --(int) + { + type value = get(); + type result = value; + *this = value--; + return result; + } +}; + +struct with_event_binder +{ + event_binder_t event_binder; +}; + +struct test_obj +{ + void test(int) + { + event i; + auto it = i.bind(this, &test_obj::test); + i(5); + i.unbind(it); + i(6); + } +}; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 4604aa4903..0650453862 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -8,6 +8,7 @@ #include #include "d3dx12.h" #include +#include "Emu/state.h" PFN_D3D12_CREATE_DEVICE wrapD3D12CreateDevice; PFN_D3D12_GET_DEBUG_INTERFACE wrapD3D12GetDebugInterface; @@ -928,10 +929,10 @@ void D3D12GSRender::semaphore_PGRAPH_backend_release(u32 offset, u32 value) u32 m_context_dma_color_d = rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_D]; u32 m_context_dma_z = rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]; - bool needTransfer = (m_context_dma_z && Ini.GSDumpDepthBuffer.GetValue()) || - ((m_context_dma_color_a || m_context_dma_color_b || m_context_dma_color_c || m_context_dma_color_d) && Ini.GSDumpColorBuffers.GetValue()); + bool needTransfer = (m_context_dma_z && rpcs3::state.config.rsx.opengl.write_depth_buffer) || + ((m_context_dma_color_a || m_context_dma_color_b || m_context_dma_color_c || m_context_dma_color_d) && rpcs3::state.config.rsx.opengl.write_color_buffers); - if (m_context_dma_z && Ini.GSDumpDepthBuffer.GetValue()) + if (m_context_dma_z && rpcs3::state.config.rsx.opengl.write_depth_buffer) { size_t sizeInByte = clip_w * clip_h * 2; assert(m_UAVHeap.canAlloc(sizeInByte)); @@ -1016,7 +1017,7 @@ void D3D12GSRender::semaphore_PGRAPH_backend_release(u32 offset, u32 value) } ID3D12Resource *rtt0, *rtt1, *rtt2, *rtt3; - if (Ini.GSDumpColorBuffers.GetValue()) + if (rpcs3::state.config.rsx.opengl.write_color_buffers) { switch (rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]) { @@ -1067,7 +1068,7 @@ void D3D12GSRender::semaphore_PGRAPH_backend_release(u32 offset, u32 value) WaitForSingleObject(handle, INFINITE); CloseHandle(handle); - if (m_context_dma_z && Ini.GSDumpDepthBuffer.GetValue()) + if (m_context_dma_z && rpcs3::state.config.rsx.opengl.write_depth_buffer) { u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], m_context_dma_z - 0xfeed0000); auto ptr = vm::get_ptr(address); @@ -1101,7 +1102,7 @@ void D3D12GSRender::semaphore_PGRAPH_backend_release(u32 offset, u32 value) break; } - if (Ini.GSDumpColorBuffers.GetValue()) + if (rpcs3::state.config.rsx.opengl.write_color_buffers) { switch (rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]) { diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 2c9d4bb525..7ccc5b823e 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -6,6 +6,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "GLGSRender.h" +#include "Emu/state.h" #define DUMP_VERTEX_DATA 0 @@ -1536,7 +1537,7 @@ void GLGSRender::read_buffers() glDisable(GL_STENCIL_TEST); - if (Ini.GSReadColorBuffers.GetValue()) + if (rpcs3::state.config.rsx.opengl.read_color_buffers) { auto color_format = surface_color_format_to_gl(m_surface.color_format); @@ -1576,7 +1577,7 @@ void GLGSRender::read_buffers() } } - if (Ini.GSReadDepthBuffer.GetValue()) + if (rpcs3::state.config.rsx.opengl.read_depth_buffer) { auto depth_format = surface_depth_format_to_gl(m_surface.depth_format); @@ -1618,7 +1619,7 @@ void GLGSRender::write_buffers() if (!draw_fbo) return; - if (Ini.GSDumpColorBuffers.GetValue()) + if (rpcs3::state.config.rsx.opengl.write_color_buffers) { //gl::buffer pbo_color; //__glcheck pbo_color.create(m_draw_tex_color[0].width() * m_draw_tex_color[0].height() * 4); @@ -1678,7 +1679,7 @@ void GLGSRender::write_buffers() } } - if (Ini.GSDumpDepthBuffer.GetValue()) + if (rpcs3::state.config.rsx.opengl.write_depth_buffer) { auto depth_format = surface_depth_format_to_gl(m_surface.depth_format); @@ -1725,7 +1726,7 @@ void GLGSRender::flip(int buffer) u32 buffer_address = rsx::get_address(gcm_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL); bool skip_read = false; - if (draw_fbo && !Ini.GSDumpColorBuffers.GetValue()) + if (draw_fbo && !rpcs3::state.config.rsx.opengl.write_color_buffers) { skip_read = true; /* diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index dc7608d11c..92627a387d 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1,4 +1,9 @@ #include "stdafx.h" + +#include "config.h" +#include "events.h" +#include "state.h" + #include "Utilities/Log.h" #include "Utilities/File.h" #include "rpcs3/Ini.h" @@ -61,6 +66,8 @@ Emulator::Emulator() void Emulator::Init() { + rpcs3::config.load(); + rpcs3::oninit(); } void Emulator::SetPath(const std::string& path, const std::string& elf_path) @@ -166,6 +173,9 @@ void Emulator::Load() } } + //TODO: load custom config if exists + rpcs3::state.config = rpcs3::config; + LOG_NOTICE(LOADER, "Loading '%s'...", m_path.c_str()); ResetInfo(); GetVFS().Init(elf_dir); @@ -213,14 +223,18 @@ void Emulator::Load() } LOG_NOTICE(LOADER, "Resolution: %s", Ini.ResolutionIdToString(Ini.GSResolution.GetValue())); - LOG_NOTICE(LOADER, "Write Depth Buffer: %s", Ini.GSDumpDepthBuffer.GetValue() ? "Yes" : "No"); + /*LOG_NOTICE(LOADER, "Write Depth Buffer: %s", Ini.GSDumpDepthBuffer.GetValue() ? "Yes" : "No"); LOG_NOTICE(LOADER, "Write Color Buffers: %s", Ini.GSDumpColorBuffers.GetValue() ? "Yes" : "No"); LOG_NOTICE(LOADER, "Read Color Buffers: %s", Ini.GSReadColorBuffers.GetValue() ? "Yes" : "No"); - LOG_NOTICE(LOADER, "Read Depth Buffer: %s", Ini.GSReadDepthBuffer.GetValue() ? "Yes" : "No"); + LOG_NOTICE(LOADER, "Read Depth Buffer: %s", Ini.GSReadDepthBuffer.GetValue() ? "Yes" : "No");*/ LOG_NOTICE(LOADER, "Audio Out: %s", Ini.AudioOutIdToString(Ini.AudioOutMode.GetValue())); LOG_NOTICE(LOADER, "Log Everything: %s", Ini.HLELogging.GetValue() ? "Yes" : "No"); LOG_NOTICE(LOADER, "RSX Logging: %s", Ini.RSXLogging.GetValue() ? "Yes" : "No"); + LOG_NOTICE(LOADER, ""); + + LOG_NOTICE(LOADER, rpcs3::config.to_string().c_str()); + LOG_NOTICE(LOADER, ""); f.Open("/app_home/../PARAM.SFO"); const PSFLoader psf(f); @@ -284,6 +298,8 @@ void Emulator::Run() return; } + rpcs3::onstart(); + SendDbgCommand(DID_START_EMU); m_pause_start_time = 0; @@ -304,6 +320,8 @@ bool Emulator::Pause() return false; } + rpcs3::onpause(); + // update pause start time if (m_pause_start_time.exchange(start)) { @@ -351,6 +369,8 @@ void Emulator::Resume() t->awake(); // untrigger status check and signal } + rpcs3::onstart(); + SendDbgCommand(DID_RESUMED_EMU); } @@ -365,6 +385,7 @@ void Emulator::Stop() return; } + rpcs3::onstop(); SendDbgCommand(DID_STOP_EMU); { diff --git a/rpcs3/Emu/events.cpp b/rpcs3/Emu/events.cpp new file mode 100644 index 0000000000..e02d4f56f4 --- /dev/null +++ b/rpcs3/Emu/events.cpp @@ -0,0 +1,10 @@ +#include "stdafx.h" +#include "events.h" + +namespace rpcs3 +{ + event oninit; + event onstart; + event onstop; + event onpause; +} \ No newline at end of file diff --git a/rpcs3/Emu/events.h b/rpcs3/Emu/events.h new file mode 100644 index 0000000000..0398698f52 --- /dev/null +++ b/rpcs3/Emu/events.h @@ -0,0 +1,10 @@ +#pragma once +#include "Utilities/event.h" + +namespace rpcs3 +{ + extern event oninit; + extern event onstart; + extern event onstop; + extern event onpause; +} \ No newline at end of file diff --git a/rpcs3/Emu/state.cpp b/rpcs3/Emu/state.cpp new file mode 100644 index 0000000000..f58020813a --- /dev/null +++ b/rpcs3/Emu/state.cpp @@ -0,0 +1,9 @@ +#include "stdafx.h" +#include "state.h" +#include +#include + +namespace rpcs3 +{ + state_t state; +} \ No newline at end of file diff --git a/rpcs3/Emu/state.h b/rpcs3/Emu/state.h new file mode 100644 index 0000000000..3abdbef957 --- /dev/null +++ b/rpcs3/Emu/state.h @@ -0,0 +1,15 @@ +#pragma once +#include "config.h" + +namespace rpcs3 +{ + struct state_t + { + config_t config; + + std::string path_to_elf; + std::string virtual_path_to_elf; + }; + + extern state_t state; +} \ No newline at end of file diff --git a/rpcs3/Gui/SettingsDialog.cpp b/rpcs3/Gui/SettingsDialog.cpp index a2c8f74aaf..0f39bfd2fe 100644 --- a/rpcs3/Gui/SettingsDialog.cpp +++ b/rpcs3/Gui/SettingsDialog.cpp @@ -7,6 +7,22 @@ #include "Utilities/Log.h" #include +#ifdef _WIN32 +#include +#include + +#pragma comment(lib, "iphlpapi.lib") +#else + +#include +#include +#include +#include +#include +#include +#include +#endif + #if defined(DX12_SUPPORT) #undef GetHwnd #include @@ -14,7 +30,66 @@ #include #endif -SettingsDialog::SettingsDialog(wxWindow *parent) +std::vector GetAdapters() +{ + std::vector adapters; +#ifdef _WIN32 + PIP_ADAPTER_INFO pAdapterInfo; + pAdapterInfo = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO)); + ULONG buflen = sizeof(IP_ADAPTER_INFO); + + if (GetAdaptersInfo(pAdapterInfo, &buflen) == ERROR_BUFFER_OVERFLOW) + { + free(pAdapterInfo); + pAdapterInfo = (IP_ADAPTER_INFO*)malloc(buflen); + } + + if (GetAdaptersInfo(pAdapterInfo, &buflen) == NO_ERROR) + { + PIP_ADAPTER_INFO pAdapter = pAdapterInfo; + while (pAdapter) + { + adapters.emplace_back(pAdapter->Description); + pAdapter = pAdapter->Next; + } + } + else + { + LOG_ERROR(HLE, "Call to GetAdaptersInfo failed."); + } +#else + struct ifaddrs *ifaddr, *ifa; + int family, s, n; + char host[NI_MAXHOST]; + + if (getifaddrs(&ifaddr) == -1) + { + LOG_ERROR(HLE, "Call to getifaddrs returned negative."); + } + + for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) + { + if (ifa->ifa_addr == NULL) + { + continue; + } + + family = ifa->ifa_addr->sa_family; + + if (family == AF_INET || family == AF_INET6) + { + adapters.emplace_back(ifa->ifa_name); + } + } + + freeifaddrs(ifaddr); +#endif + + return adapters; +} + + +SettingsDialog::SettingsDialog(wxWindow *parent, rpcs3::config_t* cfg) : wxDialog(parent, wxID_ANY, "Settings", wxDefaultPosition) { bool paused = false; @@ -203,6 +278,7 @@ SettingsDialog::SettingsDialog(wxWindow *parent) #if defined (_WIN32) cbox_pad_handler->Append("XInput"); #endif + //cbox_pad_handler->Append("DirectInput"); cbox_keyboard_handler->Append("Null"); @@ -255,10 +331,10 @@ SettingsDialog::SettingsDialog(wxWindow *parent) // Get values from .ini chbox_core_llvm_exclud->SetValue(Ini.LLVMExclusionRange.GetValue()); chbox_gs_log_prog->SetValue(Ini.GSLogPrograms.GetValue()); - chbox_gs_dump_depth->SetValue(Ini.GSDumpDepthBuffer.GetValue()); - chbox_gs_dump_color->SetValue(Ini.GSDumpColorBuffers.GetValue()); - chbox_gs_read_color->SetValue(Ini.GSReadColorBuffers.GetValue()); - chbox_gs_read_depth->SetValue(Ini.GSReadDepthBuffer.GetValue()); + chbox_gs_dump_depth->SetValue((bool)cfg->rsx.opengl.write_depth_buffer); + chbox_gs_dump_color->SetValue((bool)cfg->rsx.opengl.write_color_buffers); + chbox_gs_read_color->SetValue((bool)cfg->rsx.opengl.read_color_buffers); + chbox_gs_read_depth->SetValue((bool)cfg->rsx.opengl.read_depth_buffer); chbox_gs_vsync->SetValue(Ini.GSVSyncEnable.GetValue()); chbox_gs_debug_output->SetValue(Ini.GSDebugOutputEnable.GetValue()); chbox_gs_3dmonitor->SetValue(Ini.GS3DTV.GetValue()); @@ -438,10 +514,10 @@ SettingsDialog::SettingsDialog(wxWindow *parent) Ini.GSAspectRatio.SetValue(cbox_gs_aspect->GetSelection() + 1); Ini.GSFrameLimit.SetValue(cbox_gs_frame_limit->GetSelection()); Ini.GSLogPrograms.SetValue(chbox_gs_log_prog->GetValue()); - Ini.GSDumpDepthBuffer.SetValue(chbox_gs_dump_depth->GetValue()); - Ini.GSDumpColorBuffers.SetValue(chbox_gs_dump_color->GetValue()); - Ini.GSReadColorBuffers.SetValue(chbox_gs_read_color->GetValue()); - Ini.GSReadDepthBuffer.SetValue(chbox_gs_read_depth->GetValue()); + cfg->rsx.opengl.write_depth_buffer = chbox_gs_dump_depth->GetValue(); + cfg->rsx.opengl.write_color_buffers = chbox_gs_dump_color->GetValue(); + cfg->rsx.opengl.read_color_buffers = chbox_gs_read_color->GetValue(); + cfg->rsx.opengl.read_depth_buffer = chbox_gs_read_depth->GetValue(); Ini.GSVSyncEnable.SetValue(chbox_gs_vsync->GetValue()); Ini.GSDebugOutputEnable.SetValue(chbox_gs_debug_output->GetValue()); Ini.GS3DTV.SetValue(chbox_gs_3dmonitor->GetValue()); @@ -472,6 +548,7 @@ SettingsDialog::SettingsDialog(wxWindow *parent) Ini.SysEmulationDirPathEnable.SetValue(chbox_emulationdir_enable->GetValue()); Ini.SysEmulationDirPath.SetValue(txt_emulationdir_path->GetValue().ToStdString()); + cfg->save(); Ini.Save(); } diff --git a/rpcs3/Gui/SettingsDialog.h b/rpcs3/Gui/SettingsDialog.h index 8786a84850..21fcbfedd9 100644 --- a/rpcs3/Gui/SettingsDialog.h +++ b/rpcs3/Gui/SettingsDialog.h @@ -1,82 +1,11 @@ #pragma once -#include "Utilities/Log.h" +#include "config.h" -#ifdef _WIN32 -#include -#include - -#pragma comment(lib, "iphlpapi.lib") -#else - -#include -#include -#include -#include -#include -#include -#include -#endif +std::vector GetAdapters(); class SettingsDialog : public wxDialog { public: - SettingsDialog(wxWindow *parent); + SettingsDialog(wxWindow *parent, rpcs3::config_t* cfg = &rpcs3::config); }; -static std::vector GetAdapters() -{ - std::vector adapters; -#ifdef _WIN32 - PIP_ADAPTER_INFO pAdapterInfo; - pAdapterInfo = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO)); - ULONG buflen = sizeof(IP_ADAPTER_INFO); - - if (GetAdaptersInfo(pAdapterInfo, &buflen) == ERROR_BUFFER_OVERFLOW) - { - free(pAdapterInfo); - pAdapterInfo = (IP_ADAPTER_INFO*)malloc(buflen); - } - - if (GetAdaptersInfo(pAdapterInfo, &buflen) == NO_ERROR) - { - PIP_ADAPTER_INFO pAdapter = pAdapterInfo; - while (pAdapter) - { - adapters.emplace_back(pAdapter->Description); - pAdapter = pAdapter->Next; - } - } - else - { - LOG_ERROR(HLE, "Call to GetAdaptersInfo failed."); - } -#else - struct ifaddrs *ifaddr, *ifa; - int family, s, n; - char host[NI_MAXHOST]; - - if (getifaddrs(&ifaddr) == -1) - { - LOG_ERROR(HLE, "Call to getifaddrs returned negative."); - } - - for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) - { - if (ifa->ifa_addr == NULL) - { - continue; - } - - family = ifa->ifa_addr->sa_family; - - if (family == AF_INET || family == AF_INET6) - { - adapters.emplace_back(ifa->ifa_name); - } - } - - freeifaddrs(ifaddr); -#endif - - return adapters; -} diff --git a/rpcs3/Ini.h b/rpcs3/Ini.h index 197de5936d..139df08436 100644 --- a/rpcs3/Ini.h +++ b/rpcs3/Ini.h @@ -109,10 +109,6 @@ public: IniEntry GSAspectRatio; IniEntry GSFrameLimit; IniEntry GSLogPrograms; - IniEntry GSDumpColorBuffers; - IniEntry GSDumpDepthBuffer; - IniEntry GSReadColorBuffers; - IniEntry GSReadDepthBuffer; IniEntry GSVSyncEnable; IniEntry GS3DTV; IniEntry GSDebugOutputEnable; @@ -201,10 +197,6 @@ public: GSAspectRatio.Init("GS_AspectRatio", path); GSFrameLimit.Init("GS_FrameLimit", path); GSLogPrograms.Init("GS_LogPrograms", path); - GSDumpColorBuffers.Init("GS_DumpColorBuffers", path); - GSDumpDepthBuffer.Init("GS_DumpDepthBuffer", path); - GSReadColorBuffers.Init("GS_ReadColorBuffer", path); - GSReadDepthBuffer.Init("GS_ReadDepthBuffer", path); GSVSyncEnable.Init("GS_VSyncEnable", path); GSDebugOutputEnable.Init("GS_DebugOutputEnable", path); GS3DTV.Init("GS_3DTV", path); @@ -289,10 +281,6 @@ public: GSAspectRatio.Load(2); GSFrameLimit.Load(0); GSLogPrograms.Load(false); - GSDumpColorBuffers.Load(false); - GSDumpDepthBuffer.Load(false); - GSReadColorBuffers.Load(false); - GSReadDepthBuffer.Load(false); GSVSyncEnable.Load(false); GSDebugOutputEnable.Load(false); GS3DTV.Load(false); @@ -377,10 +365,6 @@ public: GSAspectRatio.Save(); GSFrameLimit.Save(); GSLogPrograms.Save(); - GSDumpColorBuffers.Save(); - GSDumpDepthBuffer.Save(); - GSReadColorBuffers.Save(); - GSReadDepthBuffer.Save(); GSVSyncEnable.Save(); GSDebugOutputEnable.Save(); GS3DTV.Save(); diff --git a/rpcs3/config.cpp b/rpcs3/config.cpp new file mode 100644 index 0000000000..5d4960f6c9 --- /dev/null +++ b/rpcs3/config.cpp @@ -0,0 +1,45 @@ +#include "stdafx.h" +#include "config.h" +#include + +namespace rpcs3 +{ + config_t::config_t(const std::string &path_) + { + path(path_); + } + config_t::config_t(const config_t& rhs) + { + assign(rhs); + } + + config_t& config_t::operator =(const config_t& rhs) + { + assign(rhs); + return *this; + } + + void config_t::path(const std::string &new_path) + { + m_path = new_path; + } + + std::string config_t::path() const + { + return m_path; + } + + void config_t::load() + { + if (!m_path.empty()) + deserialize(std::ifstream{ m_path }); + } + + void config_t::save() const + { + if (!m_path.empty()) + serialize(std::ofstream{ m_path }); + } + + config_t config{ "rpcs3.new.ini" }; +} \ No newline at end of file diff --git a/rpcs3/config.h b/rpcs3/config.h new file mode 100644 index 0000000000..c6c95e4be8 --- /dev/null +++ b/rpcs3/config.h @@ -0,0 +1,241 @@ +#pragma once +#include "Utilities/convert.h" +#include "Utilities/config_context.h" + +enum class audio_output_type +{ + Null, + OpenAL, + XAudio2 +}; + +template<> +struct convert::to_impl_t +{ + static std::string func(audio_output_type value) + { + switch (value) + { + case audio_output_type::Null: return "Null"; + case audio_output_type::OpenAL: return "OpenAL"; + case audio_output_type::XAudio2: return "XAudio2"; + } + + return "Unknown"; + } +}; + +template<> +struct convert::to_impl_t +{ + static audio_output_type func(const std::string &value) + { + if (value == "Null") + return audio_output_type::Null; + + if (value == "OpenAL") + return audio_output_type::OpenAL; + + if (value == "XAudio2") + return audio_output_type::XAudio2; + + return audio_output_type::Null; + } +}; + +enum class rsx_renderer_type +{ + Null, + OpenGL, + DX12 +}; + +template<> +struct convert::to_impl_t +{ + static std::string func(rsx_renderer_type value) + { + switch (value) + { + case rsx_renderer_type::Null: return "Null"; + case rsx_renderer_type::OpenGL: return "OpenGL"; + case rsx_renderer_type::DX12: return "DX12"; + } + + return "Unknown"; + } +}; + +template<> +struct convert::to_impl_t +{ + static rsx_renderer_type func(const std::string &value) + { + if (value == "Null") + return rsx_renderer_type::Null; + + if (value == "OpenGL") + return rsx_renderer_type::OpenGL; + + if (value == "DX12") + return rsx_renderer_type::DX12; + + return rsx_renderer_type::Null; + } +}; + +enum class ppu_decoder_type +{ + interpreter, + interpreter2, + recompiler_llvm +}; + +template<> +struct convert::to_impl_t +{ + static std::string func(ppu_decoder_type value) + { + switch (value) + { + case ppu_decoder_type::interpreter: return "interpreter"; + case ppu_decoder_type::interpreter2: return "interpreter2"; + case ppu_decoder_type::recompiler_llvm: return "recompiler_llvm"; + } + + return "Unknown"; + } +}; + +template<> +struct convert::to_impl_t +{ + static ppu_decoder_type func(const std::string &value) + { + if (value == "interpreter") + return ppu_decoder_type::interpreter; + + if (value == "interpreter2") + return ppu_decoder_type::interpreter2; + + if (value == "DX12") + return ppu_decoder_type::recompiler_llvm; + + return ppu_decoder_type::interpreter; + } +}; + + +enum class spu_decoder_type +{ + interpreter_precise, + interpreter_fast, + recompiler_asmjit +}; + +template<> +struct convert::to_impl_t +{ + static std::string func(spu_decoder_type value) + { + switch (value) + { + case spu_decoder_type::interpreter_precise: return "interpreter_precise"; + case spu_decoder_type::interpreter_fast: return "interpreter_fast"; + case spu_decoder_type::recompiler_asmjit: return "recompiler_asmjit"; + } + + return "Unknown"; + } +}; + +template<> +struct convert::to_impl_t +{ + static spu_decoder_type func(const std::string &value) + { + if (value == "interpreter_precise") + return spu_decoder_type::interpreter_precise; + + if (value == "interpreter_fast") + return spu_decoder_type::interpreter_fast; + + if (value == "recompiler_asmjit") + return spu_decoder_type::recompiler_asmjit; + + return spu_decoder_type::interpreter_precise; + } +}; + +namespace rpcs3 +{ + class config_t : public config_context_t + { + std::string m_path; + + public: + struct core_group : protected group + { + core_group(config_context_t *cfg) : group{ cfg, "core" } {} + + entry ppu_decoder{ this, "PPU Decoder", ppu_decoder_type::interpreter }; + entry spu_decoder{ this, "SPU Decoder", spu_decoder_type::interpreter_precise }; + entry load_liblv2{ this, "Load liblv2.sprx", false }; + } core{ this }; + + struct rsx_group : protected group + { + struct opengl_group : protected group + { + opengl_group(group *grp) : group{ grp, "opengl" } {} + + entry write_color_buffers{ this, "Write Color Buffers", true }; + entry write_depth_buffer{ this, "Write Depth Buffer", true }; + entry read_color_buffers{ this, "Read Color Buffers", true }; + entry read_depth_buffer{ this, "Read Depth Buffer", true }; + } opengl{ this }; + + rsx_group(config_context_t *cfg) : group{ cfg, "rsx" } {} + + entry renderer{ this, "Renderer", rsx_renderer_type::OpenGL }; + } rsx{ this }; + + struct audio_group : protected group + { + audio_group(config_context_t *cfg) : group{ cfg, "audio" } {} + + entry test{ this, "Audio Out", audio_output_type::OpenAL }; + } audio{ this }; + + struct io_group : protected group + { + io_group(config_context_t *cfg) : group{ cfg, "io" } {} + } io{ this }; + + struct misc_group : protected group + { + misc_group(config_context_t *cfg) : group{ cfg, "misc" } {} + } misc{ this }; + + struct system_group : protected group + { + system_group(config_context_t *cfg) : group{ cfg, "system" } {} + } system{ this }; + + config_t() = default; + config_t(const std::string &path); + config_t(const config_t& rhs); + config_t(config_t&& rhs) = delete; + + config_t& operator =(const config_t& rhs); + config_t& operator =(config_t&& rhs) = delete; + + void path(const std::string &new_path); + std::string path() const; + + void load(); + void save() const; + }; + + extern config_t config; +} \ No newline at end of file diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 9363293a30..f46a79b26c 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -40,6 +40,7 @@ + @@ -52,11 +53,13 @@ + + @@ -78,6 +81,7 @@ + @@ -379,6 +383,9 @@ + + + @@ -397,6 +404,7 @@ + @@ -508,6 +516,7 @@ + @@ -572,6 +581,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index e75f69456f..e0576323cf 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1001,6 +1001,16 @@ Emu\GPU\RSX\GL + + Utilities + + + + Emu + + + Emu + @@ -1906,5 +1916,21 @@ Emu\GPU\RSX\GL + + Utilities + + + Utilities + + + Utilities + + + + Emu + + + Emu + \ No newline at end of file