Compare commits
128 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92ce241d4d | ||
|
|
d3123079e8 | ||
|
|
5da72a891f | ||
|
|
f8a7d6a0ae | ||
|
|
da31326c17 | ||
|
|
45672d43e3 | ||
|
|
a3bac5550d | ||
|
|
4faea2bbf4 | ||
|
|
fa10374d39 | ||
|
|
98135dee16 | ||
|
|
7bf4bec257 | ||
|
|
f7d95d0a3a | ||
|
|
bbb202ceed | ||
|
|
789da737af | ||
|
|
b541a35e27 | ||
|
|
6bc1a477bf | ||
|
|
9bfd4d880e | ||
|
|
6a56f42f5d | ||
|
|
b81caf1879 | ||
|
|
b1d633532f | ||
|
|
12c0f682e6 | ||
|
|
9ff891ce71 | ||
|
|
82d80869fc | ||
|
|
20cbf6f3db | ||
|
|
dca4f0687a | ||
|
|
b8c03411e7 | ||
|
|
3ff7a5de1a | ||
|
|
4447c9a46e | ||
|
|
e2f32e8c88 | ||
|
|
beba9c9b61 | ||
|
|
a222f02c7a | ||
|
|
0104e28fe4 | ||
|
|
c5f519e1e4 | ||
|
|
5a5bb91f40 | ||
|
|
4fce72c902 | ||
|
|
77b0d01639 | ||
|
|
18bdf45868 | ||
|
|
09e3029c11 | ||
|
|
2221afaf26 | ||
|
|
45fcde817e | ||
|
|
29fbce9fe6 | ||
|
|
5754456292 | ||
|
|
3cc3176ad6 | ||
|
|
d5f53da79d | ||
|
|
a4696285af | ||
|
|
179adee396 | ||
|
|
f44c60321e | ||
|
|
f6868ae4dd | ||
|
|
0ed80c9818 | ||
|
|
339a37f8cb | ||
|
|
da58eb6208 | ||
|
|
b32b9524ad | ||
|
|
3e1e6c66c0 | ||
|
|
8ef9075b1b | ||
|
|
0c531ff911 | ||
|
|
d5684dbe7d | ||
|
|
ed37192441 | ||
|
|
623429a27e | ||
|
|
456322dde6 | ||
|
|
821da3ed54 | ||
|
|
8d1d6e149f | ||
|
|
1085bbb0a3 | ||
|
|
a5bc86a9ac | ||
|
|
6982423931 | ||
|
|
e532b74e11 | ||
|
|
985ed1e160 | ||
|
|
f6e705737a | ||
|
|
66c4331de5 | ||
|
|
c586ac9be2 | ||
|
|
0e265db873 | ||
|
|
5b837157bd | ||
|
|
37014e9127 | ||
|
|
1e64b5e2ec | ||
|
|
15d63c3d3d | ||
|
|
41461514d6 | ||
|
|
bf0b957c05 | ||
|
|
bfdd512787 | ||
|
|
9704acb982 | ||
|
|
e1f5f4bdea | ||
|
|
08d4e7c7af | ||
|
|
4b7e73e0a6 | ||
|
|
d8534ea140 | ||
|
|
bbdb6d391e | ||
|
|
a86af1b776 | ||
|
|
131ed37803 | ||
|
|
a225ba4cda | ||
|
|
e86e144a7c | ||
|
|
99494e77c3 | ||
|
|
dba84458be | ||
|
|
bb3440f7c4 | ||
|
|
f385175aa2 | ||
|
|
7c68f93bdf | ||
|
|
04779b3d2a | ||
|
|
90145c424d | ||
|
|
7e7a23363a | ||
|
|
eadc1ae1e7 | ||
|
|
e7f9f58fa4 | ||
|
|
e6ae720c33 | ||
|
|
fedd857054 | ||
|
|
d8da9a2afd | ||
|
|
2b40cdf04f | ||
|
|
a84676c2aa | ||
|
|
e26c86a6e7 | ||
|
|
9bbb77637e | ||
|
|
bcf59ff3a7 | ||
|
|
e4a16f50ef | ||
|
|
87543b9dea | ||
|
|
7bf4b45349 | ||
|
|
4255e30722 | ||
|
|
78eeefb030 | ||
|
|
efa8711bf3 | ||
|
|
c3fd211b43 | ||
|
|
dcca650599 | ||
|
|
dddc9bb8f1 | ||
|
|
4769d798f9 | ||
|
|
7381f873e9 | ||
|
|
3b19f741bd | ||
|
|
c7f32300b2 | ||
|
|
6352c5dc31 | ||
|
|
752236caad | ||
|
|
a52d0b82a6 | ||
|
|
3b9db85646 | ||
|
|
8e17b5469f | ||
|
|
6072b22a0b | ||
|
|
a4725bcb73 | ||
|
|
be05cb640c | ||
|
|
a78372110c | ||
|
|
0d6a8824d0 |
@@ -22,6 +22,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_OPENGL "Enable OpenGL" ON)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT6 "Allow usage of Qt6 to be attempted" OFF)
|
||||
set(QT6_LOCATION "" CACHE PATH "Additional Location to search for Qt6 libraries like C:/Qt/6.3.1/msvc2019_64/")
|
||||
@@ -31,8 +33,6 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSV
|
||||
|
||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
|
||||
option(YUZU_USE_BUNDLED_LIBUSB "Compile bundled libusb" OFF)
|
||||
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" "${WIN32}")
|
||||
|
||||
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
|
||||
@@ -43,8 +43,6 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||
|
||||
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
|
||||
|
||||
option(YUZU_USE_BUNDLED_OPUS "Compile bundled opus" ON)
|
||||
|
||||
option(YUZU_TESTS "Compile tests" ON)
|
||||
|
||||
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
||||
@@ -55,6 +53,8 @@ option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
|
||||
|
||||
option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
|
||||
|
||||
if (YUZU_USE_BUNDLED_VCPKG)
|
||||
if (YUZU_TESTS)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
|
||||
@@ -201,24 +201,40 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
# System imported libraries
|
||||
# =======================================================================
|
||||
|
||||
find_package(fmt 8.0.1 REQUIRED CONFIG)
|
||||
find_package(nlohmann_json 3.8 REQUIRED CONFIG)
|
||||
find_package(enet 1.3)
|
||||
find_package(fmt 9 REQUIRED)
|
||||
find_package(inih)
|
||||
find_package(libusb 1.0.24)
|
||||
find_package(lz4 REQUIRED)
|
||||
find_package(nlohmann_json 3.8 REQUIRED)
|
||||
find_package(Opus 1.3)
|
||||
find_package(Vulkan 1.3.213)
|
||||
find_package(ZLIB 1.2 REQUIRED)
|
||||
find_package(zstd 1.5 REQUIRED)
|
||||
|
||||
# Search for config-only package first (for vcpkg), then try non-config
|
||||
find_package(zstd 1.5 CONFIG)
|
||||
if (NOT zstd_FOUND)
|
||||
find_package(zstd 1.5 REQUIRED)
|
||||
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
||||
find_package(xbyak 6)
|
||||
endif()
|
||||
|
||||
# lz4 1.8 is required, but vcpkg's lz4-config.cmake does not have version info
|
||||
find_package(lz4 CONFIG)
|
||||
if (NOT lz4_FOUND)
|
||||
find_package(lz4 1.8 REQUIRED)
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
find_package(dynarmic 6.4.0)
|
||||
endif()
|
||||
|
||||
if (ENABLE_CUBEB)
|
||||
find_package(cubeb)
|
||||
endif()
|
||||
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
find_package(DiscordRPC)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
find_package(cpp-jwt 1.4)
|
||||
find_package(httplib 0.11)
|
||||
endif()
|
||||
|
||||
if (YUZU_TESTS)
|
||||
find_package(Catch2 2.13.7 REQUIRED CONFIG)
|
||||
find_package(Catch2 2.13.7 REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(Boost 1.73.0 COMPONENTS context)
|
||||
@@ -420,23 +436,13 @@ if (ENABLE_SDL2)
|
||||
set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
|
||||
set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
|
||||
|
||||
add_library(SDL2 INTERFACE)
|
||||
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
|
||||
target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
|
||||
add_library(SDL2::SDL2 INTERFACE IMPORTED)
|
||||
target_link_libraries(SDL2::SDL2 INTERFACE "${SDL2_LIBRARY}")
|
||||
target_include_directories(SDL2::SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
|
||||
elseif (YUZU_USE_EXTERNAL_SDL2)
|
||||
message(STATUS "Using SDL2 from externals.")
|
||||
else()
|
||||
find_package(SDL2 2.0.18 REQUIRED)
|
||||
|
||||
# Some installations don't set SDL2_LIBRARIES
|
||||
if("${SDL2_LIBRARIES}" STREQUAL "")
|
||||
message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
|
||||
set(SDL2_LIBRARIES "SDL2::SDL2")
|
||||
endif()
|
||||
|
||||
include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
|
||||
add_library(SDL2 INTERFACE)
|
||||
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -448,26 +454,6 @@ if (TARGET Boost::boost)
|
||||
add_library(boost ALIAS Boost::boost)
|
||||
endif()
|
||||
|
||||
# Ensure libusb is properly configured (based on dolphin libusb include)
|
||||
if(NOT YUZU_USE_BUNDLED_LIBUSB)
|
||||
find_package(PkgConfig)
|
||||
if (PKG_CONFIG_FOUND AND NOT CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD")
|
||||
pkg_check_modules(LIBUSB QUIET libusb-1.0>=1.0.24)
|
||||
else()
|
||||
find_package(LibUSB)
|
||||
endif()
|
||||
|
||||
if (LIBUSB_FOUND)
|
||||
add_library(usb INTERFACE)
|
||||
target_include_directories(usb INTERFACE "${LIBUSB_INCLUDEDIR}" "${LIBUSB_INCLUDE_DIRS}")
|
||||
target_link_directories(usb INTERFACE "${LIBUSB_LIBRARY_DIRS}")
|
||||
target_link_libraries(usb INTERFACE "${LIBUSB_LIBRARIES}")
|
||||
else()
|
||||
message(WARNING "libusb not found, falling back to externals")
|
||||
set(YUZU_USE_BUNDLED_LIBUSB ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# List of all FFmpeg components required
|
||||
set(FFmpeg_COMPONENTS
|
||||
avcodec
|
||||
@@ -597,6 +583,21 @@ if (MSVC AND CMAKE_GENERATOR STREQUAL "Ninja")
|
||||
)
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_FASTER_LD AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# We will assume that if the compiler is GCC, it will attempt to use ld.bfd by default.
|
||||
# Try to pick a faster linker.
|
||||
find_program(LLD lld)
|
||||
find_program(MOLD mold)
|
||||
|
||||
if (MOLD AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
|
||||
message(NOTICE "Selecting mold as linker")
|
||||
add_link_options("-fuse-ld=mold")
|
||||
elseif (LLD)
|
||||
message(NOTICE "Selecting lld as linker")
|
||||
add_link_options("-fuse-ld=lld")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(externals)
|
||||
add_subdirectory(src)
|
||||
|
||||
49
externals/CMakeLists.txt
vendored
49
externals/CMakeLists.txt
vendored
@@ -6,15 +6,16 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/externals/find-modules")
|
||||
include(DownloadExternals)
|
||||
|
||||
# xbyak
|
||||
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
||||
if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
|
||||
add_subdirectory(xbyak EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# Dynarmic
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
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)
|
||||
add_subdirectory(dynarmic)
|
||||
add_subdirectory(dynarmic EXCLUDE_FROM_ALL)
|
||||
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
||||
endif()
|
||||
|
||||
# getopt
|
||||
@@ -26,7 +27,9 @@ endif()
|
||||
add_subdirectory(glad)
|
||||
|
||||
# inih
|
||||
add_subdirectory(inih)
|
||||
if (NOT TARGET inih::INIReader)
|
||||
add_subdirectory(inih)
|
||||
endif()
|
||||
|
||||
# mbedtls
|
||||
add_subdirectory(mbedtls EXCLUDE_FROM_ALL)
|
||||
@@ -42,8 +45,8 @@ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER
|
||||
endif()
|
||||
|
||||
# libusb
|
||||
if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB)
|
||||
add_subdirectory(libusb)
|
||||
if (NOT TARGET libusb::usb)
|
||||
add_subdirectory(libusb EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# SDL2
|
||||
@@ -72,25 +75,30 @@ if (YUZU_USE_EXTERNAL_SDL2)
|
||||
endif()
|
||||
|
||||
# ENet
|
||||
add_subdirectory(enet)
|
||||
target_include_directories(enet INTERFACE ./enet/include)
|
||||
if (NOT TARGET enet::enet)
|
||||
add_subdirectory(enet EXCLUDE_FROM_ALL)
|
||||
target_include_directories(enet INTERFACE ./enet/include)
|
||||
add_library(enet::enet ALIAS enet)
|
||||
endif()
|
||||
|
||||
# Cubeb
|
||||
if(ENABLE_CUBEB)
|
||||
if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb)
|
||||
set(BUILD_TESTS OFF CACHE BOOL "")
|
||||
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
|
||||
add_library(cubeb::cubeb ALIAS cubeb)
|
||||
endif()
|
||||
|
||||
# DiscordRPC
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
if (USE_DISCORD_PRESENCE AND NOT TARGET DiscordRPC::discord-rpc)
|
||||
add_subdirectory(discord-rpc EXCLUDE_FROM_ALL)
|
||||
target_include_directories(discord-rpc INTERFACE ./discord-rpc/include)
|
||||
add_library(DiscordRPC::discord-rpc ALIAS discord-rpc)
|
||||
endif()
|
||||
|
||||
# Sirit
|
||||
add_subdirectory(sirit)
|
||||
add_subdirectory(sirit EXCLUDE_FROM_ALL)
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
|
||||
if (NOT WIN32)
|
||||
find_package(OpenSSL 1.1)
|
||||
if (OPENSSL_FOUND)
|
||||
@@ -118,18 +126,20 @@ if (ENABLE_WEB_SERVICE)
|
||||
if (WIN32)
|
||||
target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32)
|
||||
endif()
|
||||
|
||||
# cpp-jwt
|
||||
add_library(httplib::httplib ALIAS httplib)
|
||||
endif()
|
||||
|
||||
# cpp-jwt
|
||||
if (ENABLE_WEB_SERVICE AND NOT TARGET cpp-jwt::cpp-jwt)
|
||||
add_library(cpp-jwt INTERFACE)
|
||||
target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
|
||||
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
|
||||
add_library(cpp-jwt::cpp-jwt ALIAS cpp-jwt)
|
||||
endif()
|
||||
|
||||
# Opus
|
||||
if (YUZU_USE_BUNDLED_OPUS)
|
||||
if (NOT TARGET Opus::opus)
|
||||
add_subdirectory(opus EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
find_package(Opus 1.3 REQUIRED)
|
||||
endif()
|
||||
|
||||
# FFMpeg
|
||||
@@ -140,3 +150,8 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE)
|
||||
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
# Vulkan-Headers
|
||||
if (NOT TARGET Vulkan::Headers)
|
||||
add_subdirectory(Vulkan-Headers EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: a76a2fff53...bd570e093c
27
externals/find-modules/FindDiscordRPC.cmake
vendored
Normal file
27
externals/find-modules/FindDiscordRPC.cmake
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
find_path(DiscordRPC_INCLUDE_DIR discord_rpc.h)
|
||||
|
||||
find_library(DiscordRPC_LIBRARY discord-rpc)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(DiscordRPC
|
||||
REQUIRED_VARS
|
||||
DiscordRPC_LIBRARY
|
||||
DiscordRPC_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if (DiscordRPC_FOUND AND NOT TARGET DiscordRPC::discord-rpc)
|
||||
add_library(DiscordRPC::discord-rpc UNKNOWN IMPORTED)
|
||||
set_target_properties(DiscordRPC::discord-rpc PROPERTIES
|
||||
IMPORTED_LOCATION "${DiscordRPC_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${DiscordRPC_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
DiscordRPC_INCLUDE_DIR
|
||||
DiscordRPC_LIBRARY
|
||||
)
|
||||
44
externals/find-modules/FindLibUSB.cmake
vendored
44
externals/find-modules/FindLibUSB.cmake
vendored
@@ -1,44 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2009 Michal Cihar <michal@cihar.com>
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# - Find libusb-1.0 library
|
||||
# This module defines
|
||||
# LIBUSB_INCLUDE_DIR, where to find bluetooth.h
|
||||
# LIBUSB_LIBRARIES, the libraries needed to use libusb-1.0.
|
||||
# LIBUSB_FOUND, If false, do not try to use libusb-1.0.
|
||||
#
|
||||
# vim: expandtab sw=4 ts=4 sts=4:
|
||||
|
||||
if(ANDROID)
|
||||
set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found")
|
||||
message(STATUS "libusb-1.0 not found.")
|
||||
elseif (NOT LIBUSB_FOUND)
|
||||
pkg_check_modules (LIBUSB_PKG libusb-1.0)
|
||||
|
||||
find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h
|
||||
PATHS
|
||||
${LIBUSB_PKG_INCLUDE_DIRS}
|
||||
/usr/include/libusb-1.0
|
||||
/usr/include
|
||||
/usr/local/include/libusb-1.0
|
||||
/usr/local/include
|
||||
)
|
||||
|
||||
find_library(LIBUSB_LIBRARIES NAMES usb-1.0 usb
|
||||
PATHS
|
||||
${LIBUSB_PKG_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
)
|
||||
|
||||
if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
|
||||
set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found")
|
||||
message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}")
|
||||
else(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
|
||||
set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found")
|
||||
message(STATUS "libusb-1.0 not found.")
|
||||
endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
|
||||
|
||||
mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)
|
||||
endif ()
|
||||
|
||||
20
externals/find-modules/FindOpus.cmake
vendored
20
externals/find-modules/FindOpus.cmake
vendored
@@ -1,19 +1,15 @@
|
||||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_search_module(opus IMPORTED_TARGET GLOBAL opus)
|
||||
if (opus_FOUND)
|
||||
add_library(Opus::opus ALIAS PkgConfig::opus)
|
||||
endif()
|
||||
endif()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(OPUS QUIET IMPORTED_TARGET opus)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Opus
|
||||
REQUIRED_VARS
|
||||
opus_LINK_LIBRARIES
|
||||
opus_FOUND
|
||||
VERSION_VAR opus_VERSION
|
||||
REQUIRED_VARS OPUS_LINK_LIBRARIES
|
||||
VERSION_VAR OPUS_VERSION
|
||||
)
|
||||
|
||||
if (Opus_FOUND AND NOT TARGET Opus::opus)
|
||||
add_library(Opus::opus ALIAS PkgConfig::OPUS)
|
||||
endif()
|
||||
|
||||
16
externals/find-modules/Findenet.cmake
vendored
Normal file
16
externals/find-modules/Findenet.cmake
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(ENET QUIET IMPORTED_TARGET libenet)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(enet
|
||||
REQUIRED_VARS ENET_LINK_LIBRARIES
|
||||
VERSION_VAR ENET_VERSION
|
||||
)
|
||||
|
||||
if (enet_FOUND AND NOT TARGET enet::enet)
|
||||
add_library(enet::enet ALIAS PkgConfig::ENET)
|
||||
endif()
|
||||
21
externals/find-modules/Findhttplib.cmake
vendored
Normal file
21
externals/find-modules/Findhttplib.cmake
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(httplib QUIET CONFIG)
|
||||
if (httplib_FOUND)
|
||||
find_package_handle_standard_args(httplib CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(HTTPLIB QUIET IMPORTED_TARGET cpp-httplib)
|
||||
find_package_handle_standard_args(httplib
|
||||
REQUIRED_VARS HTTPLIB_INCLUDEDIR
|
||||
VERSION_VAR HTTPLIB_VERSION
|
||||
)
|
||||
endif()
|
||||
|
||||
if (httplib_FOUND AND NOT TARGET httplib::httplib)
|
||||
add_library(httplib::httplib ALIAS PkgConfig::HTTPLIB)
|
||||
endif()
|
||||
16
externals/find-modules/Findinih.cmake
vendored
Normal file
16
externals/find-modules/Findinih.cmake
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(INIREADER QUIET IMPORTED_TARGET INIReader)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(inih
|
||||
REQUIRED_VARS INIREADER_LINK_LIBRARIES
|
||||
VERSION_VAR INIREADER_VERSION
|
||||
)
|
||||
|
||||
if (inih_FOUND AND NOT TARGET inih::INIReader)
|
||||
add_library(inih::INIReader ALIAS PkgConfig::INIREADER)
|
||||
endif()
|
||||
16
externals/find-modules/Findlibusb.cmake
vendored
Normal file
16
externals/find-modules/Findlibusb.cmake
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(LIBUSB QUIET IMPORTED_TARGET libusb-1.0)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(libusb
|
||||
REQUIRED_VARS LIBUSB_LINK_LIBRARIES
|
||||
VERSION_VAR LIBUSB_VERSION
|
||||
)
|
||||
|
||||
if (libusb_FOUND AND NOT TARGET libusb::usb)
|
||||
add_library(libusb::usb ALIAS PkgConfig::LIBUSB)
|
||||
endif()
|
||||
33
externals/find-modules/Findlz4.cmake
vendored
33
externals/find-modules/Findlz4.cmake
vendored
@@ -1,19 +1,26 @@
|
||||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
find_package(PkgConfig)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_search_module(liblz4 IMPORTED_TARGET GLOBAL liblz4)
|
||||
if (liblz4_FOUND)
|
||||
add_library(lz4::lz4 ALIAS PkgConfig::liblz4)
|
||||
endif()
|
||||
find_package(lz4 QUIET CONFIG)
|
||||
if (lz4_FOUND)
|
||||
find_package_handle_standard_args(lz4 CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4)
|
||||
find_package_handle_standard_args(lz4
|
||||
REQUIRED_VARS LZ4_LINK_LIBRARIES
|
||||
VERSION_VAR LZ4_VERSION
|
||||
)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(lz4
|
||||
REQUIRED_VARS
|
||||
liblz4_LINK_LIBRARIES
|
||||
liblz4_FOUND
|
||||
VERSION_VAR liblz4_VERSION
|
||||
)
|
||||
if (lz4_FOUND AND NOT TARGET lz4::lz4)
|
||||
if (TARGET LZ4::lz4_shared)
|
||||
add_library(lz4::lz4 ALIAS LZ4::lz4_shared)
|
||||
elseif (TARGET LZ4::lz4_static)
|
||||
add_library(lz4::lz4 ALIAS LZ4::lz4_static)
|
||||
else()
|
||||
add_library(lz4::lz4 ALIAS PkgConfig::LZ4)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
33
externals/find-modules/Findzstd.cmake
vendored
33
externals/find-modules/Findzstd.cmake
vendored
@@ -1,19 +1,26 @@
|
||||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
find_package(PkgConfig)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_search_module(libzstd IMPORTED_TARGET GLOBAL libzstd)
|
||||
if (libzstd_FOUND)
|
||||
add_library(zstd::zstd ALIAS PkgConfig::libzstd)
|
||||
endif()
|
||||
find_package(zstd QUIET CONFIG)
|
||||
if (zstd_FOUND)
|
||||
find_package_handle_standard_args(zstd CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd)
|
||||
find_package_handle_standard_args(zstd
|
||||
REQUIRED_VARS ZSTD_LINK_LIBRARIES
|
||||
VERSION_VAR ZSTD_VERSION
|
||||
)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(zstd
|
||||
REQUIRED_VARS
|
||||
libzstd_LINK_LIBRARIES
|
||||
libzstd_FOUND
|
||||
VERSION_VAR libzstd_VERSION
|
||||
)
|
||||
if (zstd_FOUND AND NOT TARGET zstd::zstd)
|
||||
if (TARGET zstd::libzstd_shared)
|
||||
add_library(zstd::zstd ALIAS zstd::libzstd_shared)
|
||||
elseif (TARGET zstd::libzstd_static)
|
||||
add_library(zstd::zstd ALIAS zstd::libzstd_static)
|
||||
else()
|
||||
add_library(zstd::zstd ALIAS PkgConfig::ZSTD)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
3
externals/inih/CMakeLists.txt
vendored
3
externals/inih/CMakeLists.txt
vendored
@@ -9,4 +9,5 @@ add_library(inih
|
||||
)
|
||||
|
||||
create_target_directory_groups(inih)
|
||||
target_include_directories(inih INTERFACE .)
|
||||
target_include_directories(inih INTERFACE inih/cpp)
|
||||
add_library(inih::INIReader ALIAS inih)
|
||||
|
||||
2
externals/libusb/CMakeLists.txt
vendored
2
externals/libusb/CMakeLists.txt
vendored
@@ -273,3 +273,5 @@ else() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
||||
configure_file(config.h.in config.h)
|
||||
endif() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
||||
add_library(libusb::usb ALIAS usb)
|
||||
|
||||
@@ -219,19 +219,15 @@ endif()
|
||||
|
||||
target_link_libraries(audio_core PUBLIC common core)
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
target_link_libraries(audio_core PRIVATE dynarmic)
|
||||
target_link_libraries(audio_core PRIVATE dynarmic::dynarmic)
|
||||
endif()
|
||||
|
||||
if(ENABLE_CUBEB)
|
||||
target_link_libraries(audio_core PRIVATE cubeb)
|
||||
target_link_libraries(audio_core PRIVATE cubeb::cubeb)
|
||||
target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1)
|
||||
endif()
|
||||
if(ENABLE_SDL2)
|
||||
if (YUZU_USE_EXTERNAL_SDL2)
|
||||
target_link_libraries(audio_core PRIVATE SDL2-static)
|
||||
else()
|
||||
target_link_libraries(audio_core PRIVATE SDL2)
|
||||
endif()
|
||||
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();
|
||||
|
||||
@@ -16,7 +16,6 @@ class CommandGenerator;
|
||||
*/
|
||||
class DetailAspect {
|
||||
public:
|
||||
DetailAspect() = default;
|
||||
DetailAspect(CommandGenerator& command_generator, PerformanceEntryType entry_type, s32 node_id,
|
||||
PerformanceDetailType detail_type);
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ class CommandGenerator;
|
||||
*/
|
||||
class EntryAspect {
|
||||
public:
|
||||
EntryAspect() = default;
|
||||
EntryAspect(CommandGenerator& command_generator, PerformanceEntryType type, s32 node_id);
|
||||
|
||||
/// Command generator the command will be generated into
|
||||
|
||||
@@ -34,8 +34,6 @@ add_library(common STATIC
|
||||
bit_util.h
|
||||
cityhash.cpp
|
||||
cityhash.h
|
||||
cache_management.cpp
|
||||
cache_management.h
|
||||
common_funcs.h
|
||||
common_precompiled_headers.h
|
||||
common_types.h
|
||||
@@ -149,7 +147,7 @@ if(ARCHITECTURE_x86_64)
|
||||
x64/xbyak_abi.h
|
||||
x64/xbyak_util.h
|
||||
)
|
||||
target_link_libraries(common PRIVATE xbyak)
|
||||
target_link_libraries(common PRIVATE xbyak::xbyak)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
@@ -174,17 +172,7 @@ endif()
|
||||
create_target_directory_groups(common)
|
||||
|
||||
target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile Threads::Threads)
|
||||
if (TARGET lz4::lz4)
|
||||
target_link_libraries(common PRIVATE lz4::lz4)
|
||||
else()
|
||||
target_link_libraries(common PRIVATE LZ4::lz4_shared)
|
||||
endif()
|
||||
if (TARGET zstd::zstd)
|
||||
target_link_libraries(common PRIVATE zstd::zstd)
|
||||
else()
|
||||
target_link_libraries(common PRIVATE
|
||||
$<IF:$<TARGET_EXISTS:zstd::libzstd_shared>,zstd::libzstd_shared,zstd::libzstd_static>)
|
||||
endif()
|
||||
target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd)
|
||||
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
target_precompile_headers(common PRIVATE precompiled_headers.h)
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/cache_management.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
#if defined(ARCHITECTURE_x86_64)
|
||||
|
||||
// Most cache operations are no-ops on x86
|
||||
|
||||
void DataCacheLineCleanByVAToPoU(void* start, size_t size) {}
|
||||
void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size) {}
|
||||
void DataCacheLineCleanByVAToPoC(void* start, size_t size) {}
|
||||
void DataCacheZeroByVA(void* start, size_t size) {
|
||||
std::memset(start, 0, size);
|
||||
}
|
||||
|
||||
#elif defined(ARCHITECTURE_arm64)
|
||||
|
||||
// BS/DminLine is log2(cache size in words), we want size in bytes
|
||||
#define EXTRACT_DMINLINE(ctr_el0) (1 << ((((ctr_el0) >> 16) & 0xf) + 2))
|
||||
#define EXTRACT_BS(dczid_el0) (1 << (((dczid_el0)&0xf) + 2))
|
||||
|
||||
#define DEFINE_DC_OP(op_name, function_name) \
|
||||
void function_name(void* start, size_t size) { \
|
||||
size_t ctr_el0; \
|
||||
asm volatile("mrs %[ctr_el0], ctr_el0\n\t" : [ctr_el0] "=r"(ctr_el0)); \
|
||||
size_t cacheline_size = EXTRACT_DMINLINE(ctr_el0); \
|
||||
uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \
|
||||
uintptr_t va_end = va_start + size; \
|
||||
for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \
|
||||
asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DEFINE_DC_OP_DCZID(op_name, function_name) \
|
||||
void function_name(void* start, size_t size) { \
|
||||
size_t dczid_el0; \
|
||||
asm volatile("mrs %[dczid_el0], dczid_el0\n\t" : [dczid_el0] "=r"(dczid_el0)); \
|
||||
size_t cacheline_size = EXTRACT_BS(dczid_el0); \
|
||||
uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \
|
||||
uintptr_t va_end = va_start + size; \
|
||||
for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \
|
||||
asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \
|
||||
} \
|
||||
}
|
||||
|
||||
DEFINE_DC_OP(cvau, DataCacheLineCleanByVAToPoU);
|
||||
DEFINE_DC_OP(civac, DataCacheLineCleanAndInvalidateByVAToPoC);
|
||||
DEFINE_DC_OP(cvac, DataCacheLineCleanByVAToPoC);
|
||||
DEFINE_DC_OP_DCZID(zva, DataCacheZeroByVA);
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Common
|
||||
@@ -1,27 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace Common {
|
||||
|
||||
// Data cache instructions enabled at EL0 by SCTLR_EL1.UCI.
|
||||
// VA = virtual address
|
||||
// PoC = point of coherency
|
||||
// PoU = point of unification
|
||||
|
||||
// dc cvau
|
||||
void DataCacheLineCleanByVAToPoU(void* start, size_t size);
|
||||
|
||||
// dc civac
|
||||
void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size);
|
||||
|
||||
// dc cvac
|
||||
void DataCacheLineCleanByVAToPoC(void* start, size_t size);
|
||||
|
||||
// dc zva
|
||||
void DataCacheZeroByVA(void* start, size_t size);
|
||||
|
||||
} // 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());
|
||||
|
||||
@@ -76,7 +76,8 @@ enum class ScalingFilter : u32 {
|
||||
enum class AntiAliasing : u32 {
|
||||
None = 0,
|
||||
Fxaa = 1,
|
||||
LastAA = Fxaa,
|
||||
Smaa = 2,
|
||||
LastAA = Smaa,
|
||||
};
|
||||
|
||||
struct ResolutionScalingInfo {
|
||||
@@ -400,6 +401,7 @@ struct Values {
|
||||
Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
|
||||
Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
|
||||
Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
|
||||
Setting<bool> cpuopt_ignore_memory_aborts{true, "cpuopt_ignore_memory_aborts"};
|
||||
|
||||
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
|
||||
@@ -456,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`
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include "common/common_types.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
@@ -69,7 +70,7 @@ public:
|
||||
explicit Barrier(std::size_t count_) : count(count_) {}
|
||||
|
||||
/// Blocks until all "count" threads have called Sync()
|
||||
void Sync() {
|
||||
bool Sync(std::stop_token token = {}) {
|
||||
std::unique_lock lk{mutex};
|
||||
const std::size_t current_generation = generation;
|
||||
|
||||
@@ -77,14 +78,16 @@ public:
|
||||
generation++;
|
||||
waiting = 0;
|
||||
condvar.notify_all();
|
||||
return true;
|
||||
} else {
|
||||
condvar.wait(lk,
|
||||
[this, current_generation] { return current_generation != generation; });
|
||||
CondvarWait(condvar, lk, token,
|
||||
[this, current_generation] { return current_generation != generation; });
|
||||
return !token.stop_requested();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::condition_variable condvar;
|
||||
std::condition_variable_any condvar;
|
||||
std::mutex mutex;
|
||||
std::size_t count;
|
||||
std::size_t waiting = 0;
|
||||
|
||||
@@ -528,6 +528,8 @@ add_library(core STATIC
|
||||
hle/service/mnpp/mnpp_app.h
|
||||
hle/service/ncm/ncm.cpp
|
||||
hle/service/ncm/ncm.h
|
||||
hle/service/nfc/mifare_user.cpp
|
||||
hle/service/nfc/mifare_user.h
|
||||
hle/service/nfc/nfc.cpp
|
||||
hle/service/nfc/nfc.h
|
||||
hle/service/nfc/nfc_device.cpp
|
||||
@@ -824,7 +826,7 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
hle/service/jit/jit.cpp
|
||||
hle/service/jit/jit.h
|
||||
)
|
||||
target_link_libraries(core PRIVATE dynarmic)
|
||||
target_link_libraries(core PRIVATE dynarmic::dynarmic)
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
|
||||
@@ -145,11 +145,15 @@ void ARM_Interface::Run() {
|
||||
// Notify the debugger and go to sleep if a breakpoint was hit,
|
||||
// or if the thread is unable to continue for any reason.
|
||||
if (Has(hr, breakpoint) || Has(hr, no_execute)) {
|
||||
RewindBreakpointInstruction();
|
||||
if (!Has(hr, no_execute)) {
|
||||
RewindBreakpointInstruction();
|
||||
}
|
||||
if (system.DebuggerEnabled()) {
|
||||
system.GetDebugger().NotifyThreadStopped(current_thread);
|
||||
} else {
|
||||
LogBacktrace();
|
||||
}
|
||||
current_thread->RequestSuspend(Kernel::SuspendType::Debug);
|
||||
current_thread->RequestSuspend(SuspendType::Debug);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,9 @@ class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
||||
public:
|
||||
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
|
||||
: parent{parent_},
|
||||
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {}
|
||||
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()},
|
||||
check_memory_access{debugger_enabled ||
|
||||
!Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
|
||||
|
||||
u8 MemoryRead8(u32 vaddr) override {
|
||||
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
|
||||
@@ -154,6 +156,17 @@ public:
|
||||
}
|
||||
|
||||
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
|
||||
if (!check_memory_access) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!memory.IsValidVirtualAddressRange(addr, size)) {
|
||||
LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
|
||||
addr);
|
||||
parent.jit.load()->HaltExecution(ARM_Interface::no_execute);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!debugger_enabled) {
|
||||
return true;
|
||||
}
|
||||
@@ -181,7 +194,8 @@ public:
|
||||
ARM_Dynarmic_32& parent;
|
||||
Core::Memory::Memory& memory;
|
||||
std::size_t num_interpreted_instructions{};
|
||||
bool debugger_enabled{};
|
||||
const bool debugger_enabled{};
|
||||
const bool check_memory_access{};
|
||||
static constexpr u64 minimum_run_cycles = 10000U;
|
||||
};
|
||||
|
||||
@@ -264,6 +278,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
|
||||
if (!Settings::values.cpuopt_recompile_exclusives) {
|
||||
config.recompile_on_exclusive_fastmem_failure = false;
|
||||
}
|
||||
if (!Settings::values.cpuopt_ignore_memory_aborts) {
|
||||
config.check_halt_on_memory_access = true;
|
||||
}
|
||||
} else {
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
|
||||
|
||||
@@ -29,7 +29,9 @@ class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
|
||||
public:
|
||||
explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_)
|
||||
: parent{parent_},
|
||||
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {}
|
||||
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()},
|
||||
check_memory_access{debugger_enabled ||
|
||||
!Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
|
||||
|
||||
u8 MemoryRead8(u64 vaddr) override {
|
||||
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
|
||||
@@ -198,6 +200,17 @@ public:
|
||||
}
|
||||
|
||||
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
|
||||
if (!check_memory_access) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!memory.IsValidVirtualAddressRange(addr, size)) {
|
||||
LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
|
||||
addr);
|
||||
parent.jit.load()->HaltExecution(ARM_Interface::no_execute);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!debugger_enabled) {
|
||||
return true;
|
||||
}
|
||||
@@ -226,7 +239,8 @@ public:
|
||||
Core::Memory::Memory& memory;
|
||||
u64 tpidrro_el0 = 0;
|
||||
u64 tpidr_el0 = 0;
|
||||
bool debugger_enabled{};
|
||||
const bool debugger_enabled{};
|
||||
const bool check_memory_access{};
|
||||
static constexpr u64 minimum_run_cycles = 10000U;
|
||||
};
|
||||
|
||||
@@ -323,6 +337,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
|
||||
if (!Settings::values.cpuopt_recompile_exclusives) {
|
||||
config.recompile_on_exclusive_fastmem_failure = false;
|
||||
}
|
||||
if (!Settings::values.cpuopt_ignore_memory_aborts) {
|
||||
config.check_halt_on_memory_access = true;
|
||||
}
|
||||
} else {
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
|
||||
|
||||
@@ -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 {
|
||||
@@ -389,7 +383,9 @@ struct System::Impl {
|
||||
kernel.ShutdownCores();
|
||||
cpu_manager.Shutdown();
|
||||
debugger.reset();
|
||||
services->KillNVNFlinger();
|
||||
if (services) {
|
||||
services->KillNVNFlinger();
|
||||
}
|
||||
kernel.CloseServices();
|
||||
services.reset();
|
||||
service_manager.reset();
|
||||
@@ -551,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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -20,23 +20,20 @@ namespace Core {
|
||||
CpuManager::CpuManager(System& system_) : system{system_} {}
|
||||
CpuManager::~CpuManager() = default;
|
||||
|
||||
void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager,
|
||||
std::size_t core) {
|
||||
cpu_manager.RunThread(core);
|
||||
}
|
||||
|
||||
void CpuManager::Initialize() {
|
||||
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
|
||||
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
|
||||
|
||||
for (std::size_t core = 0; core < num_cores; core++) {
|
||||
core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core);
|
||||
core_data[core].host_thread =
|
||||
std::jthread([this, core](std::stop_token token) { RunThread(token, core); });
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::Shutdown() {
|
||||
for (std::size_t core = 0; core < num_cores; core++) {
|
||||
if (core_data[core].host_thread.joinable()) {
|
||||
core_data[core].host_thread.request_stop();
|
||||
core_data[core].host_thread.join();
|
||||
}
|
||||
}
|
||||
@@ -184,7 +181,7 @@ void CpuManager::ShutdownThread() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void CpuManager::RunThread(std::size_t core) {
|
||||
void CpuManager::RunThread(std::stop_token token, std::size_t core) {
|
||||
/// Initialization
|
||||
system.RegisterCoreThread(core);
|
||||
std::string name;
|
||||
@@ -206,7 +203,9 @@ void CpuManager::RunThread(std::size_t core) {
|
||||
});
|
||||
|
||||
// Running
|
||||
gpu_barrier->Sync();
|
||||
if (!gpu_barrier->Sync(token)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_async_gpu && !is_multicore) {
|
||||
system.GPU().ObtainContext();
|
||||
|
||||
@@ -81,12 +81,10 @@ private:
|
||||
void SingleCoreRunGuestThread();
|
||||
void SingleCoreRunIdleThread();
|
||||
|
||||
static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core);
|
||||
|
||||
void GuestActivate();
|
||||
void HandleInterrupt();
|
||||
void ShutdownThread();
|
||||
void RunThread(std::size_t core);
|
||||
void RunThread(std::stop_token stop_token, std::size_t core);
|
||||
|
||||
struct CoreData {
|
||||
std::shared_ptr<Common::Fiber> host_context;
|
||||
|
||||
@@ -16,7 +16,7 @@ DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_
|
||||
|
||||
DefaultControllerApplet::~DefaultControllerApplet() = default;
|
||||
|
||||
void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
|
||||
void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callback,
|
||||
const ControllerParameters& parameters) const {
|
||||
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
|
||||
|
||||
|
||||
@@ -36,9 +36,11 @@ struct ControllerParameters {
|
||||
|
||||
class ControllerApplet {
|
||||
public:
|
||||
using ReconfigureCallback = std::function<void()>;
|
||||
|
||||
virtual ~ControllerApplet();
|
||||
|
||||
virtual void ReconfigureControllers(std::function<void()> callback,
|
||||
virtual void ReconfigureControllers(ReconfigureCallback callback,
|
||||
const ControllerParameters& parameters) const = 0;
|
||||
};
|
||||
|
||||
@@ -47,7 +49,7 @@ public:
|
||||
explicit DefaultControllerApplet(HID::HIDCore& hid_core_);
|
||||
~DefaultControllerApplet() override;
|
||||
|
||||
void ReconfigureControllers(std::function<void()> callback,
|
||||
void ReconfigureControllers(ReconfigureCallback callback,
|
||||
const ControllerParameters& parameters) const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -8,13 +8,13 @@ namespace Core::Frontend {
|
||||
|
||||
ErrorApplet::~ErrorApplet() = default;
|
||||
|
||||
void DefaultErrorApplet::ShowError(Result error, std::function<void()> finished) const {
|
||||
void DefaultErrorApplet::ShowError(Result error, FinishedCallback finished) const {
|
||||
LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",
|
||||
error.module.Value(), error.description.Value(), error.raw);
|
||||
}
|
||||
|
||||
void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
|
||||
std::function<void()> finished) const {
|
||||
FinishedCallback finished) const {
|
||||
LOG_CRITICAL(
|
||||
Service_Fatal,
|
||||
"Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}",
|
||||
@@ -23,7 +23,7 @@ void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::secon
|
||||
|
||||
void DefaultErrorApplet::ShowCustomErrorText(Result error, std::string main_text,
|
||||
std::string detail_text,
|
||||
std::function<void()> finished) const {
|
||||
FinishedCallback finished) const {
|
||||
LOG_CRITICAL(Service_Fatal,
|
||||
"Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})",
|
||||
error.module.Value(), error.description.Value(), error.raw);
|
||||
|
||||
@@ -12,25 +12,27 @@ namespace Core::Frontend {
|
||||
|
||||
class ErrorApplet {
|
||||
public:
|
||||
using FinishedCallback = std::function<void()>;
|
||||
|
||||
virtual ~ErrorApplet();
|
||||
|
||||
virtual void ShowError(Result error, std::function<void()> finished) const = 0;
|
||||
virtual void ShowError(Result error, FinishedCallback finished) const = 0;
|
||||
|
||||
virtual void ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
|
||||
std::function<void()> finished) const = 0;
|
||||
FinishedCallback finished) const = 0;
|
||||
|
||||
virtual void ShowCustomErrorText(Result error, std::string dialog_text,
|
||||
std::string fullscreen_text,
|
||||
std::function<void()> finished) const = 0;
|
||||
FinishedCallback finished) const = 0;
|
||||
};
|
||||
|
||||
class DefaultErrorApplet final : public ErrorApplet {
|
||||
public:
|
||||
void ShowError(Result error, std::function<void()> finished) const override;
|
||||
void ShowError(Result error, FinishedCallback finished) const override;
|
||||
void ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
|
||||
std::function<void()> finished) const override;
|
||||
FinishedCallback finished) const override;
|
||||
void ShowCustomErrorText(Result error, std::string main_text, std::string detail_text,
|
||||
std::function<void()> finished) const override;
|
||||
FinishedCallback finished) const override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Core::Frontend {
|
||||
|
||||
MiiEditApplet::~MiiEditApplet() = default;
|
||||
|
||||
void DefaultMiiEditApplet::ShowMiiEdit(const std::function<void()>& callback) const {
|
||||
void DefaultMiiEditApplet::ShowMiiEdit(const MiiEditCallback& callback) const {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
callback();
|
||||
|
||||
@@ -9,14 +9,16 @@ namespace Core::Frontend {
|
||||
|
||||
class MiiEditApplet {
|
||||
public:
|
||||
using MiiEditCallback = std::function<void()>;
|
||||
|
||||
virtual ~MiiEditApplet();
|
||||
|
||||
virtual void ShowMiiEdit(const std::function<void()>& callback) const = 0;
|
||||
virtual void ShowMiiEdit(const MiiEditCallback& callback) const = 0;
|
||||
};
|
||||
|
||||
class DefaultMiiEditApplet final : public MiiEditApplet {
|
||||
public:
|
||||
void ShowMiiEdit(const std::function<void()>& callback) const override;
|
||||
void ShowMiiEdit(const MiiEditCallback& callback) const override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -9,8 +9,7 @@ namespace Core::Frontend {
|
||||
|
||||
ProfileSelectApplet::~ProfileSelectApplet() = default;
|
||||
|
||||
void DefaultProfileSelectApplet::SelectProfile(
|
||||
std::function<void(std::optional<Common::UUID>)> callback) const {
|
||||
void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback) const {
|
||||
Service::Account::ProfileManager manager;
|
||||
callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));
|
||||
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
|
||||
|
||||
@@ -11,14 +11,16 @@ namespace Core::Frontend {
|
||||
|
||||
class ProfileSelectApplet {
|
||||
public:
|
||||
using SelectProfileCallback = std::function<void(std::optional<Common::UUID>)>;
|
||||
|
||||
virtual ~ProfileSelectApplet();
|
||||
|
||||
virtual void SelectProfile(std::function<void(std::optional<Common::UUID>)> callback) const = 0;
|
||||
virtual void SelectProfile(SelectProfileCallback callback) const = 0;
|
||||
};
|
||||
|
||||
class DefaultProfileSelectApplet final : public ProfileSelectApplet {
|
||||
public:
|
||||
void SelectProfile(std::function<void(std::optional<Common::UUID>)> callback) const override;
|
||||
void SelectProfile(SelectProfileCallback callback) const override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -15,10 +15,7 @@ DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
|
||||
|
||||
void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
|
||||
bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) {
|
||||
SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) {
|
||||
if (is_inline) {
|
||||
LOG_WARNING(
|
||||
Service_AM,
|
||||
|
||||
@@ -54,14 +54,17 @@ struct InlineTextParameters {
|
||||
|
||||
class SoftwareKeyboardApplet {
|
||||
public:
|
||||
using SubmitInlineCallback =
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>;
|
||||
using SubmitNormalCallback =
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>;
|
||||
|
||||
virtual ~SoftwareKeyboardApplet();
|
||||
|
||||
virtual void InitializeKeyboard(
|
||||
bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) = 0;
|
||||
virtual void InitializeKeyboard(bool is_inline,
|
||||
KeyboardInitializeParameters initialize_parameters,
|
||||
SubmitNormalCallback submit_normal_callback_,
|
||||
SubmitInlineCallback submit_inline_callback_) = 0;
|
||||
|
||||
virtual void ShowNormalKeyboard() const = 0;
|
||||
|
||||
@@ -81,12 +84,9 @@ class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
|
||||
public:
|
||||
~DefaultSoftwareKeyboardApplet() override;
|
||||
|
||||
void InitializeKeyboard(
|
||||
bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) override;
|
||||
void InitializeKeyboard(bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
SubmitNormalCallback submit_normal_callback_,
|
||||
SubmitInlineCallback submit_inline_callback_) override;
|
||||
|
||||
void ShowNormalKeyboard() const override;
|
||||
|
||||
@@ -105,12 +105,10 @@ private:
|
||||
void SubmitNormalText(std::u16string text) const;
|
||||
void SubmitInlineText(std::u16string_view text) const;
|
||||
|
||||
KeyboardInitializeParameters parameters;
|
||||
KeyboardInitializeParameters parameters{};
|
||||
|
||||
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback;
|
||||
mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback;
|
||||
mutable SubmitNormalCallback submit_normal_callback;
|
||||
mutable SubmitInlineCallback submit_inline_callback;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -10,18 +10,17 @@ WebBrowserApplet::~WebBrowserApplet() = default;
|
||||
|
||||
DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
|
||||
|
||||
void DefaultWebBrowserApplet::OpenLocalWebPage(
|
||||
const std::string& local_url, std::function<void()> extract_romfs_callback,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
|
||||
void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url,
|
||||
ExtractROMFSCallback extract_romfs_callback,
|
||||
OpenWebPageCallback callback) const {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
|
||||
local_url);
|
||||
|
||||
callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");
|
||||
}
|
||||
|
||||
void DefaultWebBrowserApplet::OpenExternalWebPage(
|
||||
const std::string& external_url,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
|
||||
void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url,
|
||||
OpenWebPageCallback callback) const {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
|
||||
external_url);
|
||||
|
||||
|
||||
@@ -11,29 +11,29 @@ namespace Core::Frontend {
|
||||
|
||||
class WebBrowserApplet {
|
||||
public:
|
||||
using ExtractROMFSCallback = std::function<void()>;
|
||||
using OpenWebPageCallback =
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)>;
|
||||
|
||||
virtual ~WebBrowserApplet();
|
||||
|
||||
virtual void OpenLocalWebPage(
|
||||
const std::string& local_url, std::function<void()> extract_romfs_callback,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
|
||||
virtual void OpenLocalWebPage(const std::string& local_url,
|
||||
ExtractROMFSCallback extract_romfs_callback,
|
||||
OpenWebPageCallback callback) const = 0;
|
||||
|
||||
virtual void OpenExternalWebPage(
|
||||
const std::string& external_url,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
|
||||
virtual void OpenExternalWebPage(const std::string& external_url,
|
||||
OpenWebPageCallback callback) const = 0;
|
||||
};
|
||||
|
||||
class DefaultWebBrowserApplet final : public WebBrowserApplet {
|
||||
public:
|
||||
~DefaultWebBrowserApplet() override;
|
||||
|
||||
void OpenLocalWebPage(const std::string& local_url,
|
||||
std::function<void()> extract_romfs_callback,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
|
||||
callback) const override;
|
||||
void OpenLocalWebPage(const std::string& local_url, ExtractROMFSCallback extract_romfs_callback,
|
||||
OpenWebPageCallback callback) const override;
|
||||
|
||||
void OpenExternalWebPage(const std::string& external_url,
|
||||
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
|
||||
callback) const override;
|
||||
OpenWebPageCallback callback) const override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -131,6 +131,10 @@ public:
|
||||
return active_config;
|
||||
}
|
||||
|
||||
bool StrictContextRequired() const {
|
||||
return strict_context_required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the internal configuration to be replaced by the specified argument at some point in
|
||||
* the future.
|
||||
@@ -207,6 +211,8 @@ protected:
|
||||
|
||||
WindowSystemInfo window_info;
|
||||
|
||||
bool strict_context_required = false;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handler called when the minimal client area was requested to be changed via SetConfig.
|
||||
|
||||
@@ -37,7 +37,7 @@ void EmulatedConsole::SetTouchParams() {
|
||||
touchscreen_param.Set("axis_x", i * 2);
|
||||
touchscreen_param.Set("axis_y", (i * 2) + 1);
|
||||
touchscreen_param.Set("button", i);
|
||||
touch_params[index++] = touchscreen_param;
|
||||
touch_params[index++] = std::move(touchscreen_param);
|
||||
}
|
||||
|
||||
const auto button_index =
|
||||
@@ -59,7 +59,7 @@ void EmulatedConsole::SetTouchParams() {
|
||||
touch_button_params.Set("button", params.Serialize());
|
||||
touch_button_params.Set("x", x);
|
||||
touch_button_params.Set("y", y);
|
||||
touch_params[index] = touch_button_params;
|
||||
touch_params[index] = std::move(touch_button_params);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ Common::ParamPackage EmulatedConsole::GetMotionParam() const {
|
||||
}
|
||||
|
||||
void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
|
||||
motion_params = param;
|
||||
motion_params = std::move(param);
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
|
||||
|
||||
if (is_new_input) {
|
||||
touch_value.pressed.value = true;
|
||||
touch_value.id = static_cast<u32>(index);
|
||||
touch_value.id = static_cast<int>(index);
|
||||
}
|
||||
|
||||
touch_value.x = touch_input.x;
|
||||
@@ -284,7 +284,7 @@ void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
|
||||
|
||||
int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
callback_list.insert_or_assign(last_callback_key, update_callback);
|
||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
|
||||
@@ -424,15 +424,14 @@ void EmulatedController::RestoreConfig() {
|
||||
ReloadFromSettings();
|
||||
}
|
||||
|
||||
std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices(
|
||||
EmulatedDeviceIndex device_index) const {
|
||||
std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices() const {
|
||||
std::vector<Common::ParamPackage> devices;
|
||||
for (const auto& param : button_params) {
|
||||
if (!param.Has("engine")) {
|
||||
continue;
|
||||
}
|
||||
const auto devices_it = std::find_if(
|
||||
devices.begin(), devices.end(), [param](const Common::ParamPackage param_) {
|
||||
devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {
|
||||
return param.Get("engine", "") == param_.Get("engine", "") &&
|
||||
param.Get("guid", "") == param_.Get("guid", "") &&
|
||||
param.Get("port", 0) == param_.Get("port", 0) &&
|
||||
@@ -441,12 +440,12 @@ std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices(
|
||||
if (devices_it != devices.end()) {
|
||||
continue;
|
||||
}
|
||||
Common::ParamPackage device{};
|
||||
|
||||
auto& device = devices.emplace_back();
|
||||
device.Set("engine", param.Get("engine", ""));
|
||||
device.Set("guid", param.Get("guid", ""));
|
||||
device.Set("port", param.Get("port", 0));
|
||||
device.Set("pad", param.Get("pad", 0));
|
||||
devices.push_back(device);
|
||||
}
|
||||
|
||||
for (const auto& param : stick_params) {
|
||||
@@ -457,7 +456,7 @@ std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices(
|
||||
continue;
|
||||
}
|
||||
const auto devices_it = std::find_if(
|
||||
devices.begin(), devices.end(), [param](const Common::ParamPackage param_) {
|
||||
devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {
|
||||
return param.Get("engine", "") == param_.Get("engine", "") &&
|
||||
param.Get("guid", "") == param_.Get("guid", "") &&
|
||||
param.Get("port", 0) == param_.Get("port", 0) &&
|
||||
@@ -466,12 +465,12 @@ std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices(
|
||||
if (devices_it != devices.end()) {
|
||||
continue;
|
||||
}
|
||||
Common::ParamPackage device{};
|
||||
|
||||
auto& device = devices.emplace_back();
|
||||
device.Set("engine", param.Get("engine", ""));
|
||||
device.Set("guid", param.Get("guid", ""));
|
||||
device.Set("port", param.Get("port", 0));
|
||||
device.Set("pad", param.Get("pad", 0));
|
||||
devices.push_back(device);
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ public:
|
||||
void RestoreConfig();
|
||||
|
||||
/// Returns a vector of mapped devices from the mapped button and stick parameters
|
||||
std::vector<Common::ParamPackage> GetMappedDevices(EmulatedDeviceIndex device_index) const;
|
||||
std::vector<Common::ParamPackage> GetMappedDevices() const;
|
||||
|
||||
// Returns the current mapped button device
|
||||
Common::ParamPackage GetButtonParam(std::size_t index) const;
|
||||
|
||||
@@ -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>());
|
||||
}
|
||||
@@ -318,25 +326,23 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa
|
||||
}
|
||||
|
||||
std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
|
||||
std::vector<u8> buffer{};
|
||||
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
|
||||
BufferDescriptorA()[buffer_index].Size()};
|
||||
|
||||
if (is_buffer_a) {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorA().size() > buffer_index, { return buffer; },
|
||||
BufferDescriptorA().size() > buffer_index, { return {}; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
buffer.resize(BufferDescriptorA()[buffer_index].Size());
|
||||
std::vector<u8> buffer(BufferDescriptorA()[buffer_index].Size());
|
||||
memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
|
||||
return buffer;
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorX().size() > buffer_index, { return buffer; },
|
||||
BufferDescriptorX().size() > buffer_index, { return {}; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
buffer.resize(BufferDescriptorX()[buffer_index].Size());
|
||||
std::vector<u8> buffer(BufferDescriptorX()[buffer_index].Size());
|
||||
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
|
||||
|
||||
@@ -280,18 +280,19 @@ struct KMemoryInfo {
|
||||
|
||||
class KMemoryBlock : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock> {
|
||||
private:
|
||||
u16 m_device_disable_merge_left_count;
|
||||
u16 m_device_disable_merge_right_count;
|
||||
VAddr m_address;
|
||||
size_t m_num_pages;
|
||||
KMemoryState m_memory_state;
|
||||
u16 m_ipc_lock_count;
|
||||
u16 m_device_use_count;
|
||||
u16 m_ipc_disable_merge_count;
|
||||
KMemoryPermission m_permission;
|
||||
KMemoryPermission m_original_permission;
|
||||
KMemoryAttribute m_attribute;
|
||||
KMemoryBlockDisableMergeAttribute m_disable_merge_attribute;
|
||||
u16 m_device_disable_merge_left_count{};
|
||||
u16 m_device_disable_merge_right_count{};
|
||||
VAddr m_address{};
|
||||
size_t m_num_pages{};
|
||||
KMemoryState m_memory_state{KMemoryState::None};
|
||||
u16 m_ipc_lock_count{};
|
||||
u16 m_device_use_count{};
|
||||
u16 m_ipc_disable_merge_count{};
|
||||
KMemoryPermission m_permission{KMemoryPermission::None};
|
||||
KMemoryPermission m_original_permission{KMemoryPermission::None};
|
||||
KMemoryAttribute m_attribute{KMemoryAttribute::None};
|
||||
KMemoryBlockDisableMergeAttribute m_disable_merge_attribute{
|
||||
KMemoryBlockDisableMergeAttribute::None};
|
||||
|
||||
public:
|
||||
static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) {
|
||||
@@ -367,12 +368,8 @@ public:
|
||||
|
||||
constexpr KMemoryBlock(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,
|
||||
KMemoryAttribute attr)
|
||||
: Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(),
|
||||
m_device_disable_merge_left_count(), m_device_disable_merge_right_count(),
|
||||
m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0),
|
||||
m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p),
|
||||
m_original_permission(KMemoryPermission::None), m_attribute(attr),
|
||||
m_disable_merge_attribute() {}
|
||||
: Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(), m_address(addr), m_num_pages(np),
|
||||
m_memory_state(ms), m_permission(p), m_attribute(attr) {}
|
||||
|
||||
constexpr void Initialize(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,
|
||||
KMemoryAttribute attr) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
@@ -17,9 +18,9 @@ public:
|
||||
static constexpr size_t MaxBlocks = 2;
|
||||
|
||||
private:
|
||||
KMemoryBlock* m_blocks[MaxBlocks];
|
||||
size_t m_index;
|
||||
KMemoryBlockSlabManager* m_slab_manager;
|
||||
std::array<KMemoryBlock*, MaxBlocks> m_blocks{};
|
||||
size_t m_index{MaxBlocks};
|
||||
KMemoryBlockSlabManager* m_slab_manager{};
|
||||
|
||||
private:
|
||||
Result Initialize(size_t num_blocks) {
|
||||
@@ -41,7 +42,7 @@ private:
|
||||
public:
|
||||
KMemoryBlockManagerUpdateAllocator(Result* out_result, KMemoryBlockSlabManager* sm,
|
||||
size_t num_blocks = MaxBlocks)
|
||||
: m_blocks(), m_index(MaxBlocks), m_slab_manager(sm) {
|
||||
: m_slab_manager(sm) {
|
||||
*out_result = this->Initialize(num_blocks);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||
|
||||
private:
|
||||
Core::DeviceMemory* device_memory;
|
||||
Core::DeviceMemory* device_memory{};
|
||||
KProcess* owner_process{};
|
||||
KPageGroup page_list;
|
||||
Svc::MemoryPermission owner_permission{};
|
||||
|
||||
@@ -784,8 +784,8 @@ private:
|
||||
std::vector<KSynchronizationObject*> wait_objects_for_debugging;
|
||||
VAddr mutex_wait_address_for_debugging{};
|
||||
ThreadWaitReasonForDebugging wait_reason_for_debugging{};
|
||||
uintptr_t argument;
|
||||
VAddr stack_top;
|
||||
uintptr_t argument{};
|
||||
VAddr stack_top{};
|
||||
|
||||
public:
|
||||
using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
|
||||
|
||||
@@ -104,12 +104,16 @@ struct KernelCore::Impl {
|
||||
}
|
||||
|
||||
void CloseCurrentProcess() {
|
||||
(*current_process).Finalize();
|
||||
// current_process->Close();
|
||||
// TODO: The current process should be destroyed based on accurate ref counting after
|
||||
KProcess* old_process = current_process.exchange(nullptr);
|
||||
if (old_process == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// old_process->Close();
|
||||
// TODO: The process should be destroyed based on accurate ref counting after
|
||||
// calling Close(). Adding a manual Destroy() call instead to avoid a memory leak.
|
||||
(*current_process).Destroy();
|
||||
current_process = nullptr;
|
||||
old_process->Finalize();
|
||||
old_process->Destroy();
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
@@ -891,7 +895,7 @@ struct KernelCore::Impl {
|
||||
Common::ThreadWorker service_threads_manager;
|
||||
Common::Barrier service_thread_barrier;
|
||||
|
||||
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
|
||||
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads{};
|
||||
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
||||
|
||||
bool is_multicore{};
|
||||
|
||||
@@ -85,7 +85,7 @@ private:
|
||||
std::mutex guard;
|
||||
std::condition_variable on_interrupt;
|
||||
std::unique_ptr<Core::ARM_Interface> arm_interface;
|
||||
bool is_interrupted;
|
||||
bool is_interrupted{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -163,9 +163,6 @@ ServiceThread::Impl::~Impl() {
|
||||
m_wakeup_event->Signal();
|
||||
m_host_thread.join();
|
||||
|
||||
// Lock mutex.
|
||||
m_session_mutex.lock();
|
||||
|
||||
// Close all remaining sessions.
|
||||
for (const auto& [server_session, manager] : m_sessions) {
|
||||
server_session->Close();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
400
src/core/hle/service/nfc/mifare_user.cpp
Normal file
400
src/core/hle/service/nfc/mifare_user.cpp
Normal file
@@ -0,0 +1,400 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/nfc/mifare_user.h"
|
||||
#include "core/hle/service/nfc/nfc_device.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
MFIUser::MFIUser(Core::System& system_)
|
||||
: ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &MFIUser::Initialize, "Initialize"},
|
||||
{1, &MFIUser::Finalize, "Finalize"},
|
||||
{2, &MFIUser::ListDevices, "ListDevices"},
|
||||
{3, &MFIUser::StartDetection, "StartDetection"},
|
||||
{4, &MFIUser::StopDetection, "StopDetection"},
|
||||
{5, &MFIUser::Read, "Read"},
|
||||
{6, &MFIUser::Write, "Write"},
|
||||
{7, &MFIUser::GetTagInfo, "GetTagInfo"},
|
||||
{8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"},
|
||||
{9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"},
|
||||
{10, &MFIUser::GetState, "GetState"},
|
||||
{11, &MFIUser::GetDeviceState, "GetDeviceState"},
|
||||
{12, &MFIUser::GetNpadId, "GetNpadId"},
|
||||
{13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
availability_change_event = service_context.CreateEvent("MFIUser:AvailabilityChangeEvent");
|
||||
|
||||
for (u32 device_index = 0; device_index < 10; device_index++) {
|
||||
devices[device_index] =
|
||||
std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
|
||||
service_context, availability_change_event);
|
||||
}
|
||||
}
|
||||
|
||||
MFIUser ::~MFIUser() {
|
||||
availability_change_event->Close();
|
||||
}
|
||||
|
||||
void MFIUser::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
state = State::Initialized;
|
||||
|
||||
for (auto& device : devices) {
|
||||
device->Initialize();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void MFIUser::Finalize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
state = State::NonInitialized;
|
||||
|
||||
for (auto& device : devices) {
|
||||
device->Finalize();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void MFIUser::ListDevices(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CanWriteBuffer()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareInvalidArgument);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.GetWriteBufferSize() == 0) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareInvalidArgument);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u64> nfp_devices;
|
||||
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
|
||||
|
||||
for (const auto& device : devices) {
|
||||
if (nfp_devices.size() >= max_allowed_devices) {
|
||||
continue;
|
||||
}
|
||||
if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
|
||||
nfp_devices.push_back(device->GetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
if (nfp_devices.empty()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(nfp_devices);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<s32>(nfp_devices.size()));
|
||||
}
|
||||
|
||||
void MFIUser::StartDetection(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto result = device.value()->StartDetection(NFP::TagProtocol::All);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::StopDetection(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto result = device.value()->StopDetection();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::Read(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto buffer{ctx.ReadBuffer()};
|
||||
const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()};
|
||||
std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands);
|
||||
|
||||
memcpy(read_commands.data(), buffer.data(),
|
||||
number_of_commands * sizeof(NFP::MifareReadBlockParameter));
|
||||
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
|
||||
device_handle, number_of_commands);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
Result result = ResultSuccess;
|
||||
std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
|
||||
for (std::size_t i = 0; i < number_of_commands; i++) {
|
||||
result = device.value()->MifareRead(read_commands[i], out_data[i]);
|
||||
if (result.IsError()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(out_data);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::Write(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto buffer{ctx.ReadBuffer()};
|
||||
const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()};
|
||||
std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands);
|
||||
|
||||
memcpy(write_commands.data(), buffer.data(),
|
||||
number_of_commands * sizeof(NFP::MifareWriteBlockParameter));
|
||||
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
|
||||
device_handle, number_of_commands);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
Result result = ResultSuccess;
|
||||
std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
|
||||
for (std::size_t i = 0; i < number_of_commands; i++) {
|
||||
result = device.value()->MifareWrite(write_commands[i]);
|
||||
if (result.IsError()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device.value()->Flush();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::GetTagInfo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
NFP::TagInfo tag_info{};
|
||||
const auto result = device.value()->GetTagInfo(tag_info, true);
|
||||
ctx.WriteBuffer(tag_info);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::GetActivateEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(device.value()->GetActivateEvent());
|
||||
}
|
||||
|
||||
void MFIUser::GetDeactivateEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(device.value()->GetDeactivateEvent());
|
||||
}
|
||||
|
||||
void MFIUser::GetState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(state);
|
||||
}
|
||||
|
||||
void MFIUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(device.value()->GetCurrentState());
|
||||
}
|
||||
|
||||
void MFIUser::GetNpadId(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(device.value()->GetNpadId());
|
||||
}
|
||||
|
||||
void MFIUser::GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(availability_change_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<NfcDevice>> MFIUser::GetNfcDevice(u64 handle) {
|
||||
for (auto& device : devices) {
|
||||
if (device->GetHandle() == handle) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Service::NFC
|
||||
52
src/core/hle/service/nfc/mifare_user.h
Normal file
52
src/core/hle/service/nfc/mifare_user.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
class NfcDevice;
|
||||
|
||||
class MFIUser final : public ServiceFramework<MFIUser> {
|
||||
public:
|
||||
explicit MFIUser(Core::System& system_);
|
||||
~MFIUser();
|
||||
|
||||
private:
|
||||
enum class State : u32 {
|
||||
NonInitialized,
|
||||
Initialized,
|
||||
};
|
||||
|
||||
void Initialize(Kernel::HLERequestContext& ctx);
|
||||
void Finalize(Kernel::HLERequestContext& ctx);
|
||||
void ListDevices(Kernel::HLERequestContext& ctx);
|
||||
void StartDetection(Kernel::HLERequestContext& ctx);
|
||||
void StopDetection(Kernel::HLERequestContext& ctx);
|
||||
void Read(Kernel::HLERequestContext& ctx);
|
||||
void Write(Kernel::HLERequestContext& ctx);
|
||||
void GetTagInfo(Kernel::HLERequestContext& ctx);
|
||||
void GetActivateEventHandle(Kernel::HLERequestContext& ctx);
|
||||
void GetDeactivateEventHandle(Kernel::HLERequestContext& ctx);
|
||||
void GetState(Kernel::HLERequestContext& ctx);
|
||||
void GetDeviceState(Kernel::HLERequestContext& ctx);
|
||||
void GetNpadId(Kernel::HLERequestContext& ctx);
|
||||
void GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
std::array<std::shared_ptr<NfcDevice>, 10> devices{};
|
||||
|
||||
State state{State::NonInitialized};
|
||||
Kernel::KEvent* availability_change_event;
|
||||
};
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/mifare_user.h"
|
||||
#include "core/hle/service/nfc/nfc.h"
|
||||
#include "core/hle/service/nfc/nfc_user.h"
|
||||
#include "core/hle/service/service.h"
|
||||
@@ -50,32 +51,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class MFIUser final : public ServiceFramework<MFIUser> {
|
||||
public:
|
||||
explicit MFIUser(Core::System& system_) : ServiceFramework{system_, "NFC::MFIUser"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Initialize"},
|
||||
{1, nullptr, "Finalize"},
|
||||
{2, nullptr, "ListDevices"},
|
||||
{3, nullptr, "StartDetection"},
|
||||
{4, nullptr, "StopDetection"},
|
||||
{5, nullptr, "Read"},
|
||||
{6, nullptr, "Write"},
|
||||
{7, nullptr, "GetTagInfo"},
|
||||
{8, nullptr, "GetActivateEventHandle"},
|
||||
{9, nullptr, "GetDeactivateEventHandle"},
|
||||
{10, nullptr, "GetState"},
|
||||
{11, nullptr, "GetDeviceState"},
|
||||
{12, nullptr, "GetNpadId"},
|
||||
{13, nullptr, "GetAvailabilityChangeEventHandle"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class NFC_MF_U final : public ServiceFramework<NFC_MF_U> {
|
||||
public:
|
||||
explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} {
|
||||
|
||||
@@ -77,11 +77,13 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.size() != sizeof(NFP::EncryptedNTAG215File)) {
|
||||
if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
|
||||
LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
tag_data.resize(data.size());
|
||||
memcpy(tag_data.data(), data.data(), data.size());
|
||||
memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
|
||||
|
||||
device_state = NFP::DeviceState::TagFound;
|
||||
@@ -121,7 +123,7 @@ void NfcDevice::Finalize() {
|
||||
device_state = NFP::DeviceState::Unavailable;
|
||||
}
|
||||
|
||||
Result NfcDevice::StartDetection(s32 protocol_) {
|
||||
Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) {
|
||||
if (device_state != NFP::DeviceState::Initialized &&
|
||||
device_state != NFP::DeviceState::TagRemoved) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
@@ -134,7 +136,7 @@ Result NfcDevice::StartDetection(s32 protocol_) {
|
||||
}
|
||||
|
||||
device_state = NFP::DeviceState::SearchingForTag;
|
||||
protocol = protocol_;
|
||||
allowed_protocols = allowed_protocol;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
@@ -160,7 +162,7 @@ Result NfcDevice::StopDetection() {
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
|
||||
Result NfcDevice::Flush() {
|
||||
if (device_state != NFP::DeviceState::TagFound &&
|
||||
device_state != NFP::DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
@@ -170,6 +172,34 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
if (!npad_device->WriteNfc(tag_data)) {
|
||||
LOG_ERROR(Service_NFP, "Error writing to file");
|
||||
return MifareReadError;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
|
||||
if (device_state != NFP::DeviceState::TagFound &&
|
||||
device_state != NFP::DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == NFP::DeviceState::TagRemoved) {
|
||||
return TagRemoved;
|
||||
}
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
if (is_mifare) {
|
||||
tag_info = {
|
||||
.uuid = encrypted_tag_data.uuid.uid,
|
||||
.uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
|
||||
.protocol = NFP::TagProtocol::TypeA,
|
||||
.tag_type = NFP::TagType::Type4,
|
||||
};
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
// Protocol and tag type may change here
|
||||
tag_info = {
|
||||
.uuid = encrypted_tag_data.uuid.uid,
|
||||
@@ -181,6 +211,52 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter,
|
||||
NFP::MifareReadBlockData& read_block_data) {
|
||||
const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
|
||||
read_block_data.sector_number = parameter.sector_number;
|
||||
|
||||
if (device_state != NFP::DeviceState::TagFound &&
|
||||
device_state != NFP::DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == NFP::DeviceState::TagRemoved) {
|
||||
return TagRemoved;
|
||||
}
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
|
||||
return MifareReadError;
|
||||
}
|
||||
|
||||
// TODO: Use parameter.sector_key to read encrypted data
|
||||
memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) {
|
||||
const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
|
||||
|
||||
if (device_state != NFP::DeviceState::TagFound &&
|
||||
device_state != NFP::DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == NFP::DeviceState::TagRemoved) {
|
||||
return TagRemoved;
|
||||
}
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
|
||||
return MifareReadError;
|
||||
}
|
||||
|
||||
// TODO: Use parameter.sector_key to encrypt the data
|
||||
memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
u64 NfcDevice::GetHandle() const {
|
||||
// Generate a handle based of the npad id
|
||||
return static_cast<u64>(npad_id);
|
||||
|
||||
@@ -34,10 +34,16 @@ public:
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
Result StartDetection(s32 protocol_);
|
||||
Result StartDetection(NFP::TagProtocol allowed_protocol);
|
||||
Result StopDetection();
|
||||
Result Flush();
|
||||
|
||||
Result GetTagInfo(NFP::TagInfo& tag_info) const;
|
||||
Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const;
|
||||
|
||||
Result MifareRead(const NFP::MifareReadBlockParameter& parameter,
|
||||
NFP::MifareReadBlockData& read_block_data);
|
||||
|
||||
Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter);
|
||||
|
||||
u64 GetHandle() const;
|
||||
NFP::DeviceState GetCurrentState() const;
|
||||
@@ -61,10 +67,11 @@ private:
|
||||
Kernel::KEvent* deactivate_event = nullptr;
|
||||
Kernel::KEvent* availability_change_event = nullptr;
|
||||
|
||||
s32 protocol{};
|
||||
NFP::TagProtocol allowed_protocols{};
|
||||
NFP::DeviceState device_state{NFP::DeviceState::Unavailable};
|
||||
|
||||
NFP::EncryptedNTAG215File encrypted_tag_data{};
|
||||
std::vector<u8> tag_data{};
|
||||
};
|
||||
|
||||
} // namespace Service::NFC
|
||||
|
||||
@@ -12,6 +12,12 @@ constexpr Result InvalidArgument(ErrorModule::NFC, 65);
|
||||
constexpr Result WrongDeviceState(ErrorModule::NFC, 73);
|
||||
constexpr Result NfcDisabled(ErrorModule::NFC, 80);
|
||||
constexpr Result TagRemoved(ErrorModule::NFC, 97);
|
||||
constexpr Result CorruptedData(ErrorModule::NFC, 144);
|
||||
|
||||
constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64);
|
||||
constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65);
|
||||
constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73);
|
||||
constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80);
|
||||
constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97);
|
||||
constexpr Result MifareReadError(ErrorModule::NFCMifare, 288);
|
||||
|
||||
} // namespace Service::NFC
|
||||
|
||||
@@ -201,7 +201,7 @@ void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
|
||||
void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto nfp_protocol{rp.Pop<s32>()};
|
||||
const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
@@ -267,7 +267,7 @@ void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
NFP::TagInfo tag_info{};
|
||||
const auto result = device.value()->GetTagInfo(tag_info);
|
||||
const auto result = device.value()->GetTagInfo(tag_info, false);
|
||||
ctx.WriteBuffer(tag_info);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
|
||||
@@ -106,11 +106,24 @@ enum class CabinetMode : u8 {
|
||||
StartFormatter,
|
||||
};
|
||||
|
||||
enum class MifareCmd : u8 {
|
||||
AuthA = 0x60,
|
||||
AuthB = 0x61,
|
||||
Read = 0x30,
|
||||
Write = 0xA0,
|
||||
Transfer = 0xB0,
|
||||
Decrement = 0xC0,
|
||||
Increment = 0xC1,
|
||||
Store = 0xC2
|
||||
};
|
||||
|
||||
using UniqueSerialNumber = std::array<u8, 7>;
|
||||
using LockBytes = std::array<u8, 2>;
|
||||
using HashData = std::array<u8, 0x20>;
|
||||
using ApplicationArea = std::array<u8, 0xD8>;
|
||||
using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
|
||||
using DataBlock = std::array<u8, 0x10>;
|
||||
using KeyData = std::array<u8, 0x6>;
|
||||
|
||||
struct TagUuid {
|
||||
UniqueSerialNumber uid;
|
||||
@@ -323,4 +336,37 @@ struct RegisterInfo {
|
||||
};
|
||||
static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size");
|
||||
|
||||
struct SectorKey {
|
||||
MifareCmd command;
|
||||
u8 unknown; // Usually 1
|
||||
INSERT_PADDING_BYTES(0x6);
|
||||
KeyData sector_key;
|
||||
INSERT_PADDING_BYTES(0x2);
|
||||
};
|
||||
static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
|
||||
|
||||
struct MifareReadBlockParameter {
|
||||
u8 sector_number;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
SectorKey sector_key;
|
||||
};
|
||||
static_assert(sizeof(MifareReadBlockParameter) == 0x18,
|
||||
"MifareReadBlockParameter is an invalid size");
|
||||
|
||||
struct MifareReadBlockData {
|
||||
DataBlock data;
|
||||
u8 sector_number;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
};
|
||||
static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
|
||||
|
||||
struct MifareWriteBlockParameter {
|
||||
DataBlock data;
|
||||
u8 sector_number;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
SectorKey sector_key;
|
||||
};
|
||||
static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
|
||||
"MifareWriteBlockParameter is an invalid size");
|
||||
|
||||
} // namespace Service::NFP
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/atomic_ops.h"
|
||||
#include "common/cache_management.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/page_table.h"
|
||||
@@ -195,13 +194,11 @@ struct Memory::Impl {
|
||||
break;
|
||||
}
|
||||
case Common::PageType::Memory: {
|
||||
DEBUG_ASSERT(pointer);
|
||||
u8* mem_ptr = pointer + page_offset + (page_index << YUZU_PAGEBITS);
|
||||
on_memory(copy_amount, mem_ptr);
|
||||
break;
|
||||
}
|
||||
case Common::PageType::DebugMemory: {
|
||||
DEBUG_ASSERT(pointer);
|
||||
u8* const mem_ptr{GetPointerFromDebugMemory(current_vaddr)};
|
||||
on_memory(copy_amount, mem_ptr);
|
||||
break;
|
||||
@@ -342,10 +339,9 @@ struct Memory::Impl {
|
||||
LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr);
|
||||
throw InvalidMemoryException();
|
||||
},
|
||||
[&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); },
|
||||
[&](const std::size_t block_size, u8* const host_ptr) {},
|
||||
[&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) {
|
||||
system.GPU().FlushRegion(current_vaddr, block_size);
|
||||
cb(block_size, host_ptr);
|
||||
cb(current_vaddr, block_size);
|
||||
},
|
||||
[](const std::size_t block_size) {});
|
||||
} catch (InvalidMemoryException&) {
|
||||
@@ -356,27 +352,30 @@ struct Memory::Impl {
|
||||
}
|
||||
|
||||
Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
|
||||
auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
|
||||
// Do nothing; this operation (dc ivac) cannot be supported
|
||||
// from EL0
|
||||
auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) {
|
||||
// dc ivac: Invalidate to point of coherency
|
||||
// GPU flush -> CPU invalidate
|
||||
system.GPU().FlushRegion(current_vaddr, block_size);
|
||||
};
|
||||
return PerformCacheOperation(process, dest_addr, size, perform);
|
||||
return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
|
||||
}
|
||||
|
||||
Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
|
||||
auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
|
||||
auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) {
|
||||
// dc cvac: Store to point of coherency
|
||||
Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size);
|
||||
// CPU flush -> GPU invalidate
|
||||
system.GPU().InvalidateRegion(current_vaddr, block_size);
|
||||
};
|
||||
return PerformCacheOperation(process, dest_addr, size, perform);
|
||||
return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
|
||||
}
|
||||
|
||||
Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
|
||||
auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
|
||||
auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) {
|
||||
// dc civac: Store to point of coherency, and invalidate from cache
|
||||
Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size);
|
||||
// CPU flush -> GPU invalidate
|
||||
system.GPU().InvalidateRegion(current_vaddr, block_size);
|
||||
};
|
||||
return PerformCacheOperation(process, dest_addr, size, perform);
|
||||
return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
|
||||
}
|
||||
|
||||
void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) {
|
||||
|
||||
@@ -38,7 +38,7 @@ std::string GetTimestamp() {
|
||||
|
||||
using namespace nlohmann;
|
||||
|
||||
void SaveToFile(json json, const std::filesystem::path& filename) {
|
||||
void SaveToFile(const json& json, const std::filesystem::path& filename) {
|
||||
if (!Common::FS::CreateParentDirs(filename)) {
|
||||
LOG_ERROR(Core, "Failed to create path for '{}' to save report!",
|
||||
Common::FS::PathToUTF8String(filename));
|
||||
@@ -81,8 +81,8 @@ json GetReportCommonData(u64 title_id, Result result, const std::string& timesta
|
||||
}
|
||||
|
||||
json GetProcessorStateData(const std::string& architecture, u64 entry_point, u64 sp, u64 pc,
|
||||
u64 pstate, std::array<u64, 31> registers,
|
||||
std::optional<std::array<u64, 32>> backtrace = {}) {
|
||||
u64 pstate, const std::array<u64, 31>& registers,
|
||||
const std::optional<std::array<u64, 32>>& backtrace = {}) {
|
||||
auto out = json{
|
||||
{"entry_point", fmt::format("{:016X}", entry_point)},
|
||||
{"sp", fmt::format("{:016X}", sp)},
|
||||
@@ -224,11 +224,11 @@ void Reporter::SaveCrashReport(u64 title_id, Result result, u64 set_flags, u64 e
|
||||
|
||||
out["processor_state"] = std::move(proc_out);
|
||||
|
||||
SaveToFile(std::move(out), GetPath("crash_report", title_id, timestamp));
|
||||
SaveToFile(out, GetPath("crash_report", title_id, timestamp));
|
||||
}
|
||||
|
||||
void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2,
|
||||
std::optional<std::vector<u8>> resolved_buffer) const {
|
||||
const std::optional<std::vector<u8>>& resolved_buffer) const {
|
||||
if (!IsReportingEnabled()) {
|
||||
return;
|
||||
}
|
||||
@@ -250,7 +250,7 @@ void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64
|
||||
|
||||
out["svc_break"] = std::move(break_out);
|
||||
|
||||
SaveToFile(std::move(out), GetPath("svc_break_report", title_id, timestamp));
|
||||
SaveToFile(out, GetPath("svc_break_report", title_id, timestamp));
|
||||
}
|
||||
|
||||
void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id,
|
||||
@@ -271,13 +271,13 @@ void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u
|
||||
|
||||
out["function"] = std::move(function_out);
|
||||
|
||||
SaveToFile(std::move(out), GetPath("unimpl_func_report", title_id, timestamp));
|
||||
SaveToFile(out, GetPath("unimpl_func_report", title_id, timestamp));
|
||||
}
|
||||
|
||||
void Reporter::SaveUnimplementedAppletReport(
|
||||
u32 applet_id, u32 common_args_version, u32 library_version, u32 theme_color,
|
||||
bool startup_sound, u64 system_tick, std::vector<std::vector<u8>> normal_channel,
|
||||
std::vector<std::vector<u8>> interactive_channel) const {
|
||||
bool startup_sound, u64 system_tick, const std::vector<std::vector<u8>>& normal_channel,
|
||||
const std::vector<std::vector<u8>>& interactive_channel) const {
|
||||
if (!IsReportingEnabled()) {
|
||||
return;
|
||||
}
|
||||
@@ -308,10 +308,11 @@ void Reporter::SaveUnimplementedAppletReport(
|
||||
out["applet_normal_data"] = std::move(normal_out);
|
||||
out["applet_interactive_data"] = std::move(interactive_out);
|
||||
|
||||
SaveToFile(std::move(out), GetPath("unimpl_applet_report", title_id, timestamp));
|
||||
SaveToFile(out, GetPath("unimpl_applet_report", title_id, timestamp));
|
||||
}
|
||||
|
||||
void Reporter::SavePlayReport(PlayReportType type, u64 title_id, std::vector<std::vector<u8>> data,
|
||||
void Reporter::SavePlayReport(PlayReportType type, u64 title_id,
|
||||
const std::vector<std::vector<u8>>& data,
|
||||
std::optional<u64> process_id, std::optional<u128> user_id) const {
|
||||
if (!IsReportingEnabled()) {
|
||||
return;
|
||||
@@ -335,12 +336,12 @@ void Reporter::SavePlayReport(PlayReportType type, u64 title_id, std::vector<std
|
||||
out["play_report_type"] = fmt::format("{:02}", static_cast<u8>(type));
|
||||
out["play_report_data"] = std::move(data_out);
|
||||
|
||||
SaveToFile(std::move(out), GetPath("play_report", title_id, timestamp));
|
||||
SaveToFile(out, GetPath("play_report", title_id, timestamp));
|
||||
}
|
||||
|
||||
void Reporter::SaveErrorReport(u64 title_id, Result result,
|
||||
std::optional<std::string> custom_text_main,
|
||||
std::optional<std::string> custom_text_detail) const {
|
||||
const std::optional<std::string>& custom_text_main,
|
||||
const std::optional<std::string>& custom_text_detail) const {
|
||||
if (!IsReportingEnabled()) {
|
||||
return;
|
||||
}
|
||||
@@ -354,11 +355,11 @@ void Reporter::SaveErrorReport(u64 title_id, Result result,
|
||||
out["backtrace"] = GetBacktraceData(system);
|
||||
|
||||
out["error_custom_text"] = {
|
||||
{"main", *custom_text_main},
|
||||
{"detail", *custom_text_detail},
|
||||
{"main", custom_text_main.value_or("")},
|
||||
{"detail", custom_text_detail.value_or("")},
|
||||
};
|
||||
|
||||
SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp));
|
||||
SaveToFile(out, GetPath("error_report", title_id, timestamp));
|
||||
}
|
||||
|
||||
void Reporter::SaveFSAccessLog(std::string_view log_message) const {
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
|
||||
// Used by syscall svcBreak
|
||||
void SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2,
|
||||
std::optional<std::vector<u8>> resolved_buffer = {}) const;
|
||||
const std::optional<std::vector<u8>>& resolved_buffer = {}) const;
|
||||
|
||||
// Used by HLE service handler
|
||||
void SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id,
|
||||
@@ -44,10 +44,10 @@ public:
|
||||
const std::string& service_name) const;
|
||||
|
||||
// Used by stub applet implementation
|
||||
void SaveUnimplementedAppletReport(u32 applet_id, u32 common_args_version, u32 library_version,
|
||||
u32 theme_color, bool startup_sound, u64 system_tick,
|
||||
std::vector<std::vector<u8>> normal_channel,
|
||||
std::vector<std::vector<u8>> interactive_channel) const;
|
||||
void SaveUnimplementedAppletReport(
|
||||
u32 applet_id, u32 common_args_version, u32 library_version, u32 theme_color,
|
||||
bool startup_sound, u64 system_tick, const std::vector<std::vector<u8>>& normal_channel,
|
||||
const std::vector<std::vector<u8>>& interactive_channel) const;
|
||||
|
||||
enum class PlayReportType {
|
||||
Old,
|
||||
@@ -56,13 +56,13 @@ public:
|
||||
System,
|
||||
};
|
||||
|
||||
void SavePlayReport(PlayReportType type, u64 title_id, std::vector<std::vector<u8>> data,
|
||||
void SavePlayReport(PlayReportType type, u64 title_id, const std::vector<std::vector<u8>>& data,
|
||||
std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const;
|
||||
|
||||
// Used by error applet
|
||||
void SaveErrorReport(u64 title_id, Result result,
|
||||
std::optional<std::string> custom_text_main = {},
|
||||
std::optional<std::string> custom_text_detail = {}) const;
|
||||
const std::optional<std::string>& custom_text_main = {},
|
||||
const std::optional<std::string>& custom_text_detail = {}) const;
|
||||
|
||||
void SaveFSAccessLog(std::string_view log_message) const;
|
||||
|
||||
|
||||
@@ -56,18 +56,12 @@ if (ENABLE_SDL2)
|
||||
drivers/sdl_driver.cpp
|
||||
drivers/sdl_driver.h
|
||||
)
|
||||
if (YUZU_USE_EXTERNAL_SDL2)
|
||||
target_link_libraries(input_common PRIVATE SDL2-static)
|
||||
else()
|
||||
target_link_libraries(input_common PRIVATE SDL2)
|
||||
endif()
|
||||
target_link_libraries(input_common PRIVATE SDL2::SDL2)
|
||||
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
target_link_libraries(input_common PRIVATE usb)
|
||||
|
||||
create_target_directory_groups(input_common)
|
||||
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)
|
||||
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost libusb::usb)
|
||||
|
||||
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;
|
||||
|
||||
@@ -16,6 +16,8 @@ Common::UUID GetGUID(SDL_Joystick* joystick) {
|
||||
const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
|
||||
std::array<u8, 16> data{};
|
||||
std::memcpy(data.data(), guid.data, sizeof(data));
|
||||
// Clear controller name crc
|
||||
std::memset(data.data() + 2, 0, sizeof(u16));
|
||||
return Common::UUID{data};
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
@@ -47,20 +47,20 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc(
|
||||
|
||||
Common::Input::NfcState VirtualAmiibo::WriteNfcData(
|
||||
[[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) {
|
||||
const Common::FS::IOFile amiibo_file{file_path, Common::FS::FileAccessMode::ReadWrite,
|
||||
Common::FS::FileType::BinaryFile};
|
||||
const Common::FS::IOFile nfc_file{file_path, Common::FS::FileAccessMode::ReadWrite,
|
||||
Common::FS::FileType::BinaryFile};
|
||||
|
||||
if (!amiibo_file.IsOpen()) {
|
||||
if (!nfc_file.IsOpen()) {
|
||||
LOG_ERROR(Core, "Amiibo is already on use");
|
||||
return Common::Input::NfcState::WriteFailed;
|
||||
}
|
||||
|
||||
if (!amiibo_file.Write(data)) {
|
||||
if (!nfc_file.Write(data)) {
|
||||
LOG_ERROR(Service_NFP, "Error writting to file");
|
||||
return Common::Input::NfcState::WriteFailed;
|
||||
}
|
||||
|
||||
amiibo_data = data;
|
||||
nfc_data = data;
|
||||
|
||||
return Common::Input::NfcState::Success;
|
||||
}
|
||||
@@ -70,32 +70,44 @@ VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const {
|
||||
}
|
||||
|
||||
VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) {
|
||||
const Common::FS::IOFile amiibo_file{filename, Common::FS::FileAccessMode::Read,
|
||||
Common::FS::FileType::BinaryFile};
|
||||
const Common::FS::IOFile nfc_file{filename, Common::FS::FileAccessMode::Read,
|
||||
Common::FS::FileType::BinaryFile};
|
||||
|
||||
if (state != State::WaitingForAmiibo) {
|
||||
return Info::WrongDeviceState;
|
||||
}
|
||||
|
||||
if (!amiibo_file.IsOpen()) {
|
||||
if (!nfc_file.IsOpen()) {
|
||||
return Info::UnableToLoad;
|
||||
}
|
||||
|
||||
amiibo_data.resize(amiibo_size);
|
||||
|
||||
if (amiibo_file.Read(amiibo_data) < amiibo_size_without_password) {
|
||||
switch (nfc_file.GetSize()) {
|
||||
case AmiiboSize:
|
||||
case AmiiboSizeWithoutPassword:
|
||||
nfc_data.resize(AmiiboSize);
|
||||
if (nfc_file.Read(nfc_data) < AmiiboSizeWithoutPassword) {
|
||||
return Info::NotAnAmiibo;
|
||||
}
|
||||
break;
|
||||
case MifareSize:
|
||||
nfc_data.resize(MifareSize);
|
||||
if (nfc_file.Read(nfc_data) < MifareSize) {
|
||||
return Info::NotAnAmiibo;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return Info::NotAnAmiibo;
|
||||
}
|
||||
|
||||
file_path = filename;
|
||||
state = State::AmiiboIsOpen;
|
||||
SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data});
|
||||
SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data});
|
||||
return Info::Success;
|
||||
}
|
||||
|
||||
VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {
|
||||
if (state == State::AmiiboIsOpen) {
|
||||
SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data});
|
||||
SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data});
|
||||
return Info::Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,12 +53,13 @@ public:
|
||||
std::string GetLastFilePath() const;
|
||||
|
||||
private:
|
||||
static constexpr std::size_t amiibo_size = 0x21C;
|
||||
static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8;
|
||||
static constexpr std::size_t AmiiboSize = 0x21C;
|
||||
static constexpr std::size_t AmiiboSizeWithoutPassword = AmiiboSize - 0x8;
|
||||
static constexpr std::size_t MifareSize = 0x400;
|
||||
|
||||
std::string file_path{};
|
||||
State state{State::Initialized};
|
||||
std::vector<u8> amiibo_data;
|
||||
std::vector<u8> nfc_data;
|
||||
Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Pasive};
|
||||
};
|
||||
} // namespace InputCommon
|
||||
|
||||
@@ -19,7 +19,7 @@ add_library(network STATIC
|
||||
|
||||
create_target_directory_groups(network)
|
||||
|
||||
target_link_libraries(network PRIVATE common enet Boost::boost)
|
||||
target_link_libraries(network PRIVATE common enet::enet Boost::boost)
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
target_compile_definitions(network PRIVATE -DENABLE_WEB_SERVICE)
|
||||
target_link_libraries(network PRIVATE web_service)
|
||||
|
||||
@@ -461,7 +461,7 @@ void EmitSetSampleMask(EmitContext& ctx, Id value) {
|
||||
}
|
||||
|
||||
void EmitSetFragDepth(EmitContext& ctx, Id value) {
|
||||
if (!ctx.runtime_info.convert_depth_mode) {
|
||||
if (!ctx.runtime_info.convert_depth_mode || ctx.profile.support_native_ndc) {
|
||||
ctx.OpStore(ctx.frag_depth, value);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -116,7 +116,8 @@ void EmitPrologue(EmitContext& ctx) {
|
||||
}
|
||||
|
||||
void EmitEpilogue(EmitContext& ctx) {
|
||||
if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode) {
|
||||
if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode &&
|
||||
!ctx.profile.support_native_ndc) {
|
||||
ConvertDepthMode(ctx);
|
||||
}
|
||||
if (ctx.stage == Stage::Fragment) {
|
||||
@@ -125,7 +126,7 @@ void EmitEpilogue(EmitContext& ctx) {
|
||||
}
|
||||
|
||||
void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
|
||||
if (ctx.runtime_info.convert_depth_mode) {
|
||||
if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) {
|
||||
ConvertDepthMode(ctx);
|
||||
}
|
||||
if (stream.IsImmediate()) {
|
||||
|
||||
@@ -1345,8 +1345,10 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
||||
if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
|
||||
(profile.warp_size_potentially_larger_than_guest &&
|
||||
(info.uses_subgroup_vote || info.uses_subgroup_mask))) {
|
||||
AddCapability(spv::Capability::GroupNonUniform);
|
||||
subgroup_local_invocation_id =
|
||||
DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
|
||||
Decorate(subgroup_local_invocation_id, spv::Decoration::Flat);
|
||||
}
|
||||
if (info.uses_fswzadd) {
|
||||
const Id f32_one{Const(1.0f)};
|
||||
|
||||
@@ -35,6 +35,7 @@ struct Profile {
|
||||
bool support_int64_atomics{};
|
||||
bool support_derivative_control{};
|
||||
bool support_geometry_shader_passthrough{};
|
||||
bool support_native_ndc{};
|
||||
bool support_gl_nv_gpu_shader_5{};
|
||||
bool support_gl_amd_gpu_shader_half_float{};
|
||||
bool support_gl_texture_shadow_lod{};
|
||||
|
||||
@@ -33,6 +33,8 @@ add_library(video_core STATIC
|
||||
engines/sw_blitter/converter.cpp
|
||||
engines/sw_blitter/converter.h
|
||||
engines/const_buffer_info.h
|
||||
engines/draw_manager.cpp
|
||||
engines/draw_manager.h
|
||||
engines/engine_interface.h
|
||||
engines/engine_upload.cpp
|
||||
engines/engine_upload.h
|
||||
@@ -176,6 +178,8 @@ add_library(video_core STATIC
|
||||
renderer_vulkan/vk_scheduler.h
|
||||
renderer_vulkan/vk_shader_util.cpp
|
||||
renderer_vulkan/vk_shader_util.h
|
||||
renderer_vulkan/vk_smaa.cpp
|
||||
renderer_vulkan/vk_smaa.h
|
||||
renderer_vulkan/vk_staging_buffer_pool.cpp
|
||||
renderer_vulkan/vk_staging_buffer_pool.h
|
||||
renderer_vulkan/vk_state_tracker.cpp
|
||||
@@ -193,6 +197,8 @@ add_library(video_core STATIC
|
||||
shader_environment.h
|
||||
shader_notify.cpp
|
||||
shader_notify.h
|
||||
smaa_area_tex.h
|
||||
smaa_search_tex.h
|
||||
surface.cpp
|
||||
surface.h
|
||||
texture_cache/accelerated_swizzle.cpp
|
||||
@@ -264,8 +270,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})
|
||||
|
||||
add_dependencies(video_core host_shaders)
|
||||
target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
|
||||
target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
|
||||
target_link_libraries(video_core PRIVATE sirit)
|
||||
target_link_libraries(video_core PRIVATE sirit Vulkan::Headers)
|
||||
|
||||
if (ENABLE_NSIGHT_AFTERMATH)
|
||||
if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
|
||||
@@ -305,11 +310,11 @@ if (ARCHITECTURE_x86_64)
|
||||
macro/macro_jit_x64.cpp
|
||||
macro/macro_jit_x64.h
|
||||
)
|
||||
target_link_libraries(video_core PUBLIC xbyak)
|
||||
target_link_libraries(video_core PUBLIC xbyak::xbyak)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
target_link_libraries(video_core PRIVATE dynarmic)
|
||||
target_link_libraries(video_core PRIVATE dynarmic::dynarmic)
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "video_core/control/channel_state_cache.h"
|
||||
#include "video_core/delayed_destruction_ring.h"
|
||||
#include "video_core/dirty_flags.h"
|
||||
#include "video_core/engines/draw_manager.h"
|
||||
#include "video_core/engines/kepler_compute.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
@@ -664,9 +665,10 @@ void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
|
||||
if (is_indexed) {
|
||||
BindHostIndexBuffer();
|
||||
} else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
||||
const auto& regs = maxwell3d->regs;
|
||||
if (regs.draw.topology == Maxwell::PrimitiveTopology::Quads) {
|
||||
runtime.BindQuadArrayIndexBuffer(regs.vertex_buffer.first, regs.vertex_buffer.count);
|
||||
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||
if (draw_state.topology == Maxwell::PrimitiveTopology::Quads) {
|
||||
runtime.BindQuadArrayIndexBuffer(draw_state.vertex_buffer.first,
|
||||
draw_state.vertex_buffer.count);
|
||||
}
|
||||
}
|
||||
BindHostVertexBuffers();
|
||||
@@ -993,28 +995,29 @@ void BufferCache<P>::BindHostIndexBuffer() {
|
||||
TouchBuffer(buffer, index_buffer.buffer_id);
|
||||
const u32 offset = buffer.Offset(index_buffer.cpu_addr);
|
||||
const u32 size = index_buffer.size;
|
||||
if (maxwell3d->inline_index_draw_indexes.size()) {
|
||||
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||
if (!draw_state.inline_index_draw_indexes.empty()) {
|
||||
if constexpr (USE_MEMORY_MAPS) {
|
||||
auto upload_staging = runtime.UploadStagingBuffer(size);
|
||||
std::array<BufferCopy, 1> copies{
|
||||
{BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}};
|
||||
std::memcpy(upload_staging.mapped_span.data(),
|
||||
maxwell3d->inline_index_draw_indexes.data(), size);
|
||||
draw_state.inline_index_draw_indexes.data(), size);
|
||||
runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
|
||||
} else {
|
||||
buffer.ImmediateUpload(0, maxwell3d->inline_index_draw_indexes);
|
||||
buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes);
|
||||
}
|
||||
} else {
|
||||
SynchronizeBuffer(buffer, index_buffer.cpu_addr, size);
|
||||
}
|
||||
if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
||||
const u32 new_offset = offset + maxwell3d->regs.index_buffer.first *
|
||||
maxwell3d->regs.index_buffer.FormatSizeInBytes();
|
||||
const u32 new_offset =
|
||||
offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes();
|
||||
runtime.BindIndexBuffer(buffer, new_offset, size);
|
||||
} else {
|
||||
runtime.BindIndexBuffer(maxwell3d->regs.draw.topology, maxwell3d->regs.index_buffer.format,
|
||||
maxwell3d->regs.index_buffer.first,
|
||||
maxwell3d->regs.index_buffer.count, buffer, offset, size);
|
||||
runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format,
|
||||
draw_state.index_buffer.first, draw_state.index_buffer.count,
|
||||
buffer, offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1282,15 +1285,16 @@ template <class P>
|
||||
void BufferCache<P>::UpdateIndexBuffer() {
|
||||
// We have to check for the dirty flags and index count
|
||||
// The index count is currently changed without updating the dirty flags
|
||||
const auto& index_array = maxwell3d->regs.index_buffer;
|
||||
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||
const auto& index_array = draw_state.index_buffer;
|
||||
auto& flags = maxwell3d->dirty.flags;
|
||||
if (!flags[Dirty::IndexBuffer] && last_index_count == index_array.count) {
|
||||
return;
|
||||
}
|
||||
flags[Dirty::IndexBuffer] = false;
|
||||
last_index_count = index_array.count;
|
||||
if (maxwell3d->inline_index_draw_indexes.size()) {
|
||||
auto inline_index_size = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size());
|
||||
if (!draw_state.inline_index_draw_indexes.empty()) {
|
||||
auto inline_index_size = static_cast<u32>(draw_state.inline_index_draw_indexes.size());
|
||||
index_buffer = Binding{
|
||||
.cpu_addr = 0,
|
||||
.size = inline_index_size,
|
||||
|
||||
201
src/video_core/engines/draw_manager.cpp
Normal file
201
src/video_core/engines/draw_manager.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "video_core/dirty_flags.h"
|
||||
#include "video_core/engines/draw_manager.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
|
||||
namespace Tegra::Engines {
|
||||
DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {}
|
||||
|
||||
void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
|
||||
const auto& regs{maxwell3d->regs};
|
||||
switch (method) {
|
||||
case MAXWELL3D_REG_INDEX(clear_surface):
|
||||
return Clear(1);
|
||||
case MAXWELL3D_REG_INDEX(draw.begin):
|
||||
return DrawBegin();
|
||||
case MAXWELL3D_REG_INDEX(draw.end):
|
||||
return DrawEnd();
|
||||
case MAXWELL3D_REG_INDEX(vertex_buffer.first):
|
||||
case MAXWELL3D_REG_INDEX(vertex_buffer.count):
|
||||
case MAXWELL3D_REG_INDEX(index_buffer.first):
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(index_buffer.count):
|
||||
draw_state.draw_indexed = true;
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(index_buffer32_subsequent):
|
||||
case MAXWELL3D_REG_INDEX(index_buffer16_subsequent):
|
||||
case MAXWELL3D_REG_INDEX(index_buffer8_subsequent):
|
||||
draw_state.instance_count++;
|
||||
[[fallthrough]];
|
||||
case MAXWELL3D_REG_INDEX(index_buffer32_first):
|
||||
case MAXWELL3D_REG_INDEX(index_buffer16_first):
|
||||
case MAXWELL3D_REG_INDEX(index_buffer8_first):
|
||||
return DrawIndexSmall(argument);
|
||||
case MAXWELL3D_REG_INDEX(draw_inline_index):
|
||||
SetInlineIndexBuffer(argument);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
|
||||
SetInlineIndexBuffer(regs.inline_index_2x16.even);
|
||||
SetInlineIndexBuffer(regs.inline_index_2x16.odd);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
|
||||
SetInlineIndexBuffer(regs.inline_index_4x8.index0);
|
||||
SetInlineIndexBuffer(regs.inline_index_4x8.index1);
|
||||
SetInlineIndexBuffer(regs.inline_index_4x8.index2);
|
||||
SetInlineIndexBuffer(regs.inline_index_4x8.index3);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(vertex_array_instance_first):
|
||||
case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): {
|
||||
LOG_WARNING(HW_GPU, "(STUBBED) called");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawManager::Clear(u32 layer_count) {
|
||||
if (maxwell3d->ShouldExecute()) {
|
||||
maxwell3d->rasterizer->Clear(layer_count);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawManager::DrawDeferred() {
|
||||
if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0) {
|
||||
return;
|
||||
}
|
||||
DrawEnd(draw_state.instance_count + 1, true);
|
||||
draw_state.instance_count = 0;
|
||||
}
|
||||
|
||||
void DrawManager::DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
|
||||
u32 base_instance, u32 num_instances) {
|
||||
draw_state.topology = topology;
|
||||
draw_state.vertex_buffer.first = vertex_first;
|
||||
draw_state.vertex_buffer.count = vertex_count;
|
||||
draw_state.base_instance = base_instance;
|
||||
ProcessDraw(false, num_instances);
|
||||
}
|
||||
|
||||
void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count,
|
||||
u32 base_index, u32 base_instance, u32 num_instances) {
|
||||
const auto& regs{maxwell3d->regs};
|
||||
draw_state.topology = topology;
|
||||
draw_state.index_buffer = regs.index_buffer;
|
||||
draw_state.index_buffer.first = index_first;
|
||||
draw_state.index_buffer.count = index_count;
|
||||
draw_state.base_index = base_index;
|
||||
draw_state.base_instance = base_instance;
|
||||
ProcessDraw(true, num_instances);
|
||||
}
|
||||
|
||||
void DrawManager::SetInlineIndexBuffer(u32 index) {
|
||||
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
|
||||
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
|
||||
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16));
|
||||
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24));
|
||||
draw_state.draw_mode = DrawMode::InlineIndex;
|
||||
}
|
||||
|
||||
void DrawManager::DrawBegin() {
|
||||
const auto& regs{maxwell3d->regs};
|
||||
auto reset_instance_count = regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First;
|
||||
auto increment_instance_count =
|
||||
regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent;
|
||||
if (reset_instance_count) {
|
||||
DrawDeferred();
|
||||
draw_state.instance_count = 0;
|
||||
draw_state.draw_mode = DrawMode::General;
|
||||
} else if (increment_instance_count) {
|
||||
draw_state.instance_count++;
|
||||
draw_state.draw_mode = DrawMode::Instance;
|
||||
}
|
||||
|
||||
draw_state.topology = regs.draw.topology;
|
||||
}
|
||||
|
||||
void DrawManager::DrawEnd(u32 instance_count, bool force_draw) {
|
||||
const auto& regs{maxwell3d->regs};
|
||||
switch (draw_state.draw_mode) {
|
||||
case DrawMode::Instance:
|
||||
if (!force_draw) {
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case DrawMode::General:
|
||||
draw_state.base_instance = regs.global_base_instance_index;
|
||||
draw_state.base_index = regs.global_base_vertex_index;
|
||||
if (draw_state.draw_indexed) {
|
||||
draw_state.index_buffer = regs.index_buffer;
|
||||
ProcessDraw(true, instance_count);
|
||||
} else {
|
||||
draw_state.vertex_buffer = regs.vertex_buffer;
|
||||
ProcessDraw(false, instance_count);
|
||||
}
|
||||
draw_state.draw_indexed = false;
|
||||
break;
|
||||
case DrawMode::InlineIndex:
|
||||
draw_state.base_instance = regs.global_base_instance_index;
|
||||
draw_state.base_index = regs.global_base_vertex_index;
|
||||
draw_state.index_buffer = regs.index_buffer;
|
||||
draw_state.index_buffer.count =
|
||||
static_cast<u32>(draw_state.inline_index_draw_indexes.size() / 4);
|
||||
draw_state.index_buffer.format = Maxwell3D::Regs::IndexFormat::UnsignedInt;
|
||||
ProcessDraw(true, instance_count);
|
||||
draw_state.inline_index_draw_indexes.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawManager::DrawIndexSmall(u32 argument) {
|
||||
const auto& regs{maxwell3d->regs};
|
||||
IndexBufferSmall index_small_params{argument};
|
||||
draw_state.base_instance = regs.global_base_instance_index;
|
||||
draw_state.base_index = regs.global_base_vertex_index;
|
||||
draw_state.index_buffer = regs.index_buffer;
|
||||
draw_state.index_buffer.first = index_small_params.first;
|
||||
draw_state.index_buffer.count = index_small_params.count;
|
||||
draw_state.topology = index_small_params.topology;
|
||||
maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
||||
ProcessDraw(true, 1);
|
||||
}
|
||||
|
||||
void DrawManager::UpdateTopology() {
|
||||
const auto& regs{maxwell3d->regs};
|
||||
switch (regs.primitive_topology_control) {
|
||||
case PrimitiveTopologyControl::UseInBeginMethods:
|
||||
break;
|
||||
case PrimitiveTopologyControl::UseSeparateState:
|
||||
switch (regs.topology_override) {
|
||||
case PrimitiveTopologyOverride::None:
|
||||
break;
|
||||
case PrimitiveTopologyOverride::Points:
|
||||
draw_state.topology = PrimitiveTopology::Points;
|
||||
break;
|
||||
case PrimitiveTopologyOverride::Lines:
|
||||
draw_state.topology = PrimitiveTopology::Lines;
|
||||
break;
|
||||
case PrimitiveTopologyOverride::LineStrip:
|
||||
draw_state.topology = PrimitiveTopology::LineStrip;
|
||||
break;
|
||||
default:
|
||||
draw_state.topology = static_cast<PrimitiveTopology>(regs.topology_override);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) {
|
||||
LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology,
|
||||
draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count);
|
||||
|
||||
UpdateTopology();
|
||||
|
||||
if (maxwell3d->ShouldExecute()) {
|
||||
maxwell3d->rasterizer->Draw(draw_indexed, instance_count);
|
||||
}
|
||||
}
|
||||
} // namespace Tegra::Engines
|
||||
69
src/video_core/engines/draw_manager.h
Normal file
69
src/video_core/engines/draw_manager.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
|
||||
namespace VideoCore {
|
||||
class RasterizerInterface;
|
||||
}
|
||||
|
||||
namespace Tegra::Engines {
|
||||
using PrimitiveTopologyControl = Maxwell3D::Regs::PrimitiveTopologyControl;
|
||||
using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology;
|
||||
using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride;
|
||||
using IndexBuffer = Maxwell3D::Regs::IndexBuffer;
|
||||
using VertexBuffer = Maxwell3D::Regs::VertexBuffer;
|
||||
using IndexBufferSmall = Maxwell3D::Regs::IndexBufferSmall;
|
||||
|
||||
class DrawManager {
|
||||
public:
|
||||
enum class DrawMode : u32 { General = 0, Instance, InlineIndex };
|
||||
struct State {
|
||||
PrimitiveTopology topology{};
|
||||
DrawMode draw_mode{};
|
||||
bool draw_indexed{};
|
||||
u32 base_index{};
|
||||
VertexBuffer vertex_buffer;
|
||||
IndexBuffer index_buffer;
|
||||
u32 base_instance{};
|
||||
u32 instance_count{};
|
||||
std::vector<u8> inline_index_draw_indexes;
|
||||
};
|
||||
|
||||
explicit DrawManager(Maxwell3D* maxwell_3d);
|
||||
|
||||
void ProcessMethodCall(u32 method, u32 argument);
|
||||
|
||||
void Clear(u32 layer_count);
|
||||
|
||||
void DrawDeferred();
|
||||
|
||||
void DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
|
||||
u32 base_instance, u32 num_instances);
|
||||
|
||||
void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index,
|
||||
u32 base_instance, u32 num_instances);
|
||||
|
||||
const State& GetDrawState() const {
|
||||
return draw_state;
|
||||
}
|
||||
|
||||
private:
|
||||
void SetInlineIndexBuffer(u32 index);
|
||||
|
||||
void DrawBegin();
|
||||
|
||||
void DrawEnd(u32 instance_count = 1, bool force_draw = false);
|
||||
|
||||
void DrawIndexSmall(u32 argument);
|
||||
|
||||
void UpdateTopology();
|
||||
|
||||
void ProcessDraw(bool draw_indexed, u32 instance_count);
|
||||
|
||||
Maxwell3D* maxwell3d{};
|
||||
State draw_state{};
|
||||
};
|
||||
} // namespace Tegra::Engines
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "video_core/dirty_flags.h"
|
||||
#include "video_core/engines/draw_manager.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
@@ -21,8 +22,10 @@ using VideoCore::QueryType;
|
||||
constexpr u32 MacroRegistersStart = 0xE00;
|
||||
|
||||
Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
|
||||
: system{system_}, memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)},
|
||||
upload_state{memory_manager, regs.upload} {
|
||||
: draw_manager{std::make_unique<DrawManager>(this)}, system{system_},
|
||||
memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, upload_state{
|
||||
memory_manager,
|
||||
regs.upload} {
|
||||
dirty.flags.flip();
|
||||
InitializeRegisterDefaults();
|
||||
}
|
||||
@@ -116,16 +119,6 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
||||
regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill;
|
||||
|
||||
shadow_state = regs;
|
||||
|
||||
draw_command[MAXWELL3D_REG_INDEX(draw.end)] = true;
|
||||
draw_command[MAXWELL3D_REG_INDEX(draw.begin)] = true;
|
||||
draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.first)] = true;
|
||||
draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true;
|
||||
draw_command[MAXWELL3D_REG_INDEX(index_buffer.first)] = true;
|
||||
draw_command[MAXWELL3D_REG_INDEX(index_buffer.count)] = true;
|
||||
draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true;
|
||||
draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true;
|
||||
draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true;
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
|
||||
@@ -213,29 +206,6 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
|
||||
return ProcessCBBind(3);
|
||||
case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config):
|
||||
return ProcessCBBind(4);
|
||||
case MAXWELL3D_REG_INDEX(index_buffer32_first):
|
||||
regs.index_buffer.count = regs.index_buffer32_first.count;
|
||||
regs.index_buffer.first = regs.index_buffer32_first.first;
|
||||
dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
||||
draw_indexed = true;
|
||||
return ProcessDraw();
|
||||
case MAXWELL3D_REG_INDEX(index_buffer16_first):
|
||||
regs.index_buffer.count = regs.index_buffer16_first.count;
|
||||
regs.index_buffer.first = regs.index_buffer16_first.first;
|
||||
dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
||||
draw_indexed = true;
|
||||
return ProcessDraw();
|
||||
case MAXWELL3D_REG_INDEX(index_buffer8_first):
|
||||
regs.index_buffer.count = regs.index_buffer8_first.count;
|
||||
regs.index_buffer.first = regs.index_buffer8_first.first;
|
||||
dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
||||
draw_indexed = true;
|
||||
return ProcessDraw();
|
||||
case MAXWELL3D_REG_INDEX(topology_override):
|
||||
use_topology_override = true;
|
||||
return;
|
||||
case MAXWELL3D_REG_INDEX(clear_surface):
|
||||
return ProcessClearBuffers(1);
|
||||
case MAXWELL3D_REG_INDEX(report_semaphore.query):
|
||||
return ProcessQueryGet();
|
||||
case MAXWELL3D_REG_INDEX(render_enable.mode):
|
||||
@@ -254,6 +224,9 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
|
||||
return rasterizer->FragmentBarrier();
|
||||
case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
|
||||
return rasterizer->TiledCacheBarrier();
|
||||
default:
|
||||
draw_manager->ProcessMethodCall(method, argument);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +241,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters)
|
||||
// Execute the current macro.
|
||||
macro_engine->Execute(macro_positions[entry], parameters);
|
||||
|
||||
ProcessDeferredDraw();
|
||||
draw_manager->DrawDeferred();
|
||||
}
|
||||
|
||||
void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
|
||||
@@ -291,62 +264,7 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
|
||||
const u32 argument = ProcessShadowRam(method, method_argument);
|
||||
ProcessDirtyRegisters(method, argument);
|
||||
|
||||
if (draw_command[method]) {
|
||||
regs.reg_array[method] = method_argument;
|
||||
deferred_draw_method.push_back(method);
|
||||
auto update_inline_index = [&](const u32 index) {
|
||||
inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
|
||||
inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
|
||||
inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16));
|
||||
inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24));
|
||||
draw_mode = DrawMode::InlineIndex;
|
||||
};
|
||||
switch (method) {
|
||||
case MAXWELL3D_REG_INDEX(draw.begin): {
|
||||
draw_mode =
|
||||
(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) ||
|
||||
(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged)
|
||||
? DrawMode::Instance
|
||||
: DrawMode::General;
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(draw.end):
|
||||
switch (draw_mode) {
|
||||
case DrawMode::General:
|
||||
ProcessDraw();
|
||||
break;
|
||||
case DrawMode::InlineIndex:
|
||||
regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4);
|
||||
regs.index_buffer.format = Regs::IndexFormat::UnsignedInt;
|
||||
draw_indexed = true;
|
||||
ProcessDraw();
|
||||
inline_index_draw_indexes.clear();
|
||||
break;
|
||||
case DrawMode::Instance:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(index_buffer.count):
|
||||
draw_indexed = true;
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(draw_inline_index):
|
||||
update_inline_index(method_argument);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
|
||||
update_inline_index(regs.inline_index_2x16.even);
|
||||
update_inline_index(regs.inline_index_2x16.odd);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
|
||||
update_inline_index(regs.inline_index_4x8.index0);
|
||||
update_inline_index(regs.inline_index_4x8.index1);
|
||||
update_inline_index(regs.inline_index_4x8.index2);
|
||||
update_inline_index(regs.inline_index_4x8.index3);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ProcessDeferredDraw();
|
||||
ProcessMethodCall(method, argument, method_argument, is_last_call);
|
||||
}
|
||||
ProcessMethodCall(method, argument, method_argument, is_last_call);
|
||||
}
|
||||
|
||||
void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
||||
@@ -387,35 +305,6 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
||||
}
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessTopologyOverride() {
|
||||
using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology;
|
||||
using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride;
|
||||
|
||||
PrimitiveTopology topology{};
|
||||
|
||||
switch (regs.topology_override) {
|
||||
case PrimitiveTopologyOverride::None:
|
||||
topology = regs.draw.topology;
|
||||
break;
|
||||
case PrimitiveTopologyOverride::Points:
|
||||
topology = PrimitiveTopology::Points;
|
||||
break;
|
||||
case PrimitiveTopologyOverride::Lines:
|
||||
topology = PrimitiveTopology::Lines;
|
||||
break;
|
||||
case PrimitiveTopologyOverride::LineStrip:
|
||||
topology = PrimitiveTopology::LineStrip;
|
||||
break;
|
||||
default:
|
||||
topology = static_cast<PrimitiveTopology>(regs.topology_override);
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_topology_override) {
|
||||
regs.draw.topology.Assign(topology);
|
||||
}
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessMacroUpload(u32 data) {
|
||||
macro_engine->AddCode(regs.load_mme.instruction_ptr++, data);
|
||||
}
|
||||
@@ -493,41 +382,51 @@ void Maxwell3D::ProcessQueryGet() {
|
||||
|
||||
void Maxwell3D::ProcessQueryCondition() {
|
||||
const GPUVAddr condition_address{regs.render_enable.Address()};
|
||||
switch (regs.render_enable.mode) {
|
||||
case Regs::RenderEnable::Mode::True: {
|
||||
switch (regs.render_enable_override) {
|
||||
case Regs::RenderEnable::Override::AlwaysRender:
|
||||
execute_on = true;
|
||||
break;
|
||||
}
|
||||
case Regs::RenderEnable::Mode::False: {
|
||||
case Regs::RenderEnable::Override::NeverRender:
|
||||
execute_on = false;
|
||||
break;
|
||||
}
|
||||
case Regs::RenderEnable::Mode::Conditional: {
|
||||
Regs::ReportSemaphore::Compare cmp;
|
||||
memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp));
|
||||
execute_on = cmp.initial_sequence != 0U && cmp.initial_mode != 0U;
|
||||
case Regs::RenderEnable::Override::UseRenderEnable:
|
||||
switch (regs.render_enable.mode) {
|
||||
case Regs::RenderEnable::Mode::True: {
|
||||
execute_on = true;
|
||||
break;
|
||||
}
|
||||
case Regs::RenderEnable::Mode::False: {
|
||||
execute_on = false;
|
||||
break;
|
||||
}
|
||||
case Regs::RenderEnable::Mode::Conditional: {
|
||||
Regs::ReportSemaphore::Compare cmp;
|
||||
memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp));
|
||||
execute_on = cmp.initial_sequence != 0U && cmp.initial_mode != 0U;
|
||||
break;
|
||||
}
|
||||
case Regs::RenderEnable::Mode::IfEqual: {
|
||||
Regs::ReportSemaphore::Compare cmp;
|
||||
memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp));
|
||||
execute_on = cmp.initial_sequence == cmp.current_sequence &&
|
||||
cmp.initial_mode == cmp.current_mode;
|
||||
break;
|
||||
}
|
||||
case Regs::RenderEnable::Mode::IfNotEqual: {
|
||||
Regs::ReportSemaphore::Compare cmp;
|
||||
memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp));
|
||||
execute_on = cmp.initial_sequence != cmp.current_sequence ||
|
||||
cmp.initial_mode != cmp.current_mode;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNIMPLEMENTED_MSG("Uninplemented Condition Mode!");
|
||||
execute_on = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Regs::RenderEnable::Mode::IfEqual: {
|
||||
Regs::ReportSemaphore::Compare cmp;
|
||||
memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp));
|
||||
execute_on =
|
||||
cmp.initial_sequence == cmp.current_sequence && cmp.initial_mode == cmp.current_mode;
|
||||
break;
|
||||
}
|
||||
case Regs::RenderEnable::Mode::IfNotEqual: {
|
||||
Regs::ReportSemaphore::Compare cmp;
|
||||
memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp));
|
||||
execute_on =
|
||||
cmp.initial_sequence != cmp.current_sequence || cmp.initial_mode != cmp.current_mode;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNIMPLEMENTED_MSG("Uninplemented Condition Mode!");
|
||||
execute_on = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessCounterReset() {
|
||||
@@ -625,44 +524,4 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const {
|
||||
return regs.reg_array[method];
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessClearBuffers(u32 layer_count) {
|
||||
rasterizer->Clear(layer_count);
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessDraw(u32 instance_count) {
|
||||
LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(),
|
||||
draw_indexed ? regs.index_buffer.count : regs.vertex_buffer.count);
|
||||
|
||||
ProcessTopologyOverride();
|
||||
|
||||
if (ShouldExecute()) {
|
||||
rasterizer->Draw(draw_indexed, instance_count);
|
||||
}
|
||||
|
||||
draw_indexed = false;
|
||||
deferred_draw_method.clear();
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessDeferredDraw() {
|
||||
if (draw_mode != DrawMode::Instance || deferred_draw_method.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto method_count = deferred_draw_method.size();
|
||||
u32 instance_count = 1;
|
||||
u32 vertex_buffer_count = 0;
|
||||
u32 index_buffer_count = 0;
|
||||
for (size_t index = 0; index < method_count; ++index) {
|
||||
const u32 method = deferred_draw_method[index];
|
||||
if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count)) {
|
||||
instance_count = ++vertex_buffer_count;
|
||||
} else if (method == MAXWELL3D_REG_INDEX(index_buffer.count)) {
|
||||
instance_count = ++index_buffer_count;
|
||||
}
|
||||
}
|
||||
ASSERT_MSG(!(vertex_buffer_count && index_buffer_count), "Instance both indexed and direct?");
|
||||
|
||||
ProcessDraw(instance_count);
|
||||
}
|
||||
|
||||
} // namespace Tegra::Engines
|
||||
|
||||
@@ -37,6 +37,8 @@ class RasterizerInterface;
|
||||
|
||||
namespace Tegra::Engines {
|
||||
|
||||
class DrawManager;
|
||||
|
||||
/**
|
||||
* This Engine is known as GF100_3D. Documentation can be found in:
|
||||
* https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/3d/clb197.h
|
||||
@@ -2223,6 +2225,7 @@ public:
|
||||
|
||||
struct IndexBufferSmall {
|
||||
union {
|
||||
u32 raw;
|
||||
BitField<0, 16, u32> first;
|
||||
BitField<16, 12, u32> count;
|
||||
BitField<28, 4, PrimitiveTopology> topology;
|
||||
@@ -3061,10 +3064,8 @@ public:
|
||||
Tables tables{};
|
||||
} dirty;
|
||||
|
||||
std::vector<u8> inline_index_draw_indexes;
|
||||
|
||||
/// Handles a write to the CLEAR_BUFFERS register.
|
||||
void ProcessClearBuffers(u32 layer_count);
|
||||
std::unique_ptr<DrawManager> draw_manager;
|
||||
friend class DrawManager;
|
||||
|
||||
private:
|
||||
void InitializeRegisterDefaults();
|
||||
@@ -3122,15 +3123,6 @@ private:
|
||||
/// Handles a write to the CB_BIND register.
|
||||
void ProcessCBBind(size_t stage_index);
|
||||
|
||||
/// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro)
|
||||
void ProcessTopologyOverride();
|
||||
|
||||
/// Handles deferred draw(e.g., instance draw).
|
||||
void ProcessDeferredDraw();
|
||||
|
||||
/// Handles a draw.
|
||||
void ProcessDraw(u32 instance_count = 1);
|
||||
|
||||
/// Returns a query's value or an empty object if the value will be deferred through a cache.
|
||||
std::optional<u64> GetQueryResult();
|
||||
|
||||
@@ -3153,13 +3145,6 @@ private:
|
||||
Upload::State upload_state;
|
||||
|
||||
bool execute_on{true};
|
||||
bool use_topology_override{false};
|
||||
|
||||
std::array<bool, Regs::NUM_REGS> draw_command{};
|
||||
std::vector<u32> deferred_draw_method;
|
||||
enum class DrawMode : u32 { General = 0, Instance, InlineIndex };
|
||||
DrawMode draw_mode{DrawMode::General};
|
||||
bool draw_indexed{};
|
||||
};
|
||||
|
||||
#define ASSERT_REG_POSITION(field_name, position) \
|
||||
|
||||
@@ -223,8 +223,6 @@ struct GPU::Impl {
|
||||
/// core timing events.
|
||||
void Start() {
|
||||
gpu_thread.StartThread(*renderer, renderer->Context(), *scheduler);
|
||||
cpu_context = renderer->GetRenderWindow().CreateSharedContext();
|
||||
cpu_context->MakeCurrent();
|
||||
}
|
||||
|
||||
void NotifyShutdown() {
|
||||
@@ -235,6 +233,9 @@ struct GPU::Impl {
|
||||
|
||||
/// Obtain the CPU Context
|
||||
void ObtainContext() {
|
||||
if (!cpu_context) {
|
||||
cpu_context = renderer->GetRenderWindow().CreateSharedContext();
|
||||
}
|
||||
cpu_context->MakeCurrent();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,16 @@ set(SHADER_FILES
|
||||
opengl_present.frag
|
||||
opengl_present.vert
|
||||
opengl_present_scaleforce.frag
|
||||
opengl_smaa.glsl
|
||||
pitch_unswizzle.comp
|
||||
present_bicubic.frag
|
||||
present_gaussian.frag
|
||||
smaa_edge_detection.vert
|
||||
smaa_edge_detection.frag
|
||||
smaa_blending_weight_calculation.vert
|
||||
smaa_blending_weight_calculation.frag
|
||||
smaa_neighborhood_blending.vert
|
||||
smaa_neighborhood_blending.frag
|
||||
vulkan_blit_color_float.frag
|
||||
vulkan_blit_depth_stencil.frag
|
||||
vulkan_fidelityfx_fsr_easu_fp16.comp
|
||||
|
||||
@@ -11,10 +11,6 @@ string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME)
|
||||
|
||||
FILE(READ ${SOURCE_FILE} line_contents)
|
||||
|
||||
# Replace double quotes with single quotes,
|
||||
# as double quotes will be used to wrap the lines
|
||||
STRING(REGEX REPLACE "\"" "'" line_contents "${line_contents}")
|
||||
|
||||
# CMake separates list elements with semicolons, but semicolons
|
||||
# are used extensively in the shader code.
|
||||
# Replace with a temporary marker, to be reverted later.
|
||||
@@ -25,7 +21,7 @@ STRING(REGEX REPLACE "\n" ";" line_contents "${line_contents}")
|
||||
|
||||
# Build the shader string, wrapping each line in double quotes.
|
||||
foreach(line IN LISTS line_contents)
|
||||
string(CONCAT CONTENTS "${CONTENTS}" \"${line}\\n\"\n)
|
||||
string(CONCAT CONTENTS "${CONTENTS}" "R\"(${line}\n)\" ")
|
||||
endforeach()
|
||||
|
||||
# Revert the original semicolons in the source.
|
||||
|
||||
1339
src/video_core/host_shaders/opengl_smaa.glsl
Normal file
1339
src/video_core/host_shaders/opengl_smaa.glsl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#version 460
|
||||
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
layout (binding = 0) uniform sampler2D edges_tex;
|
||||
layout (binding = 1) uniform sampler2D area_tex;
|
||||
layout (binding = 2) uniform sampler2D search_tex;
|
||||
|
||||
layout (location = 0) in vec2 tex_coord;
|
||||
layout (location = 1) in vec2 pix_coord;
|
||||
layout (location = 2) in vec4 offset[3];
|
||||
|
||||
layout (location = 0) out vec4 frag_color;
|
||||
|
||||
vec4 metrics = vec4(1.0 / textureSize(edges_tex, 0), textureSize(edges_tex, 0));
|
||||
#define SMAA_RT_METRICS metrics
|
||||
#define SMAA_GLSL_4
|
||||
#define SMAA_PRESET_ULTRA
|
||||
#define SMAA_INCLUDE_VS 0
|
||||
#define SMAA_INCLUDE_PS 1
|
||||
|
||||
#include "opengl_smaa.glsl"
|
||||
|
||||
void main() {
|
||||
frag_color = SMAABlendingWeightCalculationPS(tex_coord,
|
||||
pix_coord,
|
||||
offset,
|
||||
edges_tex,
|
||||
area_tex,
|
||||
search_tex,
|
||||
vec4(0)
|
||||
);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user