This commit is contained in:
cristian64 2025-12-15 17:14:34 -06:00 committed by GitHub
commit e5b9f67a5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 294 additions and 9 deletions

8
.gitmodules vendored
View File

@ -14,6 +14,10 @@
path = Externals/libusb/libusb
url = https://github.com/libusb/libusb.git
shallow = true
[submodule "Externals/libzmq/libzmq"]
path = Externals/libzmq/libzmq
url = https://github.com/zeromq/libzmq.git
shallow = true
[submodule "Externals/spirv_cross/SPIRV-Cross"]
path = Externals/spirv_cross/SPIRV-Cross
url = https://github.com/KhronosGroup/SPIRV-Cross.git
@ -34,6 +38,10 @@
path = Externals/VulkanMemoryAllocator
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
shallow = true
[submodule "Externals/Cross-Compatible-FileLock-Windows-and-Linux"]
path = Externals/Cross-Compatible-FileLock-Windows-and-Linux
url = https://github.com/KaganCanSit/Cross-Compatible-FileLock-Windows-and-Linux.git
shallow = true
[submodule "Externals/cubeb/cubeb"]
path = Externals/cubeb/cubeb
url = https://github.com/mozilla/cubeb.git

View File

@ -786,8 +786,10 @@ endif()
add_subdirectory(Externals/watcher)
if(WIN32 OR LINUX)
if(NOT ANDROID AND NOT APPLE)
add_subdirectory(Externals/cpp-ipc)
elseif(APPLE)
add_subdirectory(Externals/libzmq)
endif()
########################################

@ -0,0 +1 @@
Subproject commit 42ffdc24b06a85383e1b7a20e09931d7849533e7

@ -1 +1 @@
Subproject commit a0c7725a1441d18bc768d748a93e512a0fa7ab52
Subproject commit ce0773b3e6d5abaa8d104100c5704321113853ca

17
Externals/libzmq/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,17 @@
set(ENABLE_DRAFTS OFF)
set(BUILD_TESTS OFF)
set(WITH_DOCS OFF)
set(BUILD_SHARED OFF)
set(BUILD_STATIC ON)
add_subdirectory(libzmq)
dolphin_disable_warnings(objects)
dolphin_disable_warnings(libzmq-static)
if (NOT MSVC)
target_compile_options(objects PRIVATE "-fexceptions")
target_compile_options(libzmq-static PRIVATE "-fexceptions")
endif ()
add_library(libzmq::libzmq ALIAS libzmq-static)

1
Externals/libzmq/libzmq vendored Submodule

@ -0,0 +1 @@
Subproject commit 7a7bfa10e6b0e99210ed9397369b59f9e69cef8e

View File

