early-access version 1778

main
pineappleEA 2021-06-11 09:34:42 +02:00
parent 246c2692dd
commit e46a402c25
10 changed files with 130 additions and 76 deletions

View File

@ -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_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) 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) option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
@ -420,14 +422,22 @@ elseif (TARGET Boost::boost)
endif() endif()
# Ensure libusb is properly configured (based on dolphin libusb include) # Ensure libusb is properly configured (based on dolphin libusb include)
if(NOT APPLE) if(NOT APPLE AND NOT YUZU_USE_BUNDLED_LIBUSB)
include(FindPkgConfig) include(FindPkgConfig)
find_package(LibUSB) if (PKG_CONFIG_FOUND)
endif() pkg_check_modules(LIBUSB QUIET libusb-1.0>=1.0.24)
if (NOT LIBUSB_FOUND) else()
add_subdirectory(externals/libusb) find_package(LibUSB)
set(LIBUSB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/libusb/libusb/libusb") endif()
set(LIBUSB_LIBRARIES usb)
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() endif()
# List of all FFmpeg components required # List of all FFmpeg components required

View File

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 1777. This is the source code for early-access 1778.
## Legal Notice ## Legal Notice

View File

@ -45,6 +45,11 @@ target_include_directories(microprofile INTERFACE ./microprofile)
add_library(unicorn-headers INTERFACE) add_library(unicorn-headers INTERFACE)
target_include_directories(unicorn-headers INTERFACE ./unicorn/include) target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
# libusb
if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB)
add_subdirectory(libusb)
endif()
# SDL2 # SDL2
if (NOT SDL2_FOUND AND ENABLE_SDL2) if (NOT SDL2_FOUND AND ENABLE_SDL2)
if (NOT WIN32) if (NOT WIN32)

View File

@ -1,10 +1,13 @@
if (MINGW) set(LIBUSB_FOUND ON CACHE BOOL "libusb is present" FORCE)
# The MinGW toolchain for some reason doesn't work with this CMakeLists file after updating to set(LIBUSB_VERSION "1.0.24" CACHE STRING "libusb version string" FORCE)
# 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?). 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_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/libusb")
set(LIBUSB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libusb") set(LIBUSB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libusb")
# Workarounds for MSYS/MinGW # Workarounds for MSYS/MinGW
if (MSYS) if (MSYS)
# CMake on Windows passes `C:/`, but we need `/C/` or `/c/` to use `configure` # 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_CONFIGURE "${LIBUSB_SRC_DIR}/configure")
set(LIBUSB_MAKEFILE "${LIBUSB_PREFIX}/Makefile") 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. if (MINGW)
# set(LIBUSB_CFLAGS "-DGUID_DEVINTERFACE_USB_DEVICE=\\(GUID\\){0xA5DCBF10,0x6530,0x11D2,{0x90,0x1F,0x00,0xC0,0x4F,0xB9,0x51,0xED}}") 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}") make_directory("${LIBUSB_PREFIX}")
add_custom_command( add_custom_command(
OUTPUT OUTPUT
"${LIBUSB_LIBRARY}" "${LIBUSB_LIBRARIES}"
COMMAND COMMAND
make make
WORKING_DIRECTORY WORKING_DIRECTORY
"${LIBUSB_PREFIX}" "${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( add_custom_command(
OUTPUT OUTPUT
"${LIBUSB_MAKEFILE}" "${LIBUSB_MAKEFILE}"
COMMAND COMMAND
# /bin/env env
# CFLAGS="${LIBUSB_CFLAGS}" CFLAGS="${LIBUSB_CFLAGS}"
/bin/sh "${LIBUSB_CONFIGURE}" sh "${LIBUSB_CONFIGURE}"
${LIBUSB_CONFIGURE_ARGS} ${LIBUSB_CONFIGURE_ARGS}
--srcdir="${LIBUSB_SRC_DIR}" --srcdir="${LIBUSB_SRC_DIR}"
WORKING_DIRECTORY WORKING_DIRECTORY
@ -59,7 +68,7 @@ if (MINGW)
OUTPUT OUTPUT
"${LIBUSB_CONFIGURE}" "${LIBUSB_CONFIGURE}"
COMMAND COMMAND
/bin/sh "${LIBUSB_SRC_DIR}/bootstrap.sh" sh "${LIBUSB_SRC_DIR}/bootstrap.sh"
WORKING_DIRECTORY WORKING_DIRECTORY
"${LIBUSB_SRC_DIR}" "${LIBUSB_SRC_DIR}"
) )
@ -68,19 +77,30 @@ if (MINGW)
OUTPUT OUTPUT
"${LIBUSB_SHARED_LIBRARY_DEST}" "${LIBUSB_SHARED_LIBRARY_DEST}"
COMMAND 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-bootstrap DEPENDS "${LIBUSB_CONFIGURE}")
add_custom_target(usb-configure ALL DEPENDS "${LIBUSB_MAKEFILE}" usb-bootstrap) add_custom_target(usb-configure DEPENDS "${LIBUSB_MAKEFILE}" usb-bootstrap)
add_custom_target(usb-build ALL DEPENDS "${LIBUSB_LIBRARY}" usb-configure) 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 # 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) add_custom_target(usb-copy ALL DEPENDS "${LIBUSB_SHARED_LIBRARY_DEST}" usb-build)
# Make `usb` alias to LIBUSB_LIBRARY
add_library(usb INTERFACE) add_library(usb INTERFACE)
target_link_libraries(usb INTERFACE "${LIBUSB_LIBRARY}") add_dependencies(usb usb-copy)
else() # MINGW 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 # Ensure libusb compiles with UTF-8 encoding on MSVC
if(MSVC) if(MSVC)
add_compile_options(/utf-8) add_compile_options(/utf-8)
@ -236,4 +256,4 @@ else() # MINGW
configure_file(config.h.in config.h) configure_file(config.h.in config.h)
endif() # MINGW endif() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")

