From e46a402c25eb66067daada2a3d7a318a0e66f1ff Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Fri, 11 Jun 2021 09:34:42 +0200 Subject: [PATCH] early-access version 1778 --- CMakeLists.txt | 24 ++++-- README.md | 2 +- externals/CMakeLists.txt | 5 ++ externals/libusb/CMakeLists.txt | 74 ++++++++++++------- src/common/fs/fs.cpp | 18 ++++- .../hle/kernel/k_light_condition_variable.h | 43 +++++++---- src/core/hle/kernel/k_light_lock.cpp | 19 ++--- src/core/hle/kernel/k_process.cpp | 16 ++-- src/core/hle/kernel/k_resource_limit.cpp | 2 +- src/input_common/CMakeLists.txt | 3 +- 10 files changed, 130 insertions(+), 76 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba207dfd1..97afaf1a9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,8 @@ option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) option(YUZU_USE_BUNDLED_BOOST "Download bundled Boost" OFF) +option(YUZU_USE_BUNDLED_LIBUSB "Compile bundled libusb" OFF) + CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" ON "WIN32" OFF) option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) @@ -420,14 +422,22 @@ elseif (TARGET Boost::boost) endif() # Ensure libusb is properly configured (based on dolphin libusb include) -if(NOT APPLE) +if(NOT APPLE AND NOT YUZU_USE_BUNDLED_LIBUSB) include(FindPkgConfig) - find_package(LibUSB) -endif() -if (NOT LIBUSB_FOUND) - add_subdirectory(externals/libusb) - set(LIBUSB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/libusb/libusb/libusb") - set(LIBUSB_LIBRARIES usb) + if (PKG_CONFIG_FOUND) + pkg_check_modules(LIBUSB QUIET libusb-1.0>=1.0.24) + else() + find_package(LibUSB) + endif() + + if (LIBUSB_FOUND) + add_library(usb INTERFACE) + target_include_directories(usb INTERFACE "${LIBUSB_INCLUDE_DIRS}") + target_link_libraries(usb INTERFACE "${LIBUSB_LIBRARIES}") + else() + message(WARNING "libusb not found, falling back to externals") + set(YUZU_USE_BUNDLED_LIBUSB ON) + endif() endif() # List of all FFmpeg components required diff --git a/README.md b/README.md index 18861014c..63383f609 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 1777. +This is the source code for early-access 1778. ## Legal Notice diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index aae0baa0b..5402a532f 100755 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -45,6 +45,11 @@ target_include_directories(microprofile INTERFACE ./microprofile) add_library(unicorn-headers INTERFACE) target_include_directories(unicorn-headers INTERFACE ./unicorn/include) +# libusb +if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB) + add_subdirectory(libusb) +endif() + # SDL2 if (NOT SDL2_FOUND AND ENABLE_SDL2) if (NOT WIN32) diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt index 3ef007b40..06ce0fba7 100755 --- a/externals/libusb/CMakeLists.txt +++ b/externals/libusb/CMakeLists.txt @@ -1,10 +1,13 @@ -if (MINGW) - # The MinGW toolchain for some reason doesn't work with this CMakeLists file after updating to - # 1.0.24, so we do it the old-fashioned way for now. We may want to move native Linux toolchains - # to here, too (TODO lat9nq?). +set(LIBUSB_FOUND ON CACHE BOOL "libusb is present" FORCE) +set(LIBUSB_VERSION "1.0.24" CACHE STRING "libusb version string" FORCE) + +if (MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")) + # GNU toolchains for some reason doesn't work with the later half of this CMakeLists after + # updating to 1.0.24, so we do it the old-fashioned way for now. set(LIBUSB_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/libusb") set(LIBUSB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libusb") + # Workarounds for MSYS/MinGW if (MSYS) # CMake on Windows passes `C:/`, but we need `/C/` or `/c/` to use `configure` @@ -19,36 +22,42 @@ if (MINGW) set(LIBUSB_CONFIGURE "${LIBUSB_SRC_DIR}/configure") set(LIBUSB_MAKEFILE "${LIBUSB_PREFIX}/Makefile") - set(LIBUSB_LIBRARY "${LIBUSB_PREFIX}/libusb/.libs/libusb-1.0.dll.a") - set(LIBUSB_SHARED_LIBRARY "${LIBUSB_PREFIX}/libusb/.libs/libusb-1.0.dll") - set(LIBUSB_SHARED_LIBRARY_DEST "${CMAKE_BINARY_DIR}/bin/libusb-1.0.dll") - # Causes "externals/libusb/libusb/libusb/os/windows_winusb.c:1427:2: error: conversion to non-scalar type requested", so cannot statically link it for now. - # set(LIBUSB_CFLAGS "-DGUID_DEVINTERFACE_USB_DEVICE=\\(GUID\\){0xA5DCBF10,0x6530,0x11D2,{0x90,0x1F,0x00,0xC0,0x4F,0xB9,0x51,0xED}}") + if (MINGW) + set(LIBUSB_LIBRARIES "${LIBUSB_PREFIX}/libusb/.libs/libusb-1.0.dll.a" CACHE PATH "libusb library path" FORCE) + set(LIBUSB_SHARED_LIBRARY "${LIBUSB_PREFIX}/libusb/.libs/libusb-1.0.dll") + set(LIBUSB_SHARED_LIBRARY_DEST "${CMAKE_BINARY_DIR}/bin/libusb-1.0.dll") + + set(LIBUSB_CONFIGURE_ARGS --host=x86_64-w64-mingw32 --build=x86_64-windows) + else() + set(LIBUSB_LIBRARIES "${LIBUSB_PREFIX}/libusb/.libs/libusb-1.0.a" CACHE PATH "libusb library path" FORCE) + endif() + + set(LIBUSB_INCLUDE_DIRS "${LIBUSB_SRC_DIR}/libusb" CACHE PATH "libusb headers path" FORCE) + + # MINGW: causes "externals/libusb/libusb/libusb/os/windows_winusb.c:1427:2: error: conversion to non-scalar type requested", so cannot statically link it for now. + if (NOT MINGW) + set(LIBUSB_CFLAGS "-DGUID_DEVINTERFACE_USB_DEVICE=\\(GUID\\){0xA5DCBF10,0x6530,0x11D2,{0x90,0x1F,0x00,0xC0,0x4F,0xB9,0x51,0xED}}") + endif() make_directory("${LIBUSB_PREFIX}") add_custom_command( OUTPUT - "${LIBUSB_LIBRARY}" + "${LIBUSB_LIBRARIES}" COMMAND make WORKING_DIRECTORY "${LIBUSB_PREFIX}" ) - # We may use this path for other GNU toolchains, so put all of the MinGW-specific stuff here - if (MINGW) - set(LIBUSB_CONFIGURE_ARGS --host=x86_64-w64-mingw32 --build=x86_64-windows) - endif() - add_custom_command( OUTPUT "${LIBUSB_MAKEFILE}" COMMAND - # /bin/env - # CFLAGS="${LIBUSB_CFLAGS}" - /bin/sh "${LIBUSB_CONFIGURE}" + env + CFLAGS="${LIBUSB_CFLAGS}" + sh "${LIBUSB_CONFIGURE}" ${LIBUSB_CONFIGURE_ARGS} --srcdir="${LIBUSB_SRC_DIR}" WORKING_DIRECTORY @@ -59,7 +68,7 @@ if (MINGW) OUTPUT "${LIBUSB_CONFIGURE}" COMMAND - /bin/sh "${LIBUSB_SRC_DIR}/bootstrap.sh" + sh "${LIBUSB_SRC_DIR}/bootstrap.sh" WORKING_DIRECTORY "${LIBUSB_SRC_DIR}" ) @@ -68,19 +77,30 @@ if (MINGW) OUTPUT "${LIBUSB_SHARED_LIBRARY_DEST}" COMMAND - /bin/cp "${LIBUSB_SHARED_LIBRARY}" "${LIBUSB_SHARED_LIBRARY_DEST}" + cp "${LIBUSB_SHARED_LIBRARY}" "${LIBUSB_SHARED_LIBRARY_DEST}" ) - add_custom_target(usb-bootstrap ALL DEPENDS "${LIBUSB_CONFIGURE}") - add_custom_target(usb-configure ALL DEPENDS "${LIBUSB_MAKEFILE}" usb-bootstrap) - add_custom_target(usb-build ALL DEPENDS "${LIBUSB_LIBRARY}" usb-configure) + add_custom_target(usb-bootstrap DEPENDS "${LIBUSB_CONFIGURE}") + add_custom_target(usb-configure DEPENDS "${LIBUSB_MAKEFILE}" usb-bootstrap) + add_custom_target(usb-build ALL DEPENDS "${LIBUSB_LIBRARIES}" usb-configure) # Workaround since static linking didn't work out -- We need to copy the DLL to the bin directory add_custom_target(usb-copy ALL DEPENDS "${LIBUSB_SHARED_LIBRARY_DEST}" usb-build) - # Make `usb` alias to LIBUSB_LIBRARY add_library(usb INTERFACE) - target_link_libraries(usb INTERFACE "${LIBUSB_LIBRARY}") -else() # MINGW + add_dependencies(usb usb-copy) + target_link_libraries(usb INTERFACE "${LIBUSB_LIBRARIES}") + target_include_directories(usb INTERFACE "${LIBUSB_INCLUDE_DIRS}") + + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + Include(FindPkgConfig) + pkg_check_modules(LIBUDEV REQUIRED libudev) + + if (LIBUDEV_FOUND) + target_include_directories(usb INTERFACE "${LIBUDEV_INCLUDE_DIRS}") + target_link_libraries(usb INTERFACE "${LIBUDEV_STATIC_LIBRARIES}") + endif() + endif() +else() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux") # Ensure libusb compiles with UTF-8 encoding on MSVC if(MSVC) add_compile_options(/utf-8) @@ -236,4 +256,4 @@ else() # MINGW configure_file(config.h.in config.h) -endif() # MINGW +endif() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux") diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index d492480d9..d3159e908 100755 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp @@ -321,7 +321,8 @@ bool RemoveDirContentsRecursively(const fs::path& path) { std::error_code ec; - for (const auto& entry : fs::recursive_directory_iterator(path, ec)) { + // TODO (Morph): Replace this with recursive_directory_iterator once it's fixed in MSVC. + for (const auto& entry : fs::directory_iterator(path, ec)) { if (ec) { LOG_ERROR(Common_Filesystem, "Failed to completely enumerate the directory at path={}, ec_message={}", @@ -337,6 +338,12 @@ bool RemoveDirContentsRecursively(const fs::path& path) { PathToUTF8String(entry.path()), ec.message()); break; } + + // TODO (Morph): Remove this when MSVC fixes recursive_directory_iterator. + // recursive_directory_iterator throws an exception despite passing in a std::error_code. + if (entry.status().type() == fs::file_type::directory) { + return RemoveDirContentsRecursively(entry.path()); + } } if (ec) { @@ -475,7 +482,8 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path, std::error_code ec; - for (const auto& entry : fs::recursive_directory_iterator(path, ec)) { + // TODO (Morph): Replace this with recursive_directory_iterator once it's fixed in MSVC. + for (const auto& entry : fs::directory_iterator(path, ec)) { if (ec) { break; } @@ -495,6 +503,12 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path, break; } } + + // TODO (Morph): Remove this when MSVC fixes recursive_directory_iterator. + // recursive_directory_iterator throws an exception despite passing in a std::error_code. + if (entry.status().type() == fs::file_type::directory) { + IterateDirEntriesRecursively(entry.path(), callback, filter); + } } if (callback_error || ec) { diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h index ca2e539a7..a95fa41f3 100755 --- a/src/core/hle/kernel/k_light_condition_variable.h +++ b/src/core/hle/kernel/k_light_condition_variable.h @@ -18,41 +18,58 @@ class KernelCore; class KLightConditionVariable { public: - explicit KLightConditionVariable(KernelCore& kernel_) - : thread_queue(kernel_), kernel(kernel_) {} + explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {} - void Wait(KLightLock* lock, s64 timeout = -1) { - WaitImpl(lock, timeout); - lock->Lock(); + void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) { + WaitImpl(lock, timeout, allow_terminating_thread); } void Broadcast() { KScopedSchedulerLock lk{kernel}; - while (thread_queue.WakeupFrontThread() != nullptr) { - // We want to signal all threads, and so should continue waking up until there's nothing - // to wake. + + // Signal all threads. + for (auto& thread : wait_list) { + thread.SetState(ThreadState::Runnable); } } private: - void WaitImpl(KLightLock* lock, s64 timeout) { + void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { KThread* owner = GetCurrentThreadPointer(kernel); // Sleep the thread. { - KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); - lock->Unlock(); + KScopedSchedulerLockAndSleep lk{kernel, owner, timeout}; - if (!thread_queue.SleepThread(owner)) { + if (!allow_terminating_thread && owner->IsTerminationRequested()) { lk.CancelSleep(); return; } + + lock->Unlock(); + + // Set the thread as waiting. + GetCurrentThread(kernel).SetState(ThreadState::Waiting); + + // Add the thread to the queue. + wait_list.push_back(GetCurrentThread(kernel)); + } + + // Remove the thread from the wait list. + { + KScopedSchedulerLock sl{kernel}; + + wait_list.erase(wait_list.iterator_to(GetCurrentThread(kernel))); } // Cancel the task that the sleep setup. kernel.TimeManager().UnscheduleTimeEvent(owner); + + // Re-acquire the lock. + lock->Lock(); } - KThreadQueue thread_queue; + KernelCore& kernel; + KThread::WaiterList wait_list{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index f974022e8..0896e705f 100755 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -59,11 +59,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { owner_thread->AddWaiter(cur_thread); // Set thread states. - if (cur_thread->GetState() == ThreadState::Runnable) { - cur_thread->SetState(ThreadState::Waiting); - } else { - KScheduler::SetSchedulerUpdateNeeded(kernel); - } + cur_thread->SetState(ThreadState::Waiting); if (owner_thread->IsSuspended()) { owner_thread->ContinueIfHasKernelWaiters(); @@ -73,10 +69,9 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { // We're no longer waiting on the lock owner. { KScopedSchedulerLock sl{kernel}; - KThread* owner_thread = cur_thread->GetLockOwner(); - if (owner_thread) { + + if (KThread* owner_thread = cur_thread->GetLockOwner(); owner_thread != nullptr) { owner_thread->RemoveWaiter(cur_thread); - KScheduler::SetSchedulerUpdateNeeded(kernel); } } } @@ -95,17 +90,13 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { // Pass the lock to the next owner. uintptr_t next_tag = 0; - if (next_owner) { + if (next_owner != nullptr) { next_tag = reinterpret_cast(next_owner); if (num_waiters > 1) { next_tag |= 0x1; } - if (next_owner->GetState() == ThreadState::Waiting) { - next_owner->SetState(ThreadState::Runnable); - } else { - KScheduler::SetSchedulerUpdateNeeded(kernel); - } + next_owner->SetState(ThreadState::Runnable); if (next_owner->IsSuspended()) { next_owner->ContinueIfHasKernelWaiters(); diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 06b8ce151..d1bd98051 100755 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -201,17 +201,15 @@ bool KProcess::ReleaseUserException(KThread* thread) { // Remove waiter thread. s32 num_waiters{}; - KThread* next = thread->RemoveWaiterByKey( - std::addressof(num_waiters), - reinterpret_cast(std::addressof(exception_thread))); - if (next != nullptr) { - if (next->GetState() == ThreadState::Waiting) { - next->SetState(ThreadState::Runnable); - } else { - KScheduler::SetSchedulerUpdateNeeded(kernel); - } + if (KThread* next = thread->RemoveWaiterByKey( + std::addressof(num_waiters), + reinterpret_cast(std::addressof(exception_thread))); + next != nullptr) { + next->SetState(ThreadState::Runnable); } + KScheduler::SetSchedulerUpdateNeeded(kernel); + return true; } else { return false; diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index f91cb65dc..da88f35bc 100755 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -117,7 +117,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { if (current_hints[index] + value <= limit_values[index] && (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) { waiter_count++; - cond_var.Wait(&lock, timeout); + cond_var.Wait(&lock, timeout, false); waiter_count--; } else { break; diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index de53e1fda..7c5763f9c 100755 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -71,8 +71,7 @@ if (ENABLE_SDL2) target_compile_definitions(input_common PRIVATE HAVE_SDL2) endif() -target_include_directories(input_common SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIR}) -target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES}) +target_link_libraries(input_common PRIVATE usb) create_target_directory_groups(input_common) target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)