This commit is contained in:
digant 2025-01-06 14:41:21 +01:00
commit dc2e45bc89
30 changed files with 177 additions and 79 deletions

View file

@ -22,6 +22,5 @@ else()
add_subdirectory(wolfssl EXCLUDE_FROM_ALL) add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
target_compile_definitions(wolfssl PUBLIC WOLFSSL_DES_ECB HAVE_WRITE_DUP) target_compile_definitions(wolfssl PUBLIC WOLFSSL_DES_ECB HAVE_WRITE_DUP FP_MAX_BITS=8192 WOLFSSL_NO_OPTIONS_H)
target_compile_definitions(wolfssl PUBLIC FP_MAX_BITS=8192)
endif() endif()

View file

@ -33,7 +33,8 @@ enum class thread_state : u32
aborting = 1, // The thread has been joined in the destructor or explicitly aborted aborting = 1, // The thread has been joined in the destructor or explicitly aborted
errored = 2, // Set after the emergency_exit call errored = 2, // Set after the emergency_exit call
finished = 3, // Final state, always set at the end of thread execution finished = 3, // Final state, always set at the end of thread execution
mask = 3 mask = 3,
destroying_context = 7, // Special value assigned to destroy data explicitly before the destructor
}; };
template <class Context> template <class Context>
@ -702,14 +703,17 @@ public:
thread::m_sync.notify_all(); thread::m_sync.notify_all();
} }
if (s == thread_state::finished) if (s == thread_state::finished || s == thread_state::destroying_context)
{ {
// This participates in emulation stopping, use destruction-alike semantics // This participates in emulation stopping, use destruction-alike semantics
thread::join(true); thread::join(true);
}
if (s == thread_state::destroying_context)
{
if constexpr (std::is_assignable_v<Context&, thread_state>) if constexpr (std::is_assignable_v<Context&, thread_state>)
{ {
static_cast<Context&>(*this) = thread_state::finished; static_cast<Context&>(*this) = thread_state::destroying_context;
} }
} }

View file

@ -14,6 +14,7 @@ enum class cheat_type : u8
signed_16_cheat, signed_16_cheat,
signed_32_cheat, signed_32_cheat,
signed_64_cheat, signed_64_cheat,
float_32_cheat,
max max
}; };

View file

@ -164,7 +164,7 @@ elseif(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt
--no-translations --no-quick --no-system-d3d-compiler --no-quick-import --no-translations --no-system-d3d-compiler --no-quick-import
--plugindir "$<IF:$<CXX_COMPILER_ID:MSVC>,$<TARGET_FILE_DIR:rpcs3>/plugins,$<TARGET_FILE_DIR:rpcs3>/share/qt6/plugins>" --plugindir "$<IF:$<CXX_COMPILER_ID:MSVC>,$<TARGET_FILE_DIR:rpcs3>/plugins,$<TARGET_FILE_DIR:rpcs3>/share/qt6/plugins>"
--verbose 0 "$<TARGET_FILE:rpcs3>") --verbose 0 "$<TARGET_FILE:rpcs3>")
endif() endif()

View file

@ -71,7 +71,7 @@ CellError lv2_cond::on_id_create()
std::function<void(void*)> lv2_cond::load(utils::serial& ar) std::function<void(void*)> lv2_cond::load(utils::serial& ar)
{ {
return load_func(make_shared<lv2_cond>(ar)); return load_func(make_shared<lv2_cond>(stx::exact_t<utils::serial&>(ar)));
} }
void lv2_cond::save(utils::serial& ar) void lv2_cond::save(utils::serial& ar)

View file

