diff options
| author | Jordan Woyak <jordan.woyak@gmail.com> | 2026-11-12 17:58:38 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-11-12 17:58:38 -0600 |
| commit | cd92a628f37c19333f5c5ee84c43aeb4b48ec9e3 (patch) | |
| tree | 253fd79ba9e7d44ba4e06c2320b5d8a17ad85300 | |
| parent | db2afcbdf8f5175a6b8414d9f5e21c978775f651 (diff) | |
| parent | af6c1f26d3ad3324b4273c49b08ee31d39500431 (diff) | |
Merge pull request #14876 from VampireFlower/usbgecko
Optimize USB Gecko Emulation
| -rw-r--r-- | Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp | 65 | ||||
| -rw-r--r-- | Source/Core/Core/HW/EXI/EXI_DeviceGecko.h | 9 |
2 files changed, 54 insertions, 20 deletions
diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp index 5d58f4a926..9d064582a7 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.cpp @@ -99,7 +99,6 @@ bool GeckoSockServer::GetAvailableSock() if (!waiting_socks.empty()) { - client = std::move(waiting_socks.front()); if (clientThread.joinable()) { client_running.Clear(); @@ -108,6 +107,9 @@ bool GeckoSockServer::GetAvailableSock() recv_fifo = std::deque<u8>(); send_fifo = std::deque<u8>(); } + client = std::move(waiting_socks.front()); + client_running.Set(); + client_connected.Set(); clientThread = std::thread(&GeckoSockServer::ClientThread, this); client_count++; waiting_socks.pop(); @@ -119,8 +121,6 @@ bool GeckoSockServer::GetAvailableSock() void GeckoSockServer::ClientThread() { - client_running.Set(); - Common::SetCurrentThreadName("Gecko Client"); client->setBlocking(false); @@ -130,7 +130,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<char, 128> buffer; @@ -145,24 +145,35 @@ 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<char> 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(); } client->disconnect(); + client_connected.Clear(); } CEXIGecko::CEXIGecko(Core::System& system) : IEXIDevice(system) @@ -174,7 +185,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) @@ -195,11 +206,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(recv_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; } @@ -208,24 +223,36 @@ 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); - _uData = recv_fifo.empty() ? 0 : 0x04000000; + 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 59a8041294..8765349e5a 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceGecko.h @@ -25,9 +25,13 @@ public: // Client for this server object std::unique_ptr<sf::TcpSocket> 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; + + std::mutex send_lock; + std::mutex recv_lock; std::deque<u8> send_fifo; std::deque<u8> recv_fifo; @@ -65,5 +69,8 @@ private: }; static const u32 ident = 0x04700000; + + // Only accessed by the CPU thread. Refilled from recv_fifo under recv_lock + std::deque<u8> m_recv_buffer; }; } // namespace ExpansionInterface |
