From bc07b9e659a825e0670c3c120a3e320d53303a11 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 4 Aug 2024 12:10:08 +0200 Subject: [PATCH] Dimensions improve locks (maybe) --- rpcs3/Emu/Io/Dimensions.cpp | 86 +++++++++++++++++++---------- rpcs3/Emu/Io/Dimensions.h | 16 +++--- rpcs3/rpcs3qt/dimensions_dialog.cpp | 4 +- 3 files changed, 66 insertions(+), 40 deletions(-) diff --git a/rpcs3/Emu/Io/Dimensions.cpp b/rpcs3/Emu/Io/Dimensions.cpp index faef761bcd..9fc8480bde 100644 --- a/rpcs3/Emu/Io/Dimensions.cpp +++ b/rpcs3/Emu/Io/Dimensions.cpp @@ -77,10 +77,10 @@ void dimensions_toypad::generate_random_number(const u8* buf, u8 sequence, std:: void dimensions_toypad::initialize_rng(u32 seed) { - random_a = 0xF1EA5EED; - random_b = seed; - random_c = seed; - random_d = seed; + m_random_a = 0xF1EA5EED; + m_random_b = seed; + m_random_c = seed; + m_random_d = seed; for (int i = 0; i < 42; i++) { @@ -90,12 +90,12 @@ void dimensions_toypad::initialize_rng(u32 seed) u32 dimensions_toypad::get_next() { - const u32 e = random_a - std::rotl(random_b, 21); - random_a = random_b ^ std::rotl(random_c, 19); - random_b = random_c + std::rotl(random_d, 6); - random_c = random_d + e; - random_d = e + random_a; - return random_d; + const u32 e = m_random_a - std::rotl(m_random_b, 21); + m_random_a = m_random_b ^ std::rotl(m_random_c, 19); + m_random_b = m_random_c + std::rotl(m_random_d, 6); + m_random_c = m_random_d + e; + m_random_d = e + m_random_a; + return m_random_d; } std::array dimensions_toypad::decrypt(const u8* buf, std::optional> key) @@ -292,7 +292,7 @@ void dimensions_toypad::get_challenge_response(const u8* buf, u8 sequence, std:: void dimensions_toypad::query_block(u8 index, u8 page, std::array& reply_buf, u8 sequence) { - std::lock_guard lock(dimensions_mutex); + std::lock_guard lock(m_dimensions_mutex); // Index from game begins at 1 rather than 0, so minus 1 here const dimensions_figure& figure = get_figure_by_index(index - 1); @@ -311,7 +311,7 @@ void dimensions_toypad::query_block(u8 index, u8 page, std::array& reply void dimensions_toypad::write_block(u8 index, u8 page, const u8* to_write_buf, std::array& reply_buf, u8 sequence) { - std::lock_guard lock(dimensions_mutex); + std::lock_guard lock(m_dimensions_mutex); // Index from game begins at 1 rather than 0, so minus 1 here dimensions_figure& figure = get_figure_by_index(index - 1); @@ -356,9 +356,12 @@ void dimensions_toypad::get_model(const u8* buf, u8 sequence, std::array reply_buf[12] = generate_checksum(reply_buf, 12); } -u32 dimensions_toypad::load_figure(const std::array& buf, fs::file in_file, u8 pad, u8 index) +u32 dimensions_toypad::load_figure(const std::array& buf, fs::file in_file, u8 pad, u8 index, bool lock) { - std::lock_guard lock(dimensions_mutex); + if (lock) + { + m_dimensions_mutex.lock(); + } const u32 id = get_figure_id(buf); @@ -374,17 +377,27 @@ u32 dimensions_toypad::load_figure(const std::array& buf, fs::f std::memcpy(&figure_change_response[6], buf.data(), 7); figure_change_response[13] = generate_checksum(figure_change_response, 13); m_figure_added_removed_responses.push(figure_change_response); + + if (lock) + { + m_dimensions_mutex.unlock(); + } return id; } -bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool save) +bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool save, bool lock) { - std::lock_guard lock(dimensions_mutex); dimensions_figure& figure = get_figure_by_index(index); if (figure.index == 255) { return false; } + + if (lock) + { + m_dimensions_mutex.lock(); + } + // When a figure is removed from the toypad, respond to the game with the pad they were removed from, their index, // the direction (0x01 in byte 6 for removed) and their UID std::array figure_change_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x01}; @@ -398,11 +411,18 @@ bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool save) figure.pad = 255; figure_change_response[13] = generate_checksum(figure_change_response, 13); m_figure_added_removed_responses.push(figure_change_response); + + if (lock) + { + m_dimensions_mutex.unlock(); + } return true; } bool dimensions_toypad::move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index) { + std::lock_guard lock(m_dimensions_mutex); + if (old_index == index) { // Don't bother removing and loading again, just send response to the game @@ -418,15 +438,15 @@ bool dimensions_toypad::move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index) // When moving figures between spaces on the toypad, remove any figure from the space they are moving to, // then remove them from their current space, then load them to the space they are moving to - remove_figure(pad, index, true); + remove_figure(pad, index, true, false); dimensions_figure& figure = get_figure_by_index(old_index); const std::array data = figure.data; fs::file in_file = std::move(figure.dim_file); - remove_figure(old_pad, old_index, false); + remove_figure(old_pad, old_index, false, false); - load_figure(data, std::move(in_file), pad, index); + load_figure(data, std::move(in_file), pad, index, false); return true; } @@ -477,16 +497,16 @@ std::array dimensions_toypad::pwd_generate(const std::array& uid) std::optional> dimensions_toypad::pop_added_removed_response() { + std::lock_guard lock(m_dimensions_mutex); + if (m_figure_added_removed_responses.empty()) { return std::nullopt; } - else - { - std::array response = m_figure_added_removed_responses.front(); - m_figure_added_removed_responses.pop(); - return response; - } + + std::array response = m_figure_added_removed_responses.front(); + m_figure_added_removed_responses.pop(); + return response; } usb_device_dimensions::usb_device_dimensions(const std::array& location) @@ -517,11 +537,13 @@ void usb_device_dimensions::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoi transfer->expected_count = buf_size; transfer->expected_result = HC_CC_NOERR; - if (endpoint == 0x81) + switch (endpoint) + { + case 0x81: { // Read Endpoint, if a request has not been sent via the write endpoint, set expected result as // EHCI_CC_HALTED so the game doesn't report the Toypad as being disconnected. - std::unique_lock lock(query_mutex); + std::lock_guard lock(m_query_mutex); std::optional> response = g_dimensionstoypad.pop_added_removed_response(); if (response) { @@ -537,9 +559,9 @@ void usb_device_dimensions::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoi transfer->expected_count = 0; transfer->expected_result = EHCI_CC_HALTED; } - lock.unlock(); + break; } - else if (endpoint == 0x01) + case 0x01: { // Write endpoint, similar structure of request to the Infinity Base with a command for byte 3, // sequence for byte 4, the payload after that, then a checksum for the final byte. @@ -620,8 +642,12 @@ void usb_device_dimensions::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoi break; } } - std::lock_guard lock(query_mutex); + std::lock_guard lock(m_query_mutex); m_queries.push(q_result); + break; + } + default: + break; } } diff --git a/rpcs3/Emu/Io/Dimensions.h b/rpcs3/Emu/Io/Dimensions.h index 7026fb522b..25117ef275 100644 --- a/rpcs3/Emu/Io/Dimensions.h +++ b/rpcs3/Emu/Io/Dimensions.h @@ -28,13 +28,13 @@ public: void get_model(const u8* buf, u8 sequence, std::array& reply_buf); std::optional> pop_added_removed_response(); - bool remove_figure(u8 pad, u8 index, bool save); - u32 load_figure(const std::array& buf, fs::file in_file, u8 pad, u8 index); + bool remove_figure(u8 pad, u8 index, bool save, bool lock); + u32 load_figure(const std::array& buf, fs::file in_file, u8 pad, u8 index, bool lock); bool move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index); static bool create_blank_character(std::array& buf, u16 id); protected: - shared_mutex dimensions_mutex; + shared_mutex m_dimensions_mutex; std::array m_figures; private: @@ -50,10 +50,10 @@ private: u32 get_next(); dimensions_figure& get_figure_by_index(u8 index); - u32 random_a; - u32 random_b; - u32 random_c; - u32 random_d; + u32 m_random_a{}; + u32 m_random_b{}; + u32 m_random_c{}; + u32 m_random_d{}; u8 m_figure_order = 0; std::queue> m_figure_added_removed_responses; @@ -72,6 +72,6 @@ public: void isochronous_transfer(UsbTransfer* transfer) override; protected: - shared_mutex query_mutex; + shared_mutex m_query_mutex; std::queue> m_queries; }; diff --git a/rpcs3/rpcs3qt/dimensions_dialog.cpp b/rpcs3/rpcs3qt/dimensions_dialog.cpp index 6fdad9cd45..0d26d35def 100644 --- a/rpcs3/rpcs3qt/dimensions_dialog.cpp +++ b/rpcs3/rpcs3qt/dimensions_dialog.cpp @@ -690,7 +690,7 @@ void dimensions_dialog::clear_figure(u8 pad, u8 index) if (figure_slots[index]) { - g_dimensionstoypad.remove_figure(pad, index, true); + g_dimensionstoypad.remove_figure(pad, index, true, true); figure_slots[index] = std::nullopt; m_edit_figures[index]->setText(tr("None")); } @@ -755,7 +755,7 @@ void dimensions_dialog::load_figure_path(u8 pad, u8 index, const QString& path) clear_figure(pad, index); - const u32 fig_num = g_dimensionstoypad.load_figure(data, std::move(dim_file), pad, index); + const u32 fig_num = g_dimensionstoypad.load_figure(data, std::move(dim_file), pad, index, true); figure_slots[index] = fig_num; const auto name = list_minifigs.find(fig_num);