Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 04e52ffed0 | |||
| 91f559a71f | |||
| 65b389da70 | |||
| 348ca07e0d | |||
| 0a6f685ad0 | |||
| 185e405bc1 | |||
| 519ddfae04 | |||
| 1914a1d21c | |||
| f34176996e | |||
| 95f45112e9 | |||
| a5ebba7e36 | |||
| a6cfc73cb2 | |||
| 90c3dd300f | |||
| f072f48806 | |||
| 2069430baa | |||
| fc708b396b | |||
| e41c8b6780 | |||
| 646622ccd4 | |||
| c7c4ef9d43 | |||
| cdabc9064b | |||
| 8592f8a2b4 | |||
| 5388e6db84 | |||
| 38dbe57797 | |||
| 7b2917b4e1 | |||
| 5a8cd1b118 | |||
| d2d7a5060f | |||
| 16ff0161b3 | |||
| ee099b2697 | |||
| 5554de3933 | |||
| 8171ad65cd | |||
| c68255f70f | |||
| 247cd92216 | |||
| 19454e71d8 | |||
| 65e20f424a | |||
| bc38d4c81b | |||
| cfb9bcbe42 | |||
| ea4b7226a6 | |||
| 3a6e2922a2 |
@@ -47,3 +47,6 @@ python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/"
|
||||
EXTERNALS_PATH="$(pwd)/build/externals"
|
||||
FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin"
|
||||
find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
|
||||
|
||||
# copy libraries from yuzu.exe path
|
||||
find "$(pwd)/build/bin/" -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
|
||||
|
||||
@@ -8,7 +8,7 @@ steps:
|
||||
displayName: 'Install vulkan-sdk'
|
||||
- script: python -m pip install --upgrade pip conan
|
||||
displayName: 'Install conan'
|
||||
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cmake --install . --config Release && cd ..
|
||||
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd ..
|
||||
displayName: 'Configure CMake'
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build'
|
||||
|
||||
+1
-1
@@ -426,7 +426,7 @@ if(NOT APPLE)
|
||||
endif()
|
||||
if (NOT LIBUSB_FOUND)
|
||||
add_subdirectory(externals/libusb)
|
||||
set(LIBUSB_INCLUDE_DIR "")
|
||||
set(LIBUSB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/libusb/libusb/libusb")
|
||||
set(LIBUSB_LIBRARIES usb)
|
||||
endif()
|
||||
|
||||
|
||||
Vendored
+12
-10
@@ -47,19 +47,21 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
|
||||
|
||||
# SDL2
|
||||
if (NOT SDL2_FOUND AND ENABLE_SDL2)
|
||||
# Yuzu itself needs: Events Joystick Haptic Sensor Timers
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
set(SDL_UNUSED_SUBSYSTEMS
|
||||
Atomic Audio Render Power Threads
|
||||
File CPUinfo Filesystem Locale)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
option(SDL_${_OPT} "" OFF)
|
||||
endforeach()
|
||||
if (NOT WIN32)
|
||||
# Yuzu itself needs: Events Joystick Haptic Sensor Timers
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
set(SDL_UNUSED_SUBSYSTEMS
|
||||
Atomic Audio Render Power Threads
|
||||
File CPUinfo Filesystem Locale)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
option(SDL_${_OPT} "" OFF)
|
||||
endforeach()
|
||||
|
||||
option(HIDAPI "" ON)
|
||||
endif()
|
||||
set(SDL_STATIC ON)
|
||||
set(SDL_SHARED OFF)
|
||||
option(HIDAPI "" ON)
|
||||
|
||||
add_subdirectory(SDL EXCLUDE_FROM_ALL)
|
||||
add_library(SDL2 ALIAS SDL2-static)
|
||||
|
||||
Vendored
+1
-1
Submodule externals/dynarmic updated: b2a4da5e65...36c3b289a0
Vendored
+215
-131
@@ -1,155 +1,239 @@
|
||||
# Ensure libusb compiles with UTF-8 encoding on MSVC
|
||||
if(MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
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?).
|
||||
|
||||
add_library(usb STATIC EXCLUDE_FROM_ALL
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/descriptor.c
|
||||
libusb/libusb/hotplug.c
|
||||
libusb/libusb/io.c
|
||||
libusb/libusb/strerror.c
|
||||
libusb/libusb/sync.c
|
||||
)
|
||||
set_target_properties(usb PROPERTIES VERSION 1.0.23)
|
||||
if(WIN32)
|
||||
target_include_directories(usb
|
||||
BEFORE
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
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`
|
||||
string(REPLACE ":/" "/" LIBUSB_SRC_DIR "${LIBUSB_SRC_DIR}")
|
||||
set(LIBUSB_SRC_DIR "/${LIBUSB_SRC_DIR}")
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
if (NOT MINGW)
|
||||
target_include_directories(usb BEFORE PRIVATE libusb/msvc)
|
||||
# And now that we are using /C/ for srcdir but everything else is using C:/, we need to
|
||||
# compile everything in the source directory, else `configure` won't think the build
|
||||
# environment is sane.
|
||||
set(LIBUSB_PREFIX "${LIBUSB_SRC_DIR}")
|
||||
endif()
|
||||
|
||||
# Works around other libraries providing their own definition of USB GUIDs (e.g. SDL2)
|
||||
target_compile_definitions(usb PRIVATE "-DGUID_DEVINTERFACE_USB_DEVICE=(GUID){ 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}")
|
||||
else()
|
||||
target_include_directories(usb
|
||||
# turns out other projects also have "config.h", so make sure the
|
||||
# LibUSB one comes first
|
||||
BEFORE
|
||||
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")
|
||||
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
# 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}}")
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
endif()
|
||||
make_directory("${LIBUSB_PREFIX}")
|
||||
|
||||
if(WIN32 OR CYGWIN)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/threads_windows.c
|
||||
libusb/libusb/os/windows_winusb.c
|
||||
libusb/libusb/os/windows_usbdk.c
|
||||
libusb/libusb/os/windows_nt_common.c
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${LIBUSB_LIBRARY}"
|
||||
COMMAND
|
||||
make
|
||||
WORKING_DIRECTORY
|
||||
"${LIBUSB_PREFIX}"
|
||||
)
|
||||
set(OS_WINDOWS TRUE)
|
||||
elseif(APPLE)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/darwin_usb.c
|
||||
|
||||
# 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}"
|
||||
${LIBUSB_CONFIGURE_ARGS}
|
||||
--srcdir="${LIBUSB_SRC_DIR}"
|
||||
WORKING_DIRECTORY
|
||||
"${LIBUSB_PREFIX}"
|
||||
)
|
||||
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
|
||||
find_library(IOKIT_LIBRARY IOKit)
|
||||
find_library(OBJC_LIBRARY objc)
|
||||
target_link_libraries(usb PRIVATE
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
${IOKIT_LIBRARY}
|
||||
${OBJC_LIBRARY}
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${LIBUSB_CONFIGURE}"
|
||||
COMMAND
|
||||
/bin/sh "${LIBUSB_SRC_DIR}/bootstrap.sh"
|
||||
WORKING_DIRECTORY
|
||||
"${LIBUSB_SRC_DIR}"
|
||||
)
|
||||
set(OS_DARWIN TRUE)
|
||||
elseif(ANDROID)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
libusb/libusb/os/linux_netlink.c
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${LIBUSB_SHARED_LIBRARY_DEST}"
|
||||
COMMAND
|
||||
/bin/cp "${LIBUSB_SHARED_LIBRARY}" "${LIBUSB_SHARED_LIBRARY_DEST}"
|
||||
)
|
||||
find_library(LOG_LIBRARY log)
|
||||
target_link_libraries(usb PRIVATE ${LOG_LIBRARY})
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
|
||||
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)
|
||||
# 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
|
||||
# Ensure libusb compiles with UTF-8 encoding on MSVC
|
||||
if(MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
|
||||
add_library(usb STATIC EXCLUDE_FROM_ALL
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/descriptor.c
|
||||
libusb/libusb/hotplug.c
|
||||
libusb/libusb/io.c
|
||||
libusb/libusb/strerror.c
|
||||
libusb/libusb/sync.c
|
||||
)
|
||||
find_package(Libudev)
|
||||
if(LIBUDEV_FOUND)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_udev.c
|
||||
set_target_properties(usb PROPERTIES VERSION 1.0.24)
|
||||
if(WIN32)
|
||||
target_include_directories(usb
|
||||
BEFORE
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
target_link_libraries(usb PRIVATE "${LIBUDEV_LIBRARIES}")
|
||||
target_include_directories(usb PRIVATE "${LIBUDEV_INCLUDE_DIR}")
|
||||
set(HAVE_LIBUDEV TRUE)
|
||||
set(USE_UDEV TRUE)
|
||||
|
||||
if (NOT MINGW)
|
||||
target_include_directories(usb BEFORE PRIVATE libusb/msvc)
|
||||
endif()
|
||||
|
||||
# Works around other libraries providing their own definition of USB GUIDs (e.g. SDL2)
|
||||
target_compile_definitions(usb PRIVATE "-DGUID_DEVINTERFACE_USB_DEVICE=(GUID){ 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}")
|
||||
else()
|
||||
target_include_directories(usb
|
||||
# turns out other projects also have "config.h", so make sure the
|
||||
# LibUSB one comes first
|
||||
BEFORE
|
||||
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR CYGWIN)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/threads_windows.c
|
||||
libusb/libusb/os/windows_winusb.c
|
||||
libusb/libusb/os/windows_usbdk.c
|
||||
libusb/libusb/os/windows_common.c
|
||||
)
|
||||
set(OS_WINDOWS TRUE)
|
||||
elseif(APPLE)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/darwin_usb.c
|
||||
)
|
||||
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
|
||||
find_library(IOKIT_LIBRARY IOKit)
|
||||
find_library(OBJC_LIBRARY objc)
|
||||
target_link_libraries(usb PRIVATE
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
${IOKIT_LIBRARY}
|
||||
${OBJC_LIBRARY}
|
||||
)
|
||||
set(OS_DARWIN TRUE)
|
||||
elseif(ANDROID)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
libusb/libusb/os/linux_netlink.c
|
||||
)
|
||||
find_library(LOG_LIBRARY log)
|
||||
target_link_libraries(usb PRIVATE ${LOG_LIBRARY})
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
)
|
||||
find_package(Libudev)
|
||||
if(LIBUDEV_FOUND)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_udev.c
|
||||
)
|
||||
target_link_libraries(usb PRIVATE "${LIBUDEV_LIBRARIES}")
|
||||
target_include_directories(usb PRIVATE "${LIBUDEV_INCLUDE_DIR}")
|
||||
set(HAVE_LIBUDEV TRUE)
|
||||
set(USE_UDEV TRUE)
|
||||
else()
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_netlink.c
|
||||
)
|
||||
endif()
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/netbsd_usb.c
|
||||
)
|
||||
set(OS_NETBSD TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/openbsd_usb.c
|
||||
)
|
||||
set(OS_OPENBSD TRUE)
|
||||
endif()
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/netbsd_usb.c
|
||||
)
|
||||
set(OS_NETBSD TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/openbsd_usb.c
|
||||
)
|
||||
set(OS_OPENBSD TRUE)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/poll_posix.c
|
||||
libusb/libusb/os/threads_posix.c
|
||||
)
|
||||
find_package(Threads REQUIRED)
|
||||
if(THREADS_HAVE_PTHREAD_ARG)
|
||||
target_compile_options(usb PUBLIC "-pthread")
|
||||
if(UNIX)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/events_posix.c
|
||||
libusb/libusb/os/threads_posix.c
|
||||
)
|
||||
find_package(Threads REQUIRED)
|
||||
if(THREADS_HAVE_PTHREAD_ARG)
|
||||
target_compile_options(usb PUBLIC "-pthread")
|
||||
endif()
|
||||
if(CMAKE_THREAD_LIBS_INIT)
|
||||
target_link_libraries(usb PRIVATE "${CMAKE_THREAD_LIBS_INIT}")
|
||||
endif()
|
||||
set(THREADS_POSIX TRUE)
|
||||
elseif(WIN32)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/events_windows.c
|
||||
libusb/libusb/os/threads_windows.c
|
||||
)
|
||||
endif()
|
||||
if(CMAKE_THREAD_LIBS_INIT)
|
||||
target_link_libraries(usb PRIVATE "${CMAKE_THREAD_LIBS_INIT}")
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckTypeSize)
|
||||
check_include_files(asm/types.h HAVE_ASM_TYPES_H)
|
||||
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
|
||||
check_include_files(linux/filter.h HAVE_LINUX_FILTER_H)
|
||||
check_include_files(linux/netlink.h HAVE_LINUX_NETLINK_H)
|
||||
check_include_files(poll.h HAVE_POLL_H)
|
||||
check_include_files(signal.h HAVE_SIGNAL_H)
|
||||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_type_size("struct timespec" STRUCT_TIMESPEC)
|
||||
check_function_exists(syslog HAVE_SYSLOG_FUNC)
|
||||
check_include_files(syslog.h HAVE_SYSLOG_H)
|
||||
check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_files(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
||||
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES poll.h)
|
||||
check_type_size("nfds_t" nfds_t)
|
||||
unset(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
if(HAVE_NFDS_T)
|
||||
set(POLL_NFDS_TYPE "nfds_t")
|
||||
else()
|
||||
set(POLL_NFDS_TYPE "unsigned int")
|
||||
endif()
|
||||
set(THREADS_POSIX TRUE)
|
||||
elseif(WIN32)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/poll_windows.c
|
||||
libusb/libusb/os/threads_windows.c
|
||||
)
|
||||
endif()
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckTypeSize)
|
||||
check_include_files(asm/types.h HAVE_ASM_TYPES_H)
|
||||
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
|
||||
check_include_files(linux/filter.h HAVE_LINUX_FILTER_H)
|
||||
check_include_files(linux/netlink.h HAVE_LINUX_NETLINK_H)
|
||||
check_include_files(poll.h HAVE_POLL_H)
|
||||
check_include_files(signal.h HAVE_SIGNAL_H)
|
||||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_type_size("struct timespec" STRUCT_TIMESPEC)
|
||||
check_function_exists(syslog HAVE_SYSLOG_FUNC)
|
||||
check_include_files(syslog.h HAVE_SYSLOG_H)
|
||||
check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_files(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
||||
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES poll.h)
|
||||
check_type_size("nfds_t" nfds_t)
|
||||
unset(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
if(HAVE_NFDS_T)
|
||||
set(POLL_NFDS_TYPE "nfds_t")
|
||||
else()
|
||||
set(POLL_NFDS_TYPE "unsigned int")
|
||||
endif()
|
||||
|
||||
check_include_files(sys/timerfd.h USBI_TIMERFD_AVAILABLE)
|
||||
check_include_files(sys/timerfd.h USBI_TIMERFD_AVAILABLE)
|
||||
|
||||
|
||||
configure_file(config.h.in config.h)
|
||||
configure_file(config.h.in config.h)
|
||||
endif() # MINGW
|
||||
|
||||
Vendored
+1
-1
Submodule externals/libusb/libusb updated: e782eeb251...c6a35c5601
@@ -154,6 +154,7 @@ add_library(common STATIC
|
||||
param_package.cpp
|
||||
param_package.h
|
||||
parent_of_member.h
|
||||
point.h
|
||||
quaternion.h
|
||||
ring_buffer.h
|
||||
scm_rev.cpp
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Common {
|
||||
|
||||
// Represents a point within a 2D space.
|
||||
template <typename T>
|
||||
struct Point {
|
||||
static_assert(std::is_arithmetic_v<T>, "T must be an arithmetic type!");
|
||||
|
||||
T x{};
|
||||
T y{};
|
||||
|
||||
#define ARITHMETIC_OP(op, compound_op) \
|
||||
friend constexpr Point operator op(const Point& lhs, const Point& rhs) noexcept { \
|
||||
return { \
|
||||
.x = static_cast<T>(lhs.x op rhs.x), \
|
||||
.y = static_cast<T>(lhs.y op rhs.y), \
|
||||
}; \
|
||||
} \
|
||||
friend constexpr Point operator op(const Point& lhs, T value) noexcept { \
|
||||
return { \
|
||||
.x = static_cast<T>(lhs.x op value), \
|
||||
.y = static_cast<T>(lhs.y op value), \
|
||||
}; \
|
||||
} \
|
||||
friend constexpr Point operator op(T value, const Point& rhs) noexcept { \
|
||||
return { \
|
||||
.x = static_cast<T>(value op rhs.x), \
|
||||
.y = static_cast<T>(value op rhs.y), \
|
||||
}; \
|
||||
} \
|
||||
friend constexpr Point& operator compound_op(Point& lhs, const Point& rhs) noexcept { \
|
||||
lhs.x = static_cast<T>(lhs.x op rhs.x); \
|
||||
lhs.y = static_cast<T>(lhs.y op rhs.y); \
|
||||
return lhs; \
|
||||
} \
|
||||
friend constexpr Point& operator compound_op(Point& lhs, T value) noexcept { \
|
||||
lhs.x = static_cast<T>(lhs.x op value); \
|
||||
lhs.y = static_cast<T>(lhs.y op value); \
|
||||
return lhs; \
|
||||
}
|
||||
ARITHMETIC_OP(+, +=)
|
||||
ARITHMETIC_OP(-, -=)
|
||||
ARITHMETIC_OP(*, *=)
|
||||
ARITHMETIC_OP(/, /=)
|
||||
#undef ARITHMETIC_OP
|
||||
|
||||
friend constexpr bool operator==(const Point&, const Point&) = default;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
#include <dynarmic/A32/a32.h>
|
||||
#include <dynarmic/A32/config.h>
|
||||
#include <dynarmic/A32/context.h>
|
||||
#include <dynarmic/interface/A32/a32.h>
|
||||
#include <dynarmic/interface/A32/config.h>
|
||||
#include <dynarmic/interface/A32/context.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/page_table.h"
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <dynarmic/A32/a32.h>
|
||||
#include <dynarmic/A64/a64.h>
|
||||
#include <dynarmic/exclusive_monitor.h>
|
||||
#include <dynarmic/interface/A32/a32.h>
|
||||
#include <dynarmic/interface/A64/a64.h>
|
||||
#include <dynarmic/interface/exclusive_monitor.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/hash.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
#include <dynarmic/A64/a64.h>
|
||||
#include <dynarmic/A64/config.h>
|
||||
#include <dynarmic/interface/A64/a64.h>
|
||||
#include <dynarmic/interface/A64/config.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/page_table.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <dynarmic/A64/a64.h>
|
||||
#include <dynarmic/interface/A64/a64.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/hash.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <dynarmic/A32/coprocessor.h>
|
||||
#include <dynarmic/interface/A32/coprocessor.h>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <dynarmic/exclusive_monitor.h>
|
||||
#include <dynarmic/interface/exclusive_monitor.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
|
||||
@@ -84,50 +84,43 @@ static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAu
|
||||
// Ensure that the token hierarchy reflects the class hierarchy.
|
||||
|
||||
// Base classes.
|
||||
static_assert(!std::is_final<KSynchronizationObject>::value &&
|
||||
std::is_base_of<KAutoObject, KSynchronizationObject>::value);
|
||||
static_assert(!std::is_final<KReadableEvent>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KReadableEvent>::value);
|
||||
static_assert(!std::is_final_v<KSynchronizationObject> &&
|
||||
std::is_base_of_v<KAutoObject, KSynchronizationObject>);
|
||||
static_assert(!std::is_final_v<KReadableEvent> &&
|
||||
std::is_base_of_v<KSynchronizationObject, KReadableEvent>);
|
||||
|
||||
// Final classes
|
||||
// static_assert(std::is_final<KInterruptEvent>::value &&
|
||||
// std::is_base_of<KReadableEvent, KInterruptEvent>::value);
|
||||
// static_assert(std::is_final<KDebug>::value &&
|
||||
// std::is_base_of<KSynchronizationObject, KDebug>::value);
|
||||
static_assert(std::is_final<KThread>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KThread>::value);
|
||||
static_assert(std::is_final<KServerPort>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KServerPort>::value);
|
||||
static_assert(std::is_final<KServerSession>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KServerSession>::value);
|
||||
static_assert(std::is_final<KClientPort>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KClientPort>::value);
|
||||
static_assert(std::is_final<KClientSession>::value &&
|
||||
std::is_base_of<KAutoObject, KClientSession>::value);
|
||||
static_assert(std::is_final<KProcess>::value &&
|
||||
std::is_base_of<KSynchronizationObject, KProcess>::value);
|
||||
static_assert(std::is_final<KResourceLimit>::value &&
|
||||
std::is_base_of<KAutoObject, KResourceLimit>::value);
|
||||
// static_assert(std::is_final<KLightSession>::value &&
|
||||
// std::is_base_of<KAutoObject, KLightSession>::value);
|
||||
static_assert(std::is_final<KPort>::value && std::is_base_of<KAutoObject, KPort>::value);
|
||||
static_assert(std::is_final<KSession>::value && std::is_base_of<KAutoObject, KSession>::value);
|
||||
static_assert(std::is_final<KSharedMemory>::value &&
|
||||
std::is_base_of<KAutoObject, KSharedMemory>::value);
|
||||
static_assert(std::is_final<KEvent>::value && std::is_base_of<KAutoObject, KEvent>::value);
|
||||
static_assert(std::is_final<KWritableEvent>::value &&
|
||||
std::is_base_of<KAutoObject, KWritableEvent>::value);
|
||||
// static_assert(std::is_final<KLightClientSession>::value &&
|
||||
// std::is_base_of<KAutoObject, KLightClientSession>::value);
|
||||
// static_assert(std::is_final<KLightServerSession>::value &&
|
||||
// std::is_base_of<KAutoObject, KLightServerSession>::value);
|
||||
static_assert(std::is_final<KTransferMemory>::value &&
|
||||
std::is_base_of<KAutoObject, KTransferMemory>::value);
|
||||
// static_assert(std::is_final<KDeviceAddressSpace>::value &&
|
||||
// std::is_base_of<KAutoObject, KDeviceAddressSpace>::value);
|
||||
// static_assert(std::is_final<KSessionRequest>::value &&
|
||||
// std::is_base_of<KAutoObject, KSessionRequest>::value);
|
||||
// static_assert(std::is_final<KCodeMemory>::value &&
|
||||
// std::is_base_of<KAutoObject, KCodeMemory>::value);
|
||||
// static_assert(std::is_final_v<KInterruptEvent> &&
|
||||
// std::is_base_of_v<KReadableEvent, KInterruptEvent>);
|
||||
// static_assert(std::is_final_v<KDebug> &&
|
||||
// std::is_base_of_v<KSynchronizationObject, KDebug>);
|
||||
static_assert(std::is_final_v<KThread> && std::is_base_of_v<KSynchronizationObject, KThread>);
|
||||
static_assert(std::is_final_v<KServerPort> &&
|
||||
std::is_base_of_v<KSynchronizationObject, KServerPort>);
|
||||
static_assert(std::is_final_v<KServerSession> &&
|
||||
std::is_base_of_v<KSynchronizationObject, KServerSession>);
|
||||
static_assert(std::is_final_v<KClientPort> &&
|
||||
std::is_base_of_v<KSynchronizationObject, KClientPort>);
|
||||
static_assert(std::is_final_v<KClientSession> && std::is_base_of_v<KAutoObject, KClientSession>);
|
||||
static_assert(std::is_final_v<KProcess> && std::is_base_of_v<KSynchronizationObject, KProcess>);
|
||||
static_assert(std::is_final_v<KResourceLimit> && std::is_base_of_v<KAutoObject, KResourceLimit>);
|
||||
// static_assert(std::is_final_v<KLightSession> &&
|
||||
// std::is_base_of_v<KAutoObject, KLightSession>);
|
||||
static_assert(std::is_final_v<KPort> && std::is_base_of_v<KAutoObject, KPort>);
|
||||
static_assert(std::is_final_v<KSession> && std::is_base_of_v<KAutoObject, KSession>);
|
||||
static_assert(std::is_final_v<KSharedMemory> && std::is_base_of_v<KAutoObject, KSharedMemory>);
|
||||
static_assert(std::is_final_v<KEvent> && std::is_base_of_v<KAutoObject, KEvent>);
|
||||
static_assert(std::is_final_v<KWritableEvent> && std::is_base_of_v<KAutoObject, KWritableEvent>);
|
||||
// static_assert(std::is_final_v<KLightClientSession> &&
|
||||
// std::is_base_of_v<KAutoObject, KLightClientSession>);
|
||||
// static_assert(std::is_final_v<KLightServerSession> &&
|
||||
// std::is_base_of_v<KAutoObject, KLightServerSession>);
|
||||
static_assert(std::is_final_v<KTransferMemory> && std::is_base_of_v<KAutoObject, KTransferMemory>);
|
||||
// static_assert(std::is_final_v<KDeviceAddressSpace> &&
|
||||
// std::is_base_of_v<KAutoObject, KDeviceAddressSpace>);
|
||||
// static_assert(std::is_final_v<KSessionRequest> &&
|
||||
// std::is_base_of_v<KAutoObject, KSessionRequest>);
|
||||
// static_assert(std::is_final_v<KCodeMemory> &&
|
||||
// std::is_base_of_v<KAutoObject, KCodeMemory>);
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -22,7 +22,7 @@ class KClientPort final : public KSynchronizationObject {
|
||||
|
||||
public:
|
||||
explicit KClientPort(KernelCore& kernel_);
|
||||
virtual ~KClientPort() override;
|
||||
~KClientPort() override;
|
||||
|
||||
void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_);
|
||||
void OnSessionFinalized();
|
||||
@@ -49,8 +49,8 @@ public:
|
||||
bool IsServerClosed() const;
|
||||
|
||||
// Overridden virtual functions.
|
||||
virtual void Destroy() override;
|
||||
virtual bool IsSignaled() const override;
|
||||
void Destroy() override;
|
||||
bool IsSignaled() const override;
|
||||
|
||||
ResultCode CreateSession(KClientSession** out);
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class KClientSession final
|
||||
|
||||
public:
|
||||
explicit KClientSession(KernelCore& kernel_);
|
||||
virtual ~KClientSession();
|
||||
~KClientSession() override;
|
||||
|
||||
void Initialize(KSession* parent_, std::string&& name_) {
|
||||
// Set member variables.
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
name = std::move(name_);
|
||||
}
|
||||
|
||||
virtual void Destroy() override;
|
||||
void Destroy() override;
|
||||
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||
|
||||
KSession* GetParent() const {
|
||||
|
||||
@@ -20,23 +20,21 @@ class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObj
|
||||
|
||||
public:
|
||||
explicit KEvent(KernelCore& kernel_);
|
||||
virtual ~KEvent();
|
||||
~KEvent() override;
|
||||
|
||||
void Initialize(std::string&& name);
|
||||
|
||||
virtual void Finalize() override;
|
||||
void Finalize() override;
|
||||
|
||||
virtual bool IsInitialized() const override {
|
||||
bool IsInitialized() const override {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
virtual uintptr_t GetPostDestroyArgument() const override {
|
||||
uintptr_t GetPostDestroyArgument() const override {
|
||||
return reinterpret_cast<uintptr_t>(owner);
|
||||
}
|
||||
|
||||
static void PostDestroy(uintptr_t arg);
|
||||
|
||||
virtual KProcess* GetOwner() const override {
|
||||
KProcess* GetOwner() const override {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@@ -48,6 +46,8 @@ public:
|
||||
return writable_event;
|
||||
}
|
||||
|
||||
static void PostDestroy(uintptr_t arg);
|
||||
|
||||
private:
|
||||
KReadableEvent readable_event;
|
||||
KWritableEvent writable_event;
|
||||
|
||||
@@ -22,7 +22,7 @@ class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjec
|
||||
|
||||
public:
|
||||
explicit KPort(KernelCore& kernel_);
|
||||
virtual ~KPort();
|
||||
~KPort() override;
|
||||
|
||||
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||
|
||||
@@ -59,7 +59,6 @@ private:
|
||||
ServerClosed = 3,
|
||||
};
|
||||
|
||||
private:
|
||||
KServerPort server;
|
||||
KClientPort client;
|
||||
State state{State::Invalid};
|
||||
|
||||
@@ -331,19 +331,19 @@ public:
|
||||
|
||||
void LoadModule(CodeSet code_set, VAddr base_addr);
|
||||
|
||||
virtual bool IsInitialized() const override {
|
||||
bool IsInitialized() const override {
|
||||
return is_initialized;
|
||||
}
|
||||
|
||||
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||
|
||||
virtual void Finalize();
|
||||
void Finalize() override;
|
||||
|
||||
virtual u64 GetId() const override final {
|
||||
u64 GetId() const override {
|
||||
return GetProcessID();
|
||||
}
|
||||
|
||||
virtual bool IsSignaled() const override;
|
||||
bool IsSignaled() const override;
|
||||
|
||||
void PinCurrentThread();
|
||||
void UnpinCurrentThread();
|
||||
|
||||
@@ -31,8 +31,8 @@ public:
|
||||
return parent;
|
||||
}
|
||||
|
||||
virtual bool IsSignaled() const override;
|
||||
virtual void Destroy() override;
|
||||
bool IsSignaled() const override;
|
||||
void Destroy() override;
|
||||
|
||||
ResultCode Signal();
|
||||
ResultCode Clear();
|
||||
|
||||
@@ -37,10 +37,10 @@ class KResourceLimit final
|
||||
|
||||
public:
|
||||
explicit KResourceLimit(KernelCore& kernel_);
|
||||
virtual ~KResourceLimit();
|
||||
~KResourceLimit() override;
|
||||
|
||||
void Initialize(const Core::Timing::CoreTiming* core_timing_);
|
||||
virtual void Finalize() override;
|
||||
void Finalize() override;
|
||||
|
||||
s64 GetLimitValue(LimitableResource which) const;
|
||||
s64 GetCurrentValue(LimitableResource which) const;
|
||||
|
||||
@@ -25,12 +25,9 @@ class SessionRequestHandler;
|
||||
class KServerPort final : public KSynchronizationObject {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject);
|
||||
|
||||
private:
|
||||
using SessionList = boost::intrusive::list<KServerSession>;
|
||||
|
||||
public:
|
||||
explicit KServerPort(KernelCore& kernel_);
|
||||
virtual ~KServerPort() override;
|
||||
~KServerPort() override;
|
||||
|
||||
void Initialize(KPort* parent_, std::string&& name_);
|
||||
|
||||
@@ -63,13 +60,14 @@ public:
|
||||
bool IsLight() const;
|
||||
|
||||
// Overridden virtual functions.
|
||||
virtual void Destroy() override;
|
||||
virtual bool IsSignaled() const override;
|
||||
void Destroy() override;
|
||||
bool IsSignaled() const override;
|
||||
|
||||
private:
|
||||
using SessionList = boost::intrusive::list<KServerSession>;
|
||||
|
||||
void CleanupSessions();
|
||||
|
||||
private:
|
||||
SessionList session_list;
|
||||
SessionRequestHandlerPtr session_handler;
|
||||
KPort* parent{};
|
||||
|
||||
@@ -42,9 +42,9 @@ class KServerSession final : public KSynchronizationObject,
|
||||
|
||||
public:
|
||||
explicit KServerSession(KernelCore& kernel_);
|
||||
virtual ~KServerSession() override;
|
||||
~KServerSession() override;
|
||||
|
||||
virtual void Destroy() override;
|
||||
void Destroy() override;
|
||||
|
||||
void Initialize(KSession* parent_, std::string&& name_);
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
return parent;
|
||||
}
|
||||
|
||||
virtual bool IsSignaled() const override;
|
||||
bool IsSignaled() const override;
|
||||
|
||||
void OnClientClosed();
|
||||
|
||||
|
||||
@@ -18,17 +18,17 @@ class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAut
|
||||
|
||||
public:
|
||||
explicit KSession(KernelCore& kernel_);
|
||||
virtual ~KSession() override;
|
||||
~KSession() override;
|
||||
|
||||
void Initialize(KClientPort* port_, const std::string& name_);
|
||||
|
||||
virtual void Finalize() override;
|
||||
void Finalize() override;
|
||||
|
||||
virtual bool IsInitialized() const override {
|
||||
bool IsInitialized() const override {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
virtual uintptr_t GetPostDestroyArgument() const override {
|
||||
uintptr_t GetPostDestroyArgument() const override {
|
||||
return reinterpret_cast<uintptr_t>(process);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,6 @@ private:
|
||||
ServerClosed = 3,
|
||||
};
|
||||
|
||||
private:
|
||||
void SetState(State state) {
|
||||
atomic_state = static_cast<u8>(state);
|
||||
}
|
||||
@@ -87,7 +86,6 @@ private:
|
||||
return static_cast<State>(atomic_state.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
private:
|
||||
KServerSession server;
|
||||
KClientSession client;
|
||||
std::atomic<std::underlying_type_t<State>> atomic_state{
|
||||
|
||||
@@ -68,9 +68,9 @@ public:
|
||||
return device_memory->GetPointer(physical_address + offset);
|
||||
}
|
||||
|
||||
virtual void Finalize() override;
|
||||
void Finalize() override;
|
||||
|
||||
virtual bool IsInitialized() const override {
|
||||
bool IsInitialized() const override {
|
||||
return is_initialized;
|
||||
}
|
||||
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||
|
||||
@@ -4,34 +4,213 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
|
||||
/// This is a placeholder class to manage slab heaps for kernel objects. For now, we just allocate
|
||||
/// these with new/delete, but this can be re-implemented later to allocate these in emulated
|
||||
/// memory.
|
||||
namespace impl {
|
||||
|
||||
class KSlabHeapImpl final : NonCopyable {
|
||||
public:
|
||||
struct Node {
|
||||
Node* next{};
|
||||
};
|
||||
|
||||
constexpr KSlabHeapImpl() = default;
|
||||
|
||||
void Initialize(std::size_t size) {
|
||||
ASSERT(head == nullptr);
|
||||
obj_size = size;
|
||||
}
|
||||
|
||||
constexpr std::size_t GetObjectSize() const {
|
||||
return obj_size;
|
||||
}
|
||||
|
||||
Node* GetHead() const {
|
||||
return head;
|
||||
}
|
||||
|
||||
void* Allocate() {
|
||||
Node* ret = head.load();
|
||||
|
||||
do {
|
||||
if (ret == nullptr) {
|
||||
break;
|
||||
}
|
||||
} while (!head.compare_exchange_weak(ret, ret->next));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Free(void* obj) {
|
||||
Node* node = static_cast<Node*>(obj);
|
||||
|
||||
Node* cur_head = head.load();
|
||||
do {
|
||||
node->next = cur_head;
|
||||
} while (!head.compare_exchange_weak(cur_head, node));
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<Node*> head{};
|
||||
std::size_t obj_size{};
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
class KSlabHeapBase : NonCopyable {
|
||||
public:
|
||||
constexpr KSlabHeapBase() = default;
|
||||
|
||||
constexpr bool Contains(uintptr_t addr) const {
|
||||
return start <= addr && addr < end;
|
||||
}
|
||||
|
||||
constexpr std::size_t GetSlabHeapSize() const {
|
||||
return (end - start) / GetObjectSize();
|
||||
}
|
||||
|
||||
constexpr std::size_t GetObjectSize() const {
|
||||
return impl.GetObjectSize();
|
||||
}
|
||||
|
||||
constexpr uintptr_t GetSlabHeapAddress() const {
|
||||
return start;
|
||||
}
|
||||
|
||||
std::size_t GetObjectIndexImpl(const void* obj) const {
|
||||
return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize();
|
||||
}
|
||||
|
||||
std::size_t GetPeakIndex() const {
|
||||
return GetObjectIndexImpl(reinterpret_cast<const void*>(peak));
|
||||
}
|
||||
|
||||
void* AllocateImpl() {
|
||||
return impl.Allocate();
|
||||
}
|
||||
|
||||
void FreeImpl(void* obj) {
|
||||
// Don't allow freeing an object that wasn't allocated from this heap
|
||||
ASSERT(Contains(reinterpret_cast<uintptr_t>(obj)));
|
||||
|
||||
impl.Free(obj);
|
||||
}
|
||||
|
||||
void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) {
|
||||
// Ensure we don't initialize a slab using null memory
|
||||
ASSERT(memory != nullptr);
|
||||
|
||||
// Initialize the base allocator
|
||||
impl.Initialize(obj_size);
|
||||
|
||||
// Set our tracking variables
|
||||
const std::size_t num_obj = (memory_size / obj_size);
|
||||
start = reinterpret_cast<uintptr_t>(memory);
|
||||
end = start + num_obj * obj_size;
|
||||
peak = start;
|
||||
|
||||
// Free the objects
|
||||
u8* cur = reinterpret_cast<u8*>(end);
|
||||
|
||||
for (std::size_t i{}; i < num_obj; i++) {
|
||||
cur -= obj_size;
|
||||
impl.Free(cur);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using Impl = impl::KSlabHeapImpl;
|
||||
|
||||
Impl impl;
|
||||
uintptr_t peak{};
|
||||
uintptr_t start{};
|
||||
uintptr_t end{};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class KSlabHeap final : NonCopyable {
|
||||
class KSlabHeap final : public KSlabHeapBase {
|
||||
public:
|
||||
KSlabHeap() = default;
|
||||
enum class AllocationType {
|
||||
Host,
|
||||
Guest,
|
||||
};
|
||||
|
||||
void Initialize([[maybe_unused]] void* memory, [[maybe_unused]] std::size_t memory_size) {
|
||||
// Placeholder that should initialize the backing slab heap implementation.
|
||||
explicit constexpr KSlabHeap(AllocationType allocation_type_ = AllocationType::Host)
|
||||
: KSlabHeapBase(), allocation_type{allocation_type_} {}
|
||||
|
||||
void Initialize(void* memory, std::size_t memory_size) {
|
||||
if (allocation_type == AllocationType::Guest) {
|
||||
InitializeImpl(sizeof(T), memory, memory_size);
|
||||
}
|
||||
}
|
||||
|
||||
T* Allocate() {
|
||||
return new T();
|
||||
switch (allocation_type) {
|
||||
case AllocationType::Host:
|
||||
// Fallback for cases where we do not yet support allocating guest memory from the slab
|
||||
// heap, such as for kernel memory regions.
|
||||
return new T;
|
||||
|
||||
case AllocationType::Guest:
|
||||
T* obj = static_cast<T*>(AllocateImpl());
|
||||
if (obj != nullptr) {
|
||||
new (obj) T();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
UNREACHABLE_MSG("Invalid AllocationType {}", allocation_type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T* AllocateWithKernel(KernelCore& kernel) {
|
||||
return new T(kernel);
|
||||
switch (allocation_type) {
|
||||
case AllocationType::Host:
|
||||
// Fallback for cases where we do not yet support allocating guest memory from the slab
|
||||
// heap, such as for kernel memory regions.
|
||||
return new T(kernel);
|
||||
|
||||
case AllocationType::Guest:
|
||||
T* obj = static_cast<T*>(AllocateImpl());
|
||||
if (obj != nullptr) {
|
||||
new (obj) T(kernel);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
UNREACHABLE_MSG("Invalid AllocationType {}", allocation_type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Free(T* obj) {
|
||||
delete obj;
|
||||
switch (allocation_type) {
|
||||
case AllocationType::Host:
|
||||
// Fallback for cases where we do not yet support allocating guest memory from the slab
|
||||
// heap, such as for kernel memory regions.
|
||||
delete obj;
|
||||
return;
|
||||
|
||||
case AllocationType::Guest:
|
||||
FreeImpl(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
UNREACHABLE_MSG("Invalid AllocationType {}", allocation_type);
|
||||
}
|
||||
|
||||
constexpr std::size_t GetObjectIndex(const T* obj) const {
|
||||
return GetObjectIndexImpl(obj);
|
||||
}
|
||||
|
||||
private:
|
||||
const AllocationType allocation_type;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
KSynchronizationObject** objects, const s32 num_objects,
|
||||
s64 timeout);
|
||||
|
||||
virtual void Finalize() override;
|
||||
void Finalize() override;
|
||||
|
||||
[[nodiscard]] virtual bool IsSignaled() const = 0;
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
|
||||
protected:
|
||||
explicit KSynchronizationObject(KernelCore& kernel);
|
||||
virtual ~KSynchronizationObject();
|
||||
~KSynchronizationObject() override;
|
||||
|
||||
virtual void OnFinalizeSynchronizationObject() {}
|
||||
|
||||
|
||||
@@ -168,13 +168,13 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
|
||||
std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0,
|
||||
sizeof(StackParameters));
|
||||
|
||||
// Setup the TLS, if needed.
|
||||
if (type == ThreadType::User) {
|
||||
tls_address = owner->CreateTLSRegion();
|
||||
}
|
||||
|
||||
// Set parent, if relevant.
|
||||
if (owner != nullptr) {
|
||||
// Setup the TLS, if needed.
|
||||
if (type == ThreadType::User) {
|
||||
tls_address = owner->CreateTLSRegion();
|
||||
}
|
||||
|
||||
parent = owner;
|
||||
parent->Open();
|
||||
parent->IncrementThreadCount();
|
||||
|
||||
@@ -358,21 +358,21 @@ public:
|
||||
return termination_requested || GetRawState() == ThreadState::Terminated;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual u64 GetId() const override final {
|
||||
[[nodiscard]] u64 GetId() const override {
|
||||
return this->GetThreadID();
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool IsInitialized() const override {
|
||||
[[nodiscard]] bool IsInitialized() const override {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual uintptr_t GetPostDestroyArgument() const override {
|
||||
[[nodiscard]] uintptr_t GetPostDestroyArgument() const override {
|
||||
return reinterpret_cast<uintptr_t>(parent) | (resource_limit_release_hint ? 1 : 0);
|
||||
}
|
||||
|
||||
virtual void Finalize() override;
|
||||
void Finalize() override;
|
||||
|
||||
[[nodiscard]] virtual bool IsSignaled() const override;
|
||||
[[nodiscard]] bool IsSignaled() const override;
|
||||
|
||||
static void PostDestroy(uintptr_t arg);
|
||||
|
||||
|
||||
@@ -27,23 +27,23 @@ class KTransferMemory final
|
||||
|
||||
public:
|
||||
explicit KTransferMemory(KernelCore& kernel_);
|
||||
virtual ~KTransferMemory() override;
|
||||
~KTransferMemory() override;
|
||||
|
||||
ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_);
|
||||
|
||||
virtual void Finalize() override;
|
||||
void Finalize() override;
|
||||
|
||||
virtual bool IsInitialized() const override {
|
||||
bool IsInitialized() const override {
|
||||
return is_initialized;
|
||||
}
|
||||
|
||||
virtual uintptr_t GetPostDestroyArgument() const override {
|
||||
uintptr_t GetPostDestroyArgument() const override {
|
||||
return reinterpret_cast<uintptr_t>(owner);
|
||||
}
|
||||
|
||||
static void PostDestroy(uintptr_t arg);
|
||||
|
||||
KProcess* GetOwner() const {
|
||||
KProcess* GetOwner() const override {
|
||||
return owner;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
explicit KWritableEvent(KernelCore& kernel_);
|
||||
~KWritableEvent() override;
|
||||
|
||||
virtual void Destroy() override;
|
||||
void Destroy() override;
|
||||
|
||||
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ struct KernelCore::Impl {
|
||||
KAutoObject::Create(thread.get());
|
||||
ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess());
|
||||
thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
|
||||
return std::move(thread);
|
||||
return thread;
|
||||
};
|
||||
|
||||
thread_local auto thread = make_thread();
|
||||
@@ -620,7 +620,8 @@ struct KernelCore::Impl {
|
||||
|
||||
void InitializePageSlab() {
|
||||
// Allocate slab heaps
|
||||
user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>();
|
||||
user_slab_heap_pages =
|
||||
std::make_unique<KSlabHeap<Page>>(KSlabHeap<Page>::AllocationType::Guest);
|
||||
|
||||
// TODO(ameerj): This should be derived, not hardcoded within the kernel
|
||||
constexpr u64 user_slab_heap_size{0x3de000};
|
||||
|
||||
@@ -273,8 +273,13 @@ void SoftwareKeyboard::ProcessTextCheck() {
|
||||
|
||||
std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck));
|
||||
|
||||
std::u16string text_check_message = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_text_check.text_check_message.data(), swkbd_text_check.text_check_message.size());
|
||||
std::u16string text_check_message =
|
||||
swkbd_text_check.text_check_result == SwkbdTextCheckResult::Failure ||
|
||||
swkbd_text_check.text_check_result == SwkbdTextCheckResult::Confirm
|
||||
? Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_text_check.text_check_message.data(),
|
||||
swkbd_text_check.text_check_message.size())
|
||||
: u"";
|
||||
|
||||
LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}",
|
||||
GetTextCheckResultName(swkbd_text_check.text_check_result),
|
||||
@@ -285,10 +290,10 @@ void SoftwareKeyboard::ProcessTextCheck() {
|
||||
SubmitNormalOutputAndExit(SwkbdResult::Ok, current_text);
|
||||
break;
|
||||
case SwkbdTextCheckResult::Failure:
|
||||
ShowTextCheckDialog(SwkbdTextCheckResult::Failure, text_check_message);
|
||||
ShowTextCheckDialog(SwkbdTextCheckResult::Failure, std::move(text_check_message));
|
||||
break;
|
||||
case SwkbdTextCheckResult::Confirm:
|
||||
ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, text_check_message);
|
||||
ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, std::move(text_check_message));
|
||||
break;
|
||||
case SwkbdTextCheckResult::Silent:
|
||||
default:
|
||||
@@ -482,7 +487,7 @@ void SoftwareKeyboard::InitializeFrontendKeyboard() {
|
||||
max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
|
||||
|
||||
Core::Frontend::KeyboardInitializeParameters initialize_parameters{
|
||||
.ok_text{ok_text},
|
||||
.ok_text{std::move(ok_text)},
|
||||
.header_text{},
|
||||
.sub_text{},
|
||||
.guide_text{},
|
||||
@@ -558,10 +563,10 @@ void SoftwareKeyboard::InitializeFrontendKeyboard() {
|
||||
: false;
|
||||
|
||||
Core::Frontend::KeyboardInitializeParameters initialize_parameters{
|
||||
.ok_text{ok_text},
|
||||
.header_text{header_text},
|
||||
.sub_text{sub_text},
|
||||
.guide_text{guide_text},
|
||||
.ok_text{std::move(ok_text)},
|
||||
.header_text{std::move(header_text)},
|
||||
.sub_text{std::move(sub_text)},
|
||||
.guide_text{std::move(guide_text)},
|
||||
.initial_text{initial_text},
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
@@ -590,7 +595,7 @@ void SoftwareKeyboard::ShowNormalKeyboard() {
|
||||
|
||||
void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message) {
|
||||
frontend.ShowTextCheckDialog(text_check_result, text_check_message);
|
||||
frontend.ShowTextCheckDialog(text_check_result, std::move(text_check_message));
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::ShowInlineKeyboard() {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/point.h"
|
||||
#include "core/frontend/input.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
@@ -63,44 +64,21 @@ private:
|
||||
};
|
||||
static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size");
|
||||
|
||||
template <typename T>
|
||||
struct Point {
|
||||
T x{};
|
||||
T y{};
|
||||
|
||||
friend Point operator+(const Point& lhs, const Point& rhs) {
|
||||
return {
|
||||
.x = lhs.x + rhs.x,
|
||||
.y = lhs.y + rhs.y,
|
||||
};
|
||||
}
|
||||
|
||||
friend Point operator-(const Point& lhs, const Point& rhs) {
|
||||
return {
|
||||
.x = lhs.x - rhs.x,
|
||||
.y = lhs.y - rhs.y,
|
||||
};
|
||||
}
|
||||
|
||||
friend bool operator==(const Point&, const Point&) = default;
|
||||
};
|
||||
static_assert(sizeof(Point<s32_le>) == 8, "Point is an invalid size");
|
||||
|
||||
struct GestureState {
|
||||
s64_le sampling_number;
|
||||
s64_le sampling_number2;
|
||||
s64_le detection_count;
|
||||
TouchType type;
|
||||
Direction direction;
|
||||
Point<s32_le> pos;
|
||||
Point<s32_le> delta;
|
||||
Common::Point<s32_le> pos;
|
||||
Common::Point<s32_le> delta;
|
||||
f32 vel_x;
|
||||
f32 vel_y;
|
||||
Attribute attributes;
|
||||
f32 scale;
|
||||
f32 rotation_angle;
|
||||
s32_le point_count;
|
||||
std::array<Point<s32_le>, 4> points;
|
||||
std::array<Common::Point<s32_le>, 4> points;
|
||||
};
|
||||
static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size");
|
||||
|
||||
@@ -111,14 +89,14 @@ private:
|
||||
static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size");
|
||||
|
||||
struct Finger {
|
||||
Point<f32> pos{};
|
||||
Common::Point<f32> pos{};
|
||||
bool pressed{};
|
||||
};
|
||||
|
||||
struct GestureProperties {
|
||||
std::array<Point<s32_le>, MAX_POINTS> points{};
|
||||
std::array<Common::Point<s32_le>, MAX_POINTS> points{};
|
||||
std::size_t active_points{};
|
||||
Point<s32_le> mid_point{};
|
||||
Common::Point<s32_le> mid_point{};
|
||||
s64_le detection_count{};
|
||||
u64_le delta_time{};
|
||||
f32 average_distance{};
|
||||
|
||||
@@ -74,8 +74,11 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
|
||||
for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
|
||||
auto& touch_entry = cur_entry.states[id];
|
||||
if (id < active_fingers_count) {
|
||||
touch_entry.x = static_cast<u16>(active_fingers[id].x * Layout::ScreenUndocked::Width);
|
||||
touch_entry.y = static_cast<u16>(active_fingers[id].y * Layout::ScreenUndocked::Height);
|
||||
const auto& [active_x, active_y] = active_fingers[id].position;
|
||||
touch_entry.position = {
|
||||
.x = static_cast<u16>(active_x * Layout::ScreenUndocked::Width),
|
||||
.y = static_cast<u16>(active_y * Layout::ScreenUndocked::Height),
|
||||
};
|
||||
touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
|
||||
touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
|
||||
touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
|
||||
@@ -86,8 +89,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
|
||||
} else {
|
||||
// Clear touch entry
|
||||
touch_entry.attribute.raw = 0;
|
||||
touch_entry.x = 0;
|
||||
touch_entry.y = 0;
|
||||
touch_entry.position = {};
|
||||
touch_entry.diameter_x = 0;
|
||||
touch_entry.diameter_y = 0;
|
||||
touch_entry.rotation_angle = 0;
|
||||
@@ -140,8 +142,7 @@ std::size_t Controller_Touchscreen::UpdateTouchInputEvent(
|
||||
fingers[finger_id].id = static_cast<u32_le>(finger_id);
|
||||
attribute.start_touch.Assign(1);
|
||||
}
|
||||
fingers[finger_id].x = x;
|
||||
fingers[finger_id].y = y;
|
||||
fingers[finger_id].position = {x, y};
|
||||
fingers[finger_id].attribute = attribute;
|
||||
return finger_id;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/point.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/frontend/input.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
@@ -55,8 +56,7 @@ private:
|
||||
u64_le delta_time;
|
||||
Attributes attribute;
|
||||
u32_le finger;
|
||||
u32_le x;
|
||||
u32_le y;
|
||||
Common::Point<u32_le> position;
|
||||
u32_le diameter_x;
|
||||
u32_le diameter_y;
|
||||
u32_le rotation_angle;
|
||||
@@ -81,8 +81,7 @@ private:
|
||||
|
||||
struct Finger {
|
||||
u64_le last_touch{};
|
||||
float x{};
|
||||
float y{};
|
||||
Common::Point<float> position;
|
||||
u32_le id{};
|
||||
bool pressed{};
|
||||
Attributes attribute;
|
||||
|
||||
@@ -215,10 +215,151 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class INetworkService final : public ServiceFramework<INetworkService> {
|
||||
public:
|
||||
explicit INetworkService(Core::System& system_) : ServiceFramework{system_, "INetworkService"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Initialize"},
|
||||
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
|
||||
{264, nullptr, "GetNetworkInterfaceLastError"},
|
||||
{272, nullptr, "GetRole"},
|
||||
{280, nullptr, "GetAdvertiseData"},
|
||||
{288, nullptr, "GetGroupInfo"},
|
||||
{296, nullptr, "GetGroupInfo2"},
|
||||
{304, nullptr, "GetGroupOwner"},
|
||||
{312, nullptr, "GetIpConfig"},
|
||||
{320, nullptr, "GetLinkLevel"},
|
||||
{512, nullptr, "Scan"},
|
||||
{768, nullptr, "CreateGroup"},
|
||||
{776, nullptr, "DestroyGroup"},
|
||||
{784, nullptr, "SetAdvertiseData"},
|
||||
{1536, nullptr, "SendToOtherGroup"},
|
||||
{1544, nullptr, "RecvFromOtherGroup"},
|
||||
{1552, nullptr, "AddAcceptableGroupId"},
|
||||
{1560, nullptr, "ClearAcceptableGroupId"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class INetworkServiceMonitor final : public ServiceFramework<INetworkServiceMonitor> {
|
||||
public:
|
||||
explicit INetworkServiceMonitor(Core::System& system_)
|
||||
: ServiceFramework{system_, "INetworkServiceMonitor"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &INetworkServiceMonitor::Initialize, "Initialize"},
|
||||
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
|
||||
{264, nullptr, "GetNetworkInterfaceLastError"},
|
||||
{272, nullptr, "GetRole"},
|
||||
{280, nullptr, "GetAdvertiseData"},
|
||||
{281, nullptr, "GetAdvertiseData2"},
|
||||
{288, nullptr, "GetGroupInfo"},
|
||||
{296, nullptr, "GetGroupInfo2"},
|
||||
{304, nullptr, "GetGroupOwner"},
|
||||
{312, nullptr, "GetIpConfig"},
|
||||
{320, nullptr, "GetLinkLevel"},
|
||||
{328, nullptr, "AttachJoinEvent"},
|
||||
{336, nullptr, "GetMembers"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERROR_DISABLED);
|
||||
}
|
||||
};
|
||||
|
||||
class LP2PAPP final : public ServiceFramework<LP2PAPP> {
|
||||
public:
|
||||
explicit LP2PAPP(Core::System& system_) : ServiceFramework{system_, "lp2p:app"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &LP2PAPP::CreateMonitorService, "CreateNetworkService"},
|
||||
{8, &LP2PAPP::CreateMonitorService, "CreateNetworkServiceMonitor"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void CreateNetworkervice(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 reserved_input = rp.Pop<u64>();
|
||||
const u32 input = rp.Pop<u32>();
|
||||
|
||||
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
|
||||
input);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<INetworkService>(system);
|
||||
}
|
||||
|
||||
void CreateMonitorService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 reserved_input = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<INetworkServiceMonitor>(system);
|
||||
}
|
||||
};
|
||||
|
||||
class LP2PSYS final : public ServiceFramework<LP2PSYS> {
|
||||
public:
|
||||
explicit LP2PSYS(Core::System& system_) : ServiceFramework{system_, "lp2p:sys"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &LP2PSYS::CreateMonitorService, "CreateNetworkService"},
|
||||
{8, &LP2PSYS::CreateMonitorService, "CreateNetworkServiceMonitor"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void CreateNetworkervice(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 reserved_input = rp.Pop<u64>();
|
||||
const u32 input = rp.Pop<u32>();
|
||||
|
||||
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
|
||||
input);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<INetworkService>(system);
|
||||
}
|
||||
|
||||
void CreateMonitorService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 reserved_input = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<INetworkServiceMonitor>(system);
|
||||
}
|
||||
};
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
|
||||
std::make_shared<LDNM>(system)->InstallAsService(sm);
|
||||
std::make_shared<LDNS>(system)->InstallAsService(sm);
|
||||
std::make_shared<LDNU>(system)->InstallAsService(sm);
|
||||
std::make_shared<LP2PAPP>(system)->InstallAsService(sm);
|
||||
std::make_shared<LP2PSYS>(system)->InstallAsService(sm);
|
||||
}
|
||||
|
||||
} // namespace Service::LDN
|
||||
|
||||
@@ -18,16 +18,6 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
#include <SDL.h>
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/math_util.h"
|
||||
#include "common/param_package.h"
|
||||
@@ -214,6 +204,40 @@ public:
|
||||
sdl_controller.reset(controller);
|
||||
}
|
||||
|
||||
bool IsJoyconLeft() const {
|
||||
return std::strstr(GetControllerName().c_str(), "Joy-Con Left") != nullptr;
|
||||
}
|
||||
|
||||
bool IsJoyconRight() const {
|
||||
return std::strstr(GetControllerName().c_str(), "Joy-Con Right") != nullptr;
|
||||
}
|
||||
|
||||
std::string GetControllerName() const {
|
||||
if (sdl_controller) {
|
||||
switch (SDL_GameControllerGetType(sdl_controller.get())) {
|
||||
case SDL_CONTROLLER_TYPE_XBOX360:
|
||||
return "XBox 360 Controller";
|
||||
case SDL_CONTROLLER_TYPE_XBOXONE:
|
||||
return "XBox One Controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const auto name = SDL_GameControllerName(sdl_controller.get());
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
if (sdl_joystick) {
|
||||
const auto name = SDL_JoystickName(sdl_joystick.get());
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
private:
|
||||
struct State {
|
||||
std::unordered_map<int, bool> buttons;
|
||||
@@ -858,23 +882,42 @@ SDLState::~SDLState() {
|
||||
std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
|
||||
std::scoped_lock lock(joystick_map_mutex);
|
||||
std::vector<Common::ParamPackage> devices;
|
||||
std::unordered_map<int, std::shared_ptr<SDLJoystick>> joycon_pairs;
|
||||
for (const auto& [key, value] : joystick_map) {
|
||||
for (const auto& joystick : value) {
|
||||
if (auto* const controller = joystick->GetSDLGameController()) {
|
||||
if (!joystick->GetSDLJoystick()) {
|
||||
continue;
|
||||
}
|
||||
std::string name =
|
||||
fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort());
|
||||
devices.emplace_back(Common::ParamPackage{
|
||||
{"class", "sdl"},
|
||||
{"display", std::move(name)},
|
||||
{"guid", joystick->GetGUID()},
|
||||
{"port", std::to_string(joystick->GetPort())},
|
||||
});
|
||||
if (joystick->IsJoyconLeft()) {
|
||||
joycon_pairs.insert_or_assign(joystick->GetPort(), joystick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add dual controllers
|
||||
for (const auto& [key, value] : joystick_map) {
|
||||
for (const auto& joystick : value) {
|
||||
if (joystick->IsJoyconRight()) {
|
||||
if (!joycon_pairs.contains(joystick->GetPort())) {
|
||||
continue;
|
||||
}
|
||||
const auto joystick2 = joycon_pairs.at(joystick->GetPort());
|
||||
|
||||
std::string name =
|
||||
fmt::format("{} {}", GetControllerName(controller), joystick->GetPort());
|
||||
devices.emplace_back(Common::ParamPackage{
|
||||
{"class", "sdl"},
|
||||
{"display", std::move(name)},
|
||||
{"guid", joystick->GetGUID()},
|
||||
{"port", std::to_string(joystick->GetPort())},
|
||||
});
|
||||
} else if (auto* const joy = joystick->GetSDLJoystick()) {
|
||||
std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
|
||||
fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort());
|
||||
devices.emplace_back(Common::ParamPackage{
|
||||
{"class", "sdl"},
|
||||
{"display", std::move(name)},
|
||||
{"guid", joystick->GetGUID()},
|
||||
{"guid2", joystick2->GetGUID()},
|
||||
{"port", std::to_string(joystick->GetPort())},
|
||||
});
|
||||
}
|
||||
@@ -883,17 +926,6 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
|
||||
return devices;
|
||||
}
|
||||
|
||||
std::string SDLState::GetControllerName(SDL_GameController* controller) const {
|
||||
switch (SDL_GameControllerGetType(controller)) {
|
||||
case SDL_CONTROLLER_TYPE_XBOX360:
|
||||
return "XBox 360 Controller";
|
||||
case SDL_CONTROLLER_TYPE_XBOXONE:
|
||||
return "XBox One Controller";
|
||||
default:
|
||||
return SDL_GameControllerName(controller);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
|
||||
float value = 0.1f) {
|
||||
@@ -1073,24 +1105,48 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa
|
||||
return {};
|
||||
}
|
||||
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
||||
|
||||
auto* controller = joystick->GetSDLGameController();
|
||||
if (controller == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const bool invert =
|
||||
SDL_GameControllerGetType(controller) != SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
|
||||
|
||||
// This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
|
||||
// We will add those afterwards
|
||||
// This list also excludes Screenshot since theres not really a mapping for that
|
||||
using ButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
|
||||
const ButtonBindings switch_to_sdl_button{{
|
||||
{Settings::NativeButton::A, invert ? SDL_CONTROLLER_BUTTON_B : SDL_CONTROLLER_BUTTON_A},
|
||||
{Settings::NativeButton::B, invert ? SDL_CONTROLLER_BUTTON_A : SDL_CONTROLLER_BUTTON_B},
|
||||
{Settings::NativeButton::X, invert ? SDL_CONTROLLER_BUTTON_Y : SDL_CONTROLLER_BUTTON_X},
|
||||
{Settings::NativeButton::Y, invert ? SDL_CONTROLLER_BUTTON_X : SDL_CONTROLLER_BUTTON_Y},
|
||||
ButtonBindings switch_to_sdl_button;
|
||||
|
||||
if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) {
|
||||
switch_to_sdl_button = GetNintendoButtonBinding(joystick);
|
||||
} else {
|
||||
switch_to_sdl_button = GetDefaultButtonBinding();
|
||||
}
|
||||
|
||||
// Add the missing bindings for ZL/ZR
|
||||
static constexpr ZButtonBindings switch_to_sdl_axis{{
|
||||
{Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
|
||||
{Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
|
||||
}};
|
||||
|
||||
// Parameters contain two joysticks return dual
|
||||
if (params.Has("guid2")) {
|
||||
const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
||||
|
||||
if (joystick2->GetSDLGameController() != nullptr) {
|
||||
return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button,
|
||||
switch_to_sdl_axis);
|
||||
}
|
||||
}
|
||||
|
||||
return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis);
|
||||
}
|
||||
|
||||
ButtonBindings SDLState::GetDefaultButtonBinding() const {
|
||||
return {
|
||||
std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
|
||||
{Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
|
||||
{Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
|
||||
{Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
|
||||
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
|
||||
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
|
||||
{Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
|
||||
@@ -1104,18 +1160,51 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa
|
||||
{Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
|
||||
{Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
|
||||
{Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
|
||||
}};
|
||||
};
|
||||
}
|
||||
|
||||
// Add the missing bindings for ZL/ZR
|
||||
using ZBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
|
||||
static constexpr ZBindings switch_to_sdl_axis{{
|
||||
{Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
|
||||
{Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
|
||||
}};
|
||||
ButtonBindings SDLState::GetNintendoButtonBinding(
|
||||
const std::shared_ptr<SDLJoystick>& joystick) const {
|
||||
// Default SL/SR mapping for pro controllers
|
||||
auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||
auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||
|
||||
if (joystick->IsJoyconLeft()) {
|
||||
sl_button = SDL_CONTROLLER_BUTTON_PADDLE2;
|
||||
sr_button = SDL_CONTROLLER_BUTTON_PADDLE4;
|
||||
}
|
||||
if (joystick->IsJoyconRight()) {
|
||||
sl_button = SDL_CONTROLLER_BUTTON_PADDLE3;
|
||||
sr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
|
||||
}
|
||||
|
||||
return {
|
||||
std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A},
|
||||
{Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B},
|
||||
{Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X},
|
||||
{Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y},
|
||||
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
|
||||
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
|
||||
{Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
|
||||
{Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
|
||||
{Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
|
||||
{Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
|
||||
{Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
|
||||
{Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
|
||||
{Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
|
||||
{Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
|
||||
{Settings::NativeButton::SL, sl_button},
|
||||
{Settings::NativeButton::SR, sr_button},
|
||||
{Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
|
||||
};
|
||||
}
|
||||
|
||||
ButtonMapping SDLState::GetSingleControllerMapping(
|
||||
const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button,
|
||||
const ZButtonBindings& switch_to_sdl_axis) const {
|
||||
ButtonMapping mapping;
|
||||
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
||||
auto* controller = joystick->GetSDLGameController();
|
||||
|
||||
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
||||
const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
|
||||
@@ -1133,11 +1222,68 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa
|
||||
return mapping;
|
||||
}
|
||||
|
||||
ButtonMapping SDLState::GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
||||
const std::shared_ptr<SDLJoystick>& joystick2,
|
||||
const ButtonBindings& switch_to_sdl_button,
|
||||
const ZButtonBindings& switch_to_sdl_axis) const {
|
||||
ButtonMapping mapping;
|
||||
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
||||
auto* controller = joystick->GetSDLGameController();
|
||||
auto* controller2 = joystick2->GetSDLGameController();
|
||||
|
||||
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
||||
if (IsButtonOnLeftSide(switch_button)) {
|
||||
const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button);
|
||||
mapping.insert_or_assign(
|
||||
switch_button,
|
||||
BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
|
||||
continue;
|
||||
}
|
||||
const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
|
||||
mapping.insert_or_assign(
|
||||
switch_button,
|
||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||
}
|
||||
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
||||
if (IsButtonOnLeftSide(switch_button)) {
|
||||
const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis);
|
||||
mapping.insert_or_assign(
|
||||
switch_button,
|
||||
BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
|
||||
continue;
|
||||
}
|
||||
const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
|
||||
mapping.insert_or_assign(
|
||||
switch_button,
|
||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
bool SDLState::IsButtonOnLeftSide(Settings::NativeButton::Values button) const {
|
||||
switch (button) {
|
||||
case Settings::NativeButton::DDown:
|
||||
case Settings::NativeButton::DLeft:
|
||||
case Settings::NativeButton::DRight:
|
||||
case Settings::NativeButton::DUp:
|
||||
case Settings::NativeButton::L:
|
||||
case Settings::NativeButton::LStick:
|
||||
case Settings::NativeButton::Minus:
|
||||
case Settings::NativeButton::Screenshot:
|
||||
case Settings::NativeButton::ZL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
|
||||
if (!params.Has("guid") || !params.Has("port")) {
|
||||
return {};
|
||||
}
|
||||
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
||||
const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
||||
auto* controller = joystick->GetSDLGameController();
|
||||
if (controller == nullptr) {
|
||||
return {};
|
||||
@@ -1148,10 +1294,17 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
const auto& binding_left_y =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
mapping.insert_or_assign(Settings::NativeAnalog::LStick,
|
||||
BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
|
||||
binding_left_x.value.axis,
|
||||
binding_left_y.value.axis));
|
||||
if (params.Has("guid2")) {
|
||||
mapping.insert_or_assign(
|
||||
Settings::NativeAnalog::LStick,
|
||||
BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(),
|
||||
binding_left_x.value.axis, binding_left_y.value.axis));
|
||||
} else {
|
||||
mapping.insert_or_assign(
|
||||
Settings::NativeAnalog::LStick,
|
||||
BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
|
||||
binding_left_x.value.axis, binding_left_y.value.axis));
|
||||
}
|
||||
const auto& binding_right_x =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||
const auto& binding_right_y =
|
||||
@@ -1168,20 +1321,32 @@ MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& pa
|
||||
return {};
|
||||
}
|
||||
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
||||
const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
||||
auto* controller = joystick->GetSDLGameController();
|
||||
if (controller == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
MotionMapping mapping = {};
|
||||
joystick->EnableMotion();
|
||||
|
||||
if (!joystick->HasGyro() && !joystick->HasAccel()) {
|
||||
return {};
|
||||
if (joystick->HasGyro() || joystick->HasAccel()) {
|
||||
mapping.insert_or_assign(Settings::NativeMotion::MotionRight,
|
||||
BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
|
||||
}
|
||||
if (params.Has("guid2")) {
|
||||
joystick2->EnableMotion();
|
||||
if (joystick2->HasGyro() || joystick2->HasAccel()) {
|
||||
mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
|
||||
BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID()));
|
||||
}
|
||||
} else {
|
||||
if (joystick->HasGyro() || joystick->HasAccel()) {
|
||||
mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
|
||||
BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
|
||||
}
|
||||
}
|
||||
|
||||
MotionMapping mapping = {};
|
||||
mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
|
||||
BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
|
||||
return mapping;
|
||||
}
|
||||
namespace Polling {
|
||||
|
||||
@@ -9,6 +9,17 @@
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
#include <SDL.h>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "input_common/sdl/sdl.h"
|
||||
@@ -18,6 +29,11 @@ using SDL_GameController = struct _SDL_GameController;
|
||||
using SDL_Joystick = struct _SDL_Joystick;
|
||||
using SDL_JoystickID = s32;
|
||||
|
||||
using ButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
|
||||
using ZButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
|
||||
|
||||
namespace InputCommon::SDL {
|
||||
|
||||
class SDLAnalogFactory;
|
||||
@@ -66,8 +82,25 @@ private:
|
||||
/// Needs to be called before SDL_QuitSubSystem.
|
||||
void CloseJoysticks();
|
||||
|
||||
/// Returns a custom name for specific controllers because the default name is not correct
|
||||
std::string GetControllerName(SDL_GameController* controller) const;
|
||||
/// Returns the default button bindings list for generic controllers
|
||||
ButtonBindings GetDefaultButtonBinding() const;
|
||||
|
||||
/// Returns the default button bindings list for nintendo controllers
|
||||
ButtonBindings GetNintendoButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;
|
||||
|
||||
/// Returns the button mappings from a single controller
|
||||
ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
||||
const ButtonBindings& switch_to_sdl_button,
|
||||
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||
|
||||
/// Returns the button mappings from two different controllers
|
||||
ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
||||
const std::shared_ptr<SDLJoystick>& joystick2,
|
||||
const ButtonBindings& switch_to_sdl_button,
|
||||
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||
|
||||
/// Returns true if the button is on the left joycon
|
||||
bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const;
|
||||
|
||||
// Set to true if SDL supports game controller subsystem
|
||||
bool has_gamecontroller = false;
|
||||
|
||||
@@ -596,7 +596,7 @@ void BufferCache<P>::PopAsyncFlushes() {
|
||||
runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies);
|
||||
}
|
||||
runtime.Finish();
|
||||
for (const auto [copy, buffer_id] : downloads) {
|
||||
for (const auto& [copy, buffer_id] : downloads) {
|
||||
const Buffer& buffer = slot_buffers[buffer_id];
|
||||
const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
|
||||
// Undo the modified offset
|
||||
@@ -606,7 +606,7 @@ void BufferCache<P>::PopAsyncFlushes() {
|
||||
}
|
||||
} else {
|
||||
const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
|
||||
for (const auto [copy, buffer_id] : downloads) {
|
||||
for (const auto& [copy, buffer_id] : downloads) {
|
||||
Buffer& buffer = slot_buffers[buffer_id];
|
||||
buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size));
|
||||
const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
|
||||
|
||||
+11
-1
@@ -104,7 +104,13 @@ void GPU::WaitFence(u32 syncpoint_id, u32 value) {
|
||||
}
|
||||
MICROPROFILE_SCOPE(GPU_wait);
|
||||
std::unique_lock lock{sync_mutex};
|
||||
sync_cv.wait(lock, [=, this] { return syncpoints.at(syncpoint_id).load() >= value; });
|
||||
sync_cv.wait(lock, [=, this] {
|
||||
if (shutting_down.load(std::memory_order_relaxed)) {
|
||||
// We're shutting down, ensure no threads continue to wait for the next syncpoint
|
||||
return true;
|
||||
}
|
||||
return syncpoints.at(syncpoint_id).load() >= value;
|
||||
});
|
||||
}
|
||||
|
||||
void GPU::IncrementSyncPoint(const u32 syncpoint_id) {
|
||||
@@ -523,6 +529,10 @@ void GPU::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) const {
|
||||
}
|
||||
|
||||
void GPU::ShutDown() {
|
||||
// Signal that threads should no longer block on syncpoint fences
|
||||
shutting_down.store(true, std::memory_order_relaxed);
|
||||
sync_cv.notify_all();
|
||||
|
||||
gpu_thread.ShutDown();
|
||||
}
|
||||
|
||||
|
||||
@@ -389,6 +389,8 @@ private:
|
||||
std::unique_ptr<Engines::KeplerMemory> kepler_memory;
|
||||
/// Shader build notifier
|
||||
std::unique_ptr<VideoCore::ShaderNotify> shader_notify;
|
||||
/// When true, we are about to shut down emulation session, so terminate outstanding tasks
|
||||
std::atomic_bool shutting_down{};
|
||||
|
||||
std::array<std::atomic<u32>, Service::Nvidia::MaxSyncPoints> syncpoints{};
|
||||
|
||||
|
||||
@@ -53,6 +53,18 @@ struct Range {
|
||||
UNREACHABLE_MSG("Invalid memory usage={}", usage);
|
||||
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
|
||||
constexpr VkExportMemoryAllocateInfo EXPORT_ALLOCATE_INFO{
|
||||
.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
#ifdef _WIN32
|
||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
|
||||
#elif __unix__
|
||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
|
||||
#else
|
||||
.handleTypes = 0,
|
||||
#endif
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
class MemoryAllocation {
|
||||
@@ -131,7 +143,7 @@ public:
|
||||
|
||||
/// Returns whether this allocation is compatible with the arguments.
|
||||
[[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const {
|
||||
return (flags & property_flags) && (type_mask & shifted_memory_type) != 0;
|
||||
return (flags & property_flags) == property_flags && (type_mask & shifted_memory_type) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -217,14 +229,18 @@ MemoryAllocator::~MemoryAllocator() = default;
|
||||
|
||||
MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) {
|
||||
// Find the fastest memory flags we can afford with the current requirements
|
||||
const VkMemoryPropertyFlags flags = MemoryPropertyFlags(requirements.memoryTypeBits, usage);
|
||||
const u32 type_mask = requirements.memoryTypeBits;
|
||||
const VkMemoryPropertyFlags usage_flags = MemoryUsagePropertyFlags(usage);
|
||||
const VkMemoryPropertyFlags flags = MemoryPropertyFlags(type_mask, usage_flags);
|
||||
if (std::optional<MemoryCommit> commit = TryCommit(requirements, flags)) {
|
||||
return std::move(*commit);
|
||||
}
|
||||
// Commit has failed, allocate more memory.
|
||||
// TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory.
|
||||
AllocMemory(flags, requirements.memoryTypeBits, AllocationChunkSize(requirements.size));
|
||||
|
||||
const u64 chunk_size = AllocationChunkSize(requirements.size);
|
||||
if (!TryAllocMemory(flags, type_mask, chunk_size)) {
|
||||
// TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory.
|
||||
throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
||||
}
|
||||
// Commit again, this time it won't fail since there's a fresh allocation above.
|
||||
// If it does, there's a bug.
|
||||
return TryCommit(requirements, flags).value();
|
||||
@@ -242,26 +258,25 @@ MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage)
|
||||
return commit;
|
||||
}
|
||||
|
||||
void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) {
|
||||
bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) {
|
||||
const u32 type = FindType(flags, type_mask).value();
|
||||
const VkExportMemoryAllocateInfo export_allocate_info{
|
||||
.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
#ifdef _WIN32
|
||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
|
||||
#elif __unix__
|
||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
|
||||
#else
|
||||
.handleTypes = 0,
|
||||
#endif
|
||||
};
|
||||
vk::DeviceMemory memory = device.GetLogical().AllocateMemory({
|
||||
vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = export_allocations ? &export_allocate_info : nullptr,
|
||||
.pNext = export_allocations ? &EXPORT_ALLOCATE_INFO : nullptr,
|
||||
.allocationSize = size,
|
||||
.memoryTypeIndex = type,
|
||||
});
|
||||
if (!memory) {
|
||||
if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) {
|
||||
// Try to allocate non device local memory
|
||||
return TryAllocMemory(flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, type_mask, size);
|
||||
} else {
|
||||
// RIP
|
||||
return false;
|
||||
}
|
||||
}
|
||||
allocations.push_back(std::make_unique<MemoryAllocation>(std::move(memory), flags, size, type));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements,
|
||||
@@ -274,24 +289,24 @@ std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirement
|
||||
return commit;
|
||||
}
|
||||
}
|
||||
if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) {
|
||||
// Look for non device local commits on failure
|
||||
return TryCommit(requirements, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const {
|
||||
return MemoryPropertyFlags(type_mask, MemoryUsagePropertyFlags(usage));
|
||||
}
|
||||
|
||||
VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask,
|
||||
VkMemoryPropertyFlags flags) const {
|
||||
if (FindType(flags, type_mask)) {
|
||||
// Found a memory type with those requirements
|
||||
return flags;
|
||||
}
|
||||
if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
|
||||
if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0) {
|
||||
// Remove host cached bit in case it's not supported
|
||||
return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
|
||||
}
|
||||
if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
|
||||
if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) {
|
||||
// Remove device local, if it's not supported by the requested resource
|
||||
return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
@@ -302,7 +317,7 @@ VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask,
|
||||
std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const {
|
||||
for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) {
|
||||
const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags;
|
||||
if ((type_mask & (1U << type_index)) && (type_flags & flags)) {
|
||||
if ((type_mask & (1U << type_index)) != 0 && (type_flags & flags) == flags) {
|
||||
// The type matches in type and in the wanted properties.
|
||||
return type_index;
|
||||
}
|
||||
|
||||
@@ -101,16 +101,13 @@ public:
|
||||
MemoryCommit Commit(const vk::Image& image, MemoryUsage usage);
|
||||
|
||||
private:
|
||||
/// Allocates a chunk of memory.
|
||||
void AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size);
|
||||
/// Tries to allocate a chunk of memory.
|
||||
bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size);
|
||||
|
||||
/// Tries to allocate a memory commit.
|
||||
std::optional<MemoryCommit> TryCommit(const VkMemoryRequirements& requirements,
|
||||
VkMemoryPropertyFlags flags);
|
||||
|
||||
/// Returns the fastest compatible memory property flags from a wanted usage.
|
||||
VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const;
|
||||
|
||||
/// Returns the fastest compatible memory property flags from the wanted flags.
|
||||
VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const;
|
||||
|
||||
|
||||
@@ -1101,12 +1101,11 @@ void QtSoftwareKeyboardDialog::NormalKeyboardButtonClicked(QPushButton* button)
|
||||
}
|
||||
|
||||
if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) {
|
||||
if (ui->topOSK->currentIndex() == 1) {
|
||||
emit SubmitNormalText(SwkbdResult::Ok,
|
||||
ui->text_edit_osk->toPlainText().toStdU16String());
|
||||
} else {
|
||||
emit SubmitNormalText(SwkbdResult::Ok, ui->line_edit_osk->text().toStdU16String());
|
||||
}
|
||||
auto text = ui->topOSK->currentIndex() == 1
|
||||
? ui->text_edit_osk->toPlainText().toStdU16String()
|
||||
: ui->line_edit_osk->text().toStdU16String();
|
||||
|
||||
emit SubmitNormalText(SwkbdResult::Ok, std::move(text));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1265,13 +1264,11 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
|
||||
if (is_inline) {
|
||||
emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
|
||||
} else {
|
||||
if (ui->topOSK->currentIndex() == 1) {
|
||||
emit SubmitNormalText(SwkbdResult::Cancel,
|
||||
ui->text_edit_osk->toPlainText().toStdU16String());
|
||||
} else {
|
||||
emit SubmitNormalText(SwkbdResult::Cancel,
|
||||
ui->line_edit_osk->text().toStdU16String());
|
||||
}
|
||||
auto text = ui->topOSK->currentIndex() == 1
|
||||
? ui->text_edit_osk->toPlainText().toStdU16String()
|
||||
: ui->line_edit_osk->text().toStdU16String();
|
||||
|
||||
emit SubmitNormalText(SwkbdResult::Cancel, std::move(text));
|
||||
}
|
||||
break;
|
||||
case HIDButton::Y:
|
||||
@@ -1563,7 +1560,7 @@ void QtSoftwareKeyboard::ShowNormalKeyboard() const {
|
||||
void QtSoftwareKeyboard::ShowTextCheckDialog(
|
||||
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message) const {
|
||||
emit MainWindowShowTextCheckDialog(text_check_result, text_check_message);
|
||||
emit MainWindowShowTextCheckDialog(text_check_result, std::move(text_check_message));
|
||||
}
|
||||
|
||||
void QtSoftwareKeyboard::ShowInlineKeyboard(
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
namespace FS = Common::FS;
|
||||
|
||||
Config::Config(const std::string& config_name, ConfigType config_type) : type(config_type) {
|
||||
Config::Config(std::string_view config_name, ConfigType config_type) : type(config_type) {
|
||||
global = config_type == ConfigType::GlobalConfig;
|
||||
|
||||
Initialize(config_name);
|
||||
@@ -242,7 +242,7 @@ const std::array<UISettings::Shortcut, 17> Config::default_hotkeys{{
|
||||
}};
|
||||
// clang-format on
|
||||
|
||||
void Config::Initialize(const std::string& config_name) {
|
||||
void Config::Initialize(std::string_view config_name) {
|
||||
const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir);
|
||||
const auto config_file = fmt::format("{}.ini", config_name);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
InputProfile,
|
||||
};
|
||||
|
||||
explicit Config(const std::string& config_name = "qt-config",
|
||||
explicit Config(std::string_view config_name = "qt-config",
|
||||
ConfigType config_type = ConfigType::GlobalConfig);
|
||||
~Config();
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
static const std::array<UISettings::Shortcut, 17> default_hotkeys;
|
||||
|
||||
private:
|
||||
void Initialize(const std::string& config_name);
|
||||
void Initialize(std::string_view config_name);
|
||||
|
||||
void ReadValues();
|
||||
void ReadPlayerValue(std::size_t player_index);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <QAbstractButton>
|
||||
@@ -17,6 +18,7 @@
|
||||
#include <QTimer>
|
||||
#include <QTreeView>
|
||||
|
||||
#include "common/fs/path_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
@@ -29,10 +31,11 @@
|
||||
#include "yuzu/uisettings.h"
|
||||
#include "yuzu/util/util.h"
|
||||
|
||||
ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id)
|
||||
ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id, std::string_view file_name)
|
||||
: QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) {
|
||||
game_config = std::make_unique<Config>(fmt::format("{:016X}", title_id),
|
||||
Config::ConfigType::PerGameConfig);
|
||||
const auto config_file_name =
|
||||
title_id == 0 ? Common::FS::GetFilename(file_name) : fmt::format("{:016X}", title_id);
|
||||
game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig);
|
||||
|
||||
Settings::SetConfiguringGlobal(false);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QDialog>
|
||||
@@ -27,7 +28,7 @@ class ConfigurePerGame : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigurePerGame(QWidget* parent, u64 title_id);
|
||||
explicit ConfigurePerGame(QWidget* parent, u64 title_id, std::string_view file_name);
|
||||
~ConfigurePerGame() override;
|
||||
|
||||
/// Save all button configurations to settings file
|
||||
|
||||
+16
-31
@@ -328,18 +328,14 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
|
||||
tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
tree_view->setStyleSheet(QStringLiteral("QTreeView{ border: none; }"));
|
||||
|
||||
item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1);
|
||||
item_model->insertColumns(0, COLUMN_COUNT);
|
||||
item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
|
||||
item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, tr("Compatibility"));
|
||||
|
||||
if (UISettings::values.show_add_ons) {
|
||||
item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
|
||||
item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
|
||||
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
|
||||
} else {
|
||||
item_model->setHeaderData(COLUMN_FILE_TYPE - 1, Qt::Horizontal, tr("File type"));
|
||||
item_model->setHeaderData(COLUMN_SIZE - 1, Qt::Horizontal, tr("Size"));
|
||||
}
|
||||
item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
|
||||
tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons);
|
||||
item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
|
||||
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
|
||||
item_model->setSortRole(GameListItemPath::SortRole);
|
||||
|
||||
connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
|
||||
@@ -347,7 +343,11 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
|
||||
connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
|
||||
connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
|
||||
connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded);
|
||||
|
||||
connect(tree_view->header(), &QHeaderView::sectionResized, this,
|
||||
&GameList::SaveInterfaceLayout);
|
||||
connect(tree_view->header(), &QHeaderView::sectionMoved, this, &GameList::SaveInterfaceLayout);
|
||||
connect(tree_view->header(), &QHeaderView::sortIndicatorChanged, this,
|
||||
&GameList::SaveInterfaceLayout);
|
||||
// We must register all custom types with the Qt Automoc system so that we are able to use
|
||||
// it with signals/slots. In this case, QList falls under the umbrells of custom types.
|
||||
qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
|
||||
@@ -561,11 +561,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
connect(remove_dlc, &QAction::triggered, [this, program_id]() {
|
||||
emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent);
|
||||
});
|
||||
connect(remove_shader_cache, &QAction::triggered, [this, program_id]() {
|
||||
emit RemoveFileRequested(program_id, GameListRemoveTarget::ShaderCache);
|
||||
connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() {
|
||||
emit RemoveFileRequested(program_id, GameListRemoveTarget::ShaderCache, path);
|
||||
});
|
||||
connect(remove_custom_config, &QAction::triggered, [this, program_id]() {
|
||||
emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration);
|
||||
connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() {
|
||||
emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path);
|
||||
});
|
||||
connect(dump_romfs, &QAction::triggered,
|
||||
[this, program_id, path]() { emit DumpRomFSRequested(program_id, path); });
|
||||
@@ -708,22 +708,7 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) {
|
||||
tree_view->setEnabled(false);
|
||||
|
||||
// Update the columns in case UISettings has changed
|
||||
item_model->removeColumns(0, item_model->columnCount());
|
||||
item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1);
|
||||
item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
|
||||
item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, tr("Compatibility"));
|
||||
|
||||
if (UISettings::values.show_add_ons) {
|
||||
item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
|
||||
item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
|
||||
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
|
||||
} else {
|
||||
item_model->setHeaderData(COLUMN_FILE_TYPE - 1, Qt::Horizontal, tr("File type"));
|
||||
item_model->setHeaderData(COLUMN_SIZE - 1, Qt::Horizontal, tr("Size"));
|
||||
item_model->removeColumns(COLUMN_COUNT - 1, 1);
|
||||
}
|
||||
|
||||
LoadInterfaceLayout();
|
||||
tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons);
|
||||
|
||||
// Delete any rows that might already exist if we're repopulating
|
||||
item_model->removeRows(0, item_model->rowCount());
|
||||
@@ -800,7 +785,7 @@ void GameList::AddFavorite(u64 program_id) {
|
||||
if (folder->child(j)->data(GameListItemPath::ProgramIdRole).toULongLong() ==
|
||||
program_id) {
|
||||
QList<QStandardItem*> list;
|
||||
for (int k = 0; k < item_model->columnCount(); k++) {
|
||||
for (int k = 0; k < COLUMN_COUNT; k++) {
|
||||
list.append(folder->child(j, k)->clone());
|
||||
}
|
||||
list[0]->setData(folder->child(j)->data(GameListItem::SortRole),
|
||||
|
||||
@@ -88,7 +88,8 @@ signals:
|
||||
const std::string& game_path);
|
||||
void OpenTransferableShaderCacheRequested(u64 program_id);
|
||||
void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type);
|
||||
void RemoveFileRequested(u64 program_id, GameListRemoveTarget target);
|
||||
void RemoveFileRequested(u64 program_id, GameListRemoveTarget target,
|
||||
std::string_view game_path);
|
||||
void DumpRomFSRequested(u64 program_id, const std::string& game_path);
|
||||
void CopyTIDRequested(u64 program_id);
|
||||
void NavigateToGamedbEntryRequested(u64 program_id,
|
||||
|
||||
@@ -215,13 +215,11 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
|
||||
new GameListItemSize(Common::FS::GetSize(path)),
|
||||
};
|
||||
|
||||
if (UISettings::values.show_add_ons) {
|
||||
const auto patch_versions = GetGameListCachedObject(
|
||||
fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
|
||||
return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable());
|
||||
});
|
||||
list.insert(2, new GameListItem(patch_versions));
|
||||
}
|
||||
const auto patch_versions = GetGameListCachedObject(
|
||||
fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
|
||||
return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable());
|
||||
});
|
||||
list.insert(2, new GameListItem(patch_versions));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
+14
-7
@@ -1334,7 +1334,10 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
|
||||
|
||||
if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) {
|
||||
// Load per game settings
|
||||
Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig);
|
||||
const auto config_file_name = title_id == 0
|
||||
? Common::FS::GetFilename(filename.toStdString())
|
||||
: fmt::format("{:016X}", title_id);
|
||||
Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig);
|
||||
}
|
||||
|
||||
ConfigureVibration::SetAllVibrationDevices();
|
||||
@@ -1795,7 +1798,8 @@ void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type)
|
||||
tr("Successfully removed %1 installed DLC.").arg(count));
|
||||
}
|
||||
|
||||
void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target) {
|
||||
void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target,
|
||||
std::string_view game_path) {
|
||||
const QString question = [this, target] {
|
||||
switch (target) {
|
||||
case GameListRemoveTarget::ShaderCache:
|
||||
@@ -1817,7 +1821,7 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ
|
||||
RemoveTransferableShaderCache(program_id);
|
||||
break;
|
||||
case GameListRemoveTarget::CustomConfiguration:
|
||||
RemoveCustomConfiguration(program_id);
|
||||
RemoveCustomConfiguration(program_id, game_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1842,9 +1846,12 @@ void GMainWindow::RemoveTransferableShaderCache(u64 program_id) {
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::RemoveCustomConfiguration(u64 program_id) {
|
||||
const auto custom_config_file_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) /
|
||||
"custom" / fmt::format("{:016X}.ini", program_id);
|
||||
void GMainWindow::RemoveCustomConfiguration(u64 program_id, std::string_view game_path) {
|
||||
const auto config_file_name = program_id == 0
|
||||
? fmt::format("{:s}.ini", Common::FS::GetFilename(game_path))
|
||||
: fmt::format("{:016X}.ini", program_id);
|
||||
const auto custom_config_file_path =
|
||||
Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "custom" / config_file_name;
|
||||
|
||||
if (!Common::FS::Exists(custom_config_file_path)) {
|
||||
QMessageBox::warning(this, tr("Error Removing Custom Configuration"),
|
||||
@@ -2635,7 +2642,7 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
|
||||
const auto v_file = Core::GetGameFileFromPath(vfs, file_name);
|
||||
const auto& system = Core::System::GetInstance();
|
||||
|
||||
ConfigurePerGame dialog(this, title_id);
|
||||
ConfigurePerGame dialog(this, title_id, file_name);
|
||||
dialog.LoadFromFile(v_file);
|
||||
const auto result = dialog.exec();
|
||||
|
||||
|
||||
+3
-2
@@ -236,7 +236,8 @@ private slots:
|
||||
const std::string& game_path);
|
||||
void OnTransferableShaderCacheOpenFile(u64 program_id);
|
||||
void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type);
|
||||
void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target);
|
||||
void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target,
|
||||
std::string_view game_path);
|
||||
void OnGameListDumpRomFS(u64 program_id, const std::string& game_path);
|
||||
void OnGameListCopyTID(u64 program_id);
|
||||
void OnGameListNavigateToGamedbEntry(u64 program_id,
|
||||
@@ -275,7 +276,7 @@ private:
|
||||
void RemoveUpdateContent(u64 program_id, const QString& entry_type);
|
||||
void RemoveAddOnContent(u64 program_id, const QString& entry_type);
|
||||
void RemoveTransferableShaderCache(u64 program_id);
|
||||
void RemoveCustomConfiguration(u64 program_id);
|
||||
void RemoveCustomConfiguration(u64 program_id, std::string_view game_path);
|
||||
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
|
||||
InstallResult InstallNSPXCI(const QString& filename);
|
||||
InstallResult InstallNCA(const QString& filename);
|
||||
|
||||
Reference in New Issue
Block a user