@ -122,7 +122,7 @@ void lv2_config::remove_service_event(u32 id)
lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) noexcept lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) noexcept
{ {
if (s == thread_state::finished) if (s == thread_state::destroying_context && !m_destroyed.exchange(true))
{ {
if (auto global = g_fxo->try_get<lv2_config>()) if (auto global = g_fxo->try_get<lv2_config>())
{ {
@ -133,6 +133,23 @@ lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) no
return *this; return *this;
} }
lv2_config_service_event::~lv2_config_service_event() noexcept
{
operator=(thread_state::destroying_context);
}
lv2_config::~lv2_config() noexcept
{
for (auto& [key, event] : events)
{
if (event)
{
// Avoid collision with lv2_config_service_event destructor
event->m_destroyed = true;
}
}
}
// LV2 Config Service Listener // LV2 Config Service Listener
bool lv2_config_service_listener::check_service(const lv2_config_service& service) const bool lv2_config_service_listener::check_service(const lv2_config_service& service) const
{ {

View file

@ -161,6 +161,8 @@ public:
return null_ptr; return null_ptr;
} }
~lv2_config() noexcept;
}; };
/* /*
@ -276,7 +278,7 @@ public:
// Utilities // Utilities
usz get_size() const { return sizeof(sys_config_service_event_t)-1 + data.size(); } usz get_size() const { return sizeof(sys_config_service_event_t)-1 + data.size(); }
shared_ptr<lv2_config_service> get_shared_ptr () const { return idm::get_unlocked<lv2_config_service>(idm_id); } shared_ptr<lv2_config_service> get_shared_ptr () const { return stx::make_shared_from_this<lv2_config_service>(this); }
u32 get_id() const { return idm_id; } u32 get_id() const { return idm_id; }
}; };
@ -342,7 +344,7 @@ public:
// Utilities // Utilities
u32 get_id() const { return idm_id; } u32 get_id() const { return idm_id; }
shared_ptr<lv2_config_service_listener> get_shared_ptr() const { return idm::get_unlocked<lv2_config_service_listener>(idm_id); } shared_ptr<lv2_config_service_listener> get_shared_ptr() const { return stx::make_shared_from_this<lv2_config_service_listener>(this); }
}; };
/* /*
@ -360,6 +362,10 @@ class lv2_config_service_event
return g_fxo->get<service_event_id>().next_id++; return g_fxo->get<service_event_id>().next_id++;
} }
atomic_t<bool> m_destroyed = false;
friend class lv2_config;
public: public:
const u32 id; const u32 id;
@ -391,8 +397,7 @@ public:
// Destructor // Destructor
lv2_config_service_event& operator=(thread_state s) noexcept; lv2_config_service_event& operator=(thread_state s) noexcept;
~lv2_config_service_event() noexcept;
~lv2_config_service_event() noexcept = default;
// Notify queue that this event exists // Notify queue that this event exists
bool notify() const; bool notify() const;

View file

@ -37,8 +37,8 @@ lv2_event_queue::lv2_event_queue(utils::serial& ar) noexcept
std::function<void(void*)> lv2_event_queue::load(utils::serial& ar) std::function<void(void*)> lv2_event_queue::load(utils::serial& ar)
{ {
auto queue = make_shared<lv2_event_queue>(ar); auto queue = make_shared<lv2_event_queue>(stx::exact_t<utils::serial&>(ar));
return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast<shared_ptr<lv2_obj>*>(storage) = ptr; }; return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast<atomic_ptr<lv2_obj>*>(storage) = ptr; };
} }
void lv2_event_queue::save(utils::serial& ar) void lv2_event_queue::save(utils::serial& ar)

View file

@ -24,7 +24,7 @@ lv2_event_flag::lv2_event_flag(utils::serial& ar)
std::function<void(void*)> lv2_event_flag::load(utils::serial& ar) std::function<void(void*)> lv2_event_flag::load(utils::serial& ar)
{ {
return load_func(make_shared<lv2_event_flag>(ar)); return load_func(make_shared<lv2_event_flag>(stx::exact_t<utils::serial&>(ar)));
} }
void lv2_event_flag::save(utils::serial& ar) void lv2_event_flag::save(utils::serial& ar)

View file

@ -33,7 +33,7 @@ std::function<void(void*)> lv2_memory_container::load(utils::serial& ar)
// Use idm::last_id() only for the instances at IDM // Use idm::last_id() only for the instances at IDM
return [ptr = make_shared<lv2_memory_container>(stx::exact_t<utils::serial&>(ar), true)](void* storage) return [ptr = make_shared<lv2_memory_container>(stx::exact_t<utils::serial&>(ar), true)](void* storage)
{ {
*static_cast<shared_ptr<lv2_memory_container>*>(storage) = ptr; *static_cast<atomic_ptr<lv2_memory_container>*>(storage) = ptr;
}; };
} }

View file

@ -84,7 +84,7 @@ CellError lv2_memory::on_id_create()
std::function<void(void*)> lv2_memory::load(utils::serial& ar) std::function<void(void*)> lv2_memory::load(utils::serial& ar)
{ {
auto mem = make_shared<lv2_memory>(ar); auto mem = make_shared<lv2_memory>(stx::exact_t<utils::serial&>(ar));
mem->exists++; // Disable on_id_create() mem->exists++; // Disable on_id_create()
auto func = load_func(mem, +mem->pshared); auto func = load_func(mem, +mem->pshared);
mem->exists--; mem->exists--;

View file

@ -27,7 +27,7 @@ lv2_mutex::lv2_mutex(utils::serial& ar)
std::function<void(void*)> lv2_mutex::load(utils::serial& ar) std::function<void(void*)> lv2_mutex::load(utils::serial& ar)
{ {
return load_func(make_shared<lv2_mutex>(ar)); return load_func(make_shared<lv2_mutex>(stx::exact_t<utils::serial&>(ar)));
} }
void lv2_mutex::save(utils::serial& ar) void lv2_mutex::save(utils::serial& ar)

View file

@ -293,7 +293,7 @@ std::function<void(void*)> lv2_socket::load(utils::serial& ar)
sock_lv2->bind(sock_lv2->last_bound_addr); sock_lv2->bind(sock_lv2->last_bound_addr);
} }
return [ptr = sock_lv2](void* storage) { *static_cast<shared_ptr<lv2_socket>*>(storage) = ptr; };; return [ptr = sock_lv2](void* storage) { *static_cast<atomic_ptr<lv2_socket>*>(storage) = ptr; };;
} }
void lv2_socket::save(utils::serial& ar, bool save_only_this_class) void lv2_socket::save(utils::serial& ar, bool save_only_this_class)

View file

@ -178,7 +178,7 @@ void lv2_socket::queue_wake(ppu_thread* ppu)
lv2_socket& lv2_socket::operator=(thread_state s) noexcept lv2_socket& lv2_socket::operator=(thread_state s) noexcept
{ {
if (s == thread_state::finished) if (s == thread_state::destroying_context)
{ {
close(); close();
} }

View file

@ -112,7 +112,7 @@ std::function<void(void*)> lv2_overlay::load(utils::serial& ar)
return [ovlm](void* storage) return [ovlm](void* storage)
{ {
*static_cast<shared_ptr<lv2_obj>*>(storage) = ovlm; *static_cast<atomic_ptr<lv2_obj>*>(storage) = ovlm;
}; };
} }

View file

@ -372,7 +372,7 @@ std::function<void(void*)> lv2_prx::load(utils::serial& ar)
return [prx](void* storage) return [prx](void* storage)
{ {
*static_cast<shared_ptr<lv2_obj>*>(storage) = prx; *static_cast<atomic_ptr<lv2_obj>*>(storage) = prx;
}; };
} }

View file

@ -449,7 +449,7 @@ public:
static std::function<void(void*)> load_func(shared_ptr<T> make, u64 pshared = umax) static std::function<void(void*)> load_func(shared_ptr<T> make, u64 pshared = umax)
{ {
const u64 key = make->key; const u64 key = make->key;
return [ptr = load<T>(key, make, pshared)](void* storage) { *static_cast<shared_ptr<Storage>*>(storage) = ptr; }; return [ptr = load<T>(key, make, pshared)](void* storage) { *static_cast<atomic_ptr<Storage>*>(storage) = ptr; };
} }
static bool wait_timeout(u64 usec, ppu_thread* cpu = {}, bool scale = true, bool is_usleep = false); static bool wait_timeout(u64 usec, ppu_thread* cpu = {}, bool scale = true, bool is_usleep = false);

View file

@ -123,7 +123,7 @@ namespace id_manager
ptr = stx::make_shared<T>(stx::exact_t<utils::serial&>(ar)); ptr = stx::make_shared<T>(stx::exact_t<utils::serial&>(ar));
} }
return [ptr](void* storage) { *static_cast<stx::shared_ptr<T>*>(storage) = ptr; }; return [ptr](void* storage) { *static_cast<stx::atomic_ptr<T>*>(storage) = ptr; };
}; };
}; };
@ -805,8 +805,8 @@ public:
{ {
if (ptr) if (ptr)
{ {
constexpr thread_state finished{3}; constexpr thread_state destroying_context{7};
*static_cast<Get*>(ptr.get()) = finished; *static_cast<Get*>(ptr.get()) = destroying_context;
} }
} }
@ -837,8 +837,8 @@ public:
{ {
if (ptr) if (ptr)
{ {
constexpr thread_state finished{3}; constexpr thread_state destroying_context{7};
*static_cast<Get*>(ptr.get()) = finished; *static_cast<Get*>(ptr.get()) = destroying_context;
} }
} }

View file

@ -78,6 +78,7 @@ namespace vk
break; break;
case vk::driver_vendor::LAVAPIPE: case vk::driver_vendor::LAVAPIPE:
case vk::driver_vendor::V3DV: case vk::driver_vendor::V3DV:
case vk::driver_vendor::PANVK:
// TODO: Actually bench this. Using 32 for now to match other common configurations. // TODO: Actually bench this. Using 32 for now to match other common configurations.
case vk::driver_vendor::DOZEN: case vk::driver_vendor::DOZEN:
// Actual optimal size depends on the D3D device. Use 32 since it should work well on both AMD and NVIDIA // Actual optimal size depends on the D3D device. Use 32 since it should work well on both AMD and NVIDIA

View file

@ -144,6 +144,9 @@ namespace vk
case driver_vendor::HONEYKRISP: case driver_vendor::HONEYKRISP:
// Needs more testing // Needs more testing
break; break;
case driver_vendor::PANVK:
// Needs more testing
break;
default: default:
rsx_log.warning("Unsupported device: %s", gpu_name); rsx_log.warning("Unsupported device: %s", gpu_name);
} }

View file

@ -190,6 +190,7 @@ namespace vk
case driver_vendor::LAVAPIPE: case driver_vendor::LAVAPIPE:
case driver_vendor::V3DV: case driver_vendor::V3DV:
case driver_vendor::HONEYKRISP: case driver_vendor::HONEYKRISP:
case driver_vendor::PANVK:
break; break;
} }

View file

@ -54,7 +54,8 @@ namespace vk
LAVAPIPE, LAVAPIPE,
NVK, NVK,
V3DV, V3DV,
HONEYKRISP HONEYKRISP,
PANVK
}; };
driver_vendor get_driver_vendor(); driver_vendor get_driver_vendor();

View file

@ -302,6 +302,11 @@ namespace vk
return driver_vendor::HONEYKRISP; return driver_vendor::HONEYKRISP;
} }
if (gpu_name.find("Panfrost") != umax)
{
return driver_vendor::PANVK;
}
return driver_vendor::unknown; return driver_vendor::unknown;
} }
else else
@ -329,6 +334,8 @@ namespace vk
return driver_vendor::V3DV; return driver_vendor::V3DV;
case VK_DRIVER_ID_MESA_HONEYKRISP: case VK_DRIVER_ID_MESA_HONEYKRISP:
return driver_vendor::HONEYKRISP; return driver_vendor::HONEYKRISP;
case VK_DRIVER_ID_MESA_PANVK:
return driver_vendor::PANVK;
default: default:
// Mobile? // Mobile?
return driver_vendor::unknown; return driver_vendor::unknown;
@ -659,6 +666,12 @@ namespace vk
enabled_features.textureCompressionBC = VK_FALSE; enabled_features.textureCompressionBC = VK_FALSE;
} }
if (!pgpu->features.textureCompressionBC && pgpu->get_driver_vendor() == driver_vendor::PANVK)
{
rsx_log.error("Your GPU running on the PANVK driver does not support full texture block compression. Graphics may not render correctly.");
enabled_features.textureCompressionBC = VK_FALSE;
}
VkDeviceCreateInfo device = {}; VkDeviceCreateInfo device = {};
device.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device.pNext = nullptr; device.pNext = nullptr;

View file

@ -41,6 +41,7 @@ void progress_dialog_server::operator()()
{ {
std::shared_ptr<rsx::overlays::progress_dialog> native_dlg; std::shared_ptr<rsx::overlays::progress_dialog> native_dlg;
g_system_progress_stopping = false; g_system_progress_stopping = false;
g_system_progress_canceled = false;
const auto get_state = []() const auto get_state = []()
{ {

View file

@ -43,6 +43,7 @@ void fmt_class_string<cheat_type>::format(std::string& out, u64 arg)
case cheat_type::signed_16_cheat: return "Signed 16 bits"; case cheat_type::signed_16_cheat: return "Signed 16 bits";
case cheat_type::signed_32_cheat: return "Signed 32 bits"; case cheat_type::signed_32_cheat: return "Signed 32 bits";
case cheat_type::signed_64_cheat: return "Signed 64 bits"; case cheat_type::signed_64_cheat: return "Signed 64 bits";
case cheat_type::float_32_cheat: return "Float 32 bits";
case cheat_type::max: break; case cheat_type::max: break;
} }
@ -612,8 +613,9 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent)
return; return;
} }
bool success; bool success = false;
u64 result_value; u64 result_value {};
f64 result_value_f {};
switch (cheat->type) switch (cheat->type)
{ {
@ -625,6 +627,7 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent)
case cheat_type::signed_16_cheat: result_value = cheat_engine::get_value<s16>(final_offset, success); break; case cheat_type::signed_16_cheat: result_value = cheat_engine::get_value<s16>(final_offset, success); break;
case cheat_type::signed_32_cheat: result_value = cheat_engine::get_value<s32>(final_offset, success); break; case cheat_type::signed_32_cheat: result_value = cheat_engine::get_value<s32>(final_offset, success); break;
case cheat_type::signed_64_cheat: result_value = cheat_engine::get_value<s64>(final_offset, success); break; case cheat_type::signed_64_cheat: result_value = cheat_engine::get_value<s64>(final_offset, success); break;
case cheat_type::float_32_cheat: result_value_f = cheat_engine::get_value<f32>(final_offset, success); break;
default: log_cheat.fatal("Unsupported cheat type"); return; default: log_cheat.fatal("Unsupported cheat type"); return;
} }
@ -632,6 +635,8 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent)
{ {
if (cheat->type >= cheat_type::signed_8_cheat && cheat->type <= cheat_type::signed_64_cheat) if (cheat->type >= cheat_type::signed_8_cheat && cheat->type <= cheat_type::signed_64_cheat)
edt_value_final->setText(tr("%1").arg(static_cast<s64>(result_value))); edt_value_final->setText(tr("%1").arg(static_cast<s64>(result_value)));
else if (cheat->type == cheat_type::float_32_cheat)
edt_value_final->setText(tr("%1").arg(result_value_f));
else else
edt_value_final->setText(tr("%1").arg(result_value)); edt_value_final->setText(tr("%1").arg(result_value));
} }
@ -795,6 +800,7 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent)
case cheat_type::signed_16_cheat: results = convert_and_set<s16>(final_offset); break; case cheat_type::signed_16_cheat: results = convert_and_set<s16>(final_offset); break;
case cheat_type::signed_32_cheat: results = convert_and_set<s32>(final_offset); break; case cheat_type::signed_32_cheat: results = convert_and_set<s32>(final_offset); break;
case cheat_type::signed_64_cheat: results = convert_and_set<s64>(final_offset); break; case cheat_type::signed_64_cheat: results = convert_and_set<s64>(final_offset); break;
case cheat_type::float_32_cheat: results = convert_and_set<f32>(final_offset); break;
default: log_cheat.fatal("Unsupported cheat type"); return; default: log_cheat.fatal("Unsupported cheat type"); return;
} }
@ -888,8 +894,6 @@ cheat_manager_dialog* cheat_manager_dialog::get_dlg(QWidget* parent)
template <typename T> template <typename T>
T cheat_manager_dialog::convert_from_QString(const QString& str, bool& success) T cheat_manager_dialog::convert_from_QString(const QString& str, bool& success)
{ {
T result;
if constexpr (std::is_same_v<T, u8>) if constexpr (std::is_same_v<T, u8>)
{ {
const u16 result_16 = str.toUShort(&success); const u16 result_16 = str.toUShort(&success);
@ -897,17 +901,17 @@ T cheat_manager_dialog::convert_from_QString(const QString& str, bool& success)
if (result_16 > 0xFF) if (result_16 > 0xFF)
success = false; success = false;
result = static_cast<T>(result_16); return static_cast<T>(result_16);
} }
if constexpr (std::is_same_v<T, u16>) if constexpr (std::is_same_v<T, u16>)
result = str.toUShort(&success); return str.toUShort(&success);
if constexpr (std::is_same_v<T, u32>) if constexpr (std::is_same_v<T, u32>)
result = str.toUInt(&success); return str.toUInt(&success);
if constexpr (std::is_same_v<T, u64>) if constexpr (std::is_same_v<T, u64>)
result = str.toULongLong(&success); return str.toULongLong(&success);
if constexpr (std::is_same_v<T, s8>) if constexpr (std::is_same_v<T, s8>)
{ {
@ -915,28 +919,31 @@ T cheat_manager_dialog::convert_from_QString(const QString& str, bool& success)
if (result_16 < -128 || result_16 > 127) if (result_16 < -128 || result_16 > 127)
success = false; success = false;
result = static_cast<T>(result_16); return static_cast<T>(result_16);
} }
if constexpr (std::is_same_v<T, s16>) if constexpr (std::is_same_v<T, s16>)
result = str.toShort(&success); return str.toShort(&success);
if constexpr (std::is_same_v<T, s32>) if constexpr (std::is_same_v<T, s32>)
result = str.toInt(&success); return str.toInt(&success);
if constexpr (std::is_same_v<T, s64>) if constexpr (std::is_same_v<T, s64>)
result = str.toLongLong(&success); return str.toLongLong(&success);
return result; if constexpr (std::is_same_v<T, f32>)
return str.toFloat(&success);
return {};
} }
template <typename T> template <typename T>
bool cheat_manager_dialog::convert_and_search() bool cheat_manager_dialog::convert_and_search()
{ {
bool res_conv; bool res_conv = false;
const QString to_search = edt_cheat_search_value->text(); const QString to_search = edt_cheat_search_value->text();
T value = convert_from_QString<T>(to_search, res_conv); const T value = convert_from_QString<T>(to_search, res_conv);
if (!res_conv) if (!res_conv)
return false; return false;
@ -948,10 +955,10 @@ bool cheat_manager_dialog::convert_and_search()
template <typename T> template <typename T>
std::pair<bool, bool> cheat_manager_dialog::convert_and_set(u32 offset) std::pair<bool, bool> cheat_manager_dialog::convert_and_set(u32 offset)
{ {
bool res_conv; bool res_conv = false;
const QString to_set = edt_value_final->text(); const QString to_set = edt_value_final->text();
T value = convert_from_QString<T>(to_set, res_conv); const T value = convert_from_QString<T>(to_set, res_conv);
if (!res_conv) if (!res_conv)
return {false, false}; return {false, false};
@ -974,6 +981,7 @@ void cheat_manager_dialog::do_the_search()
case cheat_type::signed_16_cheat: res_conv = convert_and_search<s16>(); break; case cheat_type::signed_16_cheat: res_conv = convert_and_search<s16>(); break;
case cheat_type::signed_32_cheat: res_conv = convert_and_search<s32>(); break; case cheat_type::signed_32_cheat: res_conv = convert_and_search<s32>(); break;
case cheat_type::signed_64_cheat: res_conv = convert_and_search<s64>(); break; case cheat_type::signed_64_cheat: res_conv = convert_and_search<s64>(); break;
case cheat_type::float_32_cheat: res_conv = convert_and_search<f32>(); break;
default: log_cheat.fatal("Unsupported cheat type"); break; default: log_cheat.fatal("Unsupported cheat type"); break;
} }
@ -1065,6 +1073,7 @@ QString cheat_manager_dialog::get_localized_cheat_type(cheat_type type)
case cheat_type::signed_16_cheat: return tr("Signed 16 bits"); case cheat_type::signed_16_cheat: return tr("Signed 16 bits");
case cheat_type::signed_32_cheat: return tr("Signed 32 bits"); case cheat_type::signed_32_cheat: return tr("Signed 32 bits");
case cheat_type::signed_64_cheat: return tr("Signed 64 bits"); case cheat_type::signed_64_cheat: return tr("Signed 64 bits");
case cheat_type::float_32_cheat: return tr("Float 32 bits");
case cheat_type::max: break; case cheat_type::max: break;
} }
std::string type_formatted; std::string type_formatted;

View file

@ -2282,6 +2282,8 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set
// Concurrent tasks should not wait (at least not in current implementation) // Concurrent tasks should not wait (at least not in current implementation)
ensure(!should_wait_cb || !can_be_concurrent); ensure(!should_wait_cb || !can_be_concurrent);
g_system_progress_canceled = false;
const std::shared_ptr<std::function<bool(int)>> iterate_over_serial = std::make_shared<std::function<bool(int)>>(); const std::shared_ptr<std::function<bool(int)>> iterate_over_serial = std::make_shared<std::function<bool(int)>>();
const std::shared_ptr<atomic_t<int>> index = std::make_shared<atomic_t<int>>(0); const std::shared_ptr<atomic_t<int>> index = std::make_shared<atomic_t<int>>(0);
@ -2297,12 +2299,16 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set
const std::string& serial = *std::next(serials.begin(), index); const std::string& serial = *std::next(serials.begin(), index);
if (pdlg->wasCanceled() || g_system_progress_canceled) if (pdlg->wasCanceled() || g_system_progress_canceled.exchange(false))
{
if (cancel_log)
{ {
cancel_log(index, serials_size); cancel_log(index, serials_size);
}
return false; return false;
} }
else if (action(serial))
if (action(serial))
{ {
const int done = index_ptr->load(); const int done = index_ptr->load();
pdlg->setLabelText(progressLabel.arg(done + 1).arg(serials_size)); pdlg->setLabelText(progressLabel.arg(done + 1).arg(serials_size));
@ -2360,20 +2366,18 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set
if ((*iterate_over_serial)(*index)) if ((*iterate_over_serial)(*index))
{ {
QTimer::singleShot(1, this, *periodic_func); QTimer::singleShot(1, this, *periodic_func);
return;
} }
else
{
pdlg->setLabelText(progressLabel.arg(*index).arg(serials_size)); pdlg->setLabelText(progressLabel.arg(*index).arg(serials_size));
pdlg->setCancelButtonText(tr("OK")); pdlg->setCancelButtonText(tr("OK"));
connect(pdlg, &progress_dialog::canceled, this, [pdlg](){ pdlg->deleteLater(); });
QApplication::beep(); QApplication::beep();
if (refresh_on_finish && index) if (refresh_on_finish && index)
{ {
Refresh(true); Refresh(true);
} }
pdlg->deleteLater();
}
}; };
// Invoked on the next event loop processing iteration // Invoked on the next event loop processing iteration
@ -2414,6 +2418,14 @@ void game_list_frame::BatchCreateCPUCaches(const std::vector<game_info>& game_da
pdlg->setAutoReset(false); pdlg->setAutoReset(false);
pdlg->open(); pdlg->open();
connect(pdlg, &progress_dialog::canceled, this, []()
{
if (!Emu.IsStopped())
{
Emu.GracefulShutdown(false, true);
}
});
BatchActionBySerials(pdlg, serials, tr("%0\nProgress: %1/%2 caches compiled").arg(main_label), BatchActionBySerials(pdlg, serials, tr("%0\nProgress: %1/%2 caches compiled").arg(main_label),
[&, game_data](const std::string& serial) [&, game_data](const std::string& serial)
{ {

View file

@ -2852,6 +2852,7 @@ void main_window::CreateConnects()
connect(dlg, &settings_dialog::EmuSettingsApplied, this, &main_window::NotifyEmuSettingsChange); connect(dlg, &settings_dialog::EmuSettingsApplied, this, &main_window::NotifyEmuSettingsChange);
connect(dlg, &settings_dialog::EmuSettingsApplied, this, &main_window::update_gui_pad_thread); connect(dlg, &settings_dialog::EmuSettingsApplied, this, &main_window::update_gui_pad_thread);
connect(dlg, &settings_dialog::EmuSettingsApplied, m_log_frame, &log_frame::LoadSettings); connect(dlg, &settings_dialog::EmuSettingsApplied, m_log_frame, &log_frame::LoadSettings);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->open(); dlg->open();
}; };

View file

@ -1247,7 +1247,16 @@ bool patch_manager_dialog::handle_json(const QByteArray& data)
if (patch_engine::load(patches, "From Download", content, true, &log_message)) if (patch_engine::load(patches, "From Download", content, true, &log_message))
{ {
patch_log.notice("Successfully validated downloaded patch file"); patch_log.notice("Successfully validated downloaded patch file");
const std::string path = patch_engine::get_patches_path() + "patch.yml";
const std::string patches_path = patch_engine::get_patches_path();
if (!fs::create_path(patches_path))
{
patch_log.fatal("Failed to create path: %s (%s)", patches_path, fs::g_tls_error);
return false;
}
const std::string path = patches_path + "patch.yml";
// Back up current patch file if possible // Back up current patch file if possible
if (fs::is_file(path)) if (fs::is_file(path))

View file

@ -347,6 +347,19 @@ namespace stx
} }
} }
// Order semi-destructors before the actual destructors
// This allows to safely access data that may be deallocated or destroyed from other members of FXO regardless of their intialization time
for (u32 i = 0; i < _max; i++)
{
const auto info = (*std::prev(m_info, i + 1));
if (auto op = info->thread_op)
{
constexpr thread_state destroying_context{7};
op(*std::prev(m_order, i + 1), destroying_context);
}
}
// Destroy objects in reverse order // Destroy objects in reverse order
for (; _max; _max--) for (; _max; _max--)
{ {

View file

@ -361,13 +361,8 @@ namespace stx
[[deprecated("Use null_ptr")]] shared_ptr(std::nullptr_t) = delete; [[deprecated("Use null_ptr")]] shared_ptr(std::nullptr_t) = delete;
// Not-so-aliasing constructor: emulates std::enable_shared_from_this without its overhead // Not-so-aliasing constructor: emulates std::enable_shared_from_this without its overhead
explicit shared_ptr(T* _this) noexcept template <typename Type>
: m_ptr(_this) friend shared_ptr<Type> make_shared_from_this(const Type* _this) noexcept;
{
// Random checks which may fail on invalid pointer
ensure((reinterpret_cast<u64>(d()->destroy) - 0x10000) >> 47 == 0);
ensure((d()->refs++ - 1) >> 58 == 0);
}
template <typename U> requires same_ptr_implicit_v<T, U> template <typename U> requires same_ptr_implicit_v<T, U>
shared_ptr(const shared_ptr<U>& r) noexcept shared_ptr(const shared_ptr<U>& r) noexcept
@ -562,11 +557,29 @@ namespace stx
template <typename T> template <typename T>
requires (std::is_constructible_v<std::remove_reference_t<T>, T&&>) requires (std::is_constructible_v<std::remove_reference_t<T>, T&&>)
static shared_ptr<std::remove_reference_t<T>> make_shared_value(T&& value) static shared_ptr<std::remove_reference_t<T>> make_shared_value(T&& value) noexcept
{ {
return make_single_value(std::forward<T>(value)); return make_single_value(std::forward<T>(value));
} }
// Not-so-aliasing constructor: emulates std::enable_shared_from_this without its overhead
template <typename T>
static shared_ptr<T> make_shared_from_this(const T* _this) noexcept
{
shared_ptr<T> r;
r.m_ptr = const_cast<T*>(_this);
if (!_this) [[unlikely]]
{
return r;
}
// Random checks which may fail on invalid pointer
ensure((reinterpret_cast<u64>(r.d()->destroy.load()) - 0x10000) >> 47 == 0);
ensure((r.d()->refs++ - 1) >> 58 == 0);
return r;
}
// Atomic simplified shared pointer // Atomic simplified shared pointer
template <typename T> template <typename T>
class atomic_ptr class atomic_ptr
@ -1059,9 +1072,9 @@ namespace stx
do do
{ {
// Update old head with current value // Update old head with current value
next.m_ptr = reinterpret_cast<T*>(old.m_val.raw() >> c_ref_size); next.m_ptr = std::launder(ptr_to(old.m_val.raw()));
} while (!m_val.compare_exchange(old.m_val.raw(), reinterpret_cast<uptr>(exch.m_ptr) << c_ref_size)); } while (!m_val.compare_exchange(old.m_val.raw(), to_val(exch.m_ptr)));
// This argument is consumed (moved from) // This argument is consumed (moved from)
exch.m_ptr = nullptr; exch.m_ptr = nullptr;
@ -1076,7 +1089,7 @@ namespace stx
// Simple atomic load is much more effective than load(), but it's a non-owning reference // Simple atomic load is much more effective than load(), but it's a non-owning reference
T* observe() const noexcept T* observe() const noexcept
{ {
return reinterpret_cast<T*>(m_val >> c_ref_size); return std::launder(ptr_to(m_val));
} }
explicit constexpr operator bool() const noexcept explicit constexpr operator bool() const noexcept
@ -1138,11 +1151,6 @@ namespace stx
return false; return false;
} }
constexpr std::nullptr_t get() const noexcept
{
return nullptr;
}
} null_ptr; } null_ptr;
} }