From 7508842859bc1c791d1fff2ba514f547a59a631d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 2 Jan 2025 15:39:41 +0100 Subject: Android: Clean up naming in Java_GCAdapter and Java_WiimoteAdapter This isn't how we name things in Java/Kotlin. --- Source/Core/InputCommon/GCAdapter.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Source/Core/InputCommon/GCAdapter.cpp') diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 5cfe513935..103af024fd 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -180,14 +180,14 @@ static void ReadThreadFunc() bool first_read = true; JNIEnv* const env = IDCache::GetEnvForThread(); - const jfieldID payload_field = env->GetStaticFieldID(s_adapter_class, "controller_payload", "[B"); + const jfieldID payload_field = env->GetStaticFieldID(s_adapter_class, "controllerPayload", "[B"); jobject payload_object = env->GetStaticObjectField(s_adapter_class, payload_field); auto* const java_controller_payload = reinterpret_cast(&payload_object); // Get function pointers - const jmethodID getfd_func = env->GetStaticMethodID(s_adapter_class, "GetFD", "()I"); - const jmethodID input_func = env->GetStaticMethodID(s_adapter_class, "Input", "()I"); - const jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "OpenAdapter", "()Z"); + const jmethodID getfd_func = env->GetStaticMethodID(s_adapter_class, "getFd", "()I"); + const jmethodID input_func = env->GetStaticMethodID(s_adapter_class, "input", "()I"); + const jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "openAdapter", "()Z"); const bool connected = env->CallStaticBooleanMethod(s_adapter_class, openadapter_func); @@ -279,7 +279,7 @@ static void WriteThreadFunc() int size = 0; #elif GCADAPTER_USE_ANDROID_IMPLEMENTATION JNIEnv* const env = IDCache::GetEnvForThread(); - const jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "Output", "([B)I"); + const jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "output", "([B)I"); #endif while (s_write_adapter_thread_running.IsSet()) @@ -394,7 +394,7 @@ static void ScanThreadFunc() JNIEnv* const env = IDCache::GetEnvForThread(); const jmethodID queryadapter_func = - env->GetStaticMethodID(s_adapter_class, "QueryAdapter", "()Z"); + env->GetStaticMethodID(s_adapter_class, "queryAdapter", "()Z"); while (s_adapter_detect_thread_running.IsSet()) { @@ -456,7 +456,7 @@ void Init() #elif GCADAPTER_USE_ANDROID_IMPLEMENTATION JNIEnv* const env = IDCache::GetEnvForThread(); - const jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_GCAdapter"); + const jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/GCAdapter"); s_adapter_class = reinterpret_cast(env->NewGlobalRef(adapter_class)); #endif -- cgit v1.2.3 From e2e33becc9934f9af850fc2e2b5c77cf0eb15683 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 2 Jan 2025 17:22:29 +0100 Subject: Android: Detect GCAdapter connection using BroadcastReceiver We can register a BroadcastReceiver to have Android tell us when a GC adapter gets connected instead of having a loop where we continuously call SleepCurrentThread(1000) and poll the current status. When waiting for a GC adapter to connect, this both reduces power usage and improves responsiveness. Note that I made openAdapter get the UsbDevice that's been stored by the hotplug code instead of having openAdapter find the UsbDevice on its own like before. This is only because I want to ensure that the UsbDevice being tracked for disconnection is the same as the UsbDevice actually being used, in case the user has multiple adapters connected. --- Source/Core/InputCommon/GCAdapter.cpp | 41 +++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'Source/Core/InputCommon/GCAdapter.cpp') diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 103af024fd..2da4cf3f15 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -144,9 +144,9 @@ static std::mutex s_write_mutex; static std::thread s_adapter_detect_thread; static Common::Flag s_adapter_detect_thread_running; -#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION static Common::Event s_hotplug_event; +#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION static std::function s_detect_callback; #if defined(__FreeBSD__) && __FreeBSD__ >= 11 @@ -344,6 +344,23 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl return 0; } #endif +#elif GCADAPTER_USE_ANDROID_IMPLEMENTATION +extern "C" { + +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_utils_GCAdapter_onAdapterConnected(JNIEnv* env, jclass) +{ + INFO_LOG_FMT(CONTROLLERINTERFACE, "GC adapter connected"); + if (!s_detected) + s_hotplug_event.Set(); +} + +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_utils_GCAdapter_onAdapterDisconnected(JNIEnv* env, jclass) +{ + INFO_LOG_FMT(CONTROLLERINTERFACE, "GC adapter disconnected"); +} +} #endif static void ScanThreadFunc() @@ -393,15 +410,22 @@ static void ScanThreadFunc() #elif GCADAPTER_USE_ANDROID_IMPLEMENTATION JNIEnv* const env = IDCache::GetEnvForThread(); - const jmethodID queryadapter_func = - env->GetStaticMethodID(s_adapter_class, "queryAdapter", "()Z"); + const jmethodID enable_hotplug_callback_func = + env->GetStaticMethodID(s_adapter_class, "enableHotplugCallback", "()V"); + env->CallStaticVoidMethod(s_adapter_class, enable_hotplug_callback_func); + + const jmethodID is_usb_device_available_func = + env->GetStaticMethodID(s_adapter_class, "isUsbDeviceAvailable", "()Z"); while (s_adapter_detect_thread_running.IsSet()) { if (!s_detected && UseAdapter() && - env->CallStaticBooleanMethod(s_adapter_class, queryadapter_func)) + env->CallStaticBooleanMethod(s_adapter_class, is_usb_device_available_func)) + { Setup(); - Common::SleepCurrentThread(1000); + } + + s_hotplug_event.Wait(); } #endif @@ -484,9 +508,7 @@ void StopScanThread() { if (s_adapter_detect_thread_running.TestAndClear()) { -#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION s_hotplug_event.Set(); -#endif s_adapter_detect_thread.join(); } } @@ -691,6 +713,11 @@ void Shutdown() if (s_libusb_context && s_libusb_context->IsValid() && s_libusb_hotplug_enabled) libusb_hotplug_deregister_callback(*s_libusb_context, s_hotplug_handle); #endif +#elif GCADAPTER_USE_ANDROID_IMPLEMENTATION + JNIEnv* const env = IDCache::GetEnvForThread(); + const jmethodID disable_hotplug_callback_func = + env->GetStaticMethodID(s_adapter_class, "disableHotplugCallback", "()V"); + env->CallStaticVoidMethod(s_adapter_class, disable_hotplug_callback_func); #endif Reset(CalledFromReadThread::No); -- cgit v1.2.3 From 185569778c062f52bdd87137f74dc0d4483b74cb Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 2 Jan 2025 17:37:57 +0100 Subject: Android: Detect GCAdapter disconnection using BroadcastReceiver This lets us get rid of the Reset call in ProcessInputPayload, which was causing us some threading headaches (see 74ed5e5532). Instead we handle disconnection in the same way as the libusb implementation does. --- Source/Core/InputCommon/GCAdapter.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'Source/Core/InputCommon/GCAdapter.cpp') diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 2da4cf3f15..38c8220737 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -134,10 +134,9 @@ static std::thread s_write_adapter_thread; static Common::Flag s_write_adapter_thread_running; static Common::Event s_write_happened; -static std::mutex s_read_mutex; -#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION static std::mutex s_init_mutex; -#elif GCADAPTER_USE_ANDROID_IMPLEMENTATION +static std::mutex s_read_mutex; +#if GCADAPTER_USE_ANDROID_IMPLEMENTATION static std::mutex s_write_mutex; #endif @@ -359,6 +358,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_utils_GCAdapter_onAdapterDisconnected(JNIEnv* env, jclass) { INFO_LOG_FMT(CONTROLLERINTERFACE, "GC adapter disconnected"); + if (s_detected) + Reset(CalledFromReadThread::No); } } #endif @@ -422,6 +423,7 @@ static void ScanThreadFunc() if (!s_detected && UseAdapter() && env->CallStaticBooleanMethod(s_adapter_class, is_usb_device_available_func)) { + std::lock_guard lk(s_init_mutex); Setup(); } @@ -735,10 +737,10 @@ void Shutdown() static void Reset(CalledFromReadThread called_from_read_thread) { -#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION std::unique_lock lock(s_init_mutex, std::defer_lock); if (!lock.try_lock()) return; +#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION if (s_status != AdapterStatus::Detected) return; #elif GCADAPTER_USE_ANDROID_IMPLEMENTATION @@ -834,9 +836,6 @@ void ProcessInputPayload(const u8* data, std::size_t size) // This can occur for a few frames on initialization. ERROR_LOG_FMT(CONTROLLERINTERFACE, "error reading payload (size: {}, type: {:02x})", size, data[0]); -#if GCADAPTER_USE_ANDROID_IMPLEMENTATION - Reset(CalledFromReadThread::Yes); -#endif } else { -- cgit v1.2.3 From 1c7df370d9d5b443b5878c38aa03e1a64437309a Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 2 Jan 2025 17:50:17 +0100 Subject: Revert "Android/GCAdapter: Don't join current thread" This reverts commit 74ed5e55326b9d8e67dfbb8dd6f61d04bcae2445. It solves a problem that no longer exists. --- Source/Core/InputCommon/GCAdapter.cpp | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) (limited to 'Source/Core/InputCommon/GCAdapter.cpp') diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 38c8220737..df212e8f4e 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -66,13 +66,7 @@ static void AddGCAdapter(libusb_device* device); static void ResetRumbleLockNeeded(); #endif -enum class CalledFromReadThread -{ - No, - Yes, -}; - -static void Reset(CalledFromReadThread called_from_read_thread); +static void Reset(); static void Setup(); static void ProcessInputPayload(const u8* data, std::size_t size); static void ReadThreadFunc(); @@ -129,7 +123,6 @@ static std::atomic s_controller_write_payload_size{0}; static std::thread s_read_adapter_thread; static Common::Flag s_read_adapter_thread_running; -static Common::Flag s_read_adapter_thread_needs_joining; static std::thread s_write_adapter_thread; static Common::Flag s_write_adapter_thread_running; static Common::Event s_write_happened; @@ -330,7 +323,7 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { if (s_handle != nullptr && libusb_get_device(s_handle) == dev) - Reset(CalledFromReadThread::No); + Reset(); // Reset a potential error status now that the adapter is unplugged if (s_status == AdapterStatus::Error) @@ -359,7 +352,7 @@ Java_org_dolphinemu_dolphinemu_utils_GCAdapter_onAdapterDisconnected(JNIEnv* env { INFO_LOG_FMT(CONTROLLERINTERFACE, "GC adapter disconnected"); if (s_detected) - Reset(CalledFromReadThread::No); + Reset(); } } #endif @@ -547,11 +540,8 @@ static void Setup() s_detected = true; // Make sure the thread isn't in the middle of shutting down while starting a new one - if (s_read_adapter_thread_needs_joining.TestAndClear() || - s_read_adapter_thread_running.TestAndClear()) - { + if (s_read_adapter_thread_running.TestAndClear()) s_read_adapter_thread.join(); - } s_read_adapter_thread_running.Set(true); s_read_adapter_thread = std::thread(ReadThreadFunc); @@ -721,7 +711,7 @@ void Shutdown() env->GetStaticMethodID(s_adapter_class, "disableHotplugCallback", "()V"); env->CallStaticVoidMethod(s_adapter_class, disable_hotplug_callback_func); #endif - Reset(CalledFromReadThread::No); + Reset(); #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION s_libusb_context.reset(); @@ -735,7 +725,7 @@ void Shutdown() } } -static void Reset(CalledFromReadThread called_from_read_thread) +static void Reset() { std::unique_lock lock(s_init_mutex, std::defer_lock); if (!lock.try_lock()) @@ -748,16 +738,8 @@ static void Reset(CalledFromReadThread called_from_read_thread) return; #endif - if (called_from_read_thread == CalledFromReadThread::No) - { - if (s_read_adapter_thread_running.TestAndClear()) - s_read_adapter_thread.join(); - } - else - { - s_read_adapter_thread_needs_joining.Set(); - s_read_adapter_thread_running.Clear(); - } + if (s_read_adapter_thread_running.TestAndClear()) + s_read_adapter_thread.join(); // The read thread will close the write thread s_port_states.fill({}); -- cgit v1.2.3