Compare commits
159 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 688a9fbfa6 | |||
| e82e3e06be | |||
| 4d9af4a9d2 | |||
| b78328f19a | |||
| 3ecc03ec1b | |||
| a0c697124c | |||
| 03ccd8bf43 | |||
| bbeb6e460c | |||
| ddbf851ef6 | |||
| a045e860dd | |||
| b62ffb612d | |||
| 6f031f08fe | |||
| 04cb05fce0 | |||
| a7e610403d | |||
| eceee8c3d9 | |||
| 2b110d61e7 | |||
| 6804a43f49 | |||
| 48bcb91a2e | |||
| 09c9be3703 | |||
| 80bcc18788 | |||
| ebd811b535 | |||
| 306c791e67 | |||
| 1dfcf19c36 | |||
| f9c6d39a6c | |||
| 4814d87385 | |||
| d09aa0182f | |||
| 581a7d785b | |||
| 3630bfaef3 | |||
| 2793304117 | |||
| 8d694701bc | |||
| 4c82e47edd | |||
| d33251db93 | |||
| f800e485c9 | |||
| c897c55e3c | |||
| cb1497d0d7 | |||
| ce448ce770 | |||
| 18637766ef | |||
| aad0cbf024 | |||
| 93ac5a6a6d | |||
| c541559767 | |||
| 0f89828073 | |||
| a5a94f52ff | |||
| d46c9c4659 | |||
| a12a4f2a13 | |||
| bee395d2f0 | |||
| 92103d4ff3 | |||
| b2d8bbe0e0 | |||
| 0b228fde15 | |||
| fd1831b65b | |||
| 4d7be85e73 | |||
| 72722986d0 | |||
| 88f5d38b93 | |||
| 5d36d4b143 | |||
| 28cfc2146f | |||
| 0ac34bd058 | |||
| 05c709bebe | |||
| c3af6d8372 | |||
| 73167b12b5 | |||
| 1df5d12b19 | |||
| 8594f287b8 | |||
| 10eaf31af3 | |||
| 9fdacb5e3a | |||
| 9ce23bde24 | |||
| c18cf05a06 | |||
| 60419dd35e | |||
| be43b62d79 | |||
| 3c2aa183a1 | |||
| 106cf27135 | |||
| 2ccf175324 | |||
| c5de54d509 | |||
| 343c01b87a | |||
| 2d7f9fb21b | |||
| dce2649daf | |||
| 6a397bc8ed | |||
| 86d5b4e556 | |||
| ac00ead7d4 | |||
| bc4126acd7 | |||
| 7584d36922 | |||
| 1209d428f1 | |||
| c448b3af2f | |||
| 28d9c30861 | |||
| 3392fdac9b | |||
| 9933121256 | |||
| c6767704fb | |||
| ea70d9c79e | |||
| 3e6850f00b | |||
| cb7f0c2ec3 | |||
| c86e21abe4 | |||
| 201733d1b5 | |||
| db15142ac9 | |||
| fa231645f2 | |||
| 646656412f | |||
| c3a5522830 | |||
| 99eccf581e | |||
| 80670a5b6c | |||
| 60ce34aa80 | |||
| ae6015a69b | |||
| 053ad04d3f | |||
| 1b11e0f0d3 | |||
| fe126f993d | |||
| c6590ad07b | |||
| 9f199c8b0b | |||
| 6cb6b2da8e | |||
| 64869807e2 | |||
| 61e4f2d931 | |||
| bdef22ff85 | |||
| 4bc2d82130 | |||
| cfc34dd41d | |||
| 88ba5a7f22 | |||
| e44d1fe73c | |||
| b60a93a936 | |||
| 42d81aab32 | |||
| 864c8e4b2f | |||
| 690a4c9438 | |||
| 190ded7f48 | |||
| c770f25ccb | |||
| 67c0d714c5 | |||
| cf01a507fb | |||
| fcc93a445f | |||
| 79f1f326c7 | |||
| 2724ffd6e3 | |||
| ee71404d71 | |||
| dcc8abf254 | |||
| 56b0f979eb | |||
| c218c7d4da | |||
| f999d268f9 | |||
| c489cbee29 | |||
| dffeca66fa | |||
| fd1ea0fd84 | |||
| 48108a8c9b | |||
| 92ce241d4d | |||
| d3123079e8 | |||
| 5da72a891f | |||
| f8a7d6a0ae | |||
| da31326c17 | |||
| 45672d43e3 | |||
| a3bac5550d | |||
| 4faea2bbf4 | |||
| fa10374d39 | |||
| 98135dee16 | |||
| 243404bf34 | |||
| 7bf4bec257 | |||
| f7d95d0a3a | |||
| bbb202ceed | |||
| 789da737af | |||
| b541a35e27 | |||
| 6bc1a477bf | |||
| 9bfd4d880e | |||
| 6a56f42f5d | |||
| b81caf1879 | |||
| 12c0f682e6 | |||
| 20cbf6f3db | |||
| dca4f0687a | |||
| 0104e28fe4 | |||
| c5f519e1e4 | |||
| 5a5bb91f40 | |||
| 18bdf45868 | |||
| 179adee396 | |||
| f44c60321e |
@@ -11,6 +11,7 @@ ccache -s
|
||||
mkdir build || true && cd build
|
||||
cmake .. \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_CXX_FLAGS="-march=x86-64-v2" \
|
||||
-DCMAKE_CXX_COMPILER=/usr/lib/ccache/clang++ \
|
||||
-DCMAKE_C_COMPILER=/usr/lib/ccache/clang \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
|
||||
Regular → Executable
+1
-1
@@ -10,7 +10,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
|
||||
fi
|
||||
|
||||
# Default clang-format points to default 3.5 version one
|
||||
CLANG_FORMAT=clang-format-12
|
||||
CLANG_FORMAT=${CLANG_FORMAT:-clang-format-12}
|
||||
$CLANG_FORMAT --version
|
||||
|
||||
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
|
||||
|
||||
@@ -12,6 +12,7 @@ mkdir build || true && cd build
|
||||
cmake .. \
|
||||
-DBoost_USE_STATIC_LIBS=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_CXX_FLAGS="-march=x86-64-v2" \
|
||||
-DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \
|
||||
-DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
|
||||
@@ -9,7 +9,7 @@ parameters:
|
||||
steps:
|
||||
- script: choco install vulkan-sdk
|
||||
displayName: 'Install vulkan-sdk'
|
||||
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -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} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd ..
|
||||
- script: refreshenv && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw /GA /Gr /Ob2" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -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} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd ..
|
||||
displayName: 'Configure CMake'
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build'
|
||||
|
||||
+24
-16
@@ -3,13 +3,8 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
# Dynarmic has cmake_minimum_required(3.12) and we may want to override
|
||||
# some of its variables, which is only possible in 3.13+
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/find-modules")
|
||||
include(DownloadExternals)
|
||||
include(CMakeDependentOption)
|
||||
|
||||
@@ -22,6 +17,8 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON
|
||||
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF)
|
||||
|
||||
option(ENABLE_LIBUSB "Enable the use of LibUSB" ON)
|
||||
|
||||
option(ENABLE_OPENGL "Enable OpenGL" ON)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
@@ -35,6 +32,8 @@ option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" "${WIN32}")
|
||||
|
||||
option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON)
|
||||
|
||||
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
|
||||
|
||||
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
|
||||
@@ -47,6 +46,8 @@ option(YUZU_TESTS "Compile tests" ON)
|
||||
|
||||
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
||||
|
||||
option(YUZU_ROOM "Compile LDN room server" ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
|
||||
|
||||
option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
|
||||
@@ -201,36 +202,43 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
# System imported libraries
|
||||
# =======================================================================
|
||||
|
||||
find_package(enet 1.3)
|
||||
# Enforce the search mode of non-required packages for better and shorter failure messages
|
||||
find_package(enet 1.3 MODULE)
|
||||
find_package(fmt 9 REQUIRED)
|
||||
find_package(inih)
|
||||
find_package(libusb 1.0.24)
|
||||
find_package(inih MODULE)
|
||||
find_package(lz4 REQUIRED)
|
||||
find_package(nlohmann_json 3.8 REQUIRED)
|
||||
find_package(Opus 1.3)
|
||||
find_package(Vulkan 1.3.213)
|
||||
find_package(Opus 1.3 MODULE)
|
||||
find_package(ZLIB 1.2 REQUIRED)
|
||||
find_package(zstd 1.5 REQUIRED)
|
||||
|
||||
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
|
||||
find_package(Vulkan 1.3.238 REQUIRED)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LIBUSB)
|
||||
find_package(libusb 1.0.24 MODULE)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
||||
find_package(xbyak 6)
|
||||
find_package(xbyak 6 CONFIG)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
find_package(dynarmic 6.4.0)
|
||||
find_package(dynarmic 6.4.0 CONFIG)
|
||||
endif()
|
||||
|
||||
if (ENABLE_CUBEB)
|
||||
find_package(cubeb)
|
||||
find_package(cubeb CONFIG)
|
||||
endif()
|
||||
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
find_package(DiscordRPC)
|
||||
find_package(DiscordRPC MODULE)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
find_package(cpp-jwt 1.4)
|
||||
find_package(httplib 0.11)
|
||||
find_package(cpp-jwt 1.4 CONFIG)
|
||||
find_package(httplib 0.11 MODULE)
|
||||
endif()
|
||||
|
||||
if (YUZU_TESTS)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(httplib QUIET CONFIG)
|
||||
if (httplib_FOUND)
|
||||
if (httplib_CONSIDERED_CONFIGS)
|
||||
find_package_handle_standard_args(httplib CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
@@ -4,7 +4,7 @@
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(lz4 QUIET CONFIG)
|
||||
if (lz4_FOUND)
|
||||
if (lz4_CONSIDERED_CONFIGS)
|
||||
find_package_handle_standard_args(lz4 CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
@@ -4,7 +4,7 @@
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(zstd QUIET CONFIG)
|
||||
if (zstd_FOUND)
|
||||
if (zstd_CONSIDERED_CONFIGS)
|
||||
find_package_handle_standard_args(zstd CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
Vendored
+734
-600
File diff suppressed because it is too large
Load Diff
Vendored
+734
-600
File diff suppressed because it is too large
Load Diff
Vendored
+733
-599
File diff suppressed because it is too large
Load Diff
Vendored
+757
-623
File diff suppressed because it is too large
Load Diff
Vendored
+733
-599
File diff suppressed because it is too large
Load Diff
Vendored
+736
-602
File diff suppressed because it is too large
Load Diff
Vendored
+740
-603
File diff suppressed because it is too large
Load Diff
Vendored
+733
-599
File diff suppressed because it is too large
Load Diff
Vendored
+782
-649
File diff suppressed because it is too large
Load Diff
Vendored
+734
-600
File diff suppressed because it is too large
Load Diff
Vendored
+734
-600
File diff suppressed because it is too large
Load Diff
Vendored
+734
-600
File diff suppressed because it is too large
Load Diff
Vendored
+734
-600
File diff suppressed because it is too large
Load Diff
Vendored
+734
-601
File diff suppressed because it is too large
Load Diff
Vendored
+759
-625
File diff suppressed because it is too large
Load Diff
Vendored
+741
-607
File diff suppressed because it is too large
Load Diff
Vendored
+819
-682
File diff suppressed because it is too large
Load Diff
Vendored
+734
-600
File diff suppressed because it is too large
Load Diff
Vendored
+742
-604
File diff suppressed because it is too large
Load Diff
Vendored
+806
-669
File diff suppressed because it is too large
Load Diff
Vendored
+733
-599
File diff suppressed because it is too large
Load Diff
Vendored
+733
-599
File diff suppressed because it is too large
Load Diff
Vendored
+737
-600
File diff suppressed because it is too large
Load Diff
Vendored
+739
-602
File diff suppressed because it is too large
Load Diff
Vendored
+11
-12
@@ -1,9 +1,9 @@
|
||||
# SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/externals/find-modules")
|
||||
include(DownloadExternals)
|
||||
# Dynarmic has cmake_minimum_required(3.12) and we may want to override
|
||||
# some of its variables, which is only possible in 3.13+
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
# xbyak
|
||||
if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
|
||||
@@ -12,8 +12,7 @@ endif()
|
||||
|
||||
# Dynarmic
|
||||
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic)
|
||||
set(DYNARMIC_NO_BUNDLED_FMT ON)
|
||||
set(DYNARMIC_IGNORE_ASSERTS ON CACHE BOOL "" FORCE)
|
||||
set(DYNARMIC_IGNORE_ASSERTS ON)
|
||||
add_subdirectory(dynarmic EXCLUDE_FROM_ALL)
|
||||
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
||||
endif()
|
||||
@@ -45,7 +44,7 @@ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER
|
||||
endif()
|
||||
|
||||
# libusb
|
||||
if (NOT TARGET libusb::usb)
|
||||
if (ENABLE_LIBUSB AND NOT TARGET libusb::usb)
|
||||
add_subdirectory(libusb EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
@@ -60,10 +59,10 @@ if (YUZU_USE_EXTERNAL_SDL2)
|
||||
Locale Power Render)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
option(SDL_${_OPT} "" OFF)
|
||||
set(SDL_${_OPT} OFF)
|
||||
endforeach()
|
||||
|
||||
option(HIDAPI "" ON)
|
||||
set(HIDAPI ON)
|
||||
endif()
|
||||
set(SDL_STATIC ON)
|
||||
set(SDL_SHARED OFF)
|
||||
@@ -83,7 +82,7 @@ endif()
|
||||
|
||||
# Cubeb
|
||||
if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb)
|
||||
set(BUILD_TESTS OFF CACHE BOOL "")
|
||||
set(BUILD_TESTS OFF)
|
||||
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
|
||||
add_library(cubeb::cubeb ALIAS cubeb)
|
||||
endif()
|
||||
@@ -98,6 +97,7 @@ endif()
|
||||
# Sirit
|
||||
add_subdirectory(sirit EXCLUDE_FROM_ALL)
|
||||
|
||||
# httplib
|
||||
if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
|
||||
if (NOT WIN32)
|
||||
find_package(OpenSSL 1.1)
|
||||
@@ -108,7 +108,7 @@ if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
|
||||
|
||||
if (WIN32 OR NOT OPENSSL_FOUND)
|
||||
# LibreSSL
|
||||
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
|
||||
set(LIBRESSL_SKIP_INSTALL ON)
|
||||
set(OPENSSLDIR "/etc/ssl/")
|
||||
add_subdirectory(libressl EXCLUDE_FROM_ALL)
|
||||
target_include_directories(ssl INTERFACE ./libressl/include)
|
||||
@@ -118,7 +118,6 @@ if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
|
||||
DEFINITION OPENSSL_LIBS)
|
||||
endif()
|
||||
|
||||
# httplib
|
||||
add_library(httplib INTERFACE)
|
||||
target_include_directories(httplib INTERFACE ./cpp-httplib)
|
||||
target_compile_definitions(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
@@ -152,6 +151,6 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
endif()
|
||||
|
||||
# Vulkan-Headers
|
||||
if (NOT TARGET Vulkan::Headers)
|
||||
if (YUZU_USE_EXTERNAL_VULKAN_HEADERS)
|
||||
add_subdirectory(Vulkan-Headers EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
Vendored
+1
-1
Submodule externals/Vulkan-Headers updated: 2826791bed...00671c64ba
+4
-1
@@ -161,7 +161,10 @@ add_subdirectory(video_core)
|
||||
add_subdirectory(network)
|
||||
add_subdirectory(input_common)
|
||||
add_subdirectory(shader_recompiler)
|
||||
add_subdirectory(dedicated_room)
|
||||
|
||||
if (YUZU_ROOM)
|
||||
add_subdirectory(dedicated_room)
|
||||
endif()
|
||||
|
||||
if (YUZU_TESTS)
|
||||
add_subdirectory(tests)
|
||||
|
||||
@@ -187,11 +187,7 @@ add_library(audio_core STATIC
|
||||
renderer/voice/voice_info.cpp
|
||||
renderer/voice/voice_info.h
|
||||
renderer/voice/voice_state.h
|
||||
sink/cubeb_sink.cpp
|
||||
sink/cubeb_sink.h
|
||||
sink/null_sink.h
|
||||
sink/sdl2_sink.cpp
|
||||
sink/sdl2_sink.h
|
||||
sink/sink.h
|
||||
sink/sink_details.cpp
|
||||
sink/sink_details.h
|
||||
@@ -222,11 +218,22 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
target_link_libraries(audio_core PRIVATE dynarmic::dynarmic)
|
||||
endif()
|
||||
|
||||
if(ENABLE_CUBEB)
|
||||
if (ENABLE_CUBEB)
|
||||
target_sources(audio_core PRIVATE
|
||||
sink/cubeb_sink.cpp
|
||||
sink/cubeb_sink.h
|
||||
)
|
||||
|
||||
target_link_libraries(audio_core PRIVATE cubeb::cubeb)
|
||||
target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1)
|
||||
endif()
|
||||
if(ENABLE_SDL2)
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
target_sources(audio_core PRIVATE
|
||||
sink/sdl2_sink.cpp
|
||||
sink/sdl2_sink.h
|
||||
)
|
||||
|
||||
target_link_libraries(audio_core PRIVATE SDL2::SDL2)
|
||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
@@ -91,9 +91,10 @@ public:
|
||||
* @param core_timing - The CoreTiming instance
|
||||
* @param session - The device session
|
||||
*
|
||||
* @return Is the buffer was released.
|
||||
* @return If any buffer was released.
|
||||
*/
|
||||
bool ReleaseBuffers(const Core::Timing::CoreTiming& core_timing, const DeviceSession& session) {
|
||||
bool ReleaseBuffers(const Core::Timing::CoreTiming& core_timing, const DeviceSession& session,
|
||||
bool force) {
|
||||
std::scoped_lock l{lock};
|
||||
bool buffer_released{false};
|
||||
while (registered_count > 0) {
|
||||
@@ -103,7 +104,8 @@ public:
|
||||
}
|
||||
|
||||
// Check with the backend if this buffer can be released yet.
|
||||
if (!session.IsBufferConsumed(buffers[index])) {
|
||||
// If we're shutting down, we don't care if it's been played or not.
|
||||
if (!force && !session.IsBufferConsumed(buffers[index])) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,12 @@ void DeviceSession::Stop() {
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceSession::ClearBuffers() {
|
||||
if (stream) {
|
||||
stream->ClearQueue();
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const {
|
||||
for (const auto& buffer : buffers) {
|
||||
Sink::SinkBuffer new_buffer{
|
||||
|
||||
@@ -90,6 +90,11 @@ public:
|
||||
*/
|
||||
void Stop();
|
||||
|
||||
/**
|
||||
* Clear out the underlying audio buffers in the backend stream.
|
||||
*/
|
||||
void ClearBuffers();
|
||||
|
||||
/**
|
||||
* Set this device session's volume.
|
||||
*
|
||||
|
||||
@@ -23,7 +23,6 @@ System::~System() {
|
||||
void System::Finalize() {
|
||||
Stop();
|
||||
session->Finalize();
|
||||
buffer_event->Signal();
|
||||
}
|
||||
|
||||
void System::StartSession() {
|
||||
@@ -102,6 +101,10 @@ Result System::Stop() {
|
||||
if (state == State::Started) {
|
||||
session->Stop();
|
||||
session->SetVolume(0.0f);
|
||||
session->ClearBuffers();
|
||||
if (buffers.ReleaseBuffers(system.CoreTiming(), *session, true)) {
|
||||
buffer_event->Signal();
|
||||
}
|
||||
state = State::Stopped;
|
||||
}
|
||||
|
||||
@@ -138,7 +141,7 @@ void System::RegisterBuffers() {
|
||||
}
|
||||
|
||||
void System::ReleaseBuffers() {
|
||||
bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session)};
|
||||
bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session, false)};
|
||||
|
||||
if (signal) {
|
||||
// Signal if any buffer was released, or if none are registered, we need more.
|
||||
|
||||
@@ -24,7 +24,6 @@ System::~System() {
|
||||
void System::Finalize() {
|
||||
Stop();
|
||||
session->Finalize();
|
||||
buffer_event->Signal();
|
||||
}
|
||||
|
||||
std::string_view System::GetDefaultOutputDeviceName() const {
|
||||
@@ -102,6 +101,10 @@ Result System::Stop() {
|
||||
if (state == State::Started) {
|
||||
session->Stop();
|
||||
session->SetVolume(0.0f);
|
||||
session->ClearBuffers();
|
||||
if (buffers.ReleaseBuffers(system.CoreTiming(), *session, true)) {
|
||||
buffer_event->Signal();
|
||||
}
|
||||
state = State::Stopped;
|
||||
}
|
||||
|
||||
@@ -138,7 +141,7 @@ void System::RegisterBuffers() {
|
||||
}
|
||||
|
||||
void System::ReleaseBuffers() {
|
||||
bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session)};
|
||||
bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session, false)};
|
||||
if (signal) {
|
||||
// Signal if any buffer was released, or if none are registered, we need more.
|
||||
buffer_event->Signal();
|
||||
|
||||
@@ -78,6 +78,7 @@ add_library(common STATIC
|
||||
logging/types.h
|
||||
lz4_compression.cpp
|
||||
lz4_compression.h
|
||||
make_unique_for_overwrite.h
|
||||
math_util.h
|
||||
memory_detect.cpp
|
||||
memory_detect.h
|
||||
@@ -96,11 +97,13 @@ add_library(common STATIC
|
||||
point.h
|
||||
precompiled_headers.h
|
||||
quaternion.h
|
||||
range_map.h
|
||||
reader_writer_queue.h
|
||||
ring_buffer.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
|
||||
scm_rev.h
|
||||
scope_exit.h
|
||||
scratch_buffer.h
|
||||
settings.cpp
|
||||
settings.h
|
||||
settings_input.cpp
|
||||
|
||||
+2
-2
@@ -69,7 +69,7 @@ void assert_fail_impl();
|
||||
#define ASSERT_OR_EXECUTE(_a_, _b_) \
|
||||
do { \
|
||||
ASSERT(_a_); \
|
||||
if (!(_a_)) { \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
_b_ \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -78,7 +78,7 @@ void assert_fail_impl();
|
||||
#define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \
|
||||
do { \
|
||||
ASSERT_MSG(_a_, __VA_ARGS__); \
|
||||
if (!(_a_)) { \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
_b_ \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -393,12 +393,27 @@ public:
|
||||
}
|
||||
|
||||
// Virtual memory initialization
|
||||
virtual_base = static_cast<u8*>(
|
||||
mmap(nullptr, virtual_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
#if defined(__FreeBSD__)
|
||||
virtual_base =
|
||||
static_cast<u8*>(mmap(nullptr, virtual_size, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER, -1, 0));
|
||||
if (virtual_base == MAP_FAILED) {
|
||||
virtual_base = static_cast<u8*>(
|
||||
mmap(nullptr, virtual_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
if (virtual_base == MAP_FAILED) {
|
||||
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
}
|
||||
#else
|
||||
virtual_base = static_cast<u8*>(mmap(nullptr, virtual_size, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0));
|
||||
if (virtual_base == MAP_FAILED) {
|
||||
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
madvise(virtual_base, virtual_size, MADV_HUGEPAGE);
|
||||
#endif
|
||||
|
||||
good = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <class T>
|
||||
requires(!std::is_array_v<T>) std::unique_ptr<T> make_unique_for_overwrite() {
|
||||
return std::unique_ptr<T>(new T);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires std::is_unbounded_array_v<T> std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
|
||||
return std::unique_ptr<T>(new std::remove_extent_t<T>[n]);
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
requires std::is_bounded_array_v<T>
|
||||
void make_unique_for_overwrite(Args&&...) = delete;
|
||||
|
||||
} // namespace Common
|
||||
@@ -0,0 +1,139 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <typename KeyTBase, typename ValueT>
|
||||
class RangeMap {
|
||||
private:
|
||||
using KeyT =
|
||||
std::conditional_t<std::is_signed_v<KeyTBase>, KeyTBase, std::make_signed_t<KeyTBase>>;
|
||||
|
||||
public:
|
||||
explicit RangeMap(ValueT null_value_) : null_value{null_value_} {
|
||||
container.emplace(std::numeric_limits<KeyT>::min(), null_value);
|
||||
};
|
||||
~RangeMap() = default;
|
||||
|
||||
void Map(KeyTBase address, KeyTBase address_end, ValueT value) {
|
||||
KeyT new_address = static_cast<KeyT>(address);
|
||||
KeyT new_address_end = static_cast<KeyT>(address_end);
|
||||
if (new_address < 0) {
|
||||
new_address = 0;
|
||||
}
|
||||
if (new_address_end < 0) {
|
||||
new_address_end = 0;
|
||||
}
|
||||
InternalMap(new_address, new_address_end, value);
|
||||
}
|
||||
|
||||
void Unmap(KeyTBase address, KeyTBase address_end) {
|
||||
Map(address, address_end, null_value);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t GetContinousSizeFrom(KeyTBase address) const {
|
||||
const KeyT new_address = static_cast<KeyT>(address);
|
||||
if (new_address < 0) {
|
||||
return 0;
|
||||
}
|
||||
return ContinousSizeInternal(new_address);
|
||||
}
|
||||
|
||||
[[nodiscard]] ValueT GetValueAt(KeyT address) const {
|
||||
const KeyT new_address = static_cast<KeyT>(address);
|
||||
if (new_address < 0) {
|
||||
return null_value;
|
||||
}
|
||||
return GetValueInternal(new_address);
|
||||
}
|
||||
|
||||
private:
|
||||
using MapType = std::map<KeyT, ValueT>;
|
||||
using IteratorType = typename MapType::iterator;
|
||||
using ConstIteratorType = typename MapType::const_iterator;
|
||||
|
||||
size_t ContinousSizeInternal(KeyT address) const {
|
||||
const auto it = GetFirstElementBeforeOrOn(address);
|
||||
if (it == container.end() || it->second == null_value) {
|
||||
return 0;
|
||||
}
|
||||
const auto it_end = std::next(it);
|
||||
if (it_end == container.end()) {
|
||||
return std::numeric_limits<KeyT>::max() - address;
|
||||
}
|
||||
return it_end->first - address;
|
||||
}
|
||||
|
||||
ValueT GetValueInternal(KeyT address) const {
|
||||
const auto it = GetFirstElementBeforeOrOn(address);
|
||||
if (it == container.end()) {
|
||||
return null_value;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ConstIteratorType GetFirstElementBeforeOrOn(KeyT address) const {
|
||||
auto it = container.lower_bound(address);
|
||||
if (it == container.begin()) {
|
||||
return it;
|
||||
}
|
||||
if (it != container.end() && (it->first == address)) {
|
||||
return it;
|
||||
}
|
||||
--it;
|
||||
return it;
|
||||
}
|
||||
|
||||
ValueT GetFirstValueWithin(KeyT address) {
|
||||
auto it = container.lower_bound(address);
|
||||
if (it == container.begin()) {
|
||||
return it->second;
|
||||
}
|
||||
if (it == container.end()) [[unlikely]] { // this would be a bug
|
||||
return null_value;
|
||||
}
|
||||
--it;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ValueT GetLastValueWithin(KeyT address) {
|
||||
auto it = container.upper_bound(address);
|
||||
if (it == container.end()) {
|
||||
return null_value;
|
||||
}
|
||||
if (it == container.begin()) [[unlikely]] { // this would be a bug
|
||||
return it->second;
|
||||
}
|
||||
--it;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void InternalMap(KeyT address, KeyT address_end, ValueT value) {
|
||||
const bool must_add_start = GetFirstValueWithin(address) != value;
|
||||
const ValueT last_value = GetLastValueWithin(address_end);
|
||||
const bool must_add_end = last_value != value;
|
||||
auto it = container.lower_bound(address);
|
||||
const auto it_end = container.upper_bound(address_end);
|
||||
while (it != it_end) {
|
||||
it = container.erase(it);
|
||||
}
|
||||
if (must_add_start) {
|
||||
container.emplace(address, value);
|
||||
}
|
||||
if (must_add_end) {
|
||||
container.emplace(address_end, last_value);
|
||||
}
|
||||
}
|
||||
|
||||
ValueT null_value;
|
||||
MapType container;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
@@ -0,0 +1,95 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/make_unique_for_overwrite.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
/**
|
||||
* ScratchBuffer class
|
||||
* This class creates a default initialized heap allocated buffer for cases such as intermediate
|
||||
* buffers being copied into entirely, where value initializing members during allocation or resize
|
||||
* is redundant.
|
||||
*/
|
||||
template <typename T>
|
||||
class ScratchBuffer {
|
||||
public:
|
||||
ScratchBuffer() = default;
|
||||
|
||||
explicit ScratchBuffer(size_t initial_capacity)
|
||||
: last_requested_size{initial_capacity}, buffer_capacity{initial_capacity},
|
||||
buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
|
||||
|
||||
~ScratchBuffer() = default;
|
||||
|
||||
/// This will only grow the buffer's capacity if size is greater than the current capacity.
|
||||
/// The previously held data will remain intact.
|
||||
void resize(size_t size) {
|
||||
if (size > buffer_capacity) {
|
||||
auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
|
||||
std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get());
|
||||
buffer = std::move(new_buffer);
|
||||
buffer_capacity = size;
|
||||
}
|
||||
last_requested_size = size;
|
||||
}
|
||||
|
||||
/// This will only grow the buffer's capacity if size is greater than the current capacity.
|
||||
/// The previously held data will be destroyed if a reallocation occurs.
|
||||
void resize_destructive(size_t size) {
|
||||
if (size > buffer_capacity) {
|
||||
buffer_capacity = size;
|
||||
buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity);
|
||||
}
|
||||
last_requested_size = size;
|
||||
}
|
||||
|
||||
[[nodiscard]] T* data() noexcept {
|
||||
return buffer.get();
|
||||
}
|
||||
|
||||
[[nodiscard]] const T* data() const noexcept {
|
||||
return buffer.get();
|
||||
}
|
||||
|
||||
[[nodiscard]] T* begin() noexcept {
|
||||
return data();
|
||||
}
|
||||
|
||||
[[nodiscard]] const T* begin() const noexcept {
|
||||
return data();
|
||||
}
|
||||
|
||||
[[nodiscard]] T* end() noexcept {
|
||||
return data() + last_requested_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] const T* end() const noexcept {
|
||||
return data() + last_requested_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] T& operator[](size_t i) {
|
||||
return buffer[i];
|
||||
}
|
||||
|
||||
[[nodiscard]] const T& operator[](size_t i) const {
|
||||
return buffer[i];
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t size() const noexcept {
|
||||
return last_requested_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t capacity() const noexcept {
|
||||
return buffer_capacity;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t last_requested_size{};
|
||||
size_t buffer_capacity{};
|
||||
std::unique_ptr<T[]> buffer{};
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
@@ -40,6 +40,7 @@ void LogSettings() {
|
||||
LOG_INFO(Config, "yuzu Configuration:");
|
||||
log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
|
||||
log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
|
||||
log_setting("System_DeviceName", values.device_name.GetValue());
|
||||
log_setting("System_CurrentUser", values.current_user.GetValue());
|
||||
log_setting("System_LanguageIndex", values.language_index.GetValue());
|
||||
log_setting("System_RegionIndex", values.region_index.GetValue());
|
||||
|
||||
@@ -458,6 +458,7 @@ struct Values {
|
||||
|
||||
// System
|
||||
SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
|
||||
Setting<std::string> device_name{"Yuzu", "device_name"};
|
||||
// Measured in seconds since epoch
|
||||
std::optional<s64> custom_rtc;
|
||||
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
|
||||
@@ -530,6 +531,7 @@ struct Values {
|
||||
Setting<bool> reporting_services{false, "reporting_services"};
|
||||
Setting<bool> quest_flag{false, "quest_flag"};
|
||||
Setting<bool> disable_macro_jit{false, "disable_macro_jit"};
|
||||
Setting<bool> disable_macro_hle{false, "disable_macro_hle"};
|
||||
Setting<bool> extended_logging{false, "extended_logging"};
|
||||
Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
|
||||
Setting<bool> use_auto_stub{false, "use_auto_stub"};
|
||||
|
||||
@@ -201,6 +201,9 @@ add_library(core STATIC
|
||||
hle/kernel/k_event_info.h
|
||||
hle/kernel/k_handle_table.cpp
|
||||
hle/kernel/k_handle_table.h
|
||||
hle/kernel/k_hardware_timer_base.h
|
||||
hle/kernel/k_hardware_timer.cpp
|
||||
hle/kernel/k_hardware_timer.h
|
||||
hle/kernel/k_interrupt_manager.cpp
|
||||
hle/kernel/k_interrupt_manager.h
|
||||
hle/kernel/k_light_condition_variable.cpp
|
||||
@@ -268,6 +271,7 @@ add_library(core STATIC
|
||||
hle/kernel/k_thread_local_page.h
|
||||
hle/kernel/k_thread_queue.cpp
|
||||
hle/kernel/k_thread_queue.h
|
||||
hle/kernel/k_timer_task.h
|
||||
hle/kernel/k_trace.h
|
||||
hle/kernel/k_transfer_memory.cpp
|
||||
hle/kernel/k_transfer_memory.h
|
||||
@@ -290,8 +294,6 @@ add_library(core STATIC
|
||||
hle/kernel/svc_common.h
|
||||
hle/kernel/svc_types.h
|
||||
hle/kernel/svc_wrap.h
|
||||
hle/kernel/time_manager.cpp
|
||||
hle/kernel/time_manager.h
|
||||
hle/result.h
|
||||
hle/service/acc/acc.cpp
|
||||
hle/service/acc/acc.h
|
||||
|
||||
+6
-12
@@ -183,26 +183,20 @@ struct System::Impl {
|
||||
Initialize(system);
|
||||
}
|
||||
|
||||
SystemResultStatus Run() {
|
||||
void Run() {
|
||||
std::unique_lock<std::mutex> lk(suspend_guard);
|
||||
status = SystemResultStatus::Success;
|
||||
|
||||
kernel.Suspend(false);
|
||||
core_timing.SyncPause(false);
|
||||
is_paused.store(false, std::memory_order_relaxed);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SystemResultStatus Pause() {
|
||||
void Pause() {
|
||||
std::unique_lock<std::mutex> lk(suspend_guard);
|
||||
status = SystemResultStatus::Success;
|
||||
|
||||
core_timing.SyncPause(true);
|
||||
kernel.Suspend(true);
|
||||
is_paused.store(true, std::memory_order_relaxed);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool IsPaused() const {
|
||||
@@ -553,12 +547,12 @@ void System::Initialize() {
|
||||
impl->Initialize(*this);
|
||||
}
|
||||
|
||||
SystemResultStatus System::Run() {
|
||||
return impl->Run();
|
||||
void System::Run() {
|
||||
impl->Run();
|
||||
}
|
||||
|
||||
SystemResultStatus System::Pause() {
|
||||
return impl->Pause();
|
||||
void System::Pause() {
|
||||
impl->Pause();
|
||||
}
|
||||
|
||||
bool System::IsPaused() const {
|
||||
|
||||
+2
-2
@@ -152,13 +152,13 @@ public:
|
||||
* Run the OS and Application
|
||||
* This function will start emulation and run the relevant devices
|
||||
*/
|
||||
[[nodiscard]] SystemResultStatus Run();
|
||||
void Run();
|
||||
|
||||
/**
|
||||
* Pause the OS and Application
|
||||
* This function will pause emulation and stop the relevant devices
|
||||
*/
|
||||
[[nodiscard]] SystemResultStatus Pause();
|
||||
void Pause();
|
||||
|
||||
/// Check if the core is currently paused.
|
||||
[[nodiscard]] bool IsPaused() const;
|
||||
|
||||
@@ -194,9 +194,9 @@ std::size_t VfsFile::WriteBytes(const std::vector<u8>& data, std::size_t offset)
|
||||
|
||||
std::string VfsFile::GetFullPath() const {
|
||||
if (GetContainingDirectory() == nullptr)
|
||||
return "/" + GetName();
|
||||
return '/' + GetName();
|
||||
|
||||
return GetContainingDirectory()->GetFullPath() + "/" + GetName();
|
||||
return GetContainingDirectory()->GetFullPath() + '/' + GetName();
|
||||
}
|
||||
|
||||
VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
|
||||
@@ -435,7 +435,7 @@ std::string VfsDirectory::GetFullPath() const {
|
||||
if (IsRoot())
|
||||
return GetName();
|
||||
|
||||
return GetParentDirectory()->GetFullPath() + "/" + GetName();
|
||||
return GetParentDirectory()->GetFullPath() + '/' + GetName();
|
||||
}
|
||||
|
||||
bool ReadOnlyVfsDirectory::IsWritable() const {
|
||||
|
||||
@@ -40,6 +40,11 @@ void EmulatedConsole::SetTouchParams() {
|
||||
touch_params[index++] = std::move(touchscreen_param);
|
||||
}
|
||||
|
||||
if (Settings::values.touch_from_button_maps.empty()) {
|
||||
LOG_WARNING(Input, "touch_from_button_maps is unset by frontend config");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto button_index =
|
||||
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
|
||||
const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons;
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
namespace Core::HID {
|
||||
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
||||
constexpr s32 HID_TRIGGER_MAX = 0x7fff;
|
||||
// Use a common UUID for TAS and Virtual Gamepad
|
||||
constexpr Common::UUID TAS_UUID =
|
||||
Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
|
||||
constexpr Common::UUID VIRTUAL_UUID =
|
||||
Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
|
||||
|
||||
EmulatedController::EmulatedController(NpadIdType npad_id_type_) : npad_id_type(npad_id_type_) {}
|
||||
|
||||
@@ -145,6 +150,7 @@ void EmulatedController::LoadDevices() {
|
||||
output_params[3].Set("output", true);
|
||||
|
||||
LoadTASParams();
|
||||
LoadVirtualGamepadParams();
|
||||
|
||||
std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice);
|
||||
std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice);
|
||||
@@ -163,6 +169,12 @@ void EmulatedController::LoadDevices() {
|
||||
Common::Input::CreateInputDevice);
|
||||
std::ranges::transform(tas_stick_params, tas_stick_devices.begin(),
|
||||
Common::Input::CreateInputDevice);
|
||||
|
||||
// Initialize virtual gamepad devices
|
||||
std::ranges::transform(virtual_button_params, virtual_button_devices.begin(),
|
||||
Common::Input::CreateInputDevice);
|
||||
std::ranges::transform(virtual_stick_params, virtual_stick_devices.begin(),
|
||||
Common::Input::CreateInputDevice);
|
||||
}
|
||||
|
||||
void EmulatedController::LoadTASParams() {
|
||||
@@ -203,6 +215,53 @@ void EmulatedController::LoadTASParams() {
|
||||
tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
|
||||
tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2);
|
||||
tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3);
|
||||
|
||||
// set to optimal stick to avoid sanitizing the stick and tweaking the coordinates
|
||||
// making sure they play back in the game as originally written down in the script file
|
||||
tas_stick_params[Settings::NativeAnalog::LStick].Set("deadzone", 0.0f);
|
||||
tas_stick_params[Settings::NativeAnalog::LStick].Set("range", 1.0f);
|
||||
tas_stick_params[Settings::NativeAnalog::RStick].Set("deadzone", 0.0f);
|
||||
tas_stick_params[Settings::NativeAnalog::RStick].Set("range", 1.0f);
|
||||
}
|
||||
|
||||
void EmulatedController::LoadVirtualGamepadParams() {
|
||||
const auto player_index = NpadIdTypeToIndex(npad_id_type);
|
||||
Common::ParamPackage common_params{};
|
||||
common_params.Set("engine", "virtual_gamepad");
|
||||
common_params.Set("port", static_cast<int>(player_index));
|
||||
for (auto& param : virtual_button_params) {
|
||||
param = common_params;
|
||||
}
|
||||
for (auto& param : virtual_stick_params) {
|
||||
param = common_params;
|
||||
}
|
||||
|
||||
// TODO(german77): Replace this with an input profile or something better
|
||||
virtual_button_params[Settings::NativeButton::A].Set("button", 0);
|
||||
virtual_button_params[Settings::NativeButton::B].Set("button", 1);
|
||||
virtual_button_params[Settings::NativeButton::X].Set("button", 2);
|
||||
virtual_button_params[Settings::NativeButton::Y].Set("button", 3);
|
||||
virtual_button_params[Settings::NativeButton::LStick].Set("button", 4);
|
||||
virtual_button_params[Settings::NativeButton::RStick].Set("button", 5);
|
||||
virtual_button_params[Settings::NativeButton::L].Set("button", 6);
|
||||
virtual_button_params[Settings::NativeButton::R].Set("button", 7);
|
||||
virtual_button_params[Settings::NativeButton::ZL].Set("button", 8);
|
||||
virtual_button_params[Settings::NativeButton::ZR].Set("button", 9);
|
||||
virtual_button_params[Settings::NativeButton::Plus].Set("button", 10);
|
||||
virtual_button_params[Settings::NativeButton::Minus].Set("button", 11);
|
||||
virtual_button_params[Settings::NativeButton::DLeft].Set("button", 12);
|
||||
virtual_button_params[Settings::NativeButton::DUp].Set("button", 13);
|
||||
virtual_button_params[Settings::NativeButton::DRight].Set("button", 14);
|
||||
virtual_button_params[Settings::NativeButton::DDown].Set("button", 15);
|
||||
virtual_button_params[Settings::NativeButton::SL].Set("button", 16);
|
||||
virtual_button_params[Settings::NativeButton::SR].Set("button", 17);
|
||||
virtual_button_params[Settings::NativeButton::Home].Set("button", 18);
|
||||
virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
|
||||
|
||||
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
|
||||
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
|
||||
virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2);
|
||||
virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3);
|
||||
}
|
||||
|
||||
void EmulatedController::ReloadInput() {
|
||||
@@ -294,10 +353,6 @@ void EmulatedController::ReloadInput() {
|
||||
}
|
||||
}
|
||||
|
||||
// Use a common UUID for TAS
|
||||
static constexpr Common::UUID TAS_UUID = Common::UUID{
|
||||
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
|
||||
|
||||
// Register TAS devices. No need to force update
|
||||
for (std::size_t index = 0; index < tas_button_devices.size(); ++index) {
|
||||
if (!tas_button_devices[index]) {
|
||||
@@ -322,6 +377,31 @@ void EmulatedController::ReloadInput() {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Register virtual devices. No need to force update
|
||||
for (std::size_t index = 0; index < virtual_button_devices.size(); ++index) {
|
||||
if (!virtual_button_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
virtual_button_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetButton(callback, index, VIRTUAL_UUID);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < virtual_stick_devices.size(); ++index) {
|
||||
if (!virtual_stick_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
virtual_stick_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetStick(callback, index, VIRTUAL_UUID);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedController::UnloadInput() {
|
||||
@@ -349,6 +429,12 @@ void EmulatedController::UnloadInput() {
|
||||
for (auto& stick : tas_stick_devices) {
|
||||
stick.reset();
|
||||
}
|
||||
for (auto& button : virtual_button_devices) {
|
||||
button.reset();
|
||||
}
|
||||
for (auto& stick : virtual_stick_devices) {
|
||||
stick.reset();
|
||||
}
|
||||
camera_devices.reset();
|
||||
nfc_devices.reset();
|
||||
}
|
||||
@@ -691,7 +777,12 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
||||
|
||||
// Only read stick values that have the same uuid or are over the threshold to avoid flapping
|
||||
if (controller.stick_values[index].uuid != uuid) {
|
||||
if (!stick_value.down && !stick_value.up && !stick_value.left && !stick_value.right) {
|
||||
const bool is_tas = uuid == TAS_UUID;
|
||||
if (is_tas && stick_value.x.value == 0 && stick_value.y.value == 0) {
|
||||
return;
|
||||
}
|
||||
if (!is_tas && !stick_value.down && !stick_value.up && !stick_value.left &&
|
||||
!stick_value.right) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,6 +385,9 @@ private:
|
||||
/// Set the params for TAS devices
|
||||
void LoadTASParams();
|
||||
|
||||
/// Set the params for virtual pad devices
|
||||
void LoadVirtualGamepadParams();
|
||||
|
||||
/**
|
||||
* @param use_temporary_value If true tmp_npad_type will be used
|
||||
* @return true if the controller style is fullkey
|
||||
@@ -500,6 +503,12 @@ private:
|
||||
ButtonDevices tas_button_devices;
|
||||
StickDevices tas_stick_devices;
|
||||
|
||||
// Virtual gamepad related variables
|
||||
ButtonParams virtual_button_params;
|
||||
StickParams virtual_stick_params;
|
||||
ButtonDevices virtual_button_devices;
|
||||
StickDevices virtual_stick_devices;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
mutable std::mutex callback_mutex;
|
||||
std::unordered_map<int, ControllerUpdateCallback> callback_list;
|
||||
|
||||
@@ -167,6 +167,9 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
|
||||
}
|
||||
if (incoming) {
|
||||
// Populate the object lists with the data in the IPC request.
|
||||
incoming_copy_handles.reserve(handle_descriptor_header->num_handles_to_copy);
|
||||
incoming_move_handles.reserve(handle_descriptor_header->num_handles_to_move);
|
||||
|
||||
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
|
||||
incoming_copy_handles.push_back(rp.Pop<Handle>());
|
||||
}
|
||||
@@ -181,6 +184,11 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
|
||||
}
|
||||
}
|
||||
|
||||
buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors);
|
||||
buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors);
|
||||
buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors);
|
||||
buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors);
|
||||
|
||||
for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
|
||||
buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "core/hle/kernel/k_thread_queue.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/k_hardware_timer.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
void KHardwareTimer::Initialize() {
|
||||
// Create the timing callback to register with CoreTiming.
|
||||
m_event_type = Core::Timing::CreateEvent(
|
||||
"KHardwareTimer::Callback", [](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) {
|
||||
reinterpret_cast<KHardwareTimer*>(timer_handle)->DoTask();
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
void KHardwareTimer::Finalize() {
|
||||
this->DisableInterrupt();
|
||||
m_event_type.reset();
|
||||
}
|
||||
|
||||
void KHardwareTimer::DoTask() {
|
||||
// Handle the interrupt.
|
||||
{
|
||||
KScopedSchedulerLock slk{m_kernel};
|
||||
KScopedSpinLock lk(this->GetLock());
|
||||
|
||||
//! Ignore this event if needed.
|
||||
if (!this->GetInterruptEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable the timer interrupt while we handle this.
|
||||
this->DisableInterrupt();
|
||||
|
||||
if (const s64 next_time = this->DoInterruptTaskImpl(GetTick());
|
||||
0 < next_time && next_time <= m_wakeup_time) {
|
||||
// We have a next time, so we should set the time to interrupt and turn the interrupt
|
||||
// on.
|
||||
this->EnableInterrupt(next_time);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the timer interrupt.
|
||||
// Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_NonSecurePhysicalTimer,
|
||||
// GetCurrentCoreId());
|
||||
}
|
||||
|
||||
void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
|
||||
this->DisableInterrupt();
|
||||
|
||||
m_wakeup_time = wakeup_time;
|
||||
m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time},
|
||||
m_event_type, reinterpret_cast<uintptr_t>(this),
|
||||
true);
|
||||
}
|
||||
|
||||
void KHardwareTimer::DisableInterrupt() {
|
||||
m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
|
||||
m_wakeup_time = std::numeric_limits<s64>::max();
|
||||
}
|
||||
|
||||
s64 KHardwareTimer::GetTick() const {
|
||||
return m_kernel.System().CoreTiming().GetGlobalTimeNs().count();
|
||||
}
|
||||
|
||||
bool KHardwareTimer::GetInterruptEnabled() {
|
||||
return m_wakeup_time != std::numeric_limits<s64>::max();
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/k_hardware_timer_base.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
} // namespace Core::Timing
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KHardwareTimer : /* public KInterruptTask, */ public KHardwareTimerBase {
|
||||
public:
|
||||
explicit KHardwareTimer(KernelCore& kernel) : KHardwareTimerBase{kernel} {}
|
||||
|
||||
// Public API.
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
s64 GetCount() const {
|
||||
return GetTick();
|
||||
}
|
||||
|
||||
void RegisterTask(KTimerTask* task, s64 time_from_now) {
|
||||
this->RegisterAbsoluteTask(task, GetTick() + time_from_now);
|
||||
}
|
||||
|
||||
void RegisterAbsoluteTask(KTimerTask* task, s64 task_time) {
|
||||
KScopedDisableDispatch dd{m_kernel};
|
||||
KScopedSpinLock lk{this->GetLock()};
|
||||
|
||||
if (this->RegisterAbsoluteTaskImpl(task, task_time)) {
|
||||
if (task_time <= m_wakeup_time) {
|
||||
this->EnableInterrupt(task_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void EnableInterrupt(s64 wakeup_time);
|
||||
void DisableInterrupt();
|
||||
bool GetInterruptEnabled();
|
||||
s64 GetTick() const;
|
||||
void DoTask();
|
||||
|
||||
private:
|
||||
// Absolute time in nanoseconds
|
||||
s64 m_wakeup_time{std::numeric_limits<s64>::max()};
|
||||
std::shared_ptr<Core::Timing::EventType> m_event_type{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -0,0 +1,92 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_timer_task.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KHardwareTimerBase {
|
||||
public:
|
||||
explicit KHardwareTimerBase(KernelCore& kernel) : m_kernel{kernel} {}
|
||||
|
||||
void CancelTask(KTimerTask* task) {
|
||||
KScopedDisableDispatch dd{m_kernel};
|
||||
KScopedSpinLock lk{m_lock};
|
||||
|
||||
if (const s64 task_time = task->GetTime(); task_time > 0) {
|
||||
this->RemoveTaskFromTree(task);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
KSpinLock& GetLock() {
|
||||
return m_lock;
|
||||
}
|
||||
|
||||
s64 DoInterruptTaskImpl(s64 cur_time) {
|
||||
// We want to handle all tasks, returning the next time that a task is scheduled.
|
||||
while (true) {
|
||||
// Get the next task. If there isn't one, return 0.
|
||||
KTimerTask* task = m_next_task;
|
||||
if (task == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the task needs to be done in the future, do it in the future and not now.
|
||||
if (const s64 task_time = task->GetTime(); task_time > cur_time) {
|
||||
return task_time;
|
||||
}
|
||||
|
||||
// Remove the task from the tree of tasks, and update our next task.
|
||||
this->RemoveTaskFromTree(task);
|
||||
|
||||
// Handle the task.
|
||||
task->OnTimer();
|
||||
}
|
||||
}
|
||||
|
||||
bool RegisterAbsoluteTaskImpl(KTimerTask* task, s64 task_time) {
|
||||
ASSERT(task_time > 0);
|
||||
|
||||
// Set the task's time, and insert it into our tree.
|
||||
task->SetTime(task_time);
|
||||
m_task_tree.insert(*task);
|
||||
|
||||
// Update our next task if relevant.
|
||||
if (m_next_task != nullptr && m_next_task->GetTime() <= task_time) {
|
||||
return false;
|
||||
}
|
||||
m_next_task = task;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void RemoveTaskFromTree(KTimerTask* task) {
|
||||
// Erase from the tree.
|
||||
auto it = m_task_tree.erase(m_task_tree.iterator_to(*task));
|
||||
|
||||
// Clear the task's scheduled time.
|
||||
task->SetTime(0);
|
||||
|
||||
// Update our next task if relevant.
|
||||
if (m_next_task == task) {
|
||||
m_next_task = (it != m_task_tree.end()) ? std::addressof(*it) : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
KernelCore& m_kernel;
|
||||
|
||||
private:
|
||||
using TimerTaskTree = Common::IntrusiveRedBlackTreeBaseTraits<KTimerTask>::TreeType<KTimerTask>;
|
||||
|
||||
KSpinLock m_lock{};
|
||||
TimerTaskTree m_task_tree{};
|
||||
KTimerTask* m_next_task{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -285,6 +285,17 @@ void KProcess::UnregisterThread(KThread* thread) {
|
||||
thread_list.remove(thread);
|
||||
}
|
||||
|
||||
u64 KProcess::GetFreeThreadCount() const {
|
||||
if (resource_limit != nullptr) {
|
||||
const auto current_value =
|
||||
resource_limit->GetCurrentValue(LimitableResource::ThreadCountMax);
|
||||
const auto limit_value = resource_limit->GetLimitValue(LimitableResource::ThreadCountMax);
|
||||
return limit_value - current_value;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Result KProcess::Reset() {
|
||||
// Lock the process and the scheduler.
|
||||
KScopedLightLock lk(state_lock);
|
||||
|
||||
@@ -304,6 +304,9 @@ public:
|
||||
/// from this process' thread list.
|
||||
void UnregisterThread(KThread* thread);
|
||||
|
||||
/// Retrieves the number of available threads for this process.
|
||||
u64 GetFreeThreadCount() const;
|
||||
|
||||
/// Clears the signaled state of the process if and only if it's signaled.
|
||||
///
|
||||
/// @pre The process must not be already terminated. If this is called on a
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/global_scheduler_context.h"
|
||||
#include "core/hle/kernel/k_hardware_timer.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
~KScopedSchedulerLockAndSleep() {
|
||||
// Register the sleep.
|
||||
if (timeout_tick > 0) {
|
||||
kernel.TimeManager().ScheduleTimeEvent(thread, timeout_tick);
|
||||
kernel.HardwareTimer().RegisterTask(thread, timeout_tick);
|
||||
}
|
||||
|
||||
// Unlock the scheduler.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_system_resource.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
|
||||
@@ -18,19 +19,19 @@ KSharedMemory::~KSharedMemory() {
|
||||
}
|
||||
|
||||
Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
|
||||
KPageGroup&& page_list_, Svc::MemoryPermission owner_permission_,
|
||||
Svc::MemoryPermission user_permission_, PAddr physical_address_,
|
||||
std::size_t size_, std::string name_) {
|
||||
Svc::MemoryPermission owner_permission_,
|
||||
Svc::MemoryPermission user_permission_, std::size_t size_,
|
||||
std::string name_) {
|
||||
// Set members.
|
||||
owner_process = owner_process_;
|
||||
device_memory = &device_memory_;
|
||||
page_list = std::move(page_list_);
|
||||
owner_permission = owner_permission_;
|
||||
user_permission = user_permission_;
|
||||
physical_address = physical_address_;
|
||||
size = size_;
|
||||
size = Common::AlignUp(size_, PageSize);
|
||||
name = std::move(name_);
|
||||
|
||||
const size_t num_pages = Common::DivideUp(size, PageSize);
|
||||
|
||||
// Get the resource limit.
|
||||
KResourceLimit* reslimit = kernel.GetSystemResourceLimit();
|
||||
|
||||
@@ -39,6 +40,17 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
|
||||
size_);
|
||||
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
|
||||
|
||||
// Allocate the memory.
|
||||
|
||||
//! HACK: Open continuous mapping from sysmodule pool.
|
||||
auto option = KMemoryManager::EncodeOption(KMemoryManager::Pool::Secure,
|
||||
KMemoryManager::Direction::FromBack);
|
||||
physical_address = kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, option);
|
||||
R_UNLESS(physical_address != 0, ResultOutOfMemory);
|
||||
|
||||
//! Insert the result into our page group.
|
||||
page_group.emplace(physical_address, num_pages);
|
||||
|
||||
// Commit our reservation.
|
||||
memory_reservation.Commit();
|
||||
|
||||
@@ -50,12 +62,23 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
|
||||
is_initialized = true;
|
||||
|
||||
// Clear all pages in the memory.
|
||||
std::memset(device_memory_.GetPointer<void>(physical_address_), 0, size_);
|
||||
for (const auto& block : page_group->Nodes()) {
|
||||
std::memset(device_memory_.GetPointer<void>(block.GetAddress()), 0, block.GetSize());
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void KSharedMemory::Finalize() {
|
||||
// Close and finalize the page group.
|
||||
// page_group->Close();
|
||||
// page_group->Finalize();
|
||||
|
||||
//! HACK: Manually close.
|
||||
for (const auto& block : page_group->Nodes()) {
|
||||
kernel.MemoryManager().Close(block.GetAddress(), block.GetNumPages());
|
||||
}
|
||||
|
||||
// Release the memory reservation.
|
||||
resource_limit->Release(LimitableResource::PhysicalMemoryMax, size);
|
||||
resource_limit->Close();
|
||||
@@ -65,32 +88,28 @@ void KSharedMemory::Finalize() {
|
||||
}
|
||||
|
||||
Result KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t map_size,
|
||||
Svc::MemoryPermission permissions) {
|
||||
const u64 page_count{(map_size + PageSize - 1) / PageSize};
|
||||
Svc::MemoryPermission map_perm) {
|
||||
// Validate the size.
|
||||
R_UNLESS(size == map_size, ResultInvalidSize);
|
||||
|
||||
if (page_list.GetNumPages() != page_count) {
|
||||
UNIMPLEMENTED_MSG("Page count does not match");
|
||||
}
|
||||
|
||||
const Svc::MemoryPermission expected =
|
||||
// Validate the permission.
|
||||
const Svc::MemoryPermission test_perm =
|
||||
&target_process == owner_process ? owner_permission : user_permission;
|
||||
|
||||
if (permissions != expected) {
|
||||
UNIMPLEMENTED_MSG("Permission does not match");
|
||||
if (test_perm == Svc::MemoryPermission::DontCare) {
|
||||
ASSERT(map_perm == Svc::MemoryPermission::Read || map_perm == Svc::MemoryPermission::Write);
|
||||
} else {
|
||||
R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission);
|
||||
}
|
||||
|
||||
return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared,
|
||||
ConvertToKMemoryPermission(permissions));
|
||||
return target_process.PageTable().MapPages(address, *page_group, KMemoryState::Shared,
|
||||
ConvertToKMemoryPermission(map_perm));
|
||||
}
|
||||
|
||||
Result KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) {
|
||||
const u64 page_count{(unmap_size + PageSize - 1) / PageSize};
|
||||
// Validate the size.
|
||||
R_UNLESS(size == unmap_size, ResultInvalidSize);
|
||||
|
||||
if (page_list.GetNumPages() != page_count) {
|
||||
UNIMPLEMENTED_MSG("Page count does not match");
|
||||
}
|
||||
|
||||
return target_process.PageTable().UnmapPages(address, page_list, KMemoryState::Shared);
|
||||
return target_process.PageTable().UnmapPages(address, *page_group, KMemoryState::Shared);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
@@ -26,9 +27,8 @@ public:
|
||||
~KSharedMemory() override;
|
||||
|
||||
Result Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
|
||||
KPageGroup&& page_list_, Svc::MemoryPermission owner_permission_,
|
||||
Svc::MemoryPermission user_permission_, PAddr physical_address_,
|
||||
std::size_t size_, std::string name_);
|
||||
Svc::MemoryPermission owner_permission_,
|
||||
Svc::MemoryPermission user_permission_, std::size_t size_, std::string name_);
|
||||
|
||||
/**
|
||||
* Maps a shared memory block to an address in the target process' address space
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
private:
|
||||
Core::DeviceMemory* device_memory{};
|
||||
KProcess* owner_process{};
|
||||
KPageGroup page_list;
|
||||
std::optional<KPageGroup> page_group{};
|
||||
Svc::MemoryPermission owner_permission{};
|
||||
Svc::MemoryPermission user_permission{};
|
||||
PAddr physical_address{};
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/kernel/k_timer_task.h"
|
||||
#include "core/hle/kernel/k_worker_task.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_common.h"
|
||||
@@ -112,7 +113,8 @@ void SetCurrentThread(KernelCore& kernel, KThread* thread);
|
||||
[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
|
||||
|
||||
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>,
|
||||
public boost::intrusive::list_base_hook<> {
|
||||
public boost::intrusive::list_base_hook<>,
|
||||
public KTimerTask {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
|
||||
|
||||
private:
|
||||
@@ -840,4 +842,8 @@ private:
|
||||
KernelCore& kernel;
|
||||
};
|
||||
|
||||
inline void KTimerTask::OnTimer() {
|
||||
static_cast<KThread*>(this)->OnTimer();
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_hardware_timer.h"
|
||||
#include "core/hle/kernel/k_thread_queue.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -22,7 +22,7 @@ void KThreadQueue::EndWait(KThread* waiting_thread, Result wait_result) {
|
||||
waiting_thread->ClearWaitQueue();
|
||||
|
||||
// Cancel the thread task.
|
||||
kernel.TimeManager().UnscheduleTimeEvent(waiting_thread);
|
||||
kernel.HardwareTimer().CancelTask(waiting_thread);
|
||||
}
|
||||
|
||||
void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) {
|
||||
@@ -37,7 +37,7 @@ void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool
|
||||
|
||||
// Cancel the thread task.
|
||||
if (cancel_timer_task) {
|
||||
kernel.TimeManager().UnscheduleTimeEvent(waiting_thread);
|
||||
kernel.HardwareTimer().CancelTask(waiting_thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KTimerTask : public Common::IntrusiveRedBlackTreeBaseNode<KTimerTask> {
|
||||
public:
|
||||
static constexpr int Compare(const KTimerTask& lhs, const KTimerTask& rhs) {
|
||||
if (lhs.GetTime() < rhs.GetTime()) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr explicit KTimerTask() = default;
|
||||
|
||||
constexpr void SetTime(s64 t) {
|
||||
m_time = t;
|
||||
}
|
||||
|
||||
constexpr s64 GetTime() const {
|
||||
return m_time;
|
||||
}
|
||||
|
||||
// NOTE: This is virtual in Nintendo's kernel. Prior to 13.0.0, KWaitObject was also a
|
||||
// TimerTask; this is no longer the case. Since this is now KThread exclusive, we have
|
||||
// devirtualized (see inline declaration for this inside k_thread.h).
|
||||
void OnTimer();
|
||||
|
||||
private:
|
||||
// Absolute time in nanoseconds
|
||||
s64 m_time{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "core/hle/kernel/k_client_port.h"
|
||||
#include "core/hle/kernel/k_dynamic_resource_manager.h"
|
||||
#include "core/hle/kernel/k_handle_table.h"
|
||||
#include "core/hle/kernel/k_hardware_timer.h"
|
||||
#include "core/hle/kernel/k_memory_layout.h"
|
||||
#include "core/hle/kernel/k_memory_manager.h"
|
||||
#include "core/hle/kernel/k_page_buffer.h"
|
||||
@@ -39,7 +40,6 @@
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/kernel/service_thread.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/memory.h"
|
||||
@@ -55,7 +55,7 @@ struct KernelCore::Impl {
|
||||
static constexpr size_t ReservedDynamicPageCount = 64;
|
||||
|
||||
explicit Impl(Core::System& system_, KernelCore& kernel_)
|
||||
: time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"},
|
||||
: service_threads_manager{1, "ServiceThreadsManager"},
|
||||
service_thread_barrier{2}, system{system_} {}
|
||||
|
||||
void SetMulticore(bool is_multi) {
|
||||
@@ -63,6 +63,9 @@ struct KernelCore::Impl {
|
||||
}
|
||||
|
||||
void Initialize(KernelCore& kernel) {
|
||||
hardware_timer = std::make_unique<Kernel::KHardwareTimer>(kernel);
|
||||
hardware_timer->Initialize();
|
||||
|
||||
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel);
|
||||
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
||||
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
|
||||
@@ -91,6 +94,7 @@ struct KernelCore::Impl {
|
||||
pt_heap_region.GetSize());
|
||||
}
|
||||
|
||||
InitializeHackSharedMemory();
|
||||
RegisterHostThread(nullptr);
|
||||
|
||||
default_service_thread = &CreateServiceThread(kernel, "DefaultServiceThread");
|
||||
@@ -193,6 +197,9 @@ struct KernelCore::Impl {
|
||||
// Ensure that the object list container is finalized and properly shutdown.
|
||||
global_object_list_container->Finalize();
|
||||
global_object_list_container.reset();
|
||||
|
||||
hardware_timer->Finalize();
|
||||
hardware_timer.reset();
|
||||
}
|
||||
|
||||
void CloseServices() {
|
||||
@@ -720,14 +727,14 @@ struct KernelCore::Impl {
|
||||
}
|
||||
|
||||
void InitializeMemoryLayout() {
|
||||
const auto system_pool = memory_layout->GetKernelSystemPoolRegionPhysicalExtents();
|
||||
|
||||
// Initialize the memory manager.
|
||||
memory_manager = std::make_unique<KMemoryManager>(system);
|
||||
const auto& management_region = memory_layout->GetPoolManagementRegion();
|
||||
ASSERT(management_region.GetEndAddress() != 0);
|
||||
memory_manager->Initialize(management_region.GetAddress(), management_region.GetSize());
|
||||
}
|
||||
|
||||
void InitializeHackSharedMemory() {
|
||||
// Setup memory regions for emulated processes
|
||||
// TODO(bunnei): These should not be hardcoded regions initialized within the kernel
|
||||
constexpr std::size_t hid_size{0x40000};
|
||||
@@ -736,39 +743,23 @@ struct KernelCore::Impl {
|
||||
constexpr std::size_t time_size{0x1000};
|
||||
constexpr std::size_t hidbus_size{0x1000};
|
||||
|
||||
const PAddr hid_phys_addr{system_pool.GetAddress()};
|
||||
const PAddr font_phys_addr{system_pool.GetAddress() + hid_size};
|
||||
const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size};
|
||||
const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size};
|
||||
const PAddr hidbus_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size +
|
||||
time_size};
|
||||
|
||||
hid_shared_mem = KSharedMemory::Create(system.Kernel());
|
||||
font_shared_mem = KSharedMemory::Create(system.Kernel());
|
||||
irs_shared_mem = KSharedMemory::Create(system.Kernel());
|
||||
time_shared_mem = KSharedMemory::Create(system.Kernel());
|
||||
hidbus_shared_mem = KSharedMemory::Create(system.Kernel());
|
||||
|
||||
hid_shared_mem->Initialize(system.DeviceMemory(), nullptr,
|
||||
{hid_phys_addr, hid_size / PageSize},
|
||||
Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
|
||||
hid_phys_addr, hid_size, "HID:SharedMemory");
|
||||
font_shared_mem->Initialize(system.DeviceMemory(), nullptr,
|
||||
{font_phys_addr, font_size / PageSize},
|
||||
Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
|
||||
font_phys_addr, font_size, "Font:SharedMemory");
|
||||
irs_shared_mem->Initialize(system.DeviceMemory(), nullptr,
|
||||
{irs_phys_addr, irs_size / PageSize},
|
||||
Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
|
||||
irs_phys_addr, irs_size, "IRS:SharedMemory");
|
||||
time_shared_mem->Initialize(system.DeviceMemory(), nullptr,
|
||||
{time_phys_addr, time_size / PageSize},
|
||||
Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
|
||||
time_phys_addr, time_size, "Time:SharedMemory");
|
||||
hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr,
|
||||
{hidbus_phys_addr, hidbus_size / PageSize},
|
||||
Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
|
||||
hidbus_phys_addr, hidbus_size, "HidBus:SharedMemory");
|
||||
hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, hid_size, "HID:SharedMemory");
|
||||
font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, font_size, "Font:SharedMemory");
|
||||
irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, irs_size, "IRS:SharedMemory");
|
||||
time_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, time_size, "Time:SharedMemory");
|
||||
hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, hidbus_size,
|
||||
"HidBus:SharedMemory");
|
||||
}
|
||||
|
||||
KClientPort* CreateNamedServicePort(std::string name) {
|
||||
@@ -832,7 +823,7 @@ struct KernelCore::Impl {
|
||||
std::vector<KProcess*> process_list;
|
||||
std::atomic<KProcess*> current_process{};
|
||||
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
||||
Kernel::TimeManager time_manager;
|
||||
std::unique_ptr<Kernel::KHardwareTimer> hardware_timer;
|
||||
|
||||
Init::KSlabResourceCounts slab_resource_counts{};
|
||||
KResourceLimit* system_resource_limit{};
|
||||
@@ -1019,12 +1010,8 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() {
|
||||
return impl->schedulers[core_id].get();
|
||||
}
|
||||
|
||||
Kernel::TimeManager& KernelCore::TimeManager() {
|
||||
return impl->time_manager;
|
||||
}
|
||||
|
||||
const Kernel::TimeManager& KernelCore::TimeManager() const {
|
||||
return impl->time_manager;
|
||||
Kernel::KHardwareTimer& KernelCore::HardwareTimer() {
|
||||
return *impl->hardware_timer;
|
||||
}
|
||||
|
||||
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
|
||||
|
||||
@@ -39,6 +39,7 @@ class KDynamicPageManager;
|
||||
class KEvent;
|
||||
class KEventInfo;
|
||||
class KHandleTable;
|
||||
class KHardwareTimer;
|
||||
class KLinkedListNode;
|
||||
class KMemoryLayout;
|
||||
class KMemoryManager;
|
||||
@@ -63,7 +64,6 @@ class KCodeMemory;
|
||||
class PhysicalCore;
|
||||
class ServiceThread;
|
||||
class Synchronization;
|
||||
class TimeManager;
|
||||
|
||||
using ServiceInterfaceFactory =
|
||||
std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
|
||||
@@ -175,11 +175,8 @@ public:
|
||||
/// Gets the an instance of the current physical CPU core.
|
||||
const Kernel::PhysicalCore& CurrentPhysicalCore() const;
|
||||
|
||||
/// Gets the an instance of the TimeManager Interface.
|
||||
Kernel::TimeManager& TimeManager();
|
||||
|
||||
/// Gets the an instance of the TimeManager Interface.
|
||||
const Kernel::TimeManager& TimeManager() const;
|
||||
/// Gets the an instance of the hardware timer.
|
||||
Kernel::KHardwareTimer& HardwareTimer();
|
||||
|
||||
/// Stops execution of 'id' core, in order to reschedule a new thread.
|
||||
void PrepareReschedule(std::size_t id);
|
||||
|
||||
+50
-80
@@ -784,63 +784,29 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han
|
||||
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
|
||||
info_sub_id, handle);
|
||||
|
||||
enum class GetInfoType : u64 {
|
||||
// 1.0.0+
|
||||
AllowedCPUCoreMask = 0,
|
||||
AllowedThreadPriorityMask = 1,
|
||||
MapRegionBaseAddr = 2,
|
||||
MapRegionSize = 3,
|
||||
HeapRegionBaseAddr = 4,
|
||||
HeapRegionSize = 5,
|
||||
TotalPhysicalMemoryAvailable = 6,
|
||||
TotalPhysicalMemoryUsed = 7,
|
||||
IsCurrentProcessBeingDebugged = 8,
|
||||
RegisterResourceLimit = 9,
|
||||
IdleTickCount = 10,
|
||||
RandomEntropy = 11,
|
||||
ThreadTickCount = 0xF0000002,
|
||||
// 2.0.0+
|
||||
ASLRRegionBaseAddr = 12,
|
||||
ASLRRegionSize = 13,
|
||||
StackRegionBaseAddr = 14,
|
||||
StackRegionSize = 15,
|
||||
// 3.0.0+
|
||||
SystemResourceSize = 16,
|
||||
SystemResourceUsage = 17,
|
||||
TitleId = 18,
|
||||
// 4.0.0+
|
||||
PrivilegedProcessId = 19,
|
||||
// 5.0.0+
|
||||
UserExceptionContextAddr = 20,
|
||||
// 6.0.0+
|
||||
TotalPhysicalMemoryAvailableWithoutSystemResource = 21,
|
||||
TotalPhysicalMemoryUsedWithoutSystemResource = 22,
|
||||
|
||||
// Homebrew only
|
||||
MesosphereCurrentProcess = 65001,
|
||||
};
|
||||
|
||||
const auto info_id_type = static_cast<GetInfoType>(info_id);
|
||||
const auto info_id_type = static_cast<InfoType>(info_id);
|
||||
|
||||
switch (info_id_type) {
|
||||
case GetInfoType::AllowedCPUCoreMask:
|
||||
case GetInfoType::AllowedThreadPriorityMask:
|
||||
case GetInfoType::MapRegionBaseAddr:
|
||||
case GetInfoType::MapRegionSize:
|
||||
case GetInfoType::HeapRegionBaseAddr:
|
||||
case GetInfoType::HeapRegionSize:
|
||||
case GetInfoType::ASLRRegionBaseAddr:
|
||||
case GetInfoType::ASLRRegionSize:
|
||||
case GetInfoType::StackRegionBaseAddr:
|
||||
case GetInfoType::StackRegionSize:
|
||||
case GetInfoType::TotalPhysicalMemoryAvailable:
|
||||
case GetInfoType::TotalPhysicalMemoryUsed:
|
||||
case GetInfoType::SystemResourceSize:
|
||||
case GetInfoType::SystemResourceUsage:
|
||||
case GetInfoType::TitleId:
|
||||
case GetInfoType::UserExceptionContextAddr:
|
||||
case GetInfoType::TotalPhysicalMemoryAvailableWithoutSystemResource:
|
||||
case GetInfoType::TotalPhysicalMemoryUsedWithoutSystemResource: {
|
||||
case InfoType::CoreMask:
|
||||
case InfoType::PriorityMask:
|
||||
case InfoType::AliasRegionAddress:
|
||||
case InfoType::AliasRegionSize:
|
||||
case InfoType::HeapRegionAddress:
|
||||
case InfoType::HeapRegionSize:
|
||||
case InfoType::AslrRegionAddress:
|
||||
case InfoType::AslrRegionSize:
|
||||
case InfoType::StackRegionAddress:
|
||||
case InfoType::StackRegionSize:
|
||||
case InfoType::TotalMemorySize:
|
||||
case InfoType::UsedMemorySize:
|
||||
case InfoType::SystemResourceSizeTotal:
|
||||
case InfoType::SystemResourceSizeUsed:
|
||||
case InfoType::ProgramId:
|
||||
case InfoType::UserExceptionContextAddress:
|
||||
case InfoType::TotalNonSystemMemorySize:
|
||||
case InfoType::UsedNonSystemMemorySize:
|
||||
case InfoType::IsApplication:
|
||||
case InfoType::FreeThreadCount: {
|
||||
if (info_sub_id != 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id,
|
||||
info_sub_id);
|
||||
@@ -856,79 +822,83 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han
|
||||
}
|
||||
|
||||
switch (info_id_type) {
|
||||
case GetInfoType::AllowedCPUCoreMask:
|
||||
case InfoType::CoreMask:
|
||||
*result = process->GetCoreMask();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::AllowedThreadPriorityMask:
|
||||
case InfoType::PriorityMask:
|
||||
*result = process->GetPriorityMask();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::MapRegionBaseAddr:
|
||||
case InfoType::AliasRegionAddress:
|
||||
*result = process->PageTable().GetAliasRegionStart();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::MapRegionSize:
|
||||
case InfoType::AliasRegionSize:
|
||||
*result = process->PageTable().GetAliasRegionSize();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::HeapRegionBaseAddr:
|
||||
case InfoType::HeapRegionAddress:
|
||||
*result = process->PageTable().GetHeapRegionStart();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::HeapRegionSize:
|
||||
case InfoType::HeapRegionSize:
|
||||
*result = process->PageTable().GetHeapRegionSize();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::ASLRRegionBaseAddr:
|
||||
case InfoType::AslrRegionAddress:
|
||||
*result = process->PageTable().GetAliasCodeRegionStart();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::ASLRRegionSize:
|
||||
case InfoType::AslrRegionSize:
|
||||
*result = process->PageTable().GetAliasCodeRegionSize();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::StackRegionBaseAddr:
|
||||
case InfoType::StackRegionAddress:
|
||||
*result = process->PageTable().GetStackRegionStart();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::StackRegionSize:
|
||||
case InfoType::StackRegionSize:
|
||||
*result = process->PageTable().GetStackRegionSize();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::TotalPhysicalMemoryAvailable:
|
||||
case InfoType::TotalMemorySize:
|
||||
*result = process->GetTotalPhysicalMemoryAvailable();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::TotalPhysicalMemoryUsed:
|
||||
case InfoType::UsedMemorySize:
|
||||
*result = process->GetTotalPhysicalMemoryUsed();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::SystemResourceSize:
|
||||
case InfoType::SystemResourceSizeTotal:
|
||||
*result = process->GetSystemResourceSize();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::SystemResourceUsage:
|
||||
case InfoType::SystemResourceSizeUsed:
|
||||
LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage");
|
||||
*result = process->GetSystemResourceUsage();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::TitleId:
|
||||
case InfoType::ProgramId:
|
||||
*result = process->GetProgramID();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::UserExceptionContextAddr:
|
||||
case InfoType::UserExceptionContextAddress:
|
||||
*result = process->GetProcessLocalRegionAddress();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::TotalPhysicalMemoryAvailableWithoutSystemResource:
|
||||
case InfoType::TotalNonSystemMemorySize:
|
||||
*result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource();
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::TotalPhysicalMemoryUsedWithoutSystemResource:
|
||||
case InfoType::UsedNonSystemMemorySize:
|
||||
*result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource();
|
||||
return ResultSuccess;
|
||||
|
||||
case InfoType::FreeThreadCount:
|
||||
*result = process->GetFreeThreadCount();
|
||||
return ResultSuccess;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -937,11 +907,11 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han
|
||||
return ResultInvalidEnumValue;
|
||||
}
|
||||
|
||||
case GetInfoType::IsCurrentProcessBeingDebugged:
|
||||
case InfoType::DebuggerAttached:
|
||||
*result = 0;
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::RegisterResourceLimit: {
|
||||
case InfoType::ResourceLimit: {
|
||||
if (handle != 0) {
|
||||
LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle);
|
||||
return ResultInvalidHandle;
|
||||
@@ -969,7 +939,7 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
case GetInfoType::RandomEntropy:
|
||||
case InfoType::RandomEntropy:
|
||||
if (handle != 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
|
||||
handle);
|
||||
@@ -985,13 +955,13 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han
|
||||
*result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id);
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::PrivilegedProcessId:
|
||||
case InfoType::InitialProcessIdRange:
|
||||
LOG_WARNING(Kernel_SVC,
|
||||
"(STUBBED) Attempted to query privileged process id bounds, returned 0");
|
||||
*result = 0;
|
||||
return ResultSuccess;
|
||||
|
||||
case GetInfoType::ThreadTickCount: {
|
||||
case InfoType::ThreadTickCount: {
|
||||
constexpr u64 num_cpus = 4;
|
||||
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
|
||||
LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
|
||||
@@ -1026,7 +996,7 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han
|
||||
*result = out_ticks;
|
||||
return ResultSuccess;
|
||||
}
|
||||
case GetInfoType::IdleTickCount: {
|
||||
case InfoType::IdleTickCount: {
|
||||
// Verify the input handle is invalid.
|
||||
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
|
||||
|
||||
@@ -1040,7 +1010,7 @@ static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle han
|
||||
*result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime();
|
||||
return ResultSuccess;
|
||||
}
|
||||
case GetInfoType::MesosphereCurrentProcess: {
|
||||
case InfoType::MesosphereCurrentProcess: {
|
||||
// Verify the input handle is invalid.
|
||||
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
TimeManager::TimeManager(Core::System& system_) : system{system_} {
|
||||
time_manager_event_type = Core::Timing::CreateEvent(
|
||||
"Kernel::TimeManagerCallback",
|
||||
[this](std::uintptr_t thread_handle, s64 time,
|
||||
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
|
||||
KThread* thread = reinterpret_cast<KThread*>(thread_handle);
|
||||
{
|
||||
KScopedSchedulerLock sl(system.Kernel());
|
||||
thread->OnTimer();
|
||||
}
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (nanoseconds > 0) {
|
||||
ASSERT(thread);
|
||||
ASSERT(thread->GetState() != ThreadState::Runnable);
|
||||
system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds},
|
||||
time_manager_event_type,
|
||||
reinterpret_cast<uintptr_t>(thread));
|
||||
}
|
||||
}
|
||||
|
||||
void TimeManager::UnscheduleTimeEvent(KThread* thread) {
|
||||
std::scoped_lock lock{mutex};
|
||||
system.CoreTiming().UnscheduleEvent(time_manager_event_type,
|
||||
reinterpret_cast<uintptr_t>(thread));
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -1,41 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
} // namespace Core::Timing
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KThread;
|
||||
|
||||
/**
|
||||
* The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp
|
||||
* method when the event is triggered.
|
||||
*/
|
||||
class TimeManager {
|
||||
public:
|
||||
explicit TimeManager(Core::System& system);
|
||||
|
||||
/// Schedule a time event on `timetask` thread that will expire in 'nanoseconds'
|
||||
void ScheduleTimeEvent(KThread* time_task, s64 nanoseconds);
|
||||
|
||||
/// Unschedule an existing time event
|
||||
void UnscheduleTimeEvent(KThread* thread);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -97,7 +97,7 @@ void IUser::IsNfcEnabled(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
@@ -83,7 +83,7 @@ void IUser::Finalize(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFP, "called");
|
||||
LOG_DEBUG(Service_NFP, "called");
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
@@ -22,15 +22,19 @@ namespace {
|
||||
|
||||
namespace Service::NIFM {
|
||||
|
||||
// This is nn::nifm::RequestState
|
||||
enum class RequestState : u32 {
|
||||
NotSubmitted = 1,
|
||||
Error = 1, ///< The duplicate 1 is intentional; it means both not submitted and error on HW.
|
||||
Pending = 2,
|
||||
Connected = 3,
|
||||
Invalid = 1, ///< The duplicate 1 is intentional; it means both not submitted and error on HW.
|
||||
OnHold = 2,
|
||||
Accepted = 3,
|
||||
Blocking = 4,
|
||||
};
|
||||
|
||||
enum class InternetConnectionType : u8 {
|
||||
WiFi = 1,
|
||||
// This is nn::nifm::NetworkInterfaceType
|
||||
enum class NetworkInterfaceType : u32 {
|
||||
Invalid = 0,
|
||||
WiFi_Ieee80211 = 1,
|
||||
Ethernet = 2,
|
||||
};
|
||||
|
||||
@@ -42,14 +46,23 @@ enum class InternetConnectionStatus : u8 {
|
||||
Connected,
|
||||
};
|
||||
|
||||
// This is nn::nifm::NetworkProfileType
|
||||
enum class NetworkProfileType : u32 {
|
||||
User,
|
||||
SsidList,
|
||||
Temporary,
|
||||
};
|
||||
|
||||
// This is nn::nifm::IpAddressSetting
|
||||
struct IpAddressSetting {
|
||||
bool is_automatic{};
|
||||
Network::IPv4Address current_address{};
|
||||
Network::IPv4Address ip_address{};
|
||||
Network::IPv4Address subnet_mask{};
|
||||
Network::IPv4Address gateway{};
|
||||
Network::IPv4Address default_gateway{};
|
||||
};
|
||||
static_assert(sizeof(IpAddressSetting) == 0xD, "IpAddressSetting has incorrect size.");
|
||||
|
||||
// This is nn::nifm::DnsSetting
|
||||
struct DnsSetting {
|
||||
bool is_automatic{};
|
||||
Network::IPv4Address primary_dns{};
|
||||
@@ -57,18 +70,26 @@ struct DnsSetting {
|
||||
};
|
||||
static_assert(sizeof(DnsSetting) == 0x9, "DnsSetting has incorrect size.");
|
||||
|
||||
// This is nn::nifm::AuthenticationSetting
|
||||
struct AuthenticationSetting {
|
||||
bool is_enabled{};
|
||||
std::array<char, 0x20> user{};
|
||||
std::array<char, 0x20> password{};
|
||||
};
|
||||
static_assert(sizeof(AuthenticationSetting) == 0x41, "AuthenticationSetting has incorrect size.");
|
||||
|
||||
// This is nn::nifm::ProxySetting
|
||||
struct ProxySetting {
|
||||
bool enabled{};
|
||||
bool is_enabled{};
|
||||
INSERT_PADDING_BYTES(1);
|
||||
u16 port{};
|
||||
std::array<char, 0x64> proxy_server{};
|
||||
bool automatic_auth_enabled{};
|
||||
std::array<char, 0x20> user{};
|
||||
std::array<char, 0x20> password{};
|
||||
AuthenticationSetting authentication{};
|
||||
INSERT_PADDING_BYTES(1);
|
||||
};
|
||||
static_assert(sizeof(ProxySetting) == 0xAA, "ProxySetting has incorrect size.");
|
||||
|
||||
// This is nn::nifm::IpSettingData
|
||||
struct IpSettingData {
|
||||
IpAddressSetting ip_address_setting{};
|
||||
DnsSetting dns_setting{};
|
||||
@@ -101,6 +122,7 @@ static_assert(sizeof(NifmWirelessSettingData) == 0x70,
|
||||
"NifmWirelessSettingData has incorrect size.");
|
||||
|
||||
#pragma pack(push, 1)
|
||||
// This is nn::nifm::detail::sf::NetworkProfileData
|
||||
struct SfNetworkProfileData {
|
||||
IpSettingData ip_setting_data{};
|
||||
u128 uuid{};
|
||||
@@ -114,13 +136,14 @@ struct SfNetworkProfileData {
|
||||
};
|
||||
static_assert(sizeof(SfNetworkProfileData) == 0x17C, "SfNetworkProfileData has incorrect size.");
|
||||
|
||||
// This is nn::nifm::NetworkProfileData
|
||||
struct NifmNetworkProfileData {
|
||||
u128 uuid{};
|
||||
std::array<char, 0x40> network_name{};
|
||||
u32 unknown_1{};
|
||||
u32 unknown_2{};
|
||||
u8 unknown_3{};
|
||||
u8 unknown_4{};
|
||||
NetworkProfileType network_profile_type{};
|
||||
NetworkInterfaceType network_interface_type{};
|
||||
bool is_auto_connect{};
|
||||
bool is_large_capacity{};
|
||||
INSERT_PADDING_BYTES(2);
|
||||
NifmWirelessSettingData wireless_setting_data{};
|
||||
IpSettingData ip_setting_data{};
|
||||
@@ -184,6 +207,7 @@ public:
|
||||
|
||||
event1 = CreateKEvent(service_context, "IRequest:Event1");
|
||||
event2 = CreateKEvent(service_context, "IRequest:Event2");
|
||||
state = RequestState::NotSubmitted;
|
||||
}
|
||||
|
||||
~IRequest() override {
|
||||
@@ -196,7 +220,7 @@ private:
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
if (state == RequestState::NotSubmitted) {
|
||||
UpdateState(RequestState::Pending);
|
||||
UpdateState(RequestState::OnHold);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -219,14 +243,14 @@ private:
|
||||
switch (state) {
|
||||
case RequestState::NotSubmitted:
|
||||
return has_connection ? ResultSuccess : ResultNetworkCommunicationDisabled;
|
||||
case RequestState::Pending:
|
||||
case RequestState::OnHold:
|
||||
if (has_connection) {
|
||||
UpdateState(RequestState::Connected);
|
||||
UpdateState(RequestState::Accepted);
|
||||
} else {
|
||||
UpdateState(RequestState::Error);
|
||||
UpdateState(RequestState::Invalid);
|
||||
}
|
||||
return ResultPendingConnection;
|
||||
case RequestState::Connected:
|
||||
case RequestState::Accepted:
|
||||
default:
|
||||
return ResultSuccess;
|
||||
}
|
||||
@@ -338,9 +362,9 @@ void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
|
||||
.ip_setting_data{
|
||||
.ip_address_setting{
|
||||
.is_automatic{true},
|
||||
.current_address{Network::TranslateIPv4(net_iface->ip_address)},
|
||||
.ip_address{Network::TranslateIPv4(net_iface->ip_address)},
|
||||
.subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
|
||||
.gateway{Network::TranslateIPv4(net_iface->gateway)},
|
||||
.default_gateway{Network::TranslateIPv4(net_iface->gateway)},
|
||||
},
|
||||
.dns_setting{
|
||||
.is_automatic{true},
|
||||
@@ -348,12 +372,14 @@ void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
|
||||
.secondary_dns{1, 0, 0, 1},
|
||||
},
|
||||
.proxy_setting{
|
||||
.enabled{false},
|
||||
.is_enabled{false},
|
||||
.port{},
|
||||
.proxy_server{},
|
||||
.automatic_auth_enabled{},
|
||||
.user{},
|
||||
.password{},
|
||||
.authentication{
|
||||
.is_enabled{},
|
||||
.user{},
|
||||
.password{},
|
||||
},
|
||||
},
|
||||
.mtu{1500},
|
||||
},
|
||||
@@ -370,7 +396,7 @@ void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
|
||||
// When we're connected to a room, spoof the hosts IP address
|
||||
if (auto room_member = network.GetRoomMember().lock()) {
|
||||
if (room_member->IsConnected()) {
|
||||
network_profile_data.ip_setting_data.ip_address_setting.current_address =
|
||||
network_profile_data.ip_setting_data.ip_address_setting.ip_address =
|
||||
room_member->GetFakeIpAddress();
|
||||
}
|
||||
}
|
||||
@@ -444,9 +470,9 @@ void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
|
||||
return IpConfigInfo{
|
||||
.ip_address_setting{
|
||||
.is_automatic{true},
|
||||
.current_address{Network::TranslateIPv4(net_iface->ip_address)},
|
||||
.ip_address{Network::TranslateIPv4(net_iface->ip_address)},
|
||||
.subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
|
||||
.gateway{Network::TranslateIPv4(net_iface->gateway)},
|
||||
.default_gateway{Network::TranslateIPv4(net_iface->gateway)},
|
||||
},
|
||||
.dns_setting{
|
||||
.is_automatic{true},
|
||||
@@ -459,7 +485,7 @@ void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
|
||||
// When we're connected to a room, spoof the hosts IP address
|
||||
if (auto room_member = network.GetRoomMember().lock()) {
|
||||
if (room_member->IsConnected()) {
|
||||
ip_config_info.ip_address_setting.current_address = room_member->GetFakeIpAddress();
|
||||
ip_config_info.ip_address_setting.ip_address = room_member->GetFakeIpAddress();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,7 +506,7 @@ void IGeneralService::GetInternetConnectionStatus(Kernel::HLERequestContext& ctx
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
struct Output {
|
||||
InternetConnectionType type{InternetConnectionType::WiFi};
|
||||
u8 type{static_cast<u8>(NetworkInterfaceType::WiFi_Ieee80211)};
|
||||
u8 wifi_strength{3};
|
||||
InternetConnectionStatus state{InternetConnectionStatus::Connected};
|
||||
};
|
||||
|
||||
@@ -191,6 +191,13 @@ void SET::GetKeyCodeMap2(Kernel::HLERequestContext& ctx) {
|
||||
GetKeyCodeMapImpl(ctx);
|
||||
}
|
||||
|
||||
void SET::GetDeviceNickName(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
ctx.WriteBuffer(Settings::values.device_name.GetValue());
|
||||
}
|
||||
|
||||
SET::SET(Core::System& system_) : ServiceFramework{system_, "set"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
@@ -205,7 +212,7 @@ SET::SET(Core::System& system_) : ServiceFramework{system_, "set"} {
|
||||
{8, &SET::GetQuestFlag, "GetQuestFlag"},
|
||||
{9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"},
|
||||
{10, nullptr, "GetFirmwareVersionForDebug"},
|
||||
{11, nullptr, "GetDeviceNickName"},
|
||||
{11, &SET::GetDeviceNickName, "GetDeviceNickName"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ private:
|
||||
void GetRegionCode(Kernel::HLERequestContext& ctx);
|
||||
void GetKeyCodeMap(Kernel::HLERequestContext& ctx);
|
||||
void GetKeyCodeMap2(Kernel::HLERequestContext& ctx);
|
||||
void GetDeviceNickName(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::Set
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/system_archive/system_version.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
@@ -176,6 +177,13 @@ void SET_SYS::GetSettingsItemValue(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(response);
|
||||
}
|
||||
|
||||
void SET_SYS::GetDeviceNickName(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
ctx.WriteBuffer(::Settings::values.device_name.GetValue());
|
||||
}
|
||||
|
||||
SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
@@ -253,7 +261,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{74, nullptr, "SetWirelessLanEnableFlag"},
|
||||
{75, nullptr, "GetInitialLaunchSettings"},
|
||||
{76, nullptr, "SetInitialLaunchSettings"},
|
||||
{77, nullptr, "GetDeviceNickName"},
|
||||
{77, &SET_SYS::GetDeviceNickName, "GetDeviceNickName"},
|
||||
{78, nullptr, "SetDeviceNickName"},
|
||||
{79, nullptr, "GetProductModel"},
|
||||
{80, nullptr, "GetLdnChannel"},
|
||||
|
||||
@@ -29,6 +29,7 @@ private:
|
||||
void GetFirmwareVersion2(Kernel::HLERequestContext& ctx);
|
||||
void GetColorSetId(Kernel::HLERequestContext& ctx);
|
||||
void SetColorSetId(Kernel::HLERequestContext& ctx);
|
||||
void GetDeviceNickName(Kernel::HLERequestContext& ctx);
|
||||
|
||||
ColorSet color_set = ColorSet::BasicWhite;
|
||||
};
|
||||
|
||||
@@ -49,6 +49,7 @@ struct SteadyClockContext {
|
||||
static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size");
|
||||
static_assert(std::is_trivially_copyable_v<SteadyClockContext>,
|
||||
"SteadyClockContext must be trivially copyable");
|
||||
using StandardSteadyClockTimePointType = SteadyClockContext;
|
||||
|
||||
struct SystemClockContext {
|
||||
s64 offset;
|
||||
|
||||
@@ -26,23 +26,24 @@ void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
|
||||
const Clock::SteadyClockContext context{
|
||||
static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
|
||||
clock_source_id};
|
||||
shared_memory_format.standard_steady_clock_timepoint.StoreData(
|
||||
system.Kernel().GetTimeSharedMem().GetPointer(), context);
|
||||
StoreToLockFreeAtomicType(&GetFormat()->standard_steady_clock_timepoint, context);
|
||||
}
|
||||
|
||||
void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
|
||||
shared_memory_format.standard_local_system_clock_context.StoreData(
|
||||
system.Kernel().GetTimeSharedMem().GetPointer(), context);
|
||||
StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context);
|
||||
}
|
||||
|
||||
void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) {
|
||||
shared_memory_format.standard_network_system_clock_context.StoreData(
|
||||
system.Kernel().GetTimeSharedMem().GetPointer(), context);
|
||||
StoreToLockFreeAtomicType(&GetFormat()->standard_network_system_clock_context, context);
|
||||
}
|
||||
|
||||
void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) {
|
||||
shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
|
||||
system.Kernel().GetTimeSharedMem().GetPointer(), is_enabled);
|
||||
StoreToLockFreeAtomicType(
|
||||
&GetFormat()->is_standard_user_system_clock_automatic_correction_enabled, is_enabled);
|
||||
}
|
||||
|
||||
SharedMemory::Format* SharedMemory::GetFormat() {
|
||||
return reinterpret_cast<SharedMemory::Format*>(system.Kernel().GetTimeSharedMem().GetPointer());
|
||||
}
|
||||
|
||||
} // namespace Service::Time
|
||||
|
||||
@@ -10,45 +10,68 @@
|
||||
|
||||
namespace Service::Time {
|
||||
|
||||
// Note: this type is not safe for concurrent writes.
|
||||
template <typename T>
|
||||
struct LockFreeAtomicType {
|
||||
u32 counter_;
|
||||
std::array<T, 2> value_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static inline void StoreToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) {
|
||||
// Get the current counter.
|
||||
auto counter = p->counter_;
|
||||
|
||||
// Increment the counter.
|
||||
++counter;
|
||||
|
||||
// Store the updated value.
|
||||
p->value_[counter % 2] = value;
|
||||
|
||||
// Fence memory.
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
|
||||
// Set the updated counter.
|
||||
p->counter_ = counter;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T LoadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) {
|
||||
while (true) {
|
||||
// Get the counter.
|
||||
auto counter = p->counter_;
|
||||
|
||||
// Get the value.
|
||||
auto value = p->value_[counter % 2];
|
||||
|
||||
// Fence memory.
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
// Check that the counter matches.
|
||||
if (counter == p->counter_) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SharedMemory final {
|
||||
public:
|
||||
explicit SharedMemory(Core::System& system_);
|
||||
~SharedMemory();
|
||||
|
||||
// TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
|
||||
template <typename T, std::size_t Offset>
|
||||
struct MemoryBarrier {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
|
||||
u32_le read_attempt{};
|
||||
std::array<T, 2> data{};
|
||||
|
||||
// These are not actually memory barriers at the moment as we don't have multicore and all
|
||||
// HLE is mutexed. This will need to properly be implemented when we start updating the time
|
||||
// points on threads. As of right now, we'll be updated both values synchronously and just
|
||||
// incrementing the read_attempt to indicate that we waited.
|
||||
void StoreData(u8* shared_memory, T data_to_store) {
|
||||
std::memcpy(this, shared_memory + Offset, sizeof(*this));
|
||||
read_attempt++;
|
||||
data[read_attempt & 1] = data_to_store;
|
||||
std::memcpy(shared_memory + Offset, this, sizeof(*this));
|
||||
}
|
||||
|
||||
// For reading we're just going to read the last stored value. If there was no value stored
|
||||
// it will just end up reading an empty value as intended.
|
||||
T ReadData(u8* shared_memory) {
|
||||
std::memcpy(this, shared_memory + Offset, sizeof(*this));
|
||||
return data[(read_attempt - 1) & 1];
|
||||
}
|
||||
};
|
||||
|
||||
// Shared memory format
|
||||
struct Format {
|
||||
MemoryBarrier<Clock::SteadyClockContext, 0x0> standard_steady_clock_timepoint;
|
||||
MemoryBarrier<Clock::SystemClockContext, 0x38> standard_local_system_clock_context;
|
||||
MemoryBarrier<Clock::SystemClockContext, 0x80> standard_network_system_clock_context;
|
||||
MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction;
|
||||
u32_le format_version;
|
||||
LockFreeAtomicType<Clock::StandardSteadyClockTimePointType> standard_steady_clock_timepoint;
|
||||
LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context;
|
||||
LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context;
|
||||
LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled;
|
||||
u32 format_version;
|
||||
};
|
||||
static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0);
|
||||
static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38);
|
||||
static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80);
|
||||
static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) ==
|
||||
0xc8);
|
||||
static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
|
||||
|
||||
void SetupStandardSteadyClock(const Common::UUID& clock_source_id,
|
||||
@@ -56,10 +79,10 @@ public:
|
||||
void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context);
|
||||
void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context);
|
||||
void SetAutomaticCorrectionEnabled(bool is_enabled);
|
||||
Format* GetFormat();
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
Format shared_memory_format{};
|
||||
};
|
||||
|
||||
} // namespace Service::Time
|
||||
|
||||
@@ -117,6 +117,8 @@ Errno TranslateNativeError(int e) {
|
||||
return Errno::NETUNREACH;
|
||||
case WSAEMSGSIZE:
|
||||
return Errno::MSGSIZE;
|
||||
case WSAETIMEDOUT:
|
||||
return Errno::TIMEDOUT;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented errno={}", e);
|
||||
return Errno::OTHER;
|
||||
@@ -211,6 +213,8 @@ Errno TranslateNativeError(int e) {
|
||||
return Errno::NETUNREACH;
|
||||
case EMSGSIZE:
|
||||
return Errno::MSGSIZE;
|
||||
case ETIMEDOUT:
|
||||
return Errno::TIMEDOUT;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented errno={}", e);
|
||||
return Errno::OTHER;
|
||||
@@ -226,7 +230,7 @@ Errno GetAndLogLastError() {
|
||||
int e = errno;
|
||||
#endif
|
||||
const Errno err = TranslateNativeError(e);
|
||||
if (err == Errno::AGAIN) {
|
||||
if (err == Errno::AGAIN || err == Errno::TIMEDOUT) {
|
||||
return err;
|
||||
}
|
||||
LOG_ERROR(Network, "Socket operation error: {}", Common::NativeErrorToString(e));
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
|
||||
|
||||
add_executable(yuzu-room
|
||||
precompiled_headers.h
|
||||
yuzu_room.cpp
|
||||
|
||||
@@ -4,14 +4,10 @@
|
||||
add_library(input_common STATIC
|
||||
drivers/camera.cpp
|
||||
drivers/camera.h
|
||||
drivers/gc_adapter.cpp
|
||||
drivers/gc_adapter.h
|
||||
drivers/keyboard.cpp
|
||||
drivers/keyboard.h
|
||||
drivers/mouse.cpp
|
||||
drivers/mouse.h
|
||||
drivers/sdl_driver.cpp
|
||||
drivers/sdl_driver.h
|
||||
drivers/tas_input.cpp
|
||||
drivers/tas_input.h
|
||||
drivers/touch_screen.cpp
|
||||
@@ -20,6 +16,8 @@ add_library(input_common STATIC
|
||||
drivers/udp_client.h
|
||||
drivers/virtual_amiibo.cpp
|
||||
drivers/virtual_amiibo.h
|
||||
drivers/virtual_gamepad.cpp
|
||||
drivers/virtual_gamepad.h
|
||||
helpers/stick_from_buttons.cpp
|
||||
helpers/stick_from_buttons.h
|
||||
helpers/touch_from_buttons.cpp
|
||||
@@ -60,8 +58,17 @@ if (ENABLE_SDL2)
|
||||
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LIBUSB)
|
||||
target_sources(input_common PRIVATE
|
||||
drivers/gc_adapter.cpp
|
||||
drivers/gc_adapter.h
|
||||
)
|
||||
target_link_libraries(input_common PRIVATE libusb::usb)
|
||||
target_compile_definitions(input_common PRIVATE HAVE_LIBUSB)
|
||||
endif()
|
||||
|
||||
create_target_directory_groups(input_common)
|
||||
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost libusb::usb)
|
||||
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)
|
||||
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
target_precompile_headers(input_common PRIVATE precompiled_headers.h)
|
||||
|
||||
@@ -17,7 +17,7 @@ Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_)
|
||||
PreSetController(identifier);
|
||||
}
|
||||
|
||||
void Camera::SetCameraData(std::size_t width, std::size_t height, std::vector<u32> data) {
|
||||
void Camera::SetCameraData(std::size_t width, std::size_t height, std::span<const u32> data) {
|
||||
const std::size_t desired_width = getImageWidth();
|
||||
const std::size_t desired_height = getImageHeight();
|
||||
status.data.resize(desired_width * desired_height);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
|
||||
#include "input_common/input_engine.h"
|
||||
|
||||
namespace InputCommon {
|
||||
@@ -15,7 +17,7 @@ class Camera final : public InputEngine {
|
||||
public:
|
||||
explicit Camera(std::string input_engine_);
|
||||
|
||||
void SetCameraData(std::size_t width, std::size_t height, std::vector<u32> data);
|
||||
void SetCameraData(std::size_t width, std::size_t height, std::span<const u32> data);
|
||||
|
||||
std::size_t getImageWidth() const;
|
||||
std::size_t getImageHeight() const;
|
||||
@@ -23,6 +25,7 @@ public:
|
||||
Common::Input::CameraError SetCameraFormat(const PadIdentifier& identifier_,
|
||||
Common::Input::CameraFormat camera_format) override;
|
||||
|
||||
private:
|
||||
Common::Input::CameraStatus status{};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "input_common/drivers/virtual_gamepad.h"
|
||||
|
||||
namespace InputCommon {
|
||||
constexpr std::size_t PlayerIndexCount = 10;
|
||||
|
||||
VirtualGamepad::VirtualGamepad(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||
for (std::size_t i = 0; i < PlayerIndexCount; i++) {
|
||||
PreSetController(GetIdentifier(i));
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualGamepad::SetButtonState(std::size_t player_index, int button_id, bool value) {
|
||||
if (player_index > PlayerIndexCount) {
|
||||
return;
|
||||
}
|
||||
const auto identifier = GetIdentifier(player_index);
|
||||
SetButton(identifier, button_id, value);
|
||||
}
|
||||
|
||||
void VirtualGamepad::SetButtonState(std::size_t player_index, VirtualButton button_id, bool value) {
|
||||
SetButtonState(player_index, static_cast<int>(button_id), value);
|
||||
}
|
||||
|
||||
void VirtualGamepad::SetStickPosition(std::size_t player_index, int axis_id, float x_value,
|
||||
float y_value) {
|
||||
if (player_index > PlayerIndexCount) {
|
||||
return;
|
||||
}
|
||||
const auto identifier = GetIdentifier(player_index);
|
||||
SetAxis(identifier, axis_id * 2, x_value);
|
||||
SetAxis(identifier, (axis_id * 2) + 1, y_value);
|
||||
}
|
||||
|
||||
void VirtualGamepad::SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value,
|
||||
float y_value) {
|
||||
SetStickPosition(player_index, static_cast<int>(axis_id), x_value, y_value);
|
||||
}
|
||||
|
||||
void VirtualGamepad::ResetControllers() {
|
||||
for (std::size_t i = 0; i < PlayerIndexCount; i++) {
|
||||
SetStickPosition(i, VirtualStick::Left, 0.0f, 0.0f);
|
||||
SetStickPosition(i, VirtualStick::Right, 0.0f, 0.0f);
|
||||
|
||||
SetButtonState(i, VirtualButton::ButtonA, false);
|
||||
SetButtonState(i, VirtualButton::ButtonB, false);
|
||||
SetButtonState(i, VirtualButton::ButtonX, false);
|
||||
SetButtonState(i, VirtualButton::ButtonY, false);
|
||||
SetButtonState(i, VirtualButton::StickL, false);
|
||||
SetButtonState(i, VirtualButton::StickR, false);
|
||||
SetButtonState(i, VirtualButton::TriggerL, false);
|
||||
SetButtonState(i, VirtualButton::TriggerR, false);
|
||||
SetButtonState(i, VirtualButton::TriggerZL, false);
|
||||
SetButtonState(i, VirtualButton::TriggerZR, false);
|
||||
SetButtonState(i, VirtualButton::ButtonPlus, false);
|
||||
SetButtonState(i, VirtualButton::ButtonMinus, false);
|
||||
SetButtonState(i, VirtualButton::ButtonLeft, false);
|
||||
SetButtonState(i, VirtualButton::ButtonUp, false);
|
||||
SetButtonState(i, VirtualButton::ButtonRight, false);
|
||||
SetButtonState(i, VirtualButton::ButtonDown, false);
|
||||
SetButtonState(i, VirtualButton::ButtonSL, false);
|
||||
SetButtonState(i, VirtualButton::ButtonSR, false);
|
||||
SetButtonState(i, VirtualButton::ButtonHome, false);
|
||||
SetButtonState(i, VirtualButton::ButtonCapture, false);
|
||||
}
|
||||
}
|
||||
|
||||
PadIdentifier VirtualGamepad::GetIdentifier(std::size_t player_index) const {
|
||||
return {
|
||||
.guid = Common::UUID{},
|
||||
.port = player_index,
|
||||
.pad = 0,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace InputCommon
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "input_common/input_engine.h"
|
||||
|
||||
namespace InputCommon {
|
||||
|
||||
/**
|
||||
* A virtual controller that is always assigned to the game input
|
||||
*/
|
||||
class VirtualGamepad final : public InputEngine {
|
||||
public:
|
||||
enum class VirtualButton {
|
||||
ButtonA,
|
||||
ButtonB,
|
||||
ButtonX,
|
||||
ButtonY,
|
||||
StickL,
|
||||
StickR,
|
||||
TriggerL,
|
||||
TriggerR,
|
||||
TriggerZL,
|
||||
TriggerZR,
|
||||
ButtonPlus,
|
||||
ButtonMinus,
|
||||
ButtonLeft,
|
||||
ButtonUp,
|
||||
ButtonRight,
|
||||
ButtonDown,
|
||||
ButtonSL,
|
||||
ButtonSR,
|
||||
ButtonHome,
|
||||
ButtonCapture,
|
||||
};
|
||||
|
||||
enum class VirtualStick {
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
};
|
||||
|
||||
explicit VirtualGamepad(std::string input_engine_);
|
||||
|
||||
/**
|
||||
* Sets the status of all buttons bound with the key to pressed
|
||||
* @param player_index the player number that will take this action
|
||||
* @param button_id the id of the button
|
||||
* @param value indicates if the button is pressed or not
|
||||
*/
|
||||
void SetButtonState(std::size_t player_index, int button_id, bool value);
|
||||
void SetButtonState(std::size_t player_index, VirtualButton button_id, bool value);
|
||||
|
||||
/**
|
||||
* Sets the status of all buttons bound with the key to released
|
||||
* @param player_index the player number that will take this action
|
||||
* @param axis_id the id of the axis to move
|
||||
* @param x_value the position of the stick in the x axis
|
||||
* @param y_value the position of the stick in the y axis
|
||||
*/
|
||||
void SetStickPosition(std::size_t player_index, int axis_id, float x_value, float y_value);
|
||||
void SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value,
|
||||
float y_value);
|
||||
|
||||
/// Restores all inputs into the neutral position
|
||||
void ResetControllers();
|
||||
|
||||
private:
|
||||
/// Returns the correct identifier corresponding to the player index
|
||||
PadIdentifier GetIdentifier(std::size_t player_index) const;
|
||||
};
|
||||
|
||||
} // namespace InputCommon
|
||||
@@ -200,12 +200,6 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const {
|
||||
return false;
|
||||
}
|
||||
// The following drivers don't need to be mapped
|
||||
if (data.engine == "tas") {
|
||||
return false;
|
||||
}
|
||||
if (data.engine == "touch") {
|
||||
return false;
|
||||
}
|
||||
if (data.engine == "touch_from_button") {
|
||||
return false;
|
||||
}
|
||||
|
||||
+115
-189
@@ -5,19 +5,23 @@
|
||||
#include "common/input.h"
|
||||
#include "common/param_package.h"
|
||||
#include "input_common/drivers/camera.h"
|
||||
#include "input_common/drivers/gc_adapter.h"
|
||||
#include "input_common/drivers/keyboard.h"
|
||||
#include "input_common/drivers/mouse.h"
|
||||
#include "input_common/drivers/tas_input.h"
|
||||
#include "input_common/drivers/touch_screen.h"
|
||||
#include "input_common/drivers/udp_client.h"
|
||||
#include "input_common/drivers/virtual_amiibo.h"
|
||||
#include "input_common/drivers/virtual_gamepad.h"
|
||||
#include "input_common/helpers/stick_from_buttons.h"
|
||||
#include "input_common/helpers/touch_from_buttons.h"
|
||||
#include "input_common/input_engine.h"
|
||||
#include "input_common/input_mapping.h"
|
||||
#include "input_common/input_poller.h"
|
||||
#include "input_common/main.h"
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
#include "input_common/drivers/gc_adapter.h"
|
||||
#endif
|
||||
#ifdef HAVE_SDL2
|
||||
#include "input_common/drivers/sdl_driver.h"
|
||||
#endif
|
||||
@@ -25,73 +29,35 @@
|
||||
namespace InputCommon {
|
||||
|
||||
struct InputSubsystem::Impl {
|
||||
void Initialize() {
|
||||
mapping_factory = std::make_shared<MappingFactory>();
|
||||
template <typename Engine>
|
||||
void RegisterEngine(std::string name, std::shared_ptr<Engine>& engine) {
|
||||
MappingCallback mapping_callback{[this](const MappingData& data) { RegisterInput(data); }};
|
||||
|
||||
keyboard = std::make_shared<Keyboard>("keyboard");
|
||||
keyboard->SetMappingCallback(mapping_callback);
|
||||
keyboard_factory = std::make_shared<InputFactory>(keyboard);
|
||||
keyboard_output_factory = std::make_shared<OutputFactory>(keyboard);
|
||||
Common::Input::RegisterInputFactory(keyboard->GetEngineName(), keyboard_factory);
|
||||
Common::Input::RegisterOutputFactory(keyboard->GetEngineName(), keyboard_output_factory);
|
||||
engine = std::make_shared<Engine>(name);
|
||||
engine->SetMappingCallback(mapping_callback);
|
||||
|
||||
mouse = std::make_shared<Mouse>("mouse");
|
||||
mouse->SetMappingCallback(mapping_callback);
|
||||
mouse_factory = std::make_shared<InputFactory>(mouse);
|
||||
mouse_output_factory = std::make_shared<OutputFactory>(mouse);
|
||||
Common::Input::RegisterInputFactory(mouse->GetEngineName(), mouse_factory);
|
||||
Common::Input::RegisterOutputFactory(mouse->GetEngineName(), mouse_output_factory);
|
||||
std::shared_ptr<InputFactory> input_factory = std::make_shared<InputFactory>(engine);
|
||||
std::shared_ptr<OutputFactory> output_factory = std::make_shared<OutputFactory>(engine);
|
||||
Common::Input::RegisterInputFactory(engine->GetEngineName(), std::move(input_factory));
|
||||
Common::Input::RegisterOutputFactory(engine->GetEngineName(), std::move(output_factory));
|
||||
}
|
||||
|
||||
touch_screen = std::make_shared<TouchScreen>("touch");
|
||||
touch_screen_factory = std::make_shared<InputFactory>(touch_screen);
|
||||
Common::Input::RegisterInputFactory(touch_screen->GetEngineName(), touch_screen_factory);
|
||||
|
||||
gcadapter = std::make_shared<GCAdapter>("gcpad");
|
||||
gcadapter->SetMappingCallback(mapping_callback);
|
||||
gcadapter_input_factory = std::make_shared<InputFactory>(gcadapter);
|
||||
gcadapter_output_factory = std::make_shared<OutputFactory>(gcadapter);
|
||||
Common::Input::RegisterInputFactory(gcadapter->GetEngineName(), gcadapter_input_factory);
|
||||
Common::Input::RegisterOutputFactory(gcadapter->GetEngineName(), gcadapter_output_factory);
|
||||
|
||||
udp_client = std::make_shared<CemuhookUDP::UDPClient>("cemuhookudp");
|
||||
udp_client->SetMappingCallback(mapping_callback);
|
||||
udp_client_input_factory = std::make_shared<InputFactory>(udp_client);
|
||||
udp_client_output_factory = std::make_shared<OutputFactory>(udp_client);
|
||||
Common::Input::RegisterInputFactory(udp_client->GetEngineName(), udp_client_input_factory);
|
||||
Common::Input::RegisterOutputFactory(udp_client->GetEngineName(),
|
||||
udp_client_output_factory);
|
||||
|
||||
tas_input = std::make_shared<TasInput::Tas>("tas");
|
||||
tas_input->SetMappingCallback(mapping_callback);
|
||||
tas_input_factory = std::make_shared<InputFactory>(tas_input);
|
||||
tas_output_factory = std::make_shared<OutputFactory>(tas_input);
|
||||
Common::Input::RegisterInputFactory(tas_input->GetEngineName(), tas_input_factory);
|
||||
Common::Input::RegisterOutputFactory(tas_input->GetEngineName(), tas_output_factory);
|
||||
|
||||
camera = std::make_shared<Camera>("camera");
|
||||
camera->SetMappingCallback(mapping_callback);
|
||||
camera_input_factory = std::make_shared<InputFactory>(camera);
|
||||
camera_output_factory = std::make_shared<OutputFactory>(camera);
|
||||
Common::Input::RegisterInputFactory(camera->GetEngineName(), camera_input_factory);
|
||||
Common::Input::RegisterOutputFactory(camera->GetEngineName(), camera_output_factory);
|
||||
|
||||
virtual_amiibo = std::make_shared<VirtualAmiibo>("virtual_amiibo");
|
||||
virtual_amiibo->SetMappingCallback(mapping_callback);
|
||||
virtual_amiibo_input_factory = std::make_shared<InputFactory>(virtual_amiibo);
|
||||
virtual_amiibo_output_factory = std::make_shared<OutputFactory>(virtual_amiibo);
|
||||
Common::Input::RegisterInputFactory(virtual_amiibo->GetEngineName(),
|
||||
virtual_amiibo_input_factory);
|
||||
Common::Input::RegisterOutputFactory(virtual_amiibo->GetEngineName(),
|
||||
virtual_amiibo_output_factory);
|
||||
void Initialize() {
|
||||
mapping_factory = std::make_shared<MappingFactory>();
|
||||
|
||||
RegisterEngine("keyboard", keyboard);
|
||||
RegisterEngine("mouse", mouse);
|
||||
RegisterEngine("touch", touch_screen);
|
||||
#ifdef HAVE_LIBUSB
|
||||
RegisterEngine("gcpad", gcadapter);
|
||||
#endif
|
||||
RegisterEngine("cemuhookudp", udp_client);
|
||||
RegisterEngine("tas", tas_input);
|
||||
RegisterEngine("camera", camera);
|
||||
RegisterEngine("virtual_amiibo", virtual_amiibo);
|
||||
RegisterEngine("virtual_gamepad", virtual_gamepad);
|
||||
#ifdef HAVE_SDL2
|
||||
sdl = std::make_shared<SDLDriver>("sdl");
|
||||
sdl->SetMappingCallback(mapping_callback);
|
||||
sdl_input_factory = std::make_shared<InputFactory>(sdl);
|
||||
sdl_output_factory = std::make_shared<OutputFactory>(sdl);
|
||||
Common::Input::RegisterInputFactory(sdl->GetEngineName(), sdl_input_factory);
|
||||
Common::Input::RegisterOutputFactory(sdl->GetEngineName(), sdl_output_factory);
|
||||
RegisterEngine("sdl", sdl);
|
||||
#endif
|
||||
|
||||
Common::Input::RegisterInputFactory("touch_from_button",
|
||||
@@ -100,42 +66,27 @@ struct InputSubsystem::Impl {
|
||||
std::make_shared<StickFromButton>());
|
||||
}
|
||||
|
||||
template <typename Engine>
|
||||
void UnregisterEngine(std::shared_ptr<Engine>& engine) {
|
||||
Common::Input::UnregisterInputFactory(engine->GetEngineName());
|
||||
Common::Input::UnregisterOutputFactory(engine->GetEngineName());
|
||||
engine.reset();
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
Common::Input::UnregisterInputFactory(keyboard->GetEngineName());
|
||||
Common::Input::UnregisterOutputFactory(keyboard->GetEngineName());
|
||||
keyboard.reset();
|
||||
|
||||
Common::Input::UnregisterInputFactory(mouse->GetEngineName());
|
||||
Common::Input::UnregisterOutputFactory(mouse->GetEngineName());
|
||||
mouse.reset();
|
||||
|
||||
Common::Input::UnregisterInputFactory(touch_screen->GetEngineName());
|
||||
touch_screen.reset();
|
||||
|
||||
Common::Input::UnregisterInputFactory(gcadapter->GetEngineName());
|
||||
Common::Input::UnregisterOutputFactory(gcadapter->GetEngineName());
|
||||
gcadapter.reset();
|
||||
|
||||
Common::Input::UnregisterInputFactory(udp_client->GetEngineName());
|
||||
Common::Input::UnregisterOutputFactory(udp_client->GetEngineName());
|
||||
udp_client.reset();
|
||||
|
||||
Common::Input::UnregisterInputFactory(tas_input->GetEngineName());
|
||||
Common::Input::UnregisterOutputFactory(tas_input->GetEngineName());
|
||||
tas_input.reset();
|
||||
|
||||
Common::Input::UnregisterInputFactory(camera->GetEngineName());
|
||||
Common::Input::UnregisterOutputFactory(camera->GetEngineName());
|
||||
camera.reset();
|
||||
|
||||
Common::Input::UnregisterInputFactory(virtual_amiibo->GetEngineName());
|
||||
Common::Input::UnregisterOutputFactory(virtual_amiibo->GetEngineName());
|
||||
virtual_amiibo.reset();
|
||||
|
||||
UnregisterEngine(keyboard);
|
||||
UnregisterEngine(mouse);
|
||||
UnregisterEngine(touch_screen);
|
||||
#ifdef HAVE_LIBUSB
|
||||
UnregisterEngine(gcadapter);
|
||||
#endif
|
||||
UnregisterEngine(udp_client);
|
||||
UnregisterEngine(tas_input);
|
||||
UnregisterEngine(camera);
|
||||
UnregisterEngine(virtual_amiibo);
|
||||
UnregisterEngine(virtual_gamepad);
|
||||
#ifdef HAVE_SDL2
|
||||
Common::Input::UnregisterInputFactory(sdl->GetEngineName());
|
||||
Common::Input::UnregisterOutputFactory(sdl->GetEngineName());
|
||||
sdl.reset();
|
||||
UnregisterEngine(sdl);
|
||||
#endif
|
||||
|
||||
Common::Input::UnregisterInputFactory("touch_from_button");
|
||||
@@ -151,8 +102,10 @@ struct InputSubsystem::Impl {
|
||||
devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end());
|
||||
auto mouse_devices = mouse->GetInputDevices();
|
||||
devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end());
|
||||
#ifdef HAVE_LIBUSB
|
||||
auto gcadapter_devices = gcadapter->GetInputDevices();
|
||||
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
|
||||
#endif
|
||||
auto udp_devices = udp_client->GetInputDevices();
|
||||
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
||||
#ifdef HAVE_SDL2
|
||||
@@ -163,117 +116,88 @@ struct InputSubsystem::Impl {
|
||||
return devices;
|
||||
}
|
||||
|
||||
[[nodiscard]] AnalogMapping GetAnalogMappingForDevice(
|
||||
[[nodiscard]] std::shared_ptr<InputEngine> GetInputEngine(
|
||||
const Common::ParamPackage& params) const {
|
||||
if (!params.Has("engine") || params.Get("engine", "") == "any") {
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
const std::string engine = params.Get("engine", "");
|
||||
if (engine == keyboard->GetEngineName()) {
|
||||
return keyboard;
|
||||
}
|
||||
if (engine == mouse->GetEngineName()) {
|
||||
return mouse->GetAnalogMappingForDevice(params);
|
||||
return mouse;
|
||||
}
|
||||
#ifdef HAVE_LIBUSB
|
||||
if (engine == gcadapter->GetEngineName()) {
|
||||
return gcadapter->GetAnalogMappingForDevice(params);
|
||||
return gcadapter;
|
||||
}
|
||||
#endif
|
||||
if (engine == udp_client->GetEngineName()) {
|
||||
return udp_client->GetAnalogMappingForDevice(params);
|
||||
}
|
||||
if (engine == tas_input->GetEngineName()) {
|
||||
return tas_input->GetAnalogMappingForDevice(params);
|
||||
return udp_client;
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
if (engine == sdl->GetEngineName()) {
|
||||
return sdl->GetAnalogMappingForDevice(params);
|
||||
return sdl;
|
||||
}
|
||||
#endif
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] AnalogMapping GetAnalogMappingForDevice(
|
||||
const Common::ParamPackage& params) const {
|
||||
const auto input_engine = GetInputEngine(params);
|
||||
|
||||
if (input_engine == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return input_engine->GetAnalogMappingForDevice(params);
|
||||
}
|
||||
|
||||
[[nodiscard]] ButtonMapping GetButtonMappingForDevice(
|
||||
const Common::ParamPackage& params) const {
|
||||
if (!params.Has("engine") || params.Get("engine", "") == "any") {
|
||||
const auto input_engine = GetInputEngine(params);
|
||||
|
||||
if (input_engine == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const std::string engine = params.Get("engine", "");
|
||||
if (engine == gcadapter->GetEngineName()) {
|
||||
return gcadapter->GetButtonMappingForDevice(params);
|
||||
}
|
||||
if (engine == udp_client->GetEngineName()) {
|
||||
return udp_client->GetButtonMappingForDevice(params);
|
||||
}
|
||||
if (engine == tas_input->GetEngineName()) {
|
||||
return tas_input->GetButtonMappingForDevice(params);
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
if (engine == sdl->GetEngineName()) {
|
||||
return sdl->GetButtonMappingForDevice(params);
|
||||
}
|
||||
#endif
|
||||
return {};
|
||||
|
||||
return input_engine->GetButtonMappingForDevice(params);
|
||||
}
|
||||
|
||||
[[nodiscard]] MotionMapping GetMotionMappingForDevice(
|
||||
const Common::ParamPackage& params) const {
|
||||
if (!params.Has("engine") || params.Get("engine", "") == "any") {
|
||||
const auto input_engine = GetInputEngine(params);
|
||||
|
||||
if (input_engine == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const std::string engine = params.Get("engine", "");
|
||||
if (engine == udp_client->GetEngineName()) {
|
||||
return udp_client->GetMotionMappingForDevice(params);
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
if (engine == sdl->GetEngineName()) {
|
||||
return sdl->GetMotionMappingForDevice(params);
|
||||
}
|
||||
#endif
|
||||
return {};
|
||||
|
||||
return input_engine->GetMotionMappingForDevice(params);
|
||||
}
|
||||
|
||||
Common::Input::ButtonNames GetButtonName(const Common::ParamPackage& params) const {
|
||||
if (!params.Has("engine") || params.Get("engine", "") == "any") {
|
||||
return Common::Input::ButtonNames::Undefined;
|
||||
}
|
||||
const std::string engine = params.Get("engine", "");
|
||||
if (engine == mouse->GetEngineName()) {
|
||||
return mouse->GetUIName(params);
|
||||
const auto input_engine = GetInputEngine(params);
|
||||
|
||||
if (input_engine == nullptr) {
|
||||
return Common::Input::ButtonNames::Invalid;
|
||||
}
|
||||
if (engine == gcadapter->GetEngineName()) {
|
||||
return gcadapter->GetUIName(params);
|
||||
}
|
||||
if (engine == udp_client->GetEngineName()) {
|
||||
return udp_client->GetUIName(params);
|
||||
}
|
||||
if (engine == tas_input->GetEngineName()) {
|
||||
return tas_input->GetUIName(params);
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
if (engine == sdl->GetEngineName()) {
|
||||
return sdl->GetUIName(params);
|
||||
}
|
||||
#endif
|
||||
return Common::Input::ButtonNames::Invalid;
|
||||
|
||||
return input_engine->GetUIName(params);
|
||||
}
|
||||
|
||||
bool IsStickInverted(const Common::ParamPackage& params) {
|
||||
const std::string engine = params.Get("engine", "");
|
||||
if (engine == mouse->GetEngineName()) {
|
||||
return mouse->IsStickInverted(params);
|
||||
const auto input_engine = GetInputEngine(params);
|
||||
|
||||
if (input_engine == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (engine == gcadapter->GetEngineName()) {
|
||||
return gcadapter->IsStickInverted(params);
|
||||
}
|
||||
if (engine == udp_client->GetEngineName()) {
|
||||
return udp_client->IsStickInverted(params);
|
||||
}
|
||||
if (engine == tas_input->GetEngineName()) {
|
||||
return tas_input->IsStickInverted(params);
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
if (engine == sdl->GetEngineName()) {
|
||||
return sdl->IsStickInverted(params);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
|
||||
return input_engine->IsStickInverted(params);
|
||||
}
|
||||
|
||||
bool IsController(const Common::ParamPackage& params) {
|
||||
@@ -281,15 +205,20 @@ struct InputSubsystem::Impl {
|
||||
if (engine == mouse->GetEngineName()) {
|
||||
return true;
|
||||
}
|
||||
#ifdef HAVE_LIBUSB
|
||||
if (engine == gcadapter->GetEngineName()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (engine == udp_client->GetEngineName()) {
|
||||
return true;
|
||||
}
|
||||
if (engine == tas_input->GetEngineName()) {
|
||||
return true;
|
||||
}
|
||||
if (engine == virtual_gamepad->GetEngineName()) {
|
||||
return true;
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
if (engine == sdl->GetEngineName()) {
|
||||
return true;
|
||||
@@ -301,7 +230,9 @@ struct InputSubsystem::Impl {
|
||||
void BeginConfiguration() {
|
||||
keyboard->BeginConfiguration();
|
||||
mouse->BeginConfiguration();
|
||||
#ifdef HAVE_LIBUSB
|
||||
gcadapter->BeginConfiguration();
|
||||
#endif
|
||||
udp_client->BeginConfiguration();
|
||||
#ifdef HAVE_SDL2
|
||||
sdl->BeginConfiguration();
|
||||
@@ -311,7 +242,9 @@ struct InputSubsystem::Impl {
|
||||
void EndConfiguration() {
|
||||
keyboard->EndConfiguration();
|
||||
mouse->EndConfiguration();
|
||||
#ifdef HAVE_LIBUSB
|
||||
gcadapter->EndConfiguration();
|
||||
#endif
|
||||
udp_client->EndConfiguration();
|
||||
#ifdef HAVE_SDL2
|
||||
sdl->EndConfiguration();
|
||||
@@ -332,34 +265,19 @@ struct InputSubsystem::Impl {
|
||||
|
||||
std::shared_ptr<Keyboard> keyboard;
|
||||
std::shared_ptr<Mouse> mouse;
|
||||
std::shared_ptr<GCAdapter> gcadapter;
|
||||
std::shared_ptr<TouchScreen> touch_screen;
|
||||
std::shared_ptr<TasInput::Tas> tas_input;
|
||||
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
|
||||
std::shared_ptr<Camera> camera;
|
||||
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
|
||||
std::shared_ptr<VirtualGamepad> virtual_gamepad;
|
||||
|
||||
std::shared_ptr<InputFactory> keyboard_factory;
|
||||
std::shared_ptr<InputFactory> mouse_factory;
|
||||
std::shared_ptr<InputFactory> gcadapter_input_factory;
|
||||
std::shared_ptr<InputFactory> touch_screen_factory;
|
||||
std::shared_ptr<InputFactory> udp_client_input_factory;
|
||||
std::shared_ptr<InputFactory> tas_input_factory;
|
||||
std::shared_ptr<InputFactory> camera_input_factory;
|
||||
std::shared_ptr<InputFactory> virtual_amiibo_input_factory;
|
||||
|
||||
std::shared_ptr<OutputFactory> keyboard_output_factory;
|
||||
std::shared_ptr<OutputFactory> mouse_output_factory;
|
||||
std::shared_ptr<OutputFactory> gcadapter_output_factory;
|
||||
std::shared_ptr<OutputFactory> udp_client_output_factory;
|
||||
std::shared_ptr<OutputFactory> tas_output_factory;
|
||||
std::shared_ptr<OutputFactory> camera_output_factory;
|
||||
std::shared_ptr<OutputFactory> virtual_amiibo_output_factory;
|
||||
#ifdef HAVE_LIBUSB
|
||||
std::shared_ptr<GCAdapter> gcadapter;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
std::shared_ptr<SDLDriver> sdl;
|
||||
std::shared_ptr<InputFactory> sdl_input_factory;
|
||||
std::shared_ptr<OutputFactory> sdl_output_factory;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -423,6 +341,14 @@ const VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() const {
|
||||
return impl->virtual_amiibo.get();
|
||||
}
|
||||
|
||||
VirtualGamepad* InputSubsystem::GetVirtualGamepad() {
|
||||
return impl->virtual_gamepad.get();
|
||||
}
|
||||
|
||||
const VirtualGamepad* InputSubsystem::GetVirtualGamepad() const {
|
||||
return impl->virtual_gamepad.get();
|
||||
}
|
||||
|
||||
std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
|
||||
return impl->GetInputDevices();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user