diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index c7897d0362..b4c69905ec 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -41,7 +41,7 @@ void spu_recompiler::init() if (!m_spurt) { m_cache = fxm::get(); - m_spurt = fxm::get_always(); + m_spurt = g_fxo->get(); } } diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index eb454a6b61..db186be3d9 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -538,8 +538,6 @@ spu_runtime::spu_runtime() fs::file(m_cache_path + "spu.log", fs::rewrite); fs::file(m_cache_path + "spu-ir.log", fs::rewrite); } - - LOG_SUCCESS(SPU, "SPU Recompiler Runtime initialized..."); } bool spu_runtime::add(u64 last_reset_count, void* _where, spu_function_t compiled) @@ -4165,7 +4163,7 @@ public: if (!m_spurt) { m_cache = fxm::get(); - m_spurt = fxm::get_always(); + m_spurt = g_fxo->get(); cpu_translator::initialize(m_jit.get_context(), m_jit.get_engine()); const auto md_name = llvm::MDString::get(m_context, "branch_weights"); diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index c5b653a575..02ce6498ee 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -76,6 +76,10 @@ public: public: spu_runtime(); + spu_runtime(const spu_runtime&) = delete; + + spu_runtime& operator=(const spu_runtime&) = delete; + const std::string& get_cache_path() const { return m_cache_path; @@ -226,7 +230,7 @@ public: }; protected: - std::shared_ptr m_spurt; + spu_runtime* m_spurt{}; u32 m_pos; u32 m_size; diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index d771ab4e51..982078e1ce 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -138,7 +138,7 @@ class idm { using traits = id_manager::id_traits; - // Note: if id is lower than base, diff / step will be higher than count + // Note: if id is lower than base, diff / step will be higher than count u32 diff = id - traits::base; if (diff % traits::step) @@ -785,6 +785,7 @@ public: }; #include "Utilities/typemap.h" +#include "util/fixed_typemap.hpp" extern utils::typemap g_typemap; @@ -793,3 +794,7 @@ constexpr utils::typemap* g_idm = &g_typemap; using utils::id_new; using utils::id_any; using utils::id_always; + +extern stx::manual_fixed_typemap g_fixed_typemap; + +constexpr stx::manual_fixed_typemap* g_fxo = &g_fixed_typemap; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 135622fd9d..688b7b8b8f 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -46,6 +46,8 @@ #include "Emu/RSX/VK/VulkanAPI.h" #endif +stx::manual_fixed_typemap g_fixed_typemap; + utils::typemap g_typemap{nullptr}; cfg_root g_cfg; @@ -318,6 +320,7 @@ void Emulator::Init() idm::init(); fxm::init(); g_idm->init(); + g_fxo->reset(); // Reset defaults, cache them g_cfg.from_default(); @@ -1511,6 +1514,7 @@ void Emulator::Load(const std::string& title_id, bool add_only, bool force_globa LOG_NOTICE(LOADER, "Cache: %s", _main->cache); } + g_fxo->init(); fxm::import(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall fxm::import(Emu.GetCallbacks().get_pad_handler, m_title_id); network_thread_init(); @@ -1735,6 +1739,7 @@ void Emulator::Stop(bool restart) idm::clear(); fxm::clear(); g_idm->init(); + g_fxo->reset(); LOG_NOTICE(GENERAL, "Objects cleared..."); diff --git a/rpcs3/util/fixed_typemap.hpp b/rpcs3/util/fixed_typemap.hpp new file mode 100644 index 0000000000..98e690584d --- /dev/null +++ b/rpcs3/util/fixed_typemap.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include +#include + +namespace stx +{ + // Typemap with exactly one object of each used type, created on init() and destroyed on clear() + template + class manual_fixed_typemap + { + // Save default constructor and destructor + struct typeinfo + { + void(*create)(void*& ptr) noexcept; + void(*destroy)(void*& ptr) noexcept; + + template + static void call_ctor(void*& ptr) noexcept + { + // Call default constructor only if available + if constexpr (std::is_default_constructible_v) + { + // Don't overwrite if already exists + if (!ptr) + { + ptr = new T{}; + } + } + } + + template + static void call_dtor(void*& ptr) noexcept + { + delete static_cast(ptr); + ptr = nullptr; + } + + template + static typeinfo make_typeinfo() + { + typeinfo r; + r.create = &call_ctor; + r.destroy = &call_dtor; + return r; + } + }; + + std::unique_ptr m_list; + + public: + constexpr manual_fixed_typemap() noexcept = default; + + manual_fixed_typemap(const manual_fixed_typemap&) = delete; + + manual_fixed_typemap(manual_fixed_typemap&& r) noexcept + { + std::swap(m_list, r.m_list); + } + + manual_fixed_typemap& operator=(const manual_fixed_typemap&) = delete; + + manual_fixed_typemap& operator=(manual_fixed_typemap&& r) noexcept + { + manual_fixed_typemap x(std::move(*this)); + std::swap(m_list, x.m_list); + } + + // Destroy all objects and keep them in uninitialized state, must be called first + void reset() noexcept + { + if (!m_list) + { + m_list = std::make_unique(stx::typeinfo_v.count()); + return; + } + + for (auto& type : stx::typeinfo_v) + { + type.destroy(m_list[type.index()]); + } + } + + // Default initialize all objects if possible and not already initialized + void init() noexcept + { + for (auto& type : stx::typeinfo_v) + { + type.create(m_list[type.index()]); + } + } + + // Explicitly (re)initialize object of type T possibly with dynamic type As and arguments + template + T* init(Args&&... args) noexcept + { + auto& ptr = m_list[stx::type_counter::template type>.index()]; + + if (ptr) + { + delete static_cast(ptr); + } + + auto* obj = static_cast(new std::decay_t(std::forward(args)...)); + ptr = obj; + return obj; + } + + // Obtain object pointer (the only thread safe function) + template + T* get() const noexcept + { + return static_cast(m_list[stx::type_counter::template type>.index()]); + } + }; +}