From 3ce096543c55fc12ca308f0300641c2f2b803993 Mon Sep 17 00:00:00 2001 From: VampireFlower Date: Fri, 18 Sep 2026 08:25:45 -0600 Subject: Optimize USB Gecko Emulation --- Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp | 23 ++++++++++++++--------- Source/Core/Core/HW/EXI/EXI_DeviceGecko.h | 5 +++++ 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'Source') diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp index 06e90f83b0..d6a1e1494f 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp @@ -92,7 +92,6 @@ bool GeckoSockServer::GetAvailableSock() if (!waiting_socks.empty()) { - client = std::move(waiting_socks.front()); if (clientThread.joinable()) { client_running.Clear(); @@ -101,6 +100,9 @@ bool GeckoSockServer::GetAvailableSock() recv_fifo = std::deque(); send_fifo = std::deque(); } + client = std::move(waiting_socks.front()); + client_running.Set(); + client_connected.Set(); clientThread = std::thread(&GeckoSockServer::ClientThread, this); client_count++; waiting_socks.pop(); @@ -112,8 +114,6 @@ bool GeckoSockServer::GetAvailableSock() void GeckoSockServer::ClientThread() { - client_running.Set(); - Common::SetCurrentThreadName("Gecko Client"); client->setBlocking(false); @@ -156,6 +156,7 @@ void GeckoSockServer::ClientThread() } client->disconnect(); + client_connected.Clear(); } CEXIGecko::CEXIGecko(Core::System& system) : IEXIDevice(system) @@ -167,7 +168,7 @@ void CEXIGecko::ImmReadWrite(u32& _uData, u32 _uSize) // We don't really care about _uSize (void)_uSize; - if (!client || client->getLocalPort() == 0) + if (!client_connected.IsSet()) GetAvailableSock(); switch (_uData >> 28) @@ -188,11 +189,15 @@ void CEXIGecko::ImmReadWrite(u32& _uData, u32 _uSize) // |= 0x08000000 if successful case CMD_RECV: { - std::lock_guard lk(transfer_lock); - if (!recv_fifo.empty()) + if (m_recv_buffer.empty()) + { + std::lock_guard lk(transfer_lock); + m_recv_buffer.swap(recv_fifo); + } + if (!m_recv_buffer.empty()) { - _uData = 0x08000000 | (recv_fifo.front() << 16); - recv_fifo.pop_front(); + _uData = 0x08000000 | (m_recv_buffer.front() << 16); + m_recv_buffer.pop_front(); } break; } @@ -218,7 +223,7 @@ void CEXIGecko::ImmReadWrite(u32& _uData, u32 _uSize) case CMD_CHK_RX: { std::lock_guard lk(transfer_lock); - _uData = recv_fifo.empty() ? 0 : 0x04000000; + _uData = m_recv_buffer.empty() && recv_fifo.empty() ? 0 : 0x04000000; break; } diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h index 6bed93b3a4..04ac9186b7 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h @@ -25,6 +25,8 @@ public: // Client for this server object std::unique_ptr client; + // Set before starting the client thread; cleared after it closes the socket. + Common::Flag client_connected{false}; void ClientThread(); std::thread clientThread; std::mutex transfer_lock; @@ -66,5 +68,8 @@ private: }; static const u32 ident = 0x04700000; + + // Only accessed by the CPU thread. Refilled from recv_fifo under transfer_lock. + std::deque m_recv_buffer; }; } // namespace ExpansionInterface -- cgit v1.2.3 From af6c1f26d3ad3324b4273c49b08ee31d39500431 Mon Sep 17 00:00:00 2001 From: VampireFlower Date: Sat, 19 Sep 2026 17:41:47 -0600 Subject: USB Gecko: Split transfer and receive locks & verify sent amount --- Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp | 44 +++++++++++++++++++++-------- Source/Core/Core/HW/EXI/EXI_DeviceGecko.h | 6 ++-- 2 files changed, 37 insertions(+), 13 deletions(-) (limited to 'Source') diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp index d6a1e1494f..18bbc8bc09 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp @@ -123,7 +123,7 @@ void GeckoSockServer::ClientThread() bool did_nothing = true; { - std::lock_guard lk(transfer_lock); + std::lock_guard lk(recv_lock); // what's an ideal buffer size? std::array buffer; @@ -138,18 +138,28 @@ void GeckoSockServer::ClientThread() recv_fifo.insert(recv_fifo.end(), buffer.data(), buffer.data() + got); } + } // unlock recv + + { + std::lock_guard lk(send_lock); if (!send_fifo.empty()) { - did_nothing = false; + std::size_t sent; std::vector packet(send_fifo.begin(), send_fifo.end()); - send_fifo.clear(); - if (client->send(&packet[0], packet.size()) == sf::Socket::Status::Disconnected) + if (client->send(packet.data(), packet.size(), sent) == sf::Socket::Status::Disconnected) client_running.Clear(); + + if (sent) + { + did_nothing = false; + + send_fifo.erase(send_fifo.begin(), send_fifo.begin() + sent); + } } - } // unlock transfer + } // unlock send if (did_nothing) Common::YieldCPU(); @@ -191,7 +201,7 @@ void CEXIGecko::ImmReadWrite(u32& _uData, u32 _uSize) { if (m_recv_buffer.empty()) { - std::lock_guard lk(transfer_lock); + std::lock_guard lk(recv_lock); m_recv_buffer.swap(recv_fifo); } if (!m_recv_buffer.empty()) @@ -206,23 +216,35 @@ void CEXIGecko::ImmReadWrite(u32& _uData, u32 _uSize) // |= 0x04000000 if successful case CMD_SEND: { - std::lock_guard lk(transfer_lock); - send_fifo.push_back(_uData >> 20); - _uData = 0x04000000; + std::lock_guard lk(send_lock); + + if (send_fifo.size() < 1024) + { + send_fifo.push_back(_uData >> 20); + _uData = 0x04000000; + } + else + { + _uData = 0; + } + break; } // Check if ok for Gecko -> PC, or FIFO full // |= 0x04000000 if FIFO is not full case CMD_CHK_TX: - _uData = 0x04000000; + { + std::lock_guard lk(send_lock); + _uData = send_fifo.size() < 1024 ? 0x04000000 : 0; break; + } // Check if data in FIFO for PC -> Gecko, or FIFO empty // |= 0x04000000 if data in recv FIFO case CMD_CHK_RX: { - std::lock_guard lk(transfer_lock); + std::lock_guard lk(recv_lock); _uData = m_recv_buffer.empty() && recv_fifo.empty() ? 0 : 0x04000000; break; } diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h index 04ac9186b7..a39ae1dfbb 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h @@ -29,7 +29,9 @@ public: Common::Flag client_connected{false}; void ClientThread(); std::thread clientThread; - std::mutex transfer_lock; + + std::mutex send_lock; + std::mutex recv_lock; std::deque send_fifo; std::deque recv_fifo; @@ -69,7 +71,7 @@ private: static const u32 ident = 0x04700000; - // Only accessed by the CPU thread. Refilled from recv_fifo under transfer_lock. + // Only accessed by the CPU thread. Refilled from recv_fifo under recv_lock std::deque m_recv_buffer; }; } // namespace ExpansionInterface -- cgit v1.2.3