@ -10,6 +10,8 @@ Dolphin includes or links code of the following third-party software projects:
[bzip2 license](https://www.sourceware.org/git/?p=bzip2.git;a=blob;f=LICENSE;hb=HEAD) (similar to 3-clause BSD)
- [cpp-ipc](https://github.com/mutouyun/cpp-ipc):
[MIT](https://github.com/mutouyun/cpp-ipc/blob/master/LICENSE)
- [Cross-Compatible-FileLock-Windows-and-Linux](https://github.com/KaganCanSit/Cross-Compatible-FileLock-Windows-and-Linux):
[MIT](https://github.com/KaganCanSit/Cross-Compatible-FileLock-Windows-and-Linux/blob/main/LICENSE)
- [cubeb](https://github.com/kinetiknz/cubeb):
[ISC](https://github.com/kinetiknz/cubeb/blob/master/LICENSE)
- [Discord-RPC](https://github.com/discordapp/discord-rpc):
@ -44,6 +46,8 @@ Dolphin includes or links code of the following third-party software projects:
[University of Illinois/NCSA Open Source license](http://llvm.org/docs/DeveloperPolicy.html#license)
- [LZO](http://www.oberhumer.com/opensource/lzo/):
[GPLv2+](http://www.oberhumer.com/opensource/gpl.html)
- [libzmq](https://github.com/zeromq/libzmq):
[MPL 2.0](https://github.com/zeromq/libzmq/blob/master/LICENSE)
- [mGBA](http://mgba.io)
[MPL 2.0](https://github.com/mgba-emu/mgba/blob/master/LICENSE)
- [MiniUPnPc](http://miniupnp.free.fr/):

View File

@ -801,9 +801,13 @@ if(UNIX)
)
endif()
if(WIN32 OR LINUX)
if(NOT ANDROID AND NOT APPLE)
target_sources(core PRIVATE HW/EXI/BBA/IPC.cpp)
target_link_libraries(core PRIVATE cpp-ipc::ipc)
elseif(APPLE)
target_sources(core PRIVATE HW/EXI/BBA/IPC_zmq.cpp)
target_link_libraries(core PRIVATE libzmq::libzmq)
target_include_directories(core PRIVATE "${CMAKE_SOURCE_DIR}/Externals/Cross-Compatible-FileLock-Windows-and-Linux/include")
endif()
if(MSVC)

View File

@ -0,0 +1,209 @@
// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <bit>
#include <chrono>
#include <cstdlib>
#include <cstring>
#include <mutex>
#include <FileLockFactory.hpp>
#include <zmq.h>
#include "Core/HW/EXI/EXI_DeviceEthernet.h"
namespace ExpansionInterface
{
CEXIETHERNET::IPCBBAInterface::IPCBBAInterface(CEXIETHERNET* const eth_ref)
: CEXIETHERNET::NetworkInterface(eth_ref), m_context(zmq_ctx_new()),
m_proxy_thread(&CEXIETHERNET::IPCBBAInterface::ProxyThreadHandler, this)
{
}
CEXIETHERNET::IPCBBAInterface::~IPCBBAInterface()
{
m_proxy_thread_shutdown.Set();
{
std::lock_guard<std::mutex> lock{m_proxy_mutex};
if (m_proxy_publisher)
{
zmq_close(m_proxy_publisher);
m_proxy_publisher = nullptr;
}
if (m_proxy_subscriber)
{
zmq_close(m_proxy_subscriber);
m_proxy_subscriber = nullptr;
}
}
zmq_ctx_term(m_context);
m_context = nullptr;
if (m_proxy_thread.joinable())
{
m_proxy_thread.join();
}
}
bool CEXIETHERNET::IPCBBAInterface::Activate()
{
if (m_active)
return false;
const u32 linger{0};
m_publisher = zmq_socket(m_context, ZMQ_PUB);
zmq_setsockopt(m_publisher, ZMQ_LINGER, &linger, sizeof(linger));
zmq_connect(m_publisher, "ipc:///tmp/dolphin-bba-outbox");
m_subscriber = zmq_socket(m_context, ZMQ_SUB);
zmq_setsockopt(m_subscriber, ZMQ_LINGER, &linger, sizeof(linger));
zmq_setsockopt(m_subscriber, ZMQ_SUBSCRIBE, "", 0);
zmq_connect(m_subscriber, "ipc:///tmp/dolphin-bba-inbox");
m_read_enabled.Clear();
m_read_thread_shutdown.Clear();
m_active = true;
return RecvInit();
}
void CEXIETHERNET::IPCBBAInterface::Deactivate()
{
if (!m_active)
return;
m_read_enabled.Clear();
m_read_thread_shutdown.Set();
if (m_read_thread.joinable())
{
m_read_thread.join();
}
zmq_close(m_publisher);
zmq_close(m_subscriber);
m_publisher = nullptr;
m_subscriber = nullptr;
m_active = false;
}
bool CEXIETHERNET::IPCBBAInterface::IsActivated()
{
return m_active;
}
bool CEXIETHERNET::IPCBBAInterface::SendFrame(const u8* const frame, const u32 size)
{
if (!m_active)
return false;
std::vector<u8> message;
const u64 self{std::bit_cast<u64>(this)};
message.resize(sizeof(self) + static_cast<u64>(size));
std::memcpy(message.data(), &self, sizeof(self));
std::memcpy(message.data() + sizeof(self), frame, static_cast<u64>(size));
zmq_send(m_publisher, message.data(), message.size(), 0);
m_eth_ref->SendComplete();
return true;
}
bool CEXIETHERNET::IPCBBAInterface::RecvInit()
{
m_read_thread = std::thread(&CEXIETHERNET::IPCBBAInterface::ReadThreadHandler, this);
return true;
}
void CEXIETHERNET::IPCBBAInterface::RecvStart()
{
m_read_enabled.Set();
}
void CEXIETHERNET::IPCBBAInterface::RecvStop()
{
m_read_enabled.Clear();
}
void CEXIETHERNET::IPCBBAInterface::ReadThreadHandler()
{
const u64 self{std::bit_cast<u64>(this)};
std::vector<u8> buffer;
buffer.resize(sizeof(self) + BBA_RECV_SIZE);
while (!m_read_thread_shutdown.IsSet())
{
zmq_pollitem_t pollitem{};
pollitem.socket = m_subscriber;
pollitem.events = ZMQ_POLLIN;
const int event_count{zmq_poll(&pollitem, 1, 50)};
for (int i{0}; i < event_count; ++i)
{
const int read{zmq_recv(m_subscriber, buffer.data(), buffer.size(), 0)};
if (read < static_cast<int>(sizeof(self)))
continue;
u64 id{};
std::memcpy(&id, buffer.data(), sizeof(self));
const bool self_message{id == self};
if (self_message)
continue;
if (!m_read_enabled.IsSet())
continue;
const u8* const frame{buffer.data() + sizeof(self)};
const u64 size{read - sizeof(self)};
std::memcpy(m_eth_ref->mRecvBuffer.get(), frame, size);
m_eth_ref->mRecvBufferLength = static_cast<u32>(size);
m_eth_ref->RecvHandlePacket();
}
}
}
void CEXIETHERNET::IPCBBAInterface::ProxyThreadHandler()
{
while (!m_proxy_thread_shutdown.IsSet())
{
// The first instance that acquires the filelock becomes the proxy.
const auto filelock = file_lock::FileLockFactory::CreateTimedLockContext(
"/tmp/dolphin-bba-filelock", std::chrono::seconds(1));
if (!filelock)
continue;
void* proxy_subscriber;
void* proxy_publisher;
{
std::lock_guard<std::mutex> lock{m_proxy_mutex};
const u32 linger{0};
m_proxy_subscriber = zmq_socket(m_context, ZMQ_XSUB);
zmq_setsockopt(m_proxy_subscriber, ZMQ_LINGER, &linger, sizeof(linger));
zmq_setsockopt(m_proxy_subscriber, ZMQ_SUBSCRIBE, "", 0);
zmq_bind(m_proxy_subscriber, "ipc:///tmp/dolphin-bba-outbox");
m_proxy_publisher = zmq_socket(m_context, ZMQ_XPUB);
zmq_setsockopt(m_proxy_publisher, ZMQ_LINGER, &linger, sizeof(linger));
zmq_bind(m_proxy_publisher, "ipc:///tmp/dolphin-bba-inbox");
proxy_subscriber = m_proxy_subscriber;
proxy_publisher = m_proxy_publisher;
}
zmq_proxy(proxy_subscriber, proxy_publisher, nullptr);
}
}
} // namespace ExpansionInterface

View File

@ -15,7 +15,7 @@
#endif
#include <SFML/Network.hpp>
#if defined(WIN32) || (defined(__linux__) && !defined(__ANDROID__))
#if !defined(__ANDROID__) && !defined(__APPLE__)
#include <libipc/ipc.h>
#endif
@ -478,13 +478,13 @@ private:
const Common::MACAddress& ResolveAddress(u32 inet_ip);
};
#if !defined(__ANDROID__) && !defined(__APPLE__)
class IPCBBAInterface : public NetworkInterface
{
public:
explicit IPCBBAInterface(CEXIETHERNET* const eth_ref) : NetworkInterface(eth_ref) {}
#if defined(WIN32) || (defined(__linux__) && !defined(__ANDROID__))
bool Activate() override;
void Deactivate() override;
bool IsActivated() override;
@ -501,9 +501,50 @@ private:
std::thread m_read_thread;
Common::Flag m_read_enabled;
Common::Flag m_read_thread_shutdown;
};
#elif defined(__APPLE__)
class IPCBBAInterface : public NetworkInterface
{
public:
explicit IPCBBAInterface(CEXIETHERNET* eth_ref);
~IPCBBAInterface() override;
bool Activate() override;
void Deactivate() override;
bool IsActivated() override;
bool SendFrame(const u8* frame, u32 size) override;
bool RecvInit() override;
void RecvStart() override;
void RecvStop() override;
private:
void ReadThreadHandler();
void ProxyThreadHandler();
bool m_active{};
void* m_context{};
void* m_publisher{};
void* m_subscriber{};
std::thread m_read_thread;
Common::Flag m_read_enabled;
Common::Flag m_read_thread_shutdown;
std::thread m_proxy_thread;
Common::Flag m_proxy_thread_shutdown;
std::mutex m_proxy_mutex;
void* m_proxy_publisher{};
void* m_proxy_subscriber{};
};
#else
class IPCBBAInterface : public NetworkInterface
{
public:
explicit IPCBBAInterface(CEXIETHERNET* const eth_ref) : NetworkInterface(eth_ref) {}
bool Activate() override { return false; }
void Deactivate() override {}
bool IsActivated() override { return false; }
@ -511,9 +552,9 @@ private:
bool RecvInit() override { return false; }
void RecvStart() override {}
void RecvStop() override {}
};
#endif
};
std::unique_ptr<NetworkInterface> m_network_interface;

View File

@ -143,9 +143,7 @@ void GameCubePane::CreateWidgets()
EXIDeviceType::EthernetXLink,
EXIDeviceType::EthernetTapServer,
EXIDeviceType::EthernetBuiltIn,
#if defined(WIN32) || (defined(__linux__) && !defined(__ANDROID__))
EXIDeviceType::EthernetIPC,
#endif
EXIDeviceType::ModemTapServer,
})
{