View File

@ -321,7 +321,8 @@ bool RemoveDirContentsRecursively(const fs::path& path) {
std::error_code ec; 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) { if (ec) {
LOG_ERROR(Common_Filesystem, LOG_ERROR(Common_Filesystem,
"Failed to completely enumerate the directory at path={}, ec_message={}", "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()); PathToUTF8String(entry.path()), ec.message());
break; 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) { if (ec) {
@ -475,7 +482,8 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path,
std::error_code ec; 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) { if (ec) {
break; break;
} }
@ -495,6 +503,12 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path,
break; 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) { if (callback_error || ec) {

View File

@ -18,41 +18,58 @@ class KernelCore;
class KLightConditionVariable { class KLightConditionVariable {
public: public:
explicit KLightConditionVariable(KernelCore& kernel_) explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {}
: thread_queue(kernel_), kernel(kernel_) {}
void Wait(KLightLock* lock, s64 timeout = -1) { void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) {
WaitImpl(lock, timeout); WaitImpl(lock, timeout, allow_terminating_thread);
lock->Lock();
} }
void Broadcast() { void Broadcast() {
KScopedSchedulerLock lk{kernel}; KScopedSchedulerLock lk{kernel};
while (thread_queue.WakeupFrontThread() != nullptr) {
// We want to signal all threads, and so should continue waking up until there's nothing // Signal all threads.
// to wake. for (auto& thread : wait_list) {
thread.SetState(ThreadState::Runnable);
} }
} }
private: private:
void WaitImpl(KLightLock* lock, s64 timeout) { void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
KThread* owner = GetCurrentThreadPointer(kernel); KThread* owner = GetCurrentThreadPointer(kernel);
// Sleep the thread. // Sleep the thread.
{ {
KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); KScopedSchedulerLockAndSleep lk{kernel, owner, timeout};
lock->Unlock();
if (!thread_queue.SleepThread(owner)) { if (!allow_terminating_thread && owner->IsTerminationRequested()) {
lk.CancelSleep(); lk.CancelSleep();
return; 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. // Cancel the task that the sleep setup.
kernel.TimeManager().UnscheduleTimeEvent(owner); kernel.TimeManager().UnscheduleTimeEvent(owner);
// Re-acquire the lock.
lock->Lock();
} }
KThreadQueue thread_queue;
KernelCore& kernel; KernelCore& kernel;
KThread::WaiterList wait_list{};
}; };
} // namespace Kernel } // namespace Kernel

View File

@ -59,11 +59,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
owner_thread->AddWaiter(cur_thread); owner_thread->AddWaiter(cur_thread);
// Set thread states. // Set thread states.
if (cur_thread->GetState() == ThreadState::Runnable) { cur_thread->SetState(ThreadState::Waiting);
cur_thread->SetState(ThreadState::Waiting);
} else {
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
if (owner_thread->IsSuspended()) { if (owner_thread->IsSuspended()) {
owner_thread->ContinueIfHasKernelWaiters(); 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. // We're no longer waiting on the lock owner.
{ {
KScopedSchedulerLock sl{kernel}; 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); 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. // Pass the lock to the next owner.
uintptr_t next_tag = 0; uintptr_t next_tag = 0;
if (next_owner) { if (next_owner != nullptr) {
next_tag = reinterpret_cast<uintptr_t>(next_owner); next_tag = reinterpret_cast<uintptr_t>(next_owner);
if (num_waiters > 1) { if (num_waiters > 1) {
next_tag |= 0x1; next_tag |= 0x1;
} }
if (next_owner->GetState() == ThreadState::Waiting) { next_owner->SetState(ThreadState::Runnable);
next_owner->SetState(ThreadState::Runnable);
} else {
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
if (next_owner->IsSuspended()) { if (next_owner->IsSuspended()) {
next_owner->ContinueIfHasKernelWaiters(); next_owner->ContinueIfHasKernelWaiters();

View File

@ -201,17 +201,15 @@ bool KProcess::ReleaseUserException(KThread* thread) {
// Remove waiter thread. // Remove waiter thread.
s32 num_waiters{}; s32 num_waiters{};
KThread* next = thread->RemoveWaiterByKey( if (KThread* next = thread->RemoveWaiterByKey(
std::addressof(num_waiters), std::addressof(num_waiters),
reinterpret_cast<uintptr_t>(std::addressof(exception_thread))); reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
if (next != nullptr) { next != nullptr) {
if (next->GetState() == ThreadState::Waiting) { next->SetState(ThreadState::Runnable);
next->SetState(ThreadState::Runnable);
} else {
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
} }
KScheduler::SetSchedulerUpdateNeeded(kernel);
return true; return true;
} else { } else {
return false; return false;

View File

@ -117,7 +117,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
if (current_hints[index] + value <= limit_values[index] && if (current_hints[index] + value <= limit_values[index] &&
(timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) { (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
waiter_count++; waiter_count++;
cond_var.Wait(&lock, timeout); cond_var.Wait(&lock, timeout, false);
waiter_count--; waiter_count--;
} else { } else {
break; break;

View File

@ -71,8 +71,7 @@ if (ENABLE_SDL2)
target_compile_definitions(input_common PRIVATE HAVE_SDL2) target_compile_definitions(input_common PRIVATE HAVE_SDL2)
endif() endif()
target_include_directories(input_common SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIR}) target_link_libraries(input_common PRIVATE usb)
target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES})
create_target_directory_groups(input_common) create_target_directory_groups(input_common)
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)