Compare commits
107 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
886043a6d2 | ||
|
|
3e6e0d8f13 | ||
|
|
dee133ab3d | ||
|
|
3c22ce035b | ||
|
|
a5e184e948 | ||
|
|
0e004269a9 | ||
|
|
a58086ae0d | ||
|
|
68f718943e | ||
|
|
70db238f80 | ||
|
|
245d60bfff | ||
|
|
a352f34462 | ||
|
|
cda24b8eb1 | ||
|
|
10636d2494 | ||
|
|
783dc9e112 | ||
|
|
864762cac9 | ||
|
|
5c7c212f61 | ||
|
|
2e32ab4e0b | ||
|
|
b6736db324 | ||
|
|
d6ebb5c171 | ||
|
|
26669d9e13 | ||
|
|
1b730827dd | ||
|
|
7666c0994c | ||
|
|
d1ac25b632 | ||
|
|
903311729a | ||
|
|
ff58ad2050 | ||
|
|
0896089092 | ||
|
|
3f9eb56972 | ||
|
|
d0a760a34a | ||
|
|
4c82c08897 | ||
|
|
148fb12bf3 | ||
|
|
c5f109bc50 | ||
|
|
6e5cc977ad | ||
|
|
230e71b255 | ||
|
|
458be11f93 | ||
|
|
9d5a56a40b | ||
|
|
8893b766c3 | ||
|
|
4a01812ebe | ||
|
|
9078f4a9c7 | ||
|
|
8d00265998 | ||
|
|
32d9a83f8e | ||
|
|
160341fcf8 | ||
|
|
d6a0975e5d | ||
|
|
c9597af39d | ||
|
|
a7f9983563 | ||
|
|
ea1f656d7e | ||
|
|
481cd86722 | ||
|
|
61bf850f3d | ||
|
|
40ab2b9348 | ||
|
|
b8fc74d74d | ||
|
|
7b9c58880f | ||
|
|
1a2e7c4dbd | ||
|
|
527188391c | ||
|
|
75a60a6e22 | ||
|
|
1498a7c9a8 | ||
|
|
8b54e219c9 | ||
|
|
3a804752cb | ||
|
|
830612ef9e | ||
|
|
ea4f62615e | ||
|
|
546af64340 | ||
|
|
eba3c59a61 | ||
|
|
18175c71ed | ||
|
|
ff3c7c068b | ||
|
|
6bf80dfee0 | ||
|
|
e9446d232f | ||
|
|
4577dcd5f9 | ||
|
|
3f942c01f0 | ||
|
|
e86a7e3691 | ||
|
|
b0727c90c5 | ||
|
|
b7e6eca8b2 | ||
|
|
1d19eac415 | ||
|
|
0913aaa42a | ||
|
|
47401016bf | ||
|
|
82dd376ba2 | ||
|
|
741dc13c5a | ||
|
|
00cb631b2f | ||
|
|
756365386a | ||
|
|
b944edc85d | ||
|
|
31e6e58101 | ||
|
|
53aec1fe2d | ||
|
|
eb3afd30b1 | ||
|
|
806e2d7900 | ||
|
|
b331bb5210 | ||
|
|
8019b2b9b5 | ||
|
|
9a9e81f2e9 | ||
|
|
f30ef98761 | ||
|
|
cde532cc52 | ||
|
|
c1b81f776c | ||
|
|
b0c9752663 | ||
|
|
2c6e940493 | ||
|
|
48d040fded | ||
|
|
e5a76d728f | ||
|
|
7784b1da6d | ||
|
|
82d232db46 | ||
|
|
13b08376b7 | ||
|
|
9137f3ec68 | ||
|
|
d4ebc9a120 | ||
|
|
64c3582705 | ||
|
|
9e4b2d60bc | ||
|
|
9fc7f60b94 | ||
|
|
2489547dc5 | ||
|
|
ee333e063d | ||
|
|
56742c6222 | ||
|
|
7791cfd960 | ||
|
|
3bf62c7a8a | ||
|
|
3be1a565f8 | ||
|
|
8ba0cac71c | ||
|
|
7b8fa78c65 |
@@ -42,3 +42,8 @@ done
|
||||
pip3 install pefile
|
||||
python3 .ci/scripts/windows/scan_dll.py package/*.exe "package/"
|
||||
python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/"
|
||||
|
||||
# copy FFmpeg libraries
|
||||
EXTERNALS_PATH="$(pwd)/build/externals"
|
||||
FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin"
|
||||
find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
|
||||
|
||||
3
.gitmodules
vendored
@@ -37,3 +37,6 @@
|
||||
[submodule "opus"]
|
||||
path = externals/opus/opus
|
||||
url = https://github.com/xiph/opus.git
|
||||
[submodule "externals/ffmpeg"]
|
||||
path = externals/ffmpeg
|
||||
url = https://git.ffmpeg.org/ffmpeg.git
|
||||
|
||||
146
CMakeLists.txt
@@ -18,6 +18,8 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "EN
|
||||
|
||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled yuzu" ON "WIN32" OFF)
|
||||
|
||||
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
|
||||
|
||||
option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON)
|
||||
@@ -384,19 +386,141 @@ if (NOT LIBUSB_FOUND)
|
||||
set(LIBUSB_LIBRARIES usb)
|
||||
endif()
|
||||
|
||||
# Use system installed ffmpeg.
|
||||
if (NOT MSVC)
|
||||
find_package(FFmpeg REQUIRED)
|
||||
else()
|
||||
set(FFMPEG_EXT_NAME "ffmpeg-4.2.1")
|
||||
set(FFMPEG_PATH "${CMAKE_BINARY_DIR}/externals/${FFMPEG_EXT_NAME}")
|
||||
download_bundled_external("ffmpeg/" ${FFMPEG_EXT_NAME} "")
|
||||
set(FFMPEG_FOUND YES)
|
||||
set(FFMPEG_INCLUDE_DIR "${FFMPEG_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
set(FFMPEG_LIBRARY_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg library" FORCE)
|
||||
set(FFMPEG_DLL_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
|
||||
# List of all FFmpeg components required
|
||||
set(FFmpeg_COMPONENTS
|
||||
avcodec
|
||||
avutil
|
||||
swscale)
|
||||
|
||||
if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
# Use system installed FFmpeg
|
||||
find_package(FFmpeg REQUIRED COMPONENTS ${FFmpeg_COMPONENTS})
|
||||
|
||||
if (FFmpeg_FOUND)
|
||||
# Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries.
|
||||
# Prevents shipping too many libraries with the AppImage.
|
||||
set(FFmpeg_LIBRARIES "")
|
||||
set(FFmpeg_INCLUDE_DIR "")
|
||||
|
||||
foreach(COMPONENT ${FFmpeg_COMPONENTS})
|
||||
set(FFmpeg_LIBRARIES ${FFmpeg_LIBRARIES} ${FFmpeg_LIBRARY_${COMPONENT}} CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
set(FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_DIR} ${FFmpeg_INCLUDE_${COMPONENT}} CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
endforeach()
|
||||
else()
|
||||
message(WARNING "FFmpeg not found, falling back to externals")
|
||||
set(YUZU_USE_BUNDLED_FFMPEG ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
if (NOT WIN32)
|
||||
# Build FFmpeg from externals
|
||||
message(STATUS "Using FFmpeg from externals")
|
||||
|
||||
# FFmpeg has source that requires one of nasm or yasm to assemble it.
|
||||
# REQUIRED throws an error if not found here during configuration rather than during compilation.
|
||||
find_program(ASSEMBLER NAMES nasm yasm REQUIRED)
|
||||
|
||||
set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg)
|
||||
set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg)
|
||||
set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile)
|
||||
make_directory(${FFmpeg_BUILD_DIR})
|
||||
|
||||
# Read version string from external
|
||||
file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION)
|
||||
set(FFmpeg_FOUND NO)
|
||||
if (NOT FFmpeg_VERSION STREQUAL "")
|
||||
set(FFmpeg_FOUND YES)
|
||||
endif()
|
||||
|
||||
foreach(COMPONENT ${FFmpeg_COMPONENTS})
|
||||
set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}")
|
||||
set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a")
|
||||
set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}")
|
||||
|
||||
set(FFmpeg_LIBRARIES
|
||||
${FFmpeg_LIBRARIES}
|
||||
${FFmpeg_${COMPONENT}_LIBRARY}
|
||||
CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
endforeach()
|
||||
|
||||
set(FFmpeg_INCLUDE_DIR
|
||||
${FFmpeg_PREFIX}
|
||||
CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
|
||||
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
|
||||
# `--disable-{vaapi,vdpau}` is needed to avoid linking issues
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_MAKEFILE}
|
||||
COMMAND
|
||||
/bin/bash ${FFmpeg_PREFIX}/configure
|
||||
--disable-avdevice
|
||||
--disable-avfilter
|
||||
--disable-avformat
|
||||
--disable-doc
|
||||
--disable-everything
|
||||
--disable-ffmpeg
|
||||
--disable-ffprobe
|
||||
--disable-network
|
||||
--disable-postproc
|
||||
--disable-swresample
|
||||
--disable-vaapi
|
||||
--disable-vdpau
|
||||
--enable-decoder=h264
|
||||
--enable-decoder=vp9
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
# Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
|
||||
# with context of the jobserver. Also helps ninja users.
|
||||
execute_process(
|
||||
COMMAND
|
||||
nproc
|
||||
OUTPUT_VARIABLE
|
||||
SYSTEM_THREADS)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_LIBRARIES}
|
||||
COMMAND
|
||||
make -j${SYSTEM_THREADS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
# ALL makes this custom target build every time
|
||||
# but it won't actually build if the DEPENDS parameter is up to date
|
||||
add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_LIBRARIES})
|
||||
add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE})
|
||||
|
||||
if (FFmpeg_FOUND)
|
||||
message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
|
||||
|
||||
add_dependencies(ffmpeg-build ffmpeg-configure)
|
||||
else()
|
||||
message(FATAL_ERROR "FFmpeg not found")
|
||||
endif()
|
||||
else() # WIN32
|
||||
# Use yuzu FFmpeg binaries
|
||||
set(FFmpeg_EXT_NAME "ffmpeg-4.2.1")
|
||||
set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
|
||||
download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
|
||||
set(FFmpeg_FOUND YES)
|
||||
set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE)
|
||||
set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
|
||||
set(FFmpeg_LIBRARIES
|
||||
${FFmpeg_LIBRARY_DIR}/swscale.lib
|
||||
${FFmpeg_LIBRARY_DIR}/avcodec.lib
|
||||
${FFmpeg_LIBRARY_DIR}/avutil.lib
|
||||
CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
unset(FFmpeg_COMPONENTS)
|
||||
|
||||
# Prefer the -pthread flag on Linux.
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
function(copy_yuzu_FFmpeg_deps target_dir)
|
||||
include(WindowsCopyFiles)
|
||||
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
|
||||
windows_copy_files(${target_dir} ${FFMPEG_DLL_DIR} ${DLL_DEST}
|
||||
windows_copy_files(${target_dir} ${FFmpeg_DLL_DIR} ${DLL_DEST}
|
||||
avcodec-58.dll
|
||||
avutil-56.dll
|
||||
swresample-3.dll
|
||||
|
||||
@@ -33,7 +33,7 @@ If you want to contribute to the user interface translation, please check out th
|
||||
|
||||
|
||||
### Support
|
||||
We happily accept monetary donations or donated games and hardware. Please see our [donations page](https://yuzu-emu.org/donate/) for more information on how you can contribute to yuzu. Any donations received will go towards things like:
|
||||
We happily accept monetary donations, or donated games and hardware. Please see our [donations page](https://yuzu-emu.org/donate/) for more information on how you can contribute to yuzu. Any donations received will go towards things like:
|
||||
* Switch consoles to explore and reverse-engineer the hardware
|
||||
* Switch games for testing, reverse-engineering, and implementing new features
|
||||
* Web hosting and infrastructure setup
|
||||
|
||||
21
dist/icons/controller/controller.qrc
vendored
@@ -1,26 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="controller">
|
||||
<file alias="dual_joycon">dual_joycon.png</file>
|
||||
<file alias="dual_joycon_dark">dual_joycon_dark.png</file>
|
||||
<file alias="dual_joycon_midnight">dual_joycon_midnight.png</file>
|
||||
<file alias="handheld">handheld.png</file>
|
||||
<file alias="handheld_dark">handheld_dark.png</file>
|
||||
<file alias="handheld_midnight">handheld_midnight.png</file>
|
||||
<file alias="pro_controller">pro_controller.png</file>
|
||||
<file alias="pro_controller_dark">pro_controller_dark.png</file>
|
||||
<file alias="pro_controller_midnight">pro_controller_midnight.png</file>
|
||||
<file alias="single_joycon_left">single_joycon_left.png</file>
|
||||
<file alias="single_joycon_left_dark">single_joycon_left_dark.png</file>
|
||||
<file alias="single_joycon_left_midnight">single_joycon_left_midnight.png</file>
|
||||
<file alias="single_joycon_right">single_joycon_right.png</file>
|
||||
<file alias="single_joycon_right_dark">single_joycon_right_dark.png</file>
|
||||
<file alias="single_joycon_right_midnight">single_joycon_right_midnight.png</file>
|
||||
<file alias="single_joycon_left_vertical">single_joycon_left_vertical.png</file>
|
||||
<file alias="single_joycon_left_vertical_dark">single_joycon_left_vertical_dark.png</file>
|
||||
<file alias="single_joycon_left_vertical_midnight">single_joycon_left_vertical_midnight.png</file>
|
||||
<file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file>
|
||||
<file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file>
|
||||
<file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file>
|
||||
<file alias="applet_dual_joycon">applet_dual_joycon.png</file>
|
||||
<file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file>
|
||||
<file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file>
|
||||
|
||||
BIN
dist/icons/controller/dual_joycon.png
vendored
|
Before Width: | Height: | Size: 36 KiB |
BIN
dist/icons/controller/dual_joycon_dark.png
vendored
|
Before Width: | Height: | Size: 35 KiB |
BIN
dist/icons/controller/dual_joycon_midnight.png
vendored
|
Before Width: | Height: | Size: 34 KiB |
BIN
dist/icons/controller/handheld.png
vendored
|
Before Width: | Height: | Size: 14 KiB |
BIN
dist/icons/controller/handheld_dark.png
vendored
|
Before Width: | Height: | Size: 13 KiB |
BIN
dist/icons/controller/handheld_midnight.png
vendored
|
Before Width: | Height: | Size: 13 KiB |
BIN
dist/icons/controller/pro_controller.png
vendored
|
Before Width: | Height: | Size: 36 KiB |
BIN
dist/icons/controller/pro_controller_dark.png
vendored
|
Before Width: | Height: | Size: 34 KiB |
BIN
dist/icons/controller/pro_controller_midnight.png
vendored
|
Before Width: | Height: | Size: 35 KiB |
BIN
dist/icons/controller/single_joycon_left.png
vendored
|
Before Width: | Height: | Size: 25 KiB |
BIN
dist/icons/controller/single_joycon_left_dark.png
vendored
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB |
BIN
dist/icons/controller/single_joycon_right.png
vendored
|
Before Width: | Height: | Size: 28 KiB |
BIN
dist/icons/controller/single_joycon_right_dark.png
vendored
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 26 KiB |
1
externals/ffmpeg
vendored
Submodule
261
externals/find-modules/FindFFmpeg.cmake
vendored
@@ -1,100 +1,187 @@
|
||||
# - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil)
|
||||
# Once done this will define
|
||||
# FindFFmpeg
|
||||
# ----------
|
||||
#
|
||||
# FFMPEG_FOUND - system has ffmpeg or libav
|
||||
# FFMPEG_INCLUDE_DIR - the ffmpeg include directory
|
||||
# FFMPEG_LIBRARIES - Link these to use ffmpeg
|
||||
# FFMPEG_LIBAVCODEC
|
||||
# FFMPEG_LIBAVFORMAT
|
||||
# FFMPEG_LIBAVUTIL
|
||||
# Copyright 2019 Citra Emulator Project
|
||||
# Licensed under GPLv2 or any later version
|
||||
#
|
||||
# Copyright (c) 2008 Andreas Schneider <mail@cynapses.org>
|
||||
# Modified for other libraries by Lasse Kärkkäinen <tronic>
|
||||
# Modified for Hedgewars by Stepik777
|
||||
# Modified for FFmpeg-example Tuukka Pasanen 2018
|
||||
# Modified for yuzu toastUnlimted 2020
|
||||
# Find the native FFmpeg includes and libraries
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# This module defines the following variables:
|
||||
#
|
||||
# FFmpeg_INCLUDE_<component>: where to find <component>.h
|
||||
# FFmpeg_LIBRARY_<component>: where to find the <component> library
|
||||
# FFmpeg_INCLUDE_DIR: aggregate all the include paths
|
||||
# FFmpeg_LIBRARIES: aggregate all the paths to the libraries
|
||||
# FFmpeg_FOUND: True if all components have been found
|
||||
#
|
||||
# This module defines the following targets, which are prefered over variables:
|
||||
#
|
||||
# FFmpeg::<component>: Target to use <component> directly, with include path,
|
||||
# library and dependencies set up. If you are using a static build, you are
|
||||
# responsible for adding any external dependencies (such as zlib, bzlib...).
|
||||
#
|
||||
# <component> can be one of:
|
||||
# avcodec
|
||||
# avdevice
|
||||
# avfilter
|
||||
# avformat
|
||||
# avutil
|
||||
# postproc
|
||||
# swresample
|
||||
# swscale
|
||||
#
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(FFMPEG
|
||||
FOUND_VAR FFMPEG_FOUND
|
||||
REQUIRED_VARS
|
||||
FFMPEG_LIBRARY
|
||||
FFMPEG_INCLUDE_DIR
|
||||
VERSION_VAR FFMPEG_VERSION
|
||||
set(_FFmpeg_ALL_COMPONENTS
|
||||
avcodec
|
||||
avdevice
|
||||
avfilter
|
||||
avformat
|
||||
avutil
|
||||
postproc
|
||||
swresample
|
||||
swscale
|
||||
)
|
||||
|
||||
if(FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
|
||||
# in cache already
|
||||
set(FFMPEG_FOUND TRUE)
|
||||
else()
|
||||
# use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
find_package(PkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(_FFMPEG_AVCODEC libavcodec)
|
||||
pkg_check_modules(_FFMPEG_AVUTIL libavutil)
|
||||
pkg_check_modules(_FFMPEG_SWSCALE libswscale)
|
||||
set(_FFmpeg_DEPS_avcodec avutil)
|
||||
set(_FFmpeg_DEPS_avdevice avcodec avformat avutil)
|
||||
set(_FFmpeg_DEPS_avfilter avutil)
|
||||
set(_FFmpeg_DEPS_avformat avcodec avutil)
|
||||
set(_FFmpeg_DEPS_postproc avutil)
|
||||
set(_FFmpeg_DEPS_swresample avutil)
|
||||
set(_FFmpeg_DEPS_swscale avutil)
|
||||
|
||||
function(find_ffmpeg LIBNAME)
|
||||
if(DEFINED ENV{FFMPEG_DIR})
|
||||
set(FFMPEG_DIR $ENV{FFMPEG_DIR})
|
||||
endif()
|
||||
|
||||
find_path(FFMPEG_AVCODEC_INCLUDE_DIR
|
||||
NAMES libavcodec/avcodec.h
|
||||
PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS}
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
PATH_SUFFIXES ffmpeg libav)
|
||||
|
||||
find_library(FFMPEG_LIBAVCODEC
|
||||
NAMES avcodec
|
||||
PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib)
|
||||
|
||||
find_library(FFMPEG_LIBAVUTIL
|
||||
NAMES avutil
|
||||
PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib)
|
||||
|
||||
find_library(FFMPEG_LIBSWSCALE
|
||||
NAMES swscale
|
||||
PATHS ${_FFMPEG_SWSCALE_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib)
|
||||
|
||||
if(FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVUTIL AND FFMPEG_LIBSWSCALE)
|
||||
set(FFMPEG_FOUND TRUE)
|
||||
endif()
|
||||
|
||||
if(FFMPEG_FOUND)
|
||||
set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR})
|
||||
set(FFMPEG_LIBRARIES
|
||||
${FFMPEG_LIBAVCODEC}
|
||||
${FFMPEG_LIBAVUTIL}
|
||||
${FFMPEG_LIBSWSCALE})
|
||||
endif()
|
||||
|
||||
if(FFMPEG_FOUND)
|
||||
if(NOT FFMPEG_FIND_QUIETLY)
|
||||
message(STATUS
|
||||
"Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}")
|
||||
endif()
|
||||
if(FFMPEG_DIR)
|
||||
list(APPEND INCLUDE_PATHS
|
||||
${FFMPEG_DIR}
|
||||
${FFMPEG_DIR}/ffmpeg
|
||||
${FFMPEG_DIR}/lib${LIBNAME}
|
||||
${FFMPEG_DIR}/include/lib${LIBNAME}
|
||||
${FFMPEG_DIR}/include/ffmpeg
|
||||
${FFMPEG_DIR}/include
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
list(APPEND LIB_PATHS
|
||||
${FFMPEG_DIR}
|
||||
${FFMPEG_DIR}/lib
|
||||
${FFMPEG_DIR}/lib${LIBNAME}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
else()
|
||||
if(FFMPEG_FIND_REQUIRED)
|
||||
message(FATAL_ERROR
|
||||
"Could not find libavcodec or libavutil or libswscale")
|
||||
list(APPEND INCLUDE_PATHS
|
||||
/usr/local/include/ffmpeg
|
||||
/usr/local/include/lib${LIBNAME}
|
||||
/usr/include/ffmpeg
|
||||
/usr/include/lib${LIBNAME}
|
||||
/usr/include/ffmpeg/lib${LIBNAME}
|
||||
)
|
||||
|
||||
list(APPEND LIB_PATHS
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
)
|
||||
endif()
|
||||
|
||||
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
|
||||
HINTS ${INCLUDE_PATHS}
|
||||
)
|
||||
|
||||
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
|
||||
HINTS ${LIB_PATHS}
|
||||
)
|
||||
|
||||
if(NOT FFMPEG_DIR AND (NOT FFmpeg_LIBRARY_${LIBNAME} OR NOT FFmpeg_INCLUDE_${LIBNAME}))
|
||||
# Didn't find it in the usual paths, try pkg-config
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(FFmpeg_PKGCONFIG_${LIBNAME} QUIET lib${LIBNAME})
|
||||
|
||||
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
|
||||
${FFmpeg_PKGCONFIG_${LIBNAME}_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
|
||||
${FFmpeg_PKGCONFIG_${LIBNAME}_LIBRARY_DIRS}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(FFmpeg_INCLUDE_${LIBNAME} AND FFmpeg_LIBRARY_${LIBNAME})
|
||||
set(FFmpeg_INCLUDE_${LIBNAME} "${FFmpeg_INCLUDE_${LIBNAME}}" PARENT_SCOPE)
|
||||
set(FFmpeg_LIBRARY_${LIBNAME} "${FFmpeg_LIBRARY_${LIBNAME}}" PARENT_SCOPE)
|
||||
|
||||
# Extract FFmpeg version from version.h
|
||||
foreach(v MAJOR MINOR MICRO)
|
||||
set(FFmpeg_${LIBNAME}_VERSION_${v} 0)
|
||||
endforeach()
|
||||
string(TOUPPER ${LIBNAME} LIBNAME_UPPER)
|
||||
file(STRINGS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version.h" _FFmpeg_VERSION_H_CONTENTS REGEX "#define LIB${LIBNAME_UPPER}_VERSION_(MAJOR|MINOR|MICRO) ")
|
||||
set(_FFmpeg_VERSION_REGEX "([0-9]+)")
|
||||
foreach(v MAJOR MINOR MICRO)
|
||||
if("${_FFmpeg_VERSION_H_CONTENTS}" MATCHES "#define LIB${LIBNAME_UPPER}_VERSION_${v}[\\t ]+${_FFmpeg_VERSION_REGEX}")
|
||||
set(FFmpeg_${LIBNAME}_VERSION_${v} "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(FFmpeg_${LIBNAME}_VERSION "${FFmpeg_${LIBNAME}_VERSION_MAJOR}.${FFmpeg_${LIBNAME}_VERSION_MINOR}.${FFmpeg_${LIBNAME}_VERSION_MICRO}")
|
||||
set(FFmpeg_${c}_VERSION "${FFmpeg_${LIBNAME}_VERSION}" PARENT_SCOPE)
|
||||
unset(_FFmpeg_VERSION_REGEX)
|
||||
unset(_FFmpeg_VERSION_H_CONTENTS)
|
||||
|
||||
set(FFmpeg_${c}_FOUND TRUE PARENT_SCOPE)
|
||||
if(NOT FFmpeg_FIND_QUIETLY)
|
||||
message("-- Found ${LIBNAME}: ${FFmpeg_INCLUDE_${LIBNAME}} ${FFmpeg_LIBRARY_${LIBNAME}} (version: ${FFmpeg_${LIBNAME}_VERSION})")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
foreach(c ${_FFmpeg_ALL_COMPONENTS})
|
||||
find_ffmpeg(${c})
|
||||
endforeach()
|
||||
|
||||
foreach(c ${_FFmpeg_ALL_COMPONENTS})
|
||||
if(FFmpeg_${c}_FOUND)
|
||||
list(APPEND FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_${c}})
|
||||
list(APPEND FFmpeg_LIBRARIES ${FFmpeg_LIBRARY_${c}})
|
||||
|
||||
add_library(FFmpeg::${c} IMPORTED UNKNOWN)
|
||||
set_target_properties(FFmpeg::${c} PROPERTIES
|
||||
IMPORTED_LOCATION ${FFmpeg_LIBRARY_${c}}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${FFmpeg_INCLUDE_${c}}
|
||||
)
|
||||
if(_FFmpeg_DEPS_${c})
|
||||
set(deps)
|
||||
foreach(dep ${_FFmpeg_DEPS_${c}})
|
||||
list(APPEND deps FFmpeg::${dep})
|
||||
endforeach()
|
||||
|
||||
set_target_properties(FFmpeg::${c} PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES "${deps}"
|
||||
)
|
||||
unset(deps)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(FFmpeg_INCLUDE_DIR)
|
||||
list(REMOVE_DUPLICATES FFmpeg_INCLUDE_DIR)
|
||||
endif()
|
||||
|
||||
foreach(c ${FFmpeg_FIND_COMPONENTS})
|
||||
list(APPEND _FFmpeg_REQUIRED_VARS FFmpeg_INCLUDE_${c} FFmpeg_LIBRARY_${c})
|
||||
endforeach()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(FFmpeg
|
||||
REQUIRED_VARS ${_FFmpeg_REQUIRED_VARS}
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
|
||||
foreach(c ${_FFmpeg_ALL_COMPONENTS})
|
||||
unset(_FFmpeg_DEPS_${c})
|
||||
endforeach()
|
||||
unset(_FFmpeg_ALL_COMPONENTS)
|
||||
unset(_FFmpeg_REQUIRED_VARS)
|
||||
|
||||
@@ -383,11 +383,14 @@ void CommandGenerator::GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, E
|
||||
const auto channel_count = params.channel_count;
|
||||
for (s32 i = 0; i < channel_count; i++) {
|
||||
// TODO(ogniK): Actually implement reverb
|
||||
/*
|
||||
if (params.input[i] != params.output[i]) {
|
||||
const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]);
|
||||
auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]);
|
||||
ApplyMix<1>(output, input, 32768, worker_params.sample_count);
|
||||
}
|
||||
}*/
|
||||
auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]);
|
||||
std::memset(output, 0, worker_params.sample_count * sizeof(s32));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,14 @@ void Stream::PlayNextBuffer(std::chrono::nanoseconds ns_late) {
|
||||
|
||||
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
|
||||
|
||||
core_timing.ScheduleEvent(GetBufferReleaseNS(*active_buffer) - ns_late, release_event, {});
|
||||
const auto buffer_release_ns = GetBufferReleaseNS(*active_buffer);
|
||||
|
||||
// If ns_late is higher than the update rate ignore the delay
|
||||
if (ns_late > buffer_release_ns) {
|
||||
ns_late = {};
|
||||
}
|
||||
|
||||
core_timing.ScheduleEvent(buffer_release_ns - ns_late, release_event, {});
|
||||
}
|
||||
|
||||
void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) {
|
||||
|
||||
@@ -206,6 +206,8 @@ if (MSVC)
|
||||
else()
|
||||
target_compile_options(common PRIVATE
|
||||
-Werror
|
||||
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -19,15 +19,14 @@ namespace Common {
|
||||
/// SPSC ring buffer
|
||||
/// @tparam T Element type
|
||||
/// @tparam capacity Number of slots in ring buffer
|
||||
/// @tparam granularity Slot size in terms of number of elements
|
||||
template <typename T, std::size_t capacity, std::size_t granularity = 1>
|
||||
template <typename T, std::size_t capacity>
|
||||
class RingBuffer {
|
||||
/// A "slot" is made of `granularity` elements of `T`.
|
||||
static constexpr std::size_t slot_size = granularity * sizeof(T);
|
||||
/// A "slot" is made of a single `T`.
|
||||
static constexpr std::size_t slot_size = sizeof(T);
|
||||
// T must be safely memcpy-able and have a trivial default constructor.
|
||||
static_assert(std::is_trivial_v<T>);
|
||||
// Ensure capacity is sensible.
|
||||
static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2 / granularity);
|
||||
static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2);
|
||||
static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two");
|
||||
// Ensure lock-free.
|
||||
static_assert(std::atomic_size_t::is_always_lock_free);
|
||||
@@ -47,7 +46,7 @@ public:
|
||||
const std::size_t second_copy = push_count - first_copy;
|
||||
|
||||
const char* in = static_cast<const char*>(new_slots);
|
||||
std::memcpy(m_data.data() + pos * granularity, in, first_copy * slot_size);
|
||||
std::memcpy(m_data.data() + pos, in, first_copy * slot_size);
|
||||
in += first_copy * slot_size;
|
||||
std::memcpy(m_data.data(), in, second_copy * slot_size);
|
||||
|
||||
@@ -74,7 +73,7 @@ public:
|
||||
const std::size_t second_copy = pop_count - first_copy;
|
||||
|
||||
char* out = static_cast<char*>(output);
|
||||
std::memcpy(out, m_data.data() + pos * granularity, first_copy * slot_size);
|
||||
std::memcpy(out, m_data.data() + pos, first_copy * slot_size);
|
||||
out += first_copy * slot_size;
|
||||
std::memcpy(out, m_data.data(), second_copy * slot_size);
|
||||
|
||||
@@ -84,9 +83,9 @@ public:
|
||||
}
|
||||
|
||||
std::vector<T> Pop(std::size_t max_slots = ~std::size_t(0)) {
|
||||
std::vector<T> out(std::min(max_slots, capacity) * granularity);
|
||||
const std::size_t count = Pop(out.data(), out.size() / granularity);
|
||||
out.resize(count * granularity);
|
||||
std::vector<T> out(std::min(max_slots, capacity));
|
||||
const std::size_t count = Pop(out.data(), out.size());
|
||||
out.resize(count);
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -113,7 +112,7 @@ private:
|
||||
alignas(128) std::atomic_size_t m_write_index{0};
|
||||
#endif
|
||||
|
||||
std::array<T, granularity * capacity> m_data;
|
||||
std::array<T, capacity> m_data;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -49,3 +49,9 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
|
||||
* \endcode
|
||||
*/
|
||||
#define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body)
|
||||
|
||||
/**
|
||||
* This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
|
||||
* used when the caller might want to cancel the ScopeExit.
|
||||
*/
|
||||
#define SCOPE_GUARD(body) detail::ScopeExit([&]() body)
|
||||
|
||||
@@ -141,27 +141,13 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
|
||||
}
|
||||
|
||||
std::string UTF16ToUTF8(const std::u16string& input) {
|
||||
#ifdef _MSC_VER
|
||||
// Workaround for missing char16_t/char32_t instantiations in MSVC2017
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
|
||||
std::basic_string<__int16> tmp_buffer(input.cbegin(), input.cend());
|
||||
return convert.to_bytes(tmp_buffer);
|
||||
#else
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||
return convert.to_bytes(input);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::u16string UTF8ToUTF16(const std::string& input) {
|
||||
#ifdef _MSC_VER
|
||||
// Workaround for missing char16_t/char32_t instantiations in MSVC2017
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
|
||||
auto tmp_buffer = convert.from_bytes(input);
|
||||
return std::u16string(tmp_buffer.cbegin(), tmp_buffer.cend());
|
||||
#else
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||
return convert.from_bytes(input);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -160,9 +160,16 @@ add_library(core STATIC
|
||||
hle/kernel/k_affinity_mask.h
|
||||
hle/kernel/k_condition_variable.cpp
|
||||
hle/kernel/k_condition_variable.h
|
||||
hle/kernel/k_event.cpp
|
||||
hle/kernel/k_event.h
|
||||
hle/kernel/k_light_condition_variable.h
|
||||
hle/kernel/k_light_lock.cpp
|
||||
hle/kernel/k_light_lock.h
|
||||
hle/kernel/k_priority_queue.h
|
||||
hle/kernel/k_readable_event.cpp
|
||||
hle/kernel/k_readable_event.h
|
||||
hle/kernel/k_resource_limit.cpp
|
||||
hle/kernel/k_resource_limit.h
|
||||
hle/kernel/k_scheduler.cpp
|
||||
hle/kernel/k_scheduler.h
|
||||
hle/kernel/k_scheduler_lock.h
|
||||
@@ -173,6 +180,8 @@ add_library(core STATIC
|
||||
hle/kernel/k_thread.cpp
|
||||
hle/kernel/k_thread.h
|
||||
hle/kernel/k_thread_queue.h
|
||||
hle/kernel/k_writable_event.cpp
|
||||
hle/kernel/k_writable_event.h
|
||||
hle/kernel/kernel.cpp
|
||||
hle/kernel/kernel.h
|
||||
hle/kernel/memory/address_space_info.cpp
|
||||
@@ -201,10 +210,6 @@ add_library(core STATIC
|
||||
hle/kernel/process.h
|
||||
hle/kernel/process_capability.cpp
|
||||
hle/kernel/process_capability.h
|
||||
hle/kernel/readable_event.cpp
|
||||
hle/kernel/readable_event.h
|
||||
hle/kernel/resource_limit.cpp
|
||||
hle/kernel/resource_limit.h
|
||||
hle/kernel/server_port.cpp
|
||||
hle/kernel/server_port.h
|
||||
hle/kernel/server_session.cpp
|
||||
@@ -225,8 +230,6 @@ add_library(core STATIC
|
||||
hle/kernel/time_manager.h
|
||||
hle/kernel/transfer_memory.cpp
|
||||
hle/kernel/transfer_memory.h
|
||||
hle/kernel/writable_event.cpp
|
||||
hle/kernel/writable_event.h
|
||||
hle/lock.cpp
|
||||
hle/lock.h
|
||||
hle/result.h
|
||||
@@ -650,6 +653,8 @@ else()
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
|
||||
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
|
||||
|
||||
-Wno-sign-conversion
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -568,6 +568,11 @@ KeyManager::KeyManager() {
|
||||
// Initialize keys
|
||||
const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath();
|
||||
const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
|
||||
|
||||
if (!Common::FS::Exists(yuzu_keys_dir)) {
|
||||
Common::FS::CreateDir(yuzu_keys_dir);
|
||||
}
|
||||
|
||||
if (Settings::values.use_dev_keys) {
|
||||
dev_mode = true;
|
||||
AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false);
|
||||
|
||||
@@ -21,6 +21,11 @@ enum class AnalogDirection : u8 {
|
||||
UP,
|
||||
DOWN,
|
||||
};
|
||||
struct AnalogProperties {
|
||||
float deadzone;
|
||||
float range;
|
||||
float threshold;
|
||||
};
|
||||
|
||||
/// An abstract class template for an input device (a button, an analog input, etc.).
|
||||
template <typename StatusType>
|
||||
@@ -30,6 +35,12 @@ public:
|
||||
virtual StatusType GetStatus() const {
|
||||
return {};
|
||||
}
|
||||
virtual StatusType GetRawStatus() const {
|
||||
return GetStatus();
|
||||
}
|
||||
virtual AnalogProperties GetAnalogProperties() const {
|
||||
return {};
|
||||
}
|
||||
virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -41,8 +41,8 @@ class KernelCore;
|
||||
class Process;
|
||||
class ServerSession;
|
||||
class KThread;
|
||||
class ReadableEvent;
|
||||
class WritableEvent;
|
||||
class KReadableEvent;
|
||||
class KWritableEvent;
|
||||
|
||||
enum class ThreadWakeupReason;
|
||||
|
||||
|
||||
@@ -118,9 +118,13 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32
|
||||
|
||||
// Check the userspace value.
|
||||
s32 user_value{};
|
||||
R_UNLESS(UpdateIfEqual(system, std::addressof(user_value), addr, value, value + 1),
|
||||
Svc::ResultInvalidCurrentMemory);
|
||||
R_UNLESS(user_value == value, Svc::ResultInvalidState);
|
||||
if (!UpdateIfEqual(system, &user_value, addr, value, value + 1)) {
|
||||
LOG_ERROR(Kernel, "Invalid current memory!");
|
||||
return Svc::ResultInvalidCurrentMemory;
|
||||
}
|
||||
if (user_value != value) {
|
||||
return Svc::ResultInvalidState;
|
||||
}
|
||||
|
||||
auto it = thread_tree.nfind_light({addr, -1});
|
||||
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
||||
@@ -143,61 +147,34 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
|
||||
// Perform signaling.
|
||||
s32 num_waiters{};
|
||||
{
|
||||
KScopedSchedulerLock sl(kernel);
|
||||
[[maybe_unused]] const KScopedSchedulerLock sl(kernel);
|
||||
|
||||
auto it = thread_tree.nfind_light({addr, -1});
|
||||
// Determine the updated value.
|
||||
s32 new_value{};
|
||||
if (/*GetTargetFirmware() >= TargetFirmware_7_0_0*/ true) {
|
||||
if (count <= 0) {
|
||||
if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) {
|
||||
new_value = value - 2;
|
||||
} else {
|
||||
new_value = value + 1;
|
||||
}
|
||||
if (count <= 0) {
|
||||
if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) {
|
||||
new_value = value - 2;
|
||||
} else {
|
||||
if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) {
|
||||
auto tmp_it = it;
|
||||
s32 tmp_num_waiters{};
|
||||
while ((++tmp_it != thread_tree.end()) &&
|
||||
(tmp_it->GetAddressArbiterKey() == addr)) {
|
||||
if ((tmp_num_waiters++) >= count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_num_waiters < count) {
|
||||
new_value = value - 1;
|
||||
} else {
|
||||
new_value = value;
|
||||
}
|
||||
} else {
|
||||
new_value = value + 1;
|
||||
}
|
||||
new_value = value + 1;
|
||||
}
|
||||
} else {
|
||||
if (count <= 0) {
|
||||
if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) {
|
||||
new_value = value - 1;
|
||||
} else {
|
||||
new_value = value + 1;
|
||||
}
|
||||
} else {
|
||||
if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) {
|
||||
auto tmp_it = it;
|
||||
s32 tmp_num_waiters{};
|
||||
while ((tmp_it != thread_tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) &&
|
||||
(tmp_num_waiters < count + 1)) {
|
||||
++tmp_num_waiters;
|
||||
++tmp_it;
|
||||
while (++tmp_it != thread_tree.end() && tmp_it->GetAddressArbiterKey() == addr) {
|
||||
if (tmp_num_waiters++ >= count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_num_waiters == 0) {
|
||||
new_value = value + 1;
|
||||
} else if (tmp_num_waiters <= count) {
|
||||
if (tmp_num_waiters < count) {
|
||||
new_value = value - 1;
|
||||
} else {
|
||||
new_value = value;
|
||||
}
|
||||
} else {
|
||||
new_value = value + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,13 +182,18 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
|
||||
s32 user_value{};
|
||||
bool succeeded{};
|
||||
if (value != new_value) {
|
||||
succeeded = UpdateIfEqual(system, std::addressof(user_value), addr, value, new_value);
|
||||
succeeded = UpdateIfEqual(system, &user_value, addr, value, new_value);
|
||||
} else {
|
||||
succeeded = ReadFromUser(system, std::addressof(user_value), addr);
|
||||
succeeded = ReadFromUser(system, &user_value, addr);
|
||||
}
|
||||
|
||||
R_UNLESS(succeeded, Svc::ResultInvalidCurrentMemory);
|
||||
R_UNLESS(user_value == value, Svc::ResultInvalidState);
|
||||
if (!succeeded) {
|
||||
LOG_ERROR(Kernel, "Invalid current memory!");
|
||||
return Svc::ResultInvalidCurrentMemory;
|
||||
}
|
||||
if (user_value != value) {
|
||||
return Svc::ResultInvalidState;
|
||||
}
|
||||
|
||||
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
||||
(it->GetAddressArbiterKey() == addr)) {
|
||||
@@ -249,9 +231,9 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
|
||||
s32 user_value{};
|
||||
bool succeeded{};
|
||||
if (decrement) {
|
||||
succeeded = DecrementIfLessThan(system, std::addressof(user_value), addr, value);
|
||||
succeeded = DecrementIfLessThan(system, &user_value, addr, value);
|
||||
} else {
|
||||
succeeded = ReadFromUser(system, std::addressof(user_value), addr);
|
||||
succeeded = ReadFromUser(system, &user_value, addr);
|
||||
}
|
||||
|
||||
if (!succeeded) {
|
||||
@@ -272,7 +254,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
|
||||
}
|
||||
|
||||
// Set the arbiter.
|
||||
cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr);
|
||||
cur_thread->SetAddressArbiter(&thread_tree, addr);
|
||||
thread_tree.insert(*cur_thread);
|
||||
cur_thread->SetState(ThreadState::Waiting);
|
||||
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
|
||||
@@ -293,7 +275,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
|
||||
|
||||
// Get the result.
|
||||
KSynchronizationObject* dummy{};
|
||||
return cur_thread->GetWaitResult(std::addressof(dummy));
|
||||
return cur_thread->GetWaitResult(&dummy);
|
||||
}
|
||||
|
||||
ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
|
||||
@@ -314,7 +296,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
|
||||
|
||||
// Read the value from userspace.
|
||||
s32 user_value{};
|
||||
if (!ReadFromUser(system, std::addressof(user_value), addr)) {
|
||||
if (!ReadFromUser(system, &user_value, addr)) {
|
||||
slp.CancelSleep();
|
||||
return Svc::ResultInvalidCurrentMemory;
|
||||
}
|
||||
@@ -332,7 +314,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
|
||||
}
|
||||
|
||||
// Set the arbiter.
|
||||
cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr);
|
||||
cur_thread->SetAddressArbiter(&thread_tree, addr);
|
||||
thread_tree.insert(*cur_thread);
|
||||
cur_thread->SetState(ThreadState::Waiting);
|
||||
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
|
||||
@@ -353,7 +335,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
|
||||
|
||||
// Get the result.
|
||||
KSynchronizationObject* dummy{};
|
||||
return cur_thread->GetWaitResult(std::addressof(dummy));
|
||||
return cur_thread->GetWaitResult(&dummy);
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool GetAffinity(s32 core) const {
|
||||
return this->mask & GetCoreBit(core);
|
||||
return (this->mask & GetCoreBit(core)) != 0;
|
||||
}
|
||||
|
||||
constexpr void SetAffinity(s32 core, bool set) {
|
||||
|
||||
32
src/core/hle/kernel/k_event.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KEvent::KEvent(KernelCore& kernel, std::string&& name) : Object{kernel, std::move(name)} {}
|
||||
|
||||
KEvent::~KEvent() = default;
|
||||
|
||||
std::shared_ptr<KEvent> KEvent::Create(KernelCore& kernel, std::string&& name) {
|
||||
return std::make_shared<KEvent>(kernel, std::move(name));
|
||||
}
|
||||
|
||||
void KEvent::Initialize() {
|
||||
// Create our sub events.
|
||||
readable_event = std::make_shared<KReadableEvent>(kernel, GetName() + ":Readable");
|
||||
writable_event = std::make_shared<KWritableEvent>(kernel, GetName() + ":Writable");
|
||||
|
||||
// Initialize our sub sessions.
|
||||
readable_event->Initialize(this);
|
||||
writable_event->Initialize(this);
|
||||
|
||||
// Mark initialized.
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
57
src/core/hle/kernel/k_event.h
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class KReadableEvent;
|
||||
class KWritableEvent;
|
||||
|
||||
class KEvent final : public Object {
|
||||
public:
|
||||
explicit KEvent(KernelCore& kernel, std::string&& name);
|
||||
~KEvent() override;
|
||||
|
||||
static std::shared_ptr<KEvent> Create(KernelCore& kernel, std::string&& name);
|
||||
|
||||
void Initialize();
|
||||
|
||||
void Finalize() override {}
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "KEvent";
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::Event;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
std::shared_ptr<KReadableEvent>& GetReadableEvent() {
|
||||
return readable_event;
|
||||
}
|
||||
|
||||
std::shared_ptr<KWritableEvent>& GetWritableEvent() {
|
||||
return writable_event;
|
||||
}
|
||||
|
||||
const std::shared_ptr<KReadableEvent>& GetReadableEvent() const {
|
||||
return readable_event;
|
||||
}
|
||||
|
||||
const std::shared_ptr<KWritableEvent>& GetWritableEvent() const {
|
||||
return writable_event;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<KReadableEvent> readable_event;
|
||||
std::shared_ptr<KWritableEvent> writable_event;
|
||||
bool initialized{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
57
src/core/hle/kernel/k_light_condition_variable.h
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// This file references various implementation details from Atmosphere, an open-source firmware for
|
||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
#include "core/hle/kernel/k_thread_queue.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
|
||||
class KLightConditionVariable {
|
||||
public:
|
||||
explicit KLightConditionVariable(KernelCore& kernel) : thread_queue(kernel), kernel(kernel) {}
|
||||
|
||||
void Wait(KLightLock* lock, s64 timeout = -1) {
|
||||
WaitImpl(lock, timeout);
|
||||
lock->Lock();
|
||||
}
|
||||
|
||||
void Broadcast() {
|
||||
KScopedSchedulerLock lk{kernel};
|
||||
while (thread_queue.WakeupFrontThread() != nullptr) {
|
||||
// We want to signal all threads, and so should continue waking up until there's nothing
|
||||
// to wake.
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void WaitImpl(KLightLock* lock, s64 timeout) {
|
||||
KThread* owner = GetCurrentThreadPointer(kernel);
|
||||
|
||||
// Sleep the thread.
|
||||
{
|
||||
KScopedSchedulerLockAndSleep lk(kernel, owner, timeout);
|
||||
lock->Unlock();
|
||||
|
||||
if (!thread_queue.SleepThread(owner)) {
|
||||
lk.CancelSleep();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel the task that the sleep setup.
|
||||
kernel.TimeManager().UnscheduleTimeEvent(owner);
|
||||
}
|
||||
KThreadQueue thread_queue;
|
||||
KernelCore& kernel;
|
||||
};
|
||||
} // namespace Kernel
|
||||
@@ -24,11 +24,11 @@ template <typename T>
|
||||
concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
|
||||
{ t.GetAffinityMask() }
|
||||
->Common::ConvertibleTo<u64>;
|
||||
{t.SetAffinityMask(std::declval<u64>())};
|
||||
{t.SetAffinityMask(0)};
|
||||
|
||||
{ t.GetAffinity(std::declval<int32_t>()) }
|
||||
{ t.GetAffinity(0) }
|
||||
->std::same_as<bool>;
|
||||
{t.SetAffinity(std::declval<int32_t>(), std::declval<bool>())};
|
||||
{t.SetAffinity(0, false)};
|
||||
{t.SetAll()};
|
||||
};
|
||||
|
||||
@@ -42,11 +42,11 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
|
||||
->std::same_as<T*>;
|
||||
{ (typename T::QueueEntry()).GetPrev() }
|
||||
->std::same_as<T*>;
|
||||
{ t.GetPriorityQueueEntry(std::declval<s32>()) }
|
||||
{ t.GetPriorityQueueEntry(0) }
|
||||
->std::same_as<typename T::QueueEntry&>;
|
||||
|
||||
{t.GetAffinityMask()};
|
||||
{ typename std::remove_cvref<decltype(t.GetAffinityMask())>::type() }
|
||||
{ std::remove_cvref_t<decltype(t.GetAffinityMask())>() }
|
||||
->KPriorityQueueAffinityMask;
|
||||
|
||||
{ t.GetActiveCore() }
|
||||
@@ -55,17 +55,17 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
|
||||
->Common::ConvertibleTo<s32>;
|
||||
};
|
||||
|
||||
template <typename Member, size_t _NumCores, int LowestPriority, int HighestPriority>
|
||||
template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
|
||||
requires KPriorityQueueMember<Member> class KPriorityQueue {
|
||||
public:
|
||||
using AffinityMaskType = typename std::remove_cv_t<
|
||||
typename std::remove_reference<decltype(std::declval<Member>().GetAffinityMask())>::type>;
|
||||
using AffinityMaskType = std::remove_cv_t<
|
||||
std::remove_reference_t<decltype(std::declval<Member>().GetAffinityMask())>>;
|
||||
|
||||
static_assert(LowestPriority >= 0);
|
||||
static_assert(HighestPriority >= 0);
|
||||
static_assert(LowestPriority >= HighestPriority);
|
||||
static constexpr size_t NumPriority = LowestPriority - HighestPriority + 1;
|
||||
static constexpr size_t NumCores = _NumCores;
|
||||
static constexpr size_t NumCores = NumCores_;
|
||||
|
||||
static constexpr bool IsValidCore(s32 core) {
|
||||
return 0 <= core && core < static_cast<s32>(NumCores);
|
||||
|
||||
57
src/core/hle/kernel/k_readable_event.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KReadableEvent::KReadableEvent(KernelCore& kernel, std::string&& name)
|
||||
: KSynchronizationObject{kernel, std::move(name)} {}
|
||||
KReadableEvent::~KReadableEvent() = default;
|
||||
|
||||
bool KReadableEvent::IsSignaled() const {
|
||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||
|
||||
return is_signaled;
|
||||
}
|
||||
|
||||
ResultCode KReadableEvent::Signal() {
|
||||
KScopedSchedulerLock lk{kernel};
|
||||
|
||||
if (!is_signaled) {
|
||||
is_signaled = true;
|
||||
NotifyAvailable();
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode KReadableEvent::Clear() {
|
||||
Reset();
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode KReadableEvent::Reset() {
|
||||
KScopedSchedulerLock lk{kernel};
|
||||
|
||||
if (!is_signaled) {
|
||||
return Svc::ResultInvalidState;
|
||||
}
|
||||
|
||||
is_signaled = false;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
51
src/core/hle/kernel/k_readable_event.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class KEvent;
|
||||
|
||||
class KReadableEvent final : public KSynchronizationObject {
|
||||
public:
|
||||
explicit KReadableEvent(KernelCore& kernel, std::string&& name);
|
||||
~KReadableEvent() override;
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "KReadableEvent";
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
KEvent* GetParent() const {
|
||||
return parent;
|
||||
}
|
||||
|
||||
void Initialize(KEvent* parent_) {
|
||||
is_signaled = false;
|
||||
parent = parent_;
|
||||
}
|
||||
|
||||
bool IsSignaled() const override;
|
||||
void Finalize() override {}
|
||||
|
||||
ResultCode Signal();
|
||||
ResultCode Clear();
|
||||
ResultCode Reset();
|
||||
|
||||
private:
|
||||
bool is_signaled{};
|
||||
KEvent* parent{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
152
src/core/hle/kernel/k_resource_limit.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// This file references various implementation details from Atmosphere, an open-source firmware for
|
||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
|
||||
namespace Kernel {
|
||||
constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
|
||||
|
||||
KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system)
|
||||
: Object{kernel}, lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {}
|
||||
KResourceLimit::~KResourceLimit() = default;
|
||||
|
||||
s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
|
||||
const auto index = static_cast<std::size_t>(which);
|
||||
s64 value{};
|
||||
{
|
||||
KScopedLightLock lk{lock};
|
||||
value = limit_values[index];
|
||||
ASSERT(value >= 0);
|
||||
ASSERT(current_values[index] <= limit_values[index]);
|
||||
ASSERT(current_hints[index] <= current_values[index]);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
s64 KResourceLimit::GetCurrentValue(LimitableResource which) const {
|
||||
const auto index = static_cast<std::size_t>(which);
|
||||
s64 value{};
|
||||
{
|
||||
KScopedLightLock lk{lock};
|
||||
value = current_values[index];
|
||||
ASSERT(value >= 0);
|
||||
ASSERT(current_values[index] <= limit_values[index]);
|
||||
ASSERT(current_hints[index] <= current_values[index]);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
s64 KResourceLimit::GetPeakValue(LimitableResource which) const {
|
||||
const auto index = static_cast<std::size_t>(which);
|
||||
s64 value{};
|
||||
{
|
||||
KScopedLightLock lk{lock};
|
||||
value = peak_values[index];
|
||||
ASSERT(value >= 0);
|
||||
ASSERT(current_values[index] <= limit_values[index]);
|
||||
ASSERT(current_hints[index] <= current_values[index]);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
|
||||
const auto index = static_cast<std::size_t>(which);
|
||||
s64 value{};
|
||||
{
|
||||
KScopedLightLock lk(lock);
|
||||
ASSERT(current_values[index] >= 0);
|
||||
ASSERT(current_values[index] <= limit_values[index]);
|
||||
ASSERT(current_hints[index] <= current_values[index]);
|
||||
value = limit_values[index] - current_values[index];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
|
||||
const auto index = static_cast<std::size_t>(which);
|
||||
KScopedLightLock lk(lock);
|
||||
R_UNLESS(current_values[index] <= value, Svc::ResultInvalidState);
|
||||
|
||||
limit_values[index] = value;
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
|
||||
return Reserve(which, value, system.CoreTiming().GetGlobalTimeNs().count() + DefaultTimeout);
|
||||
}
|
||||
|
||||
bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
|
||||
ASSERT(value >= 0);
|
||||
const auto index = static_cast<std::size_t>(which);
|
||||
KScopedLightLock lk(lock);
|
||||
|
||||
ASSERT(current_hints[index] <= current_values[index]);
|
||||
if (current_hints[index] >= limit_values[index]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loop until we reserve or run out of time.
|
||||
while (true) {
|
||||
ASSERT(current_values[index] <= limit_values[index]);
|
||||
ASSERT(current_hints[index] <= current_values[index]);
|
||||
|
||||
// If we would overflow, don't allow to succeed.
|
||||
if (current_values[index] + value <= current_values[index]) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_values[index] + value <= limit_values[index]) {
|
||||
current_values[index] += value;
|
||||
current_hints[index] += value;
|
||||
peak_values[index] = std::max(peak_values[index], current_values[index]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (current_hints[index] + value <= limit_values[index] &&
|
||||
(timeout < 0 || system.CoreTiming().GetGlobalTimeNs().count() < timeout)) {
|
||||
waiter_count++;
|
||||
cond_var.Wait(&lock, timeout);
|
||||
waiter_count--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void KResourceLimit::Release(LimitableResource which, s64 value) {
|
||||
Release(which, value, value);
|
||||
}
|
||||
|
||||
void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) {
|
||||
ASSERT(value >= 0);
|
||||
ASSERT(hint >= 0);
|
||||
|
||||
const auto index = static_cast<std::size_t>(which);
|
||||
KScopedLightLock lk(lock);
|
||||
ASSERT(current_values[index] <= limit_values[index]);
|
||||
ASSERT(current_hints[index] <= current_values[index]);
|
||||
ASSERT(value <= current_values[index]);
|
||||
ASSERT(hint <= current_hints[index]);
|
||||
|
||||
current_values[index] -= value;
|
||||
current_hints[index] -= hint;
|
||||
|
||||
if (waiter_count != 0) {
|
||||
cond_var.Broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
81
src/core/hle/kernel/k_resource_limit.h
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// This file references various implementation details from Atmosphere, an open-source firmware for
|
||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_light_condition_variable.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
enum class LimitableResource : u32 {
|
||||
PhysicalMemory = 0,
|
||||
Threads = 1,
|
||||
Events = 2,
|
||||
TransferMemory = 3,
|
||||
Sessions = 4,
|
||||
|
||||
Count,
|
||||
};
|
||||
|
||||
constexpr bool IsValidResourceType(LimitableResource type) {
|
||||
return type < LimitableResource::Count;
|
||||
}
|
||||
|
||||
class KResourceLimit final : public Object {
|
||||
public:
|
||||
explicit KResourceLimit(KernelCore& kernel, Core::System& system);
|
||||
~KResourceLimit();
|
||||
|
||||
s64 GetLimitValue(LimitableResource which) const;
|
||||
s64 GetCurrentValue(LimitableResource which) const;
|
||||
s64 GetPeakValue(LimitableResource which) const;
|
||||
s64 GetFreeValue(LimitableResource which) const;
|
||||
|
||||
ResultCode SetLimitValue(LimitableResource which, s64 value);
|
||||
|
||||
bool Reserve(LimitableResource which, s64 value);
|
||||
bool Reserve(LimitableResource which, s64 value, s64 timeout);
|
||||
void Release(LimitableResource which, s64 value);
|
||||
void Release(LimitableResource which, s64 value, s64 hint);
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "KResourceLimit";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return GetTypeName();
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
virtual void Finalize() override {}
|
||||
|
||||
private:
|
||||
using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>;
|
||||
ResourceArray limit_values{};
|
||||
ResourceArray current_values{};
|
||||
ResourceArray current_hints{};
|
||||
ResourceArray peak_values{};
|
||||
mutable KLightLock lock;
|
||||
s32 waiter_count{};
|
||||
KLightConditionVariable cond_var;
|
||||
KernelCore& kernel;
|
||||
Core::System& system;
|
||||
};
|
||||
} // namespace Kernel
|
||||
@@ -132,6 +132,9 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
|
||||
|
||||
KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {}
|
||||
|
||||
KSynchronizationObject::KSynchronizationObject(KernelCore& kernel, std::string&& name)
|
||||
: Object{kernel, std::move(name)} {}
|
||||
|
||||
KSynchronizationObject::~KSynchronizationObject() = default;
|
||||
|
||||
void KSynchronizationObject::NotifyAvailable(ResultCode result) {
|
||||
|
||||
@@ -33,6 +33,7 @@ public:
|
||||
|
||||
protected:
|
||||
explicit KSynchronizationObject(KernelCore& kernel);
|
||||
explicit KSynchronizationObject(KernelCore& kernel, std::string&& name);
|
||||
virtual ~KSynchronizationObject();
|
||||
|
||||
void NotifyAvailable(ResultCode result);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/k_condition_variable.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
@@ -29,7 +30,6 @@
|
||||
#include "core/hle/kernel/memory/memory_layout.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
#include "core/hle/result.h"
|
||||
@@ -247,7 +247,7 @@ void KThread::Finalize() {
|
||||
// Decrement the parent process's thread count.
|
||||
if (parent != nullptr) {
|
||||
parent->DecrementThreadCount();
|
||||
parent->GetResourceLimit()->Release(ResourceType::Threads, 1);
|
||||
parent->GetResourceLimit()->Release(LimitableResource::Threads, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
27
src/core/hle/kernel/k_writable_event.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KWritableEvent::KWritableEvent(KernelCore& kernel, std::string&& name)
|
||||
: Object{kernel, std::move(name)} {}
|
||||
KWritableEvent::~KWritableEvent() = default;
|
||||
|
||||
void KWritableEvent::Initialize(KEvent* parent_) {
|
||||
parent = parent_;
|
||||
}
|
||||
|
||||
ResultCode KWritableEvent::Signal() {
|
||||
return parent->GetReadableEvent()->Signal();
|
||||
}
|
||||
|
||||
ResultCode KWritableEvent::Clear() {
|
||||
return parent->GetReadableEvent()->Clear();
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
44
src/core/hle/kernel/k_writable_event.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class KEvent;
|
||||
|
||||
class KWritableEvent final : public Object {
|
||||
public:
|
||||
explicit KWritableEvent(KernelCore& kernel, std::string&& name);
|
||||
~KWritableEvent() override;
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "KWritableEvent";
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
void Initialize(KEvent* parent_);
|
||||
|
||||
void Finalize() override {}
|
||||
|
||||
ResultCode Signal();
|
||||
ResultCode Clear();
|
||||
|
||||
KEvent* GetParent() const {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private:
|
||||
KEvent* parent{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
@@ -36,7 +37,6 @@
|
||||
#include "core/hle/kernel/memory/slab_heap.h"
|
||||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/kernel/service_thread.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
@@ -66,7 +66,7 @@ struct KernelCore::Impl {
|
||||
is_phantom_mode_for_singlecore = false;
|
||||
|
||||
InitializePhysicalCores();
|
||||
InitializeSystemResourceLimit(kernel);
|
||||
InitializeSystemResourceLimit(kernel, system);
|
||||
InitializeMemoryLayout();
|
||||
InitializePreemption(kernel);
|
||||
InitializeSchedulers();
|
||||
@@ -131,19 +131,19 @@ struct KernelCore::Impl {
|
||||
}
|
||||
|
||||
// Creates the default system resource limit
|
||||
void InitializeSystemResourceLimit(KernelCore& kernel) {
|
||||
system_resource_limit = ResourceLimit::Create(kernel);
|
||||
void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) {
|
||||
system_resource_limit = std::make_shared<KResourceLimit>(kernel, system);
|
||||
|
||||
// If setting the default system values fails, then something seriously wrong has occurred.
|
||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x100000000)
|
||||
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000)
|
||||
.IsSuccess());
|
||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess());
|
||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess());
|
||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess());
|
||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
|
||||
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
|
||||
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess());
|
||||
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
|
||||
.IsSuccess());
|
||||
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 900).IsSuccess());
|
||||
|
||||
if (!system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0) ||
|
||||
!system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0x60000)) {
|
||||
if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, 0x60000)) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
@@ -320,7 +320,7 @@ struct KernelCore::Impl {
|
||||
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
||||
Kernel::TimeManager time_manager;
|
||||
|
||||
std::shared_ptr<ResourceLimit> system_resource_limit;
|
||||
std::shared_ptr<KResourceLimit> system_resource_limit;
|
||||
|
||||
std::shared_ptr<Core::Timing::EventType> preemption_event;
|
||||
|
||||
@@ -390,7 +390,7 @@ void KernelCore::Shutdown() {
|
||||
impl->Shutdown();
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
|
||||
std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const {
|
||||
return impl->system_resource_limit;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class GlobalSchedulerContext;
|
||||
class HandleTable;
|
||||
class PhysicalCore;
|
||||
class Process;
|
||||
class ResourceLimit;
|
||||
class KResourceLimit;
|
||||
class KScheduler;
|
||||
class SharedMemory;
|
||||
class ServiceThread;
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
void Shutdown();
|
||||
|
||||
/// Retrieves a shared pointer to the system resource limit instance.
|
||||
std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const;
|
||||
std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const;
|
||||
|
||||
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
|
||||
std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/memory/address_space_info.h"
|
||||
#include "core/hle/kernel/memory/memory_block.h"
|
||||
@@ -15,7 +16,6 @@
|
||||
#include "core/hle/kernel/memory/page_table.h"
|
||||
#include "core/hle/kernel/memory/system_control.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel::Memory {
|
||||
@@ -414,7 +414,7 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||
const std::size_t remaining_pages{remaining_size / PageSize};
|
||||
|
||||
if (process->GetResourceLimit() &&
|
||||
!process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, remaining_size)) {
|
||||
!process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, remaining_size)) {
|
||||
return ERR_RESOURCE_LIMIT_EXCEEDED;
|
||||
}
|
||||
|
||||
@@ -422,7 +422,7 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||
{
|
||||
auto block_guard = detail::ScopeExit([&] {
|
||||
system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool);
|
||||
process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, remaining_size);
|
||||
process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, remaining_size);
|
||||
});
|
||||
|
||||
CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages,
|
||||
@@ -474,7 +474,7 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||
CASCADE_CODE(UnmapMemory(addr, size));
|
||||
|
||||
auto process{system.Kernel().CurrentProcess()};
|
||||
process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, mapped_size);
|
||||
process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size);
|
||||
physical_memory_usage -= mapped_size;
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
@@ -783,7 +783,7 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
|
||||
|
||||
auto process{system.Kernel().CurrentProcess()};
|
||||
if (process->GetResourceLimit() && delta != 0 &&
|
||||
!process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, delta)) {
|
||||
!process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, delta)) {
|
||||
return ERR_RESOURCE_LIMIT_EXCEEDED;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Object::Object(KernelCore& kernel) : kernel{kernel}, object_id{kernel.CreateNewObjectID()} {}
|
||||
Object::Object(KernelCore& kernel_)
|
||||
: kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{"[UNKNOWN KERNEL OBJECT]"} {}
|
||||
Object::Object(KernelCore& kernel_, std::string&& name_)
|
||||
: kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{std::move(name_)} {}
|
||||
Object::~Object() = default;
|
||||
|
||||
bool Object::IsWaitable() const {
|
||||
@@ -21,6 +24,7 @@ bool Object::IsWaitable() const {
|
||||
return true;
|
||||
|
||||
case HandleType::Unknown:
|
||||
case HandleType::Event:
|
||||
case HandleType::WritableEvent:
|
||||
case HandleType::SharedMemory:
|
||||
case HandleType::TransferMemory:
|
||||
|
||||
@@ -18,6 +18,7 @@ using Handle = u32;
|
||||
|
||||
enum class HandleType : u32 {
|
||||
Unknown,
|
||||
Event,
|
||||
WritableEvent,
|
||||
ReadableEvent,
|
||||
SharedMemory,
|
||||
@@ -34,7 +35,8 @@ enum class HandleType : u32 {
|
||||
|
||||
class Object : NonCopyable, public std::enable_shared_from_this<Object> {
|
||||
public:
|
||||
explicit Object(KernelCore& kernel);
|
||||
explicit Object(KernelCore& kernel_);
|
||||
explicit Object(KernelCore& kernel_, std::string&& name_);
|
||||
virtual ~Object();
|
||||
|
||||
/// Returns a unique identifier for the object. For debugging purposes only.
|
||||
@@ -46,7 +48,7 @@ public:
|
||||
return "[BAD KERNEL OBJECT TYPE]";
|
||||
}
|
||||
virtual std::string GetName() const {
|
||||
return "[UNKNOWN KERNEL OBJECT]";
|
||||
return name;
|
||||
}
|
||||
virtual HandleType GetHandleType() const = 0;
|
||||
|
||||
@@ -69,6 +71,7 @@ protected:
|
||||
|
||||
private:
|
||||
std::atomic<u32> object_id{0};
|
||||
std::string name;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "core/file_sys/program_metadata.h"
|
||||
#include "core/hle/kernel/code_set.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
@@ -22,7 +23,7 @@
|
||||
#include "core/hle/kernel/memory/page_table.h"
|
||||
#include "core/hle/kernel/memory/slab_heap.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
@@ -116,7 +117,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
|
||||
|
||||
std::shared_ptr<Process> process = std::make_shared<Process>(system);
|
||||
process->name = std::move(name);
|
||||
process->resource_limit = ResourceLimit::Create(kernel);
|
||||
process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
|
||||
process->status = ProcessStatus::Created;
|
||||
process->program_id = 0;
|
||||
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
|
||||
@@ -132,7 +133,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
|
||||
return process;
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const {
|
||||
std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const {
|
||||
return resource_limit;
|
||||
}
|
||||
|
||||
@@ -154,7 +155,7 @@ void Process::DecrementThreadCount() {
|
||||
}
|
||||
|
||||
u64 Process::GetTotalPhysicalMemoryAvailable() const {
|
||||
const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) +
|
||||
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
|
||||
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
|
||||
main_thread_stack_size};
|
||||
|
||||
@@ -241,18 +242,16 @@ void Process::UnregisterThread(const KThread* thread) {
|
||||
thread_list.remove(thread);
|
||||
}
|
||||
|
||||
ResultCode Process::ClearSignalState() {
|
||||
KScopedSchedulerLock lock(system.Kernel());
|
||||
if (status == ProcessStatus::Exited) {
|
||||
LOG_ERROR(Kernel, "called on a terminated process instance.");
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
ResultCode Process::Reset() {
|
||||
// Lock the process and the scheduler.
|
||||
KScopedLightLock lk(state_lock);
|
||||
KScopedSchedulerLock sl{kernel};
|
||||
|
||||
if (!is_signaled) {
|
||||
LOG_ERROR(Kernel, "called on a process instance that isn't signaled.");
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
// Validate that we're in a state that we can reset.
|
||||
R_UNLESS(status != ProcessStatus::Exited, Svc::ResultInvalidState);
|
||||
R_UNLESS(is_signaled, Svc::ResultInvalidState);
|
||||
|
||||
// Clear signaled.
|
||||
is_signaled = false;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
@@ -308,13 +307,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
|
||||
|
||||
// Set initial resource limits
|
||||
resource_limit->SetLimitValue(
|
||||
ResourceType::PhysicalMemory,
|
||||
LimitableResource::PhysicalMemory,
|
||||
kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
|
||||
resource_limit->SetLimitValue(ResourceType::Threads, 608);
|
||||
resource_limit->SetLimitValue(ResourceType::Events, 700);
|
||||
resource_limit->SetLimitValue(ResourceType::TransferMemory, 128);
|
||||
resource_limit->SetLimitValue(ResourceType::Sessions, 894);
|
||||
ASSERT(resource_limit->Reserve(ResourceType::PhysicalMemory, code_size));
|
||||
resource_limit->SetLimitValue(LimitableResource::Threads, 608);
|
||||
resource_limit->SetLimitValue(LimitableResource::Events, 700);
|
||||
resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128);
|
||||
resource_limit->SetLimitValue(LimitableResource::Sessions, 894);
|
||||
ASSERT(resource_limit->Reserve(LimitableResource::PhysicalMemory, code_size));
|
||||
|
||||
// Create TLS region
|
||||
tls_region_address = CreateTLSRegion();
|
||||
@@ -331,8 +330,8 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
|
||||
ChangeStatus(ProcessStatus::Running);
|
||||
|
||||
SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top);
|
||||
resource_limit->Reserve(ResourceType::Threads, 1);
|
||||
resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size);
|
||||
resource_limit->Reserve(LimitableResource::Threads, 1);
|
||||
resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
|
||||
}
|
||||
|
||||
void Process::PrepareForTermination() {
|
||||
|
||||
@@ -29,7 +29,7 @@ class ProgramMetadata;
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class ResourceLimit;
|
||||
class KResourceLimit;
|
||||
class KThread;
|
||||
class TLSPage;
|
||||
|
||||
@@ -170,7 +170,7 @@ public:
|
||||
}
|
||||
|
||||
/// Gets the resource limit descriptor for this process
|
||||
std::shared_ptr<ResourceLimit> GetResourceLimit() const;
|
||||
std::shared_ptr<KResourceLimit> GetResourceLimit() const;
|
||||
|
||||
/// Gets the ideal CPU core ID for this process
|
||||
u8 GetIdealCoreId() const {
|
||||
@@ -312,7 +312,7 @@ public:
|
||||
/// @pre The process must be in a signaled state. If this is called on a
|
||||
/// process instance that is not signaled, ERR_INVALID_STATE will be
|
||||
/// returned.
|
||||
ResultCode ClearSignalState();
|
||||
ResultCode Reset();
|
||||
|
||||
/**
|
||||
* Loads process-specifics configuration info with metadata provided
|
||||
@@ -402,7 +402,7 @@ private:
|
||||
u32 system_resource_size = 0;
|
||||
|
||||
/// Resource limit descriptor for this process
|
||||
std::shared_ptr<ResourceLimit> resource_limit;
|
||||
std::shared_ptr<KResourceLimit> resource_limit;
|
||||
|
||||
/// The ideal CPU core for this process, threads are scheduled on this core by default.
|
||||
u8 ideal_core = 0;
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ReadableEvent::ReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {}
|
||||
ReadableEvent::~ReadableEvent() = default;
|
||||
|
||||
void ReadableEvent::Signal() {
|
||||
if (is_signaled) {
|
||||
return;
|
||||
}
|
||||
|
||||
is_signaled = true;
|
||||
NotifyAvailable();
|
||||
}
|
||||
|
||||
bool ReadableEvent::IsSignaled() const {
|
||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||
|
||||
return is_signaled;
|
||||
}
|
||||
|
||||
void ReadableEvent::Clear() {
|
||||
is_signaled = false;
|
||||
}
|
||||
|
||||
ResultCode ReadableEvent::Reset() {
|
||||
KScopedSchedulerLock lock(kernel);
|
||||
if (!is_signaled) {
|
||||
LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}",
|
||||
GetObjectId(), GetTypeName(), GetName());
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
Clear();
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class WritableEvent;
|
||||
|
||||
class ReadableEvent final : public KSynchronizationObject {
|
||||
friend class WritableEvent;
|
||||
|
||||
public:
|
||||
~ReadableEvent() override;
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "ReadableEvent";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/// Unconditionally clears the readable event's state.
|
||||
void Clear();
|
||||
|
||||
/// Clears the readable event's state if and only if it
|
||||
/// has already been signaled.
|
||||
///
|
||||
/// @pre The event must be in a signaled state. If this event
|
||||
/// is in an unsignaled state and this function is called,
|
||||
/// then ERR_INVALID_STATE will be returned.
|
||||
ResultCode Reset();
|
||||
|
||||
void Signal();
|
||||
|
||||
bool IsSignaled() const override;
|
||||
|
||||
void Finalize() override {}
|
||||
|
||||
private:
|
||||
explicit ReadableEvent(KernelCore& kernel);
|
||||
|
||||
bool is_signaled{};
|
||||
std::string name; ///< Name of event (optional)
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
namespace {
|
||||
constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
|
||||
return static_cast<std::size_t>(type);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
|
||||
ResourceLimit::~ResourceLimit() = default;
|
||||
|
||||
bool ResourceLimit::Reserve(ResourceType resource, s64 amount) {
|
||||
return Reserve(resource, amount, 10000000000);
|
||||
}
|
||||
|
||||
bool ResourceLimit::Reserve(ResourceType resource, s64 amount, u64 timeout) {
|
||||
const std::size_t index{ResourceTypeToIndex(resource)};
|
||||
|
||||
s64 new_value = current[index] + amount;
|
||||
if (new_value > limit[index] && available[index] + amount <= limit[index]) {
|
||||
// TODO(bunnei): This is wrong for multicore, we should wait the calling thread for timeout
|
||||
new_value = current[index] + amount;
|
||||
}
|
||||
|
||||
if (new_value <= limit[index]) {
|
||||
current[index] = new_value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ResourceLimit::Release(ResourceType resource, u64 amount) {
|
||||
Release(resource, amount, amount);
|
||||
}
|
||||
|
||||
void ResourceLimit::Release(ResourceType resource, u64 used_amount, u64 available_amount) {
|
||||
const std::size_t index{ResourceTypeToIndex(resource)};
|
||||
|
||||
current[index] -= used_amount;
|
||||
available[index] -= available_amount;
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) {
|
||||
return std::make_shared<ResourceLimit>(kernel);
|
||||
}
|
||||
|
||||
s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
|
||||
return limit.at(ResourceTypeToIndex(resource)) - current.at(ResourceTypeToIndex(resource));
|
||||
}
|
||||
|
||||
s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
|
||||
return limit.at(ResourceTypeToIndex(resource));
|
||||
}
|
||||
|
||||
ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) {
|
||||
const std::size_t index{ResourceTypeToIndex(resource)};
|
||||
if (current[index] <= value) {
|
||||
limit[index] = value;
|
||||
return RESULT_SUCCESS;
|
||||
} else {
|
||||
LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", resource,
|
||||
value, index);
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
} // namespace Kernel
|
||||
@@ -1,106 +0,0 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
|
||||
enum class ResourceType : u32 {
|
||||
PhysicalMemory,
|
||||
Threads,
|
||||
Events,
|
||||
TransferMemory,
|
||||
Sessions,
|
||||
|
||||
// Used as a count, not an actual type.
|
||||
ResourceTypeCount
|
||||
};
|
||||
|
||||
constexpr bool IsValidResourceType(ResourceType type) {
|
||||
return type < ResourceType::ResourceTypeCount;
|
||||
}
|
||||
|
||||
class ResourceLimit final : public Object {
|
||||
public:
|
||||
explicit ResourceLimit(KernelCore& kernel);
|
||||
~ResourceLimit() override;
|
||||
|
||||
/// Creates a resource limit object.
|
||||
static std::shared_ptr<ResourceLimit> Create(KernelCore& kernel);
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "ResourceLimit";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return GetTypeName();
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
bool Reserve(ResourceType resource, s64 amount);
|
||||
bool Reserve(ResourceType resource, s64 amount, u64 timeout);
|
||||
void Release(ResourceType resource, u64 amount);
|
||||
void Release(ResourceType resource, u64 used_amount, u64 available_amount);
|
||||
|
||||
/**
|
||||
* Gets the current value for the specified resource.
|
||||
* @param resource Requested resource type
|
||||
* @returns The current value of the resource type
|
||||
*/
|
||||
s64 GetCurrentResourceValue(ResourceType resource) const;
|
||||
|
||||
/**
|
||||
* Gets the max value for the specified resource.
|
||||
* @param resource Requested resource type
|
||||
* @returns The max value of the resource type
|
||||
*/
|
||||
s64 GetMaxResourceValue(ResourceType resource) const;
|
||||
|
||||
/**
|
||||
* Sets the limit value for a given resource type.
|
||||
*
|
||||
* @param resource The resource type to apply the limit to.
|
||||
* @param value The limit to apply to the given resource type.
|
||||
*
|
||||
* @return A result code indicating if setting the limit value
|
||||
* was successful or not.
|
||||
*
|
||||
* @note The supplied limit value *must* be greater than or equal to
|
||||
* the current resource value for the given resource type,
|
||||
* otherwise ERR_INVALID_STATE will be returned.
|
||||
*/
|
||||
ResultCode SetLimitValue(ResourceType resource, s64 value);
|
||||
|
||||
void Finalize() override {}
|
||||
|
||||
private:
|
||||
// TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
|
||||
// functions
|
||||
//
|
||||
// Currently we have no way of distinguishing if a Create was called by the running application,
|
||||
// or by a service module. Approach this once we have separated the service modules into their
|
||||
// own processes
|
||||
|
||||
using ResourceArray =
|
||||
std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>;
|
||||
|
||||
ResourceArray limit{};
|
||||
ResourceArray current{};
|
||||
ResourceArray available{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "common/fiber.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/core.h"
|
||||
@@ -26,18 +27,20 @@
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/k_address_arbiter.h"
|
||||
#include "core/hle/kernel/k_condition_variable.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/memory/memory_block.h"
|
||||
#include "core/hle/kernel/memory/memory_layout.h"
|
||||
#include "core/hle/kernel/memory/page_table.h"
|
||||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
@@ -45,7 +48,6 @@
|
||||
#include "core/hle/kernel/svc_wrap.h"
|
||||
#include "core/hle/kernel/time_manager.h"
|
||||
#include "core/hle/kernel/transfer_memory.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/service.h"
|
||||
@@ -141,7 +143,7 @@ enum class ResourceLimitValueType {
|
||||
ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
|
||||
u32 resource_type, ResourceLimitValueType value_type) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
const auto type = static_cast<ResourceType>(resource_type);
|
||||
const auto type = static_cast<LimitableResource>(resource_type);
|
||||
if (!IsValidResourceType(type)) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
|
||||
return ERR_INVALID_ENUM_VALUE;
|
||||
@@ -151,7 +153,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
|
||||
ASSERT(current_process != nullptr);
|
||||
|
||||
const auto resource_limit_object =
|
||||
current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
|
||||
current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
|
||||
if (!resource_limit_object) {
|
||||
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
|
||||
resource_limit);
|
||||
@@ -159,10 +161,10 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
|
||||
}
|
||||
|
||||
if (value_type == ResourceLimitValueType::CurrentValue) {
|
||||
return MakeResult(resource_limit_object->GetCurrentResourceValue(type));
|
||||
return MakeResult(resource_limit_object->GetCurrentValue(type));
|
||||
}
|
||||
|
||||
return MakeResult(resource_limit_object->GetMaxResourceValue(type));
|
||||
return MakeResult(resource_limit_object->GetLimitValue(type));
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
@@ -312,7 +314,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Sessions, 1));
|
||||
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::Sessions, 1));
|
||||
|
||||
auto client_port = it->second;
|
||||
|
||||
@@ -366,7 +368,10 @@ static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle t
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
// Get the thread's id.
|
||||
*out_thread_id = thread->GetThreadID();
|
||||
@@ -476,7 +481,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
// Cancel the thread's wait.
|
||||
thread->WaitCancel();
|
||||
@@ -494,8 +502,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd
|
||||
thread_handle, address, tag);
|
||||
|
||||
// Validate the input address.
|
||||
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
|
||||
R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress);
|
||||
if (Memory::IsKernelAddress(address)) {
|
||||
LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})",
|
||||
address);
|
||||
return ResultInvalidCurrentMemory;
|
||||
}
|
||||
if (!Common::IsAligned(address, sizeof(u32))) {
|
||||
LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
|
||||
return ResultInvalidAddress;
|
||||
}
|
||||
|
||||
return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag);
|
||||
}
|
||||
@@ -510,8 +525,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) {
|
||||
LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
|
||||
|
||||
// Validate the input address.
|
||||
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
|
||||
R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress);
|
||||
if (Memory::IsKernelAddress(address)) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Attempting to arbitrate an unlock on a kernel address (address={:08X})",
|
||||
address);
|
||||
return ResultInvalidCurrentMemory;
|
||||
}
|
||||
if (!Common::IsAligned(address, sizeof(u32))) {
|
||||
LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
|
||||
return ResultInvalidAddress;
|
||||
}
|
||||
|
||||
return system.Kernel().CurrentProcess()->SignalToAddress(address);
|
||||
}
|
||||
@@ -1023,37 +1046,47 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size
|
||||
return UnmapPhysicalMemory(system, addr, size);
|
||||
}
|
||||
|
||||
constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) {
|
||||
switch (thread_activity) {
|
||||
case Svc::ThreadActivity::Runnable:
|
||||
case Svc::ThreadActivity::Paused:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the thread activity
|
||||
static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
|
||||
Svc::ThreadActivity thread_activity) {
|
||||
ThreadActivity thread_activity) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
|
||||
thread_activity);
|
||||
|
||||
// Validate the activity.
|
||||
R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue);
|
||||
constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
|
||||
return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
|
||||
};
|
||||
if (!IsValidThreadActivity(thread_activity)) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})",
|
||||
thread_activity);
|
||||
return ResultInvalidEnumValue;
|
||||
}
|
||||
|
||||
// Get the thread from its handle.
|
||||
auto& kernel = system.Kernel();
|
||||
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
// Check that the activity is being set on a non-current thread for the current process.
|
||||
R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle);
|
||||
R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy);
|
||||
if (thread->GetOwnerProcess() != kernel.CurrentProcess()) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread.");
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
if (thread.get() == GetCurrentThreadPointer(kernel)) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread is busy");
|
||||
return ResultBusy;
|
||||
}
|
||||
|
||||
// Set the activity.
|
||||
R_TRY(thread->SetActivity(thread_activity));
|
||||
const auto set_result = thread->SetActivity(thread_activity);
|
||||
if (set_result.IsError()) {
|
||||
LOG_ERROR(Kernel_SVC, "Failed to set thread activity.");
|
||||
return set_result;
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
@@ -1072,16 +1105,29 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
|
||||
const auto* current_process = system.Kernel().CurrentProcess();
|
||||
const std::shared_ptr<KThread> thread =
|
||||
current_process->GetHandleTable().Get<KThread>(thread_handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
// Require the handle be to a non-current thread in the current process.
|
||||
R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle);
|
||||
R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(),
|
||||
Svc::ResultBusy);
|
||||
if (thread->GetOwnerProcess() != current_process) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process.");
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
|
||||
LOG_ERROR(Kernel_SVC, "Current thread is busy.");
|
||||
return ResultBusy;
|
||||
}
|
||||
|
||||
// Get the thread context.
|
||||
std::vector<u8> context;
|
||||
R_TRY(thread->GetThreadContext3(context));
|
||||
const auto context_result = thread->GetThreadContext3(context);
|
||||
if (context_result.IsError()) {
|
||||
LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})",
|
||||
context_result.raw);
|
||||
return context_result;
|
||||
}
|
||||
|
||||
// Copy the thread context to user space.
|
||||
system.Memory().WriteBlock(out_context, context.data(), context.size());
|
||||
@@ -1100,7 +1146,10 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
// Get the thread's priority.
|
||||
*out_priority = thread->GetPriority();
|
||||
@@ -1116,13 +1165,18 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri
|
||||
LOG_TRACE(Kernel_SVC, "called");
|
||||
|
||||
// Validate the priority.
|
||||
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
|
||||
Svc::ResultInvalidPriority);
|
||||
if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority);
|
||||
return ResultInvalidPriority;
|
||||
}
|
||||
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
// Set the thread priority.
|
||||
thread->SetBasePriority(priority);
|
||||
@@ -1438,19 +1492,31 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
|
||||
// Adjust core id, if it's the default magic.
|
||||
auto& kernel = system.Kernel();
|
||||
auto& process = *kernel.CurrentProcess();
|
||||
if (core_id == Svc::IdealCoreUseProcessValue) {
|
||||
if (core_id == IdealCoreUseProcessValue) {
|
||||
core_id = process.GetIdealCoreId();
|
||||
}
|
||||
|
||||
// Validate arguments.
|
||||
R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId);
|
||||
R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId);
|
||||
if (!IsValidCoreId(core_id)) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
|
||||
return ResultInvalidCoreId;
|
||||
}
|
||||
if (((1ULL << core_id) & process.GetCoreMask()) == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id);
|
||||
return ResultInvalidCoreId;
|
||||
}
|
||||
|
||||
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
|
||||
Svc::ResultInvalidPriority);
|
||||
R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
|
||||
if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority);
|
||||
return ResultInvalidPriority;
|
||||
}
|
||||
if (!process.CheckThreadPriority(priority)) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority);
|
||||
return ResultInvalidPriority;
|
||||
}
|
||||
|
||||
ASSERT(process.GetResourceLimit()->Reserve(ResourceType::Threads, 1));
|
||||
ASSERT(process.GetResourceLimit()->Reserve(
|
||||
LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000));
|
||||
|
||||
std::shared_ptr<KThread> thread;
|
||||
{
|
||||
@@ -1486,10 +1552,19 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
// Try to start the thread.
|
||||
R_TRY(thread->Run());
|
||||
const auto run_result = thread->Run();
|
||||
if (run_result.IsError()) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Unable to successfuly start thread (thread handle={:08X}, result={})",
|
||||
thread_handle, run_result.raw);
|
||||
return run_result;
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
@@ -1550,8 +1625,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address,
|
||||
cv_key, tag, timeout_ns);
|
||||
|
||||
// Validate input.
|
||||
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
|
||||
R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress);
|
||||
if (Memory::IsKernelAddress(address)) {
|
||||
LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address);
|
||||
return ResultInvalidCurrentMemory;
|
||||
}
|
||||
if (!Common::IsAligned(address, sizeof(s32))) {
|
||||
LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address);
|
||||
return ResultInvalidAddress;
|
||||
}
|
||||
|
||||
// Convert timeout from nanoseconds to ticks.
|
||||
s64 timeout{};
|
||||
@@ -1626,9 +1707,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit
|
||||
address, arb_type, value, timeout_ns);
|
||||
|
||||
// Validate input.
|
||||
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
|
||||
R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress);
|
||||
R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue);
|
||||
if (Memory::IsKernelAddress(address)) {
|
||||
LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address);
|
||||
return ResultInvalidCurrentMemory;
|
||||
}
|
||||
if (!Common::IsAligned(address, sizeof(s32))) {
|
||||
LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address);
|
||||
return ResultInvalidAddress;
|
||||
}
|
||||
if (!IsValidArbitrationType(arb_type)) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type);
|
||||
return ResultInvalidEnumValue;
|
||||
}
|
||||
|
||||
// Convert timeout from nanoseconds to ticks.
|
||||
s64 timeout{};
|
||||
@@ -1662,9 +1752,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign
|
||||
address, signal_type, value, count);
|
||||
|
||||
// Validate input.
|
||||
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
|
||||
R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress);
|
||||
R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue);
|
||||
if (Memory::IsKernelAddress(address)) {
|
||||
LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address);
|
||||
return ResultInvalidCurrentMemory;
|
||||
}
|
||||
if (!Common::IsAligned(address, sizeof(s32))) {
|
||||
LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address);
|
||||
return ResultInvalidAddress;
|
||||
}
|
||||
if (!IsValidSignalType(signal_type)) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type);
|
||||
return ResultInvalidEnumValue;
|
||||
}
|
||||
|
||||
return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value,
|
||||
count);
|
||||
@@ -1724,20 +1823,28 @@ static ResultCode CloseHandle32(Core::System& system, Handle handle) {
|
||||
static ResultCode ResetSignal(Core::System& system, Handle handle) {
|
||||
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
|
||||
|
||||
// Get the current handle table.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
|
||||
auto event = handle_table.Get<ReadableEvent>(handle);
|
||||
if (event) {
|
||||
return event->Reset();
|
||||
// Try to reset as readable event.
|
||||
{
|
||||
auto readable_event = handle_table.Get<KReadableEvent>(handle);
|
||||
if (readable_event) {
|
||||
return readable_event->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
auto process = handle_table.Get<Process>(handle);
|
||||
if (process) {
|
||||
return process->ClearSignalState();
|
||||
// Try to reset as process.
|
||||
{
|
||||
auto process = handle_table.Get<Process>(handle);
|
||||
if (process) {
|
||||
return process->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR(Kernel_SVC, "Invalid handle (0x{:08X})", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle);
|
||||
|
||||
return Svc::ResultInvalidHandle;
|
||||
}
|
||||
|
||||
static ResultCode ResetSignal32(Core::System& system, Handle handle) {
|
||||
@@ -1804,10 +1911,17 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
// Get the core mask.
|
||||
R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
|
||||
const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw);
|
||||
return result;
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
@@ -1835,26 +1949,46 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
|
||||
} else {
|
||||
// Validate the affinity mask.
|
||||
const u64 process_core_mask = current_process.GetCoreMask();
|
||||
R_UNLESS((affinity_mask | process_core_mask) == process_core_mask,
|
||||
Svc::ResultInvalidCoreId);
|
||||
R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination);
|
||||
if ((affinity_mask | process_core_mask) != process_core_mask) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Affinity mask does match the process core mask (affinity mask={:016X}, core "
|
||||
"mask={:016X})",
|
||||
affinity_mask, process_core_mask);
|
||||
return ResultInvalidCoreId;
|
||||
}
|
||||
if (affinity_mask == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Affinity mask is zero.");
|
||||
return ResultInvalidCombination;
|
||||
}
|
||||
|
||||
// Validate the core id.
|
||||
if (IsValidCoreId(core_id)) {
|
||||
R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination);
|
||||
if (((1ULL << core_id) & affinity_mask) == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
|
||||
return ResultInvalidCombination;
|
||||
}
|
||||
} else {
|
||||
R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare,
|
||||
Svc::ResultInvalidCoreId);
|
||||
if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
|
||||
return ResultInvalidCoreId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
// Set the core mask.
|
||||
R_TRY(thread->SetCoreMask(core_id, affinity_mask));
|
||||
const auto set_result = thread->SetCoreMask(core_id, affinity_mask);
|
||||
if (set_result.IsError()) {
|
||||
LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
|
||||
return set_result;
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
@@ -1865,80 +1999,98 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle
|
||||
return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask);
|
||||
}
|
||||
|
||||
static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) {
|
||||
static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
|
||||
|
||||
// Get the current handle table.
|
||||
const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
|
||||
// Get the writable event.
|
||||
auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
|
||||
if (!writable_event) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle);
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
return writable_event->Signal();
|
||||
}
|
||||
|
||||
static ResultCode SignalEvent32(Core::System& system, Handle event_handle) {
|
||||
return SignalEvent(system, event_handle);
|
||||
}
|
||||
|
||||
static ResultCode ClearEvent(Core::System& system, Handle event_handle) {
|
||||
LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
|
||||
|
||||
// Get the current handle table.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
|
||||
// Try to clear the writable event.
|
||||
{
|
||||
auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
|
||||
if (writable_event) {
|
||||
return writable_event->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Try to clear the readable event.
|
||||
{
|
||||
auto readable_event = handle_table.Get<KReadableEvent>(event_handle);
|
||||
if (readable_event) {
|
||||
return readable_event->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle);
|
||||
|
||||
return Svc::ResultInvalidHandle;
|
||||
}
|
||||
|
||||
static ResultCode ClearEvent32(Core::System& system, Handle event_handle) {
|
||||
return ClearEvent(system, event_handle);
|
||||
}
|
||||
|
||||
static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
|
||||
LOG_DEBUG(Kernel_SVC, "called");
|
||||
|
||||
// Get the kernel reference and handle table.
|
||||
auto& kernel = system.Kernel();
|
||||
const auto [readable_event, writable_event] =
|
||||
WritableEvent::CreateEventPair(kernel, "CreateEvent");
|
||||
|
||||
HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
||||
|
||||
const auto write_create_result = handle_table.Create(writable_event);
|
||||
// Create a new event.
|
||||
const auto event = KEvent::Create(kernel, "CreateEvent");
|
||||
if (!event) {
|
||||
LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached.");
|
||||
return ResultOutOfResource;
|
||||
}
|
||||
|
||||
// Initialize the event.
|
||||
event->Initialize();
|
||||
|
||||
// Add the writable event to the handle table.
|
||||
const auto write_create_result = handle_table.Create(event->GetWritableEvent());
|
||||
if (write_create_result.Failed()) {
|
||||
return write_create_result.Code();
|
||||
}
|
||||
*write_handle = *write_create_result;
|
||||
*out_write = *write_create_result;
|
||||
|
||||
const auto read_create_result = handle_table.Create(readable_event);
|
||||
// Add the writable event to the handle table.
|
||||
auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); });
|
||||
|
||||
// Add the readable event to the handle table.
|
||||
const auto read_create_result = handle_table.Create(event->GetReadableEvent());
|
||||
if (read_create_result.Failed()) {
|
||||
handle_table.Close(*write_create_result);
|
||||
return read_create_result.Code();
|
||||
}
|
||||
*read_handle = *read_create_result;
|
||||
*out_read = *read_create_result;
|
||||
|
||||
LOG_DEBUG(Kernel_SVC,
|
||||
"successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}",
|
||||
*write_create_result, *read_create_result);
|
||||
// We succeeded.
|
||||
handle_guard.Cancel();
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static ResultCode CreateEvent32(Core::System& system, Handle* write_handle, Handle* read_handle) {
|
||||
return CreateEvent(system, write_handle, read_handle);
|
||||
}
|
||||
|
||||
static ResultCode ClearEvent(Core::System& system, Handle handle) {
|
||||
LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
|
||||
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
|
||||
auto writable_event = handle_table.Get<WritableEvent>(handle);
|
||||
if (writable_event) {
|
||||
writable_event->Clear();
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
auto readable_event = handle_table.Get<ReadableEvent>(handle);
|
||||
if (readable_event) {
|
||||
readable_event->Clear();
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
static ResultCode ClearEvent32(Core::System& system, Handle handle) {
|
||||
return ClearEvent(system, handle);
|
||||
}
|
||||
|
||||
static ResultCode SignalEvent(Core::System& system, Handle handle) {
|
||||
LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle);
|
||||
|
||||
HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
auto writable_event = handle_table.Get<WritableEvent>(handle);
|
||||
|
||||
if (!writable_event) {
|
||||
LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
writable_event->Signal();
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static ResultCode SignalEvent32(Core::System& system, Handle handle) {
|
||||
return SignalEvent(system, handle);
|
||||
static ResultCode CreateEvent32(Core::System& system, Handle* out_write, Handle* out_read) {
|
||||
return CreateEvent(system, out_write, out_read);
|
||||
}
|
||||
|
||||
static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) {
|
||||
@@ -1972,7 +2124,7 @@ static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle)
|
||||
LOG_DEBUG(Kernel_SVC, "called");
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
auto resource_limit = ResourceLimit::Create(kernel);
|
||||
auto resource_limit = std::make_shared<KResourceLimit>(kernel, system);
|
||||
|
||||
auto* const current_process = kernel.CurrentProcess();
|
||||
ASSERT(current_process != nullptr);
|
||||
@@ -2019,7 +2171,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
|
||||
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
|
||||
resource_type, value);
|
||||
|
||||
const auto type = static_cast<ResourceType>(resource_type);
|
||||
const auto type = static_cast<LimitableResource>(resource_type);
|
||||
if (!IsValidResourceType(type)) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
|
||||
return ERR_INVALID_ENUM_VALUE;
|
||||
@@ -2029,7 +2181,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
|
||||
ASSERT(current_process != nullptr);
|
||||
|
||||
auto resource_limit_object =
|
||||
current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
|
||||
current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
|
||||
if (!resource_limit_object) {
|
||||
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
|
||||
resource_limit);
|
||||
@@ -2041,8 +2193,8 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
|
||||
LOG_ERROR(
|
||||
Kernel_SVC,
|
||||
"Attempted to lower resource limit ({}) for category '{}' below its current value ({})",
|
||||
resource_limit_object->GetMaxResourceValue(type), resource_type,
|
||||
resource_limit_object->GetCurrentResourceValue(type));
|
||||
resource_limit_object->GetLimitValue(type), resource_type,
|
||||
resource_limit_object->GetCurrentValue(type));
|
||||
return set_result;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Kernel::Svc {
|
||||
constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57};
|
||||
constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
|
||||
constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
|
||||
constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103};
|
||||
constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
|
||||
constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
|
||||
constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113};
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/assert.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {}
|
||||
WritableEvent::~WritableEvent() = default;
|
||||
|
||||
EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) {
|
||||
std::shared_ptr<WritableEvent> writable_event(new WritableEvent(kernel));
|
||||
std::shared_ptr<ReadableEvent> readable_event(new ReadableEvent(kernel));
|
||||
|
||||
writable_event->name = name + ":Writable";
|
||||
writable_event->readable = readable_event;
|
||||
readable_event->name = name + ":Readable";
|
||||
|
||||
return {std::move(readable_event), std::move(writable_event)};
|
||||
}
|
||||
|
||||
std::shared_ptr<ReadableEvent> WritableEvent::GetReadableEvent() const {
|
||||
return readable;
|
||||
}
|
||||
|
||||
void WritableEvent::Signal() {
|
||||
readable->Signal();
|
||||
}
|
||||
|
||||
void WritableEvent::Clear() {
|
||||
readable->Clear();
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class ReadableEvent;
|
||||
class WritableEvent;
|
||||
|
||||
struct EventPair {
|
||||
std::shared_ptr<ReadableEvent> readable;
|
||||
std::shared_ptr<WritableEvent> writable;
|
||||
};
|
||||
|
||||
class WritableEvent final : public Object {
|
||||
public:
|
||||
~WritableEvent() override;
|
||||
|
||||
/**
|
||||
* Creates an event
|
||||
* @param kernel The kernel instance to create this event under.
|
||||
* @param name Optional name of event
|
||||
*/
|
||||
static EventPair CreateEventPair(KernelCore& kernel, std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "WritableEvent";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
std::shared_ptr<ReadableEvent> GetReadableEvent() const;
|
||||
|
||||
void Signal();
|
||||
void Clear();
|
||||
|
||||
void Finalize() override {}
|
||||
|
||||
private:
|
||||
explicit WritableEvent(KernelCore& kernel);
|
||||
|
||||
std::shared_ptr<ReadableEvent> readable;
|
||||
|
||||
std::string name; ///< Name of event (optional)
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -41,12 +41,18 @@ constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "/system/save/8000000000000010/su/
|
||||
ProfileManager::ProfileManager() {
|
||||
ParseUserSaveFile();
|
||||
|
||||
if (user_count == 0)
|
||||
// Create an user if none are present
|
||||
if (user_count == 0) {
|
||||
CreateNewUser(UUID::Generate(), "yuzu");
|
||||
}
|
||||
|
||||
auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1);
|
||||
if (UserExistsIndex(current))
|
||||
|
||||
// If user index don't exist. Load the first user and change the active user
|
||||
if (!UserExistsIndex(current)) {
|
||||
current = 0;
|
||||
Settings::values.current_user = 0;
|
||||
}
|
||||
|
||||
OpenUser(*GetUser(current));
|
||||
}
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/transfer_memory.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
@@ -303,17 +304,18 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
launchable_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "ISelfController:LaunchableEvent");
|
||||
launchable_event = Kernel::KEvent::Create(kernel, "ISelfController:LaunchableEvent");
|
||||
launchable_event->Initialize();
|
||||
|
||||
// This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
|
||||
// called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
|
||||
// ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
|
||||
// suspended if the event has previously been created by a call to
|
||||
// GetAccumulatedSuspendedTickChangedEvent.
|
||||
accumulated_suspended_tick_changed_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, "ISelfController:AccumulatedSuspendedTickChangedEvent");
|
||||
accumulated_suspended_tick_changed_event.writable->Signal();
|
||||
accumulated_suspended_tick_changed_event =
|
||||
Kernel::KEvent::Create(kernel, "ISelfController:AccumulatedSuspendedTickChangedEvent");
|
||||
accumulated_suspended_tick_changed_event->Initialize();
|
||||
accumulated_suspended_tick_changed_event->GetWritableEvent()->Signal();
|
||||
}
|
||||
|
||||
ISelfController::~ISelfController() = default;
|
||||
@@ -372,11 +374,11 @@ void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) {
|
||||
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
launchable_event.writable->Signal();
|
||||
launchable_event->GetWritableEvent()->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(launchable_event.readable);
|
||||
rb.PushCopyObjects(launchable_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
|
||||
@@ -555,41 +557,42 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(accumulated_suspended_tick_changed_event.readable);
|
||||
rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
|
||||
on_new_message =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OnMessageReceived");
|
||||
on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived");
|
||||
on_new_message->Initialize();
|
||||
on_operation_mode_changed =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OperationModeChanged");
|
||||
Kernel::KEvent::Create(kernel, "AMMessageQueue:OperationModeChanged");
|
||||
on_operation_mode_changed->Initialize();
|
||||
}
|
||||
|
||||
AppletMessageQueue::~AppletMessageQueue() = default;
|
||||
|
||||
const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const {
|
||||
return on_new_message.readable;
|
||||
const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const {
|
||||
return on_new_message->GetReadableEvent();
|
||||
}
|
||||
|
||||
const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
|
||||
const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
|
||||
const {
|
||||
return on_operation_mode_changed.readable;
|
||||
return on_operation_mode_changed->GetReadableEvent();
|
||||
}
|
||||
|
||||
void AppletMessageQueue::PushMessage(AppletMessage msg) {
|
||||
messages.push(msg);
|
||||
on_new_message.writable->Signal();
|
||||
on_new_message->GetWritableEvent()->Signal();
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
|
||||
if (messages.empty()) {
|
||||
on_new_message.writable->Clear();
|
||||
on_new_message->GetWritableEvent()->Clear();
|
||||
return AppletMessage::NoMessage;
|
||||
}
|
||||
auto msg = messages.front();
|
||||
messages.pop();
|
||||
if (messages.empty()) {
|
||||
on_new_message.writable->Clear();
|
||||
on_new_message->GetWritableEvent()->Clear();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
@@ -601,7 +604,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const {
|
||||
void AppletMessageQueue::OperationModeChanged() {
|
||||
PushMessage(AppletMessage::OperationModeChanged);
|
||||
PushMessage(AppletMessage::PerformanceModeChanged);
|
||||
on_operation_mode_changed.writable->Signal();
|
||||
on_operation_mode_changed->GetWritableEvent()->Signal();
|
||||
}
|
||||
|
||||
void AppletMessageQueue::RequestExit() {
|
||||
@@ -1216,7 +1219,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
|
||||
{150, nullptr, "GetNotificationStorageChannelEvent"},
|
||||
{151, nullptr, "TryPopFromNotificationStorageChannel"},
|
||||
{160, nullptr, "GetHealthWarningDisappearedSystemEvent"},
|
||||
{160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"},
|
||||
{170, nullptr, "SetHdcpAuthenticationActivated"},
|
||||
{180, nullptr, "GetLaunchRequiredVersion"},
|
||||
{181, nullptr, "UpgradeLaunchRequiredVersion"},
|
||||
@@ -1229,11 +1232,15 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent");
|
||||
|
||||
friend_invitation_storage_channel_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, "IApplicationFunctions:FriendInvitationStorageChannelEvent");
|
||||
gpu_error_detected_event =
|
||||
Kernel::KEvent::Create(kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent");
|
||||
gpu_error_detected_event->Initialize();
|
||||
friend_invitation_storage_channel_event =
|
||||
Kernel::KEvent::Create(kernel, "IApplicationFunctions:FriendInvitationStorageChannelEvent");
|
||||
friend_invitation_storage_channel_event->Initialize();
|
||||
health_warning_disappeared_system_event =
|
||||
Kernel::KEvent::Create(kernel, "IApplicationFunctions:HealthWarningDisappearedSystemEvent");
|
||||
health_warning_disappeared_system_event->Initialize();
|
||||
}
|
||||
|
||||
IApplicationFunctions::~IApplicationFunctions() = default;
|
||||
@@ -1630,7 +1637,7 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(gpu_error_detected_event.readable);
|
||||
rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) {
|
||||
@@ -1638,7 +1645,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(friend_invitation_storage_channel_event.readable);
|
||||
rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(
|
||||
@@ -1649,6 +1656,14 @@ void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(
|
||||
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
|
||||
Core::System& system) {
|
||||
auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel());
|
||||
@@ -1682,8 +1697,9 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
pop_from_general_channel_event = Kernel::WritableEvent::CreateEventPair(
|
||||
system.Kernel(), "IHomeMenuFunctions:PopFromGeneralChannelEvent");
|
||||
pop_from_general_channel_event =
|
||||
Kernel::KEvent::Create(system.Kernel(), "IHomeMenuFunctions:PopFromGeneralChannelEvent");
|
||||
pop_from_general_channel_event->Initialize();
|
||||
}
|
||||
|
||||
IHomeMenuFunctions::~IHomeMenuFunctions() = default;
|
||||
@@ -1700,7 +1716,7 @@ void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(pop_from_general_channel_event.readable);
|
||||
rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
IGlobalStateController::IGlobalStateController(Core::System& system_)
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
class KEvent;
|
||||
class TransferMemory;
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -55,8 +56,8 @@ public:
|
||||
explicit AppletMessageQueue(Kernel::KernelCore& kernel);
|
||||
~AppletMessageQueue();
|
||||
|
||||
const std::shared_ptr<Kernel::ReadableEvent>& GetMessageReceiveEvent() const;
|
||||
const std::shared_ptr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
|
||||
const std::shared_ptr<Kernel::KReadableEvent>& GetMessageReceiveEvent() const;
|
||||
const std::shared_ptr<Kernel::KReadableEvent>& GetOperationModeChangedEvent() const;
|
||||
void PushMessage(AppletMessage msg);
|
||||
AppletMessage PopMessage();
|
||||
std::size_t GetMessageCount() const;
|
||||
@@ -65,8 +66,8 @@ public:
|
||||
|
||||
private:
|
||||
std::queue<AppletMessage> messages;
|
||||
Kernel::EventPair on_new_message;
|
||||
Kernel::EventPair on_operation_mode_changed;
|
||||
std::shared_ptr<Kernel::KEvent> on_new_message;
|
||||
std::shared_ptr<Kernel::KEvent> on_operation_mode_changed;
|
||||
};
|
||||
|
||||
class IWindowController final : public ServiceFramework<IWindowController> {
|
||||
@@ -153,8 +154,8 @@ private:
|
||||
};
|
||||
|
||||
NVFlinger::NVFlinger& nvflinger;
|
||||
Kernel::EventPair launchable_event;
|
||||
Kernel::EventPair accumulated_suspended_tick_changed_event;
|
||||
std::shared_ptr<Kernel::KEvent> launchable_event;
|
||||
std::shared_ptr<Kernel::KEvent> accumulated_suspended_tick_changed_event;
|
||||
|
||||
u32 idle_time_detection_extension = 0;
|
||||
u64 num_fatal_sections_entered = 0;
|
||||
@@ -290,12 +291,14 @@ private:
|
||||
void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
|
||||
void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx);
|
||||
void TryPopFromFriendInvitationStorageChannel(Kernel::HLERequestContext& ctx);
|
||||
void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx);
|
||||
|
||||
bool launch_popped_application_specific = false;
|
||||
bool launch_popped_account_preselect = false;
|
||||
s32 previous_program_index{-1};
|
||||
Kernel::EventPair gpu_error_detected_event;
|
||||
Kernel::EventPair friend_invitation_storage_channel_event;
|
||||
std::shared_ptr<Kernel::KEvent> gpu_error_detected_event;
|
||||
std::shared_ptr<Kernel::KEvent> friend_invitation_storage_channel_event;
|
||||
std::shared_ptr<Kernel::KEvent> health_warning_disappeared_system_event;
|
||||
};
|
||||
|
||||
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
|
||||
@@ -307,7 +310,7 @@ private:
|
||||
void RequestToGetForeground(Kernel::HLERequestContext& ctx);
|
||||
void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx);
|
||||
|
||||
Kernel::EventPair pop_from_general_channel_event;
|
||||
std::shared_ptr<Kernel::KEvent> pop_from_general_channel_event;
|
||||
};
|
||||
|
||||
class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
@@ -11,9 +12,10 @@
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applets/controller.h"
|
||||
@@ -27,11 +29,13 @@ namespace Service::AM::Applets {
|
||||
|
||||
AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) {
|
||||
state_changed_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:StateChangedEvent");
|
||||
pop_out_data_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:PopDataOutEvent");
|
||||
pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
Kernel::KEvent::Create(kernel, "ILibraryAppletAccessor:StateChangedEvent");
|
||||
state_changed_event->Initialize();
|
||||
pop_out_data_event = Kernel::KEvent::Create(kernel, "ILibraryAppletAccessor:PopDataOutEvent");
|
||||
pop_out_data_event->Initialize();
|
||||
pop_interactive_out_data_event =
|
||||
Kernel::KEvent::Create(kernel, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
pop_interactive_out_data_event->Initialize();
|
||||
}
|
||||
|
||||
AppletDataBroker::~AppletDataBroker() = default;
|
||||
@@ -58,7 +62,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
|
||||
|
||||
auto out = std::move(out_channel.front());
|
||||
out_channel.pop_front();
|
||||
pop_out_data_event.writable->Clear();
|
||||
pop_out_data_event->GetWritableEvent()->Clear();
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -77,7 +81,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
|
||||
|
||||
auto out = std::move(out_interactive_channel.front());
|
||||
out_interactive_channel.pop_front();
|
||||
pop_interactive_out_data_event.writable->Clear();
|
||||
pop_interactive_out_data_event->GetWritableEvent()->Clear();
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -96,7 +100,7 @@ void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storag
|
||||
|
||||
void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
|
||||
out_channel.emplace_back(std::move(storage));
|
||||
pop_out_data_event.writable->Signal();
|
||||
pop_out_data_event->GetWritableEvent()->Signal();
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
|
||||
@@ -105,23 +109,23 @@ void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& s
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
|
||||
out_interactive_channel.emplace_back(std::move(storage));
|
||||
pop_interactive_out_data_event.writable->Signal();
|
||||
pop_interactive_out_data_event->GetWritableEvent()->Signal();
|
||||
}
|
||||
|
||||
void AppletDataBroker::SignalStateChanged() const {
|
||||
state_changed_event.writable->Signal();
|
||||
state_changed_event->GetWritableEvent()->Signal();
|
||||
}
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
|
||||
return pop_out_data_event.readable;
|
||||
std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
|
||||
return pop_out_data_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
|
||||
return pop_interactive_out_data_event.readable;
|
||||
std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
|
||||
return pop_interactive_out_data_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
|
||||
return state_changed_event.readable;
|
||||
std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
|
||||
return state_changed_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
@@ -29,7 +29,9 @@ class WebBrowserApplet;
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
}
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
@@ -87,9 +89,9 @@ public:
|
||||
|
||||
void SignalStateChanged() const;
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> GetNormalDataEvent() const;
|
||||
std::shared_ptr<Kernel::ReadableEvent> GetInteractiveDataEvent() const;
|
||||
std::shared_ptr<Kernel::ReadableEvent> GetStateChangedEvent() const;
|
||||
std::shared_ptr<Kernel::KReadableEvent> GetNormalDataEvent() const;
|
||||
std::shared_ptr<Kernel::KReadableEvent> GetInteractiveDataEvent() const;
|
||||
std::shared_ptr<Kernel::KReadableEvent> GetStateChangedEvent() const;
|
||||
|
||||
private:
|
||||
// Queues are named from applet's perspective
|
||||
@@ -106,13 +108,13 @@ private:
|
||||
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
|
||||
std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
|
||||
|
||||
Kernel::EventPair state_changed_event;
|
||||
std::shared_ptr<Kernel::KEvent> state_changed_event;
|
||||
|
||||
// Signaled on PushNormalDataFromApplet
|
||||
Kernel::EventPair pop_out_data_event;
|
||||
std::shared_ptr<Kernel::KEvent> pop_out_data_event;
|
||||
|
||||
// Signaled on PushInteractiveDataFromApplet
|
||||
Kernel::EventPair pop_interactive_out_data_event;
|
||||
std::shared_ptr<Kernel::KEvent> pop_interactive_out_data_event;
|
||||
};
|
||||
|
||||
class Applet {
|
||||
|
||||
@@ -37,7 +37,7 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
|
||||
.border_colors = std::move(identification_colors),
|
||||
.enable_explain_text = enable_text,
|
||||
.explain_text = std::move(text),
|
||||
.allow_pro_controller = npad_style_set.pro_controller == 1,
|
||||
.allow_pro_controller = npad_style_set.fullkey == 1,
|
||||
.allow_handheld = npad_style_set.handheld == 1,
|
||||
.allow_dual_joycons = npad_style_set.joycon_dual == 1,
|
||||
.allow_left_joycon = npad_style_set.joycon_left == 1,
|
||||
|
||||
@@ -121,6 +121,10 @@ void SoftwareKeyboard::ExecuteInteractive() {
|
||||
std::memcpy(&request, data.data(), sizeof(Request));
|
||||
|
||||
switch (request) {
|
||||
case Request::Finalize:
|
||||
complete = true;
|
||||
broker.SignalStateChanged();
|
||||
break;
|
||||
case Request::Calc: {
|
||||
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1}));
|
||||
broker.SignalStateChanged();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/common_funcs.h"
|
||||
@@ -14,10 +15,10 @@
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/aoc/aoc_u.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/settings.h"
|
||||
@@ -62,8 +63,9 @@ public:
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
purchased_event = Kernel::WritableEvent::CreateEventPair(
|
||||
system.Kernel(), "IPurchaseEventManager:PurchasedEvent");
|
||||
purchased_event =
|
||||
Kernel::KEvent::Create(system.Kernel(), "IPurchaseEventManager:PurchasedEvent");
|
||||
purchased_event->Initialize();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -96,10 +98,10 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(purchased_event.readable);
|
||||
rb.PushCopyObjects(purchased_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
Kernel::EventPair purchased_event;
|
||||
std::shared_ptr<Kernel::KEvent> purchased_event;
|
||||
};
|
||||
|
||||
AOC_U::AOC_U(Core::System& system_)
|
||||
@@ -124,8 +126,8 @@ AOC_U::AOC_U(Core::System& system_)
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
aoc_change_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "GetAddOnContentListChanged:Event");
|
||||
aoc_change_event = Kernel::KEvent::Create(kernel, "GetAddOnContentListChanged:Event");
|
||||
aoc_change_event->Initialize();
|
||||
}
|
||||
|
||||
AOC_U::~AOC_U() = default;
|
||||
@@ -252,7 +254,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(aoc_change_event.readable);
|
||||
rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -11,7 +11,7 @@ class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class WritableEvent;
|
||||
class KEvent;
|
||||
}
|
||||
|
||||
namespace Service::AOC {
|
||||
@@ -31,7 +31,7 @@ private:
|
||||
void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::vector<u64> add_on_content;
|
||||
Kernel::EventPair aoc_change_event;
|
||||
std::shared_ptr<Kernel::KEvent> aoc_change_event;
|
||||
};
|
||||
|
||||
/// Registers all AOC services with the specified service manager.
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/audio/audout_u.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
#include "core/memory.h"
|
||||
@@ -66,13 +67,13 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
// This is the event handle used to check if the audio buffer was released
|
||||
buffer_event =
|
||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased");
|
||||
buffer_event = Kernel::KEvent::Create(system.Kernel(), "IAudioOutBufferReleased");
|
||||
buffer_event->Initialize();
|
||||
|
||||
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
|
||||
audio_params.channel_count, std::move(unique_name), [this] {
|
||||
const auto guard = LockService();
|
||||
buffer_event.writable->Signal();
|
||||
buffer_event->GetWritableEvent()->Signal();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -125,7 +126,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(buffer_event.readable);
|
||||
rb.PushCopyObjects(buffer_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
|
||||
@@ -219,7 +220,7 @@ private:
|
||||
[[maybe_unused]] AudoutParams audio_params{};
|
||||
|
||||
/// This is the event handle used to check if the audio buffer was released
|
||||
Kernel::EventPair buffer_event;
|
||||
std::shared_ptr<Kernel::KEvent> buffer_event;
|
||||
Core::Memory::Memory& main_memory;
|
||||
};
|
||||
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/audio/audren_u.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
@@ -47,13 +48,13 @@ public:
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
system_event =
|
||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
|
||||
system_event = Kernel::KEvent::Create(system.Kernel(), "IAudioRenderer:SystemEvent");
|
||||
system_event->Initialize();
|
||||
renderer = std::make_unique<AudioCore::AudioRenderer>(
|
||||
system.CoreTiming(), system.Memory(), audren_params,
|
||||
[this]() {
|
||||
const auto guard = LockService();
|
||||
system_event.writable->Signal();
|
||||
system_event->GetWritableEvent()->Signal();
|
||||
},
|
||||
instance_number);
|
||||
}
|
||||
@@ -126,7 +127,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(system_event.readable);
|
||||
rb.PushCopyObjects(system_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
|
||||
@@ -160,7 +161,7 @@ private:
|
||||
rb.Push(ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
Kernel::EventPair system_event;
|
||||
std::shared_ptr<Kernel::KEvent> system_event;
|
||||
std::unique_ptr<AudioCore::AudioRenderer> renderer;
|
||||
u32 rendering_time_limit_percent = 100;
|
||||
};
|
||||
@@ -187,17 +188,19 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
buffer_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "IAudioOutBufferReleasedEvent");
|
||||
buffer_event = Kernel::KEvent::Create(kernel, "IAudioOutBufferReleasedEvent");
|
||||
buffer_event->Initialize();
|
||||
|
||||
// Should be similar to audio_output_device_switch_event
|
||||
audio_input_device_switch_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent");
|
||||
audio_input_device_switch_event =
|
||||
Kernel::KEvent::Create(kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent");
|
||||
audio_input_device_switch_event->Initialize();
|
||||
|
||||
// Should only be signalled when an audio output device has been changed, example: speaker
|
||||
// to headset
|
||||
audio_output_device_switch_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent");
|
||||
audio_output_device_switch_event =
|
||||
Kernel::KEvent::Create(kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent");
|
||||
audio_output_device_switch_event->Initialize();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -286,11 +289,11 @@ private:
|
||||
void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
buffer_event.writable->Signal();
|
||||
buffer_event->GetWritableEvent()->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(buffer_event.readable);
|
||||
rb.PushCopyObjects(buffer_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
|
||||
@@ -307,7 +310,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(audio_input_device_switch_event.readable);
|
||||
rb.PushCopyObjects(audio_input_device_switch_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) {
|
||||
@@ -315,13 +318,13 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(audio_output_device_switch_event.readable);
|
||||
rb.PushCopyObjects(audio_output_device_switch_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
u32_le revision = 0;
|
||||
Kernel::EventPair buffer_event;
|
||||
Kernel::EventPair audio_input_device_switch_event;
|
||||
Kernel::EventPair audio_output_device_switch_event;
|
||||
std::shared_ptr<Kernel::KEvent> buffer_event;
|
||||
std::shared_ptr<Kernel::KEvent> audio_input_device_switch_event;
|
||||
std::shared_ptr<Kernel::KEvent> audio_output_device_switch_event;
|
||||
|
||||
}; // namespace Audio
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/service/bcat/backend/backend.h"
|
||||
|
||||
@@ -12,12 +15,13 @@ namespace Service::BCAT {
|
||||
|
||||
ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel,
|
||||
std::string_view event_name) {
|
||||
event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, std::string("ProgressServiceBackend:UpdateEvent:").append(event_name));
|
||||
event = Kernel::KEvent::Create(kernel,
|
||||
"ProgressServiceBackend:UpdateEvent:" + std::string(event_name));
|
||||
event->Initialize();
|
||||
}
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const {
|
||||
return event.readable;
|
||||
std::shared_ptr<Kernel::KReadableEvent> ProgressServiceBackend::GetEvent() const {
|
||||
return event->GetReadableEvent();
|
||||
}
|
||||
|
||||
DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
|
||||
@@ -85,9 +89,9 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
|
||||
void ProgressServiceBackend::SignalUpdate() const {
|
||||
if (need_hle_lock) {
|
||||
std::lock_guard lock(HLE::g_hle_lock);
|
||||
event.writable->Signal();
|
||||
event->GetWritableEvent()->Signal();
|
||||
} else {
|
||||
event.writable->Signal();
|
||||
event->GetWritableEvent()->Signal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -21,7 +19,9 @@ class System;
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
}
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::BCAT {
|
||||
|
||||
@@ -98,13 +98,13 @@ public:
|
||||
private:
|
||||
explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name);
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> GetEvent() const;
|
||||
std::shared_ptr<Kernel::KReadableEvent> GetEvent() const;
|
||||
DeliveryCacheProgressImpl& GetImpl();
|
||||
|
||||
void SignalUpdate() const;
|
||||
|
||||
DeliveryCacheProgressImpl impl{};
|
||||
Kernel::EventPair event;
|
||||
std::shared_ptr<Kernel::KEvent> event;
|
||||
bool need_hle_lock = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/bcat/backend/backend.h"
|
||||
#include "core/hle/service/bcat/bcat.h"
|
||||
#include "core/hle/service/bcat/module.h"
|
||||
@@ -89,7 +89,7 @@ struct DeliveryCacheDirectoryEntry {
|
||||
class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
|
||||
public:
|
||||
explicit IDeliveryCacheProgressService(Core::System& system_,
|
||||
std::shared_ptr<Kernel::ReadableEvent> event_,
|
||||
std::shared_ptr<Kernel::KReadableEvent> event_,
|
||||
const DeliveryCacheProgressImpl& impl_)
|
||||
: ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{std::move(event_)},
|
||||
impl{impl_} {
|
||||
@@ -121,7 +121,7 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> event;
|
||||
std::shared_ptr<Kernel::KReadableEvent> event;
|
||||
const DeliveryCacheProgressImpl& impl;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/btdrv/btdrv.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
@@ -35,7 +35,8 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
register_event = Kernel::WritableEvent::CreateEventPair(kernel, "BT:RegisterEvent");
|
||||
register_event = Kernel::KEvent::Create(kernel, "BT:RegisterEvent");
|
||||
register_event->Initialize();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -44,10 +45,10 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(register_event.readable);
|
||||
rb.PushCopyObjects(register_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
Kernel::EventPair register_event;
|
||||
std::shared_ptr<Kernel::KEvent> register_event;
|
||||
};
|
||||
|
||||
class BtDrv final : public ServiceFramework<BtDrv> {
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/btm/btm.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
@@ -58,12 +58,14 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
scan_event = Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ScanEvent");
|
||||
connection_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ConnectionEvent");
|
||||
service_discovery =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:Discovery");
|
||||
config_event = Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ConfigEvent");
|
||||
scan_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ScanEvent");
|
||||
scan_event->Initialize();
|
||||
connection_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConnectionEvent");
|
||||
connection_event->Initialize();
|
||||
service_discovery = Kernel::KEvent::Create(kernel, "IBtmUserCore:Discovery");
|
||||
service_discovery->Initialize();
|
||||
config_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConfigEvent");
|
||||
config_event->Initialize();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -72,7 +74,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(scan_event.readable);
|
||||
rb.PushCopyObjects(scan_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) {
|
||||
@@ -80,7 +82,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(connection_event.readable);
|
||||
rb.PushCopyObjects(connection_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) {
|
||||
@@ -88,7 +90,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(service_discovery.readable);
|
||||
rb.PushCopyObjects(service_discovery->GetReadableEvent());
|
||||
}
|
||||
|
||||
void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) {
|
||||
@@ -96,13 +98,13 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(config_event.readable);
|
||||
rb.PushCopyObjects(config_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
Kernel::EventPair scan_event;
|
||||
Kernel::EventPair connection_event;
|
||||
Kernel::EventPair service_discovery;
|
||||
Kernel::EventPair config_event;
|
||||
std::shared_ptr<Kernel::KEvent> scan_event;
|
||||
std::shared_ptr<Kernel::KEvent> connection_event;
|
||||
std::shared_ptr<Kernel::KEvent> service_discovery;
|
||||
std::shared_ptr<Kernel::KEvent> config_event;
|
||||
};
|
||||
|
||||
class BTM_USR final : public ServiceFramework<BTM_USR> {
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
#include "common/uuid.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/service/friend/errors.h"
|
||||
#include "core/hle/service/friend/friend.h"
|
||||
#include "core/hle/service/friend/interface.h"
|
||||
@@ -183,8 +184,9 @@ public:
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
notification_event = Kernel::WritableEvent::CreateEventPair(
|
||||
system.Kernel(), "INotificationService:NotifyEvent");
|
||||
notification_event =
|
||||
Kernel::KEvent::Create(system.Kernel(), "INotificationService:NotifyEvent");
|
||||
notification_event->Initialize();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -193,7 +195,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(notification_event.readable);
|
||||
rb.PushCopyObjects(notification_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void Clear(Kernel::HLERequestContext& ctx) {
|
||||
@@ -258,7 +260,7 @@ private:
|
||||
};
|
||||
|
||||
Common::UUID uuid{Common::INVALID_UUID};
|
||||
Kernel::EventPair notification_event;
|
||||
std::shared_ptr<Kernel::KEvent> notification_event;
|
||||
std::queue<SizedNotificationInfo> notifications;
|
||||
States states{};
|
||||
};
|
||||
|
||||
@@ -39,16 +39,25 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing,
|
||||
cur_entry.sampling_number2 = cur_entry.sampling_number;
|
||||
|
||||
cur_entry.key.fill(0);
|
||||
cur_entry.modifier = 0;
|
||||
if (Settings::values.keyboard_enabled) {
|
||||
for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
|
||||
auto& entry = cur_entry.key[i / KEYS_PER_BYTE];
|
||||
entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)));
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
|
||||
cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i);
|
||||
}
|
||||
using namespace Settings::NativeKeyboard;
|
||||
|
||||
// TODO: Assign the correct key to all modifiers
|
||||
cur_entry.modifier.control.Assign(keyboard_mods[LeftControl]->GetStatus());
|
||||
cur_entry.modifier.shift.Assign(keyboard_mods[LeftShift]->GetStatus());
|
||||
cur_entry.modifier.left_alt.Assign(keyboard_mods[LeftAlt]->GetStatus());
|
||||
cur_entry.modifier.right_alt.Assign(keyboard_mods[RightAlt]->GetStatus());
|
||||
cur_entry.modifier.gui.Assign(0);
|
||||
cur_entry.modifier.caps_lock.Assign(keyboard_mods[CapsLock]->GetStatus());
|
||||
cur_entry.modifier.scroll_lock.Assign(keyboard_mods[ScrollLock]->GetStatus());
|
||||
cur_entry.modifier.num_lock.Assign(keyboard_mods[NumLock]->GetStatus());
|
||||
cur_entry.modifier.katakana.Assign(0);
|
||||
cur_entry.modifier.hiragana.Assign(0);
|
||||
}
|
||||
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
@@ -31,12 +32,28 @@ public:
|
||||
void OnLoadInputDevices() override;
|
||||
|
||||
private:
|
||||
struct Modifiers {
|
||||
union {
|
||||
u32_le raw{};
|
||||
BitField<0, 1, u32> control;
|
||||
BitField<1, 1, u32> shift;
|
||||
BitField<2, 1, u32> left_alt;
|
||||
BitField<3, 1, u32> right_alt;
|
||||
BitField<4, 1, u32> gui;
|
||||
BitField<8, 1, u32> caps_lock;
|
||||
BitField<9, 1, u32> scroll_lock;
|
||||
BitField<10, 1, u32> num_lock;
|
||||
BitField<11, 1, u32> katakana;
|
||||
BitField<12, 1, u32> hiragana;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(Modifiers) == 0x4, "Modifiers is an invalid size");
|
||||
|
||||
struct KeyboardState {
|
||||
s64_le sampling_number;
|
||||
s64_le sampling_number2;
|
||||
|
||||
s32_le modifier;
|
||||
s32_le attribute;
|
||||
Modifiers modifier;
|
||||
std::array<u8, 32> key;
|
||||
};
|
||||
static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size");
|
||||
|
||||
@@ -36,6 +36,7 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
cur_entry.sampling_number = last_entry.sampling_number + 1;
|
||||
cur_entry.sampling_number2 = cur_entry.sampling_number;
|
||||
|
||||
cur_entry.attribute.raw = 0;
|
||||
if (Settings::values.mouse_enabled) {
|
||||
const auto [px, py, sx, sy] = mouse_device->GetStatus();
|
||||
const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width);
|
||||
@@ -46,10 +47,14 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
cur_entry.delta_y = y - last_entry.y;
|
||||
cur_entry.mouse_wheel_x = sx;
|
||||
cur_entry.mouse_wheel_y = sy;
|
||||
cur_entry.attribute.is_connected.Assign(1);
|
||||
|
||||
for (std::size_t i = 0; i < mouse_button_devices.size(); ++i) {
|
||||
cur_entry.button |= (mouse_button_devices[i]->GetStatus() << i);
|
||||
}
|
||||
using namespace Settings::NativeMouseButton;
|
||||
cur_entry.button.left.Assign(mouse_button_devices[Left]->GetStatus());
|
||||
cur_entry.button.right.Assign(mouse_button_devices[Right]->GetStatus());
|
||||
cur_entry.button.middle.Assign(mouse_button_devices[Middle]->GetStatus());
|
||||
cur_entry.button.forward.Assign(mouse_button_devices[Forward]->GetStatus());
|
||||
cur_entry.button.back.Assign(mouse_button_devices[Back]->GetStatus());
|
||||
}
|
||||
|
||||
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/frontend/input.h"
|
||||
@@ -30,6 +31,27 @@ public:
|
||||
void OnLoadInputDevices() override;
|
||||
|
||||
private:
|
||||
struct Buttons {
|
||||
union {
|
||||
u32_le raw{};
|
||||
BitField<0, 1, u32> left;
|
||||
BitField<1, 1, u32> right;
|
||||
BitField<2, 1, u32> middle;
|
||||
BitField<3, 1, u32> forward;
|
||||
BitField<4, 1, u32> back;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(Buttons) == 0x4, "Buttons is an invalid size");
|
||||
|
||||
struct Attributes {
|
||||
union {
|
||||
u32_le raw{};
|
||||
BitField<0, 1, u32> transferable;
|
||||
BitField<1, 1, u32> is_connected;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
|
||||
|
||||
struct MouseState {
|
||||
s64_le sampling_number;
|
||||
s64_le sampling_number2;
|
||||
@@ -39,8 +61,8 @@ private:
|
||||
s32_le delta_y;
|
||||
s32_le mouse_wheel_x;
|
||||
s32_le mouse_wheel_y;
|
||||
s32_le button;
|
||||
s32_le attribute;
|
||||
Buttons button;
|
||||
Attributes attribute;
|
||||
};
|
||||
static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size");
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/input.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
@@ -153,79 +154,86 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
|
||||
const auto controller_type = connected_controllers[controller_idx].type;
|
||||
auto& controller = shared_memory_entries[controller_idx];
|
||||
if (controller_type == NPadControllerType::None) {
|
||||
styleset_changed_events[controller_idx].writable->Signal();
|
||||
styleset_changed_events[controller_idx]->GetWritableEvent()->Signal();
|
||||
return;
|
||||
}
|
||||
controller.joy_styles.raw = 0; // Zero out
|
||||
controller.style_set.raw = 0; // Zero out
|
||||
controller.device_type.raw = 0;
|
||||
controller.properties.raw = 0;
|
||||
controller.system_properties.raw = 0;
|
||||
switch (controller_type) {
|
||||
case NPadControllerType::None:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case NPadControllerType::ProController:
|
||||
controller.joy_styles.pro_controller.Assign(1);
|
||||
controller.device_type.pro_controller.Assign(1);
|
||||
controller.properties.is_vertical.Assign(1);
|
||||
controller.properties.use_plus.Assign(1);
|
||||
controller.properties.use_minus.Assign(1);
|
||||
controller.pad_assignment = NpadAssignments::Single;
|
||||
controller.style_set.fullkey.Assign(1);
|
||||
controller.device_type.fullkey.Assign(1);
|
||||
controller.system_properties.is_vertical.Assign(1);
|
||||
controller.system_properties.use_plus.Assign(1);
|
||||
controller.system_properties.use_minus.Assign(1);
|
||||
controller.assignment_mode = NpadAssignments::Single;
|
||||
controller.footer_type = AppletFooterUiType::SwitchProController;
|
||||
break;
|
||||
case NPadControllerType::Handheld:
|
||||
controller.joy_styles.handheld.Assign(1);
|
||||
controller.device_type.handheld.Assign(1);
|
||||
controller.properties.is_vertical.Assign(1);
|
||||
controller.properties.use_plus.Assign(1);
|
||||
controller.properties.use_minus.Assign(1);
|
||||
controller.pad_assignment = NpadAssignments::Dual;
|
||||
controller.style_set.handheld.Assign(1);
|
||||
controller.device_type.handheld_left.Assign(1);
|
||||
controller.device_type.handheld_right.Assign(1);
|
||||
controller.system_properties.is_vertical.Assign(1);
|
||||
controller.system_properties.use_plus.Assign(1);
|
||||
controller.system_properties.use_minus.Assign(1);
|
||||
controller.assignment_mode = NpadAssignments::Dual;
|
||||
controller.footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight;
|
||||
break;
|
||||
case NPadControllerType::JoyDual:
|
||||
controller.joy_styles.joycon_dual.Assign(1);
|
||||
controller.style_set.joycon_dual.Assign(1);
|
||||
controller.device_type.joycon_left.Assign(1);
|
||||
controller.device_type.joycon_right.Assign(1);
|
||||
controller.properties.is_vertical.Assign(1);
|
||||
controller.properties.use_plus.Assign(1);
|
||||
controller.properties.use_minus.Assign(1);
|
||||
controller.pad_assignment = NpadAssignments::Dual;
|
||||
controller.system_properties.is_vertical.Assign(1);
|
||||
controller.system_properties.use_plus.Assign(1);
|
||||
controller.system_properties.use_minus.Assign(1);
|
||||
controller.assignment_mode = NpadAssignments::Dual;
|
||||
controller.footer_type = AppletFooterUiType::JoyDual;
|
||||
break;
|
||||
case NPadControllerType::JoyLeft:
|
||||
controller.joy_styles.joycon_left.Assign(1);
|
||||
controller.style_set.joycon_left.Assign(1);
|
||||
controller.device_type.joycon_left.Assign(1);
|
||||
controller.properties.is_horizontal.Assign(1);
|
||||
controller.properties.use_minus.Assign(1);
|
||||
controller.pad_assignment = NpadAssignments::Single;
|
||||
controller.system_properties.is_horizontal.Assign(1);
|
||||
controller.system_properties.use_minus.Assign(1);
|
||||
controller.assignment_mode = NpadAssignments::Single;
|
||||
controller.footer_type = AppletFooterUiType::JoyLeftHorizontal;
|
||||
break;
|
||||
case NPadControllerType::JoyRight:
|
||||
controller.joy_styles.joycon_right.Assign(1);
|
||||
controller.style_set.joycon_right.Assign(1);
|
||||
controller.device_type.joycon_right.Assign(1);
|
||||
controller.properties.is_horizontal.Assign(1);
|
||||
controller.properties.use_plus.Assign(1);
|
||||
controller.pad_assignment = NpadAssignments::Single;
|
||||
controller.system_properties.is_horizontal.Assign(1);
|
||||
controller.system_properties.use_plus.Assign(1);
|
||||
controller.assignment_mode = NpadAssignments::Single;
|
||||
controller.footer_type = AppletFooterUiType::JoyRightHorizontal;
|
||||
break;
|
||||
case NPadControllerType::Pokeball:
|
||||
controller.joy_styles.pokeball.Assign(1);
|
||||
controller.device_type.pokeball.Assign(1);
|
||||
controller.pad_assignment = NpadAssignments::Single;
|
||||
controller.style_set.palma.Assign(1);
|
||||
controller.device_type.palma.Assign(1);
|
||||
controller.assignment_mode = NpadAssignments::Single;
|
||||
break;
|
||||
}
|
||||
|
||||
controller.single_color_error = ColorReadError::ReadOk;
|
||||
controller.single_color.body_color = 0;
|
||||
controller.single_color.button_color = 0;
|
||||
controller.fullkey_color.attribute = ColorAttributes::Ok;
|
||||
controller.fullkey_color.fullkey.body = 0;
|
||||
controller.fullkey_color.fullkey.button = 0;
|
||||
|
||||
controller.dual_color_error = ColorReadError::ReadOk;
|
||||
controller.left_color.body_color =
|
||||
controller.joycon_color.attribute = ColorAttributes::Ok;
|
||||
controller.joycon_color.left.body =
|
||||
Settings::values.players.GetValue()[controller_idx].body_color_left;
|
||||
controller.left_color.button_color =
|
||||
controller.joycon_color.left.button =
|
||||
Settings::values.players.GetValue()[controller_idx].button_color_left;
|
||||
controller.right_color.body_color =
|
||||
controller.joycon_color.right.body =
|
||||
Settings::values.players.GetValue()[controller_idx].body_color_right;
|
||||
controller.right_color.button_color =
|
||||
controller.joycon_color.right.button =
|
||||
Settings::values.players.GetValue()[controller_idx].button_color_right;
|
||||
|
||||
controller.battery_level[0] = BATTERY_FULL;
|
||||
controller.battery_level[1] = BATTERY_FULL;
|
||||
controller.battery_level[2] = BATTERY_FULL;
|
||||
// TODO: Investigate when we should report all batery types
|
||||
controller.battery_level_dual = BATTERY_FULL;
|
||||
controller.battery_level_left = BATTERY_FULL;
|
||||
controller.battery_level_right = BATTERY_FULL;
|
||||
|
||||
SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
|
||||
}
|
||||
@@ -233,8 +241,9 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
|
||||
void Controller_NPad::OnInit() {
|
||||
auto& kernel = system.Kernel();
|
||||
for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
|
||||
styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));
|
||||
styleset_changed_events[i] =
|
||||
Kernel::KEvent::Create(kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));
|
||||
styleset_changed_events[i]->Initialize();
|
||||
}
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
@@ -249,8 +258,8 @@ void Controller_NPad::OnInit() {
|
||||
style.joycon_left.Assign(1);
|
||||
style.joycon_right.Assign(1);
|
||||
style.joycon_dual.Assign(1);
|
||||
style.pro_controller.Assign(1);
|
||||
style.pokeball.Assign(1);
|
||||
style.fullkey.Assign(1);
|
||||
style.palma.Assign(1);
|
||||
}
|
||||
|
||||
std::transform(Settings::values.players.GetValue().begin(),
|
||||
@@ -404,13 +413,10 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
}
|
||||
for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
|
||||
auto& npad = shared_memory_entries[i];
|
||||
const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
|
||||
&npad.handheld_states,
|
||||
&npad.dual_states,
|
||||
&npad.left_joy_states,
|
||||
&npad.right_joy_states,
|
||||
&npad.pokeball_states,
|
||||
&npad.libnx};
|
||||
const std::array<NPadGeneric*, 7> controller_npads{
|
||||
&npad.fullkey_states, &npad.handheld_states, &npad.joy_dual_states,
|
||||
&npad.joy_left_states, &npad.joy_right_states, &npad.palma_states,
|
||||
&npad.system_ext_states};
|
||||
|
||||
for (auto* main_controller : controller_npads) {
|
||||
main_controller->common.entry_count = 16;
|
||||
@@ -440,19 +446,19 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
auto& pad_state = npad_pad_states[npad_index];
|
||||
|
||||
auto& main_controller =
|
||||
npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
|
||||
npad.fullkey_states.npad[npad.fullkey_states.common.last_entry_index];
|
||||
auto& handheld_entry =
|
||||
npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
|
||||
auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index];
|
||||
auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index];
|
||||
auto& dual_entry = npad.joy_dual_states.npad[npad.joy_dual_states.common.last_entry_index];
|
||||
auto& left_entry = npad.joy_left_states.npad[npad.joy_left_states.common.last_entry_index];
|
||||
auto& right_entry =
|
||||
npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index];
|
||||
auto& pokeball_entry =
|
||||
npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index];
|
||||
auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
|
||||
npad.joy_right_states.npad[npad.joy_right_states.common.last_entry_index];
|
||||
auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index];
|
||||
auto& libnx_entry =
|
||||
npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index];
|
||||
|
||||
libnx_entry.connection_status.raw = 0;
|
||||
libnx_entry.connection_status.IsConnected.Assign(1);
|
||||
libnx_entry.connection_status.is_connected.Assign(1);
|
||||
|
||||
switch (controller_type) {
|
||||
case NPadControllerType::None:
|
||||
@@ -460,67 +466,67 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
break;
|
||||
case NPadControllerType::ProController:
|
||||
main_controller.connection_status.raw = 0;
|
||||
main_controller.connection_status.IsConnected.Assign(1);
|
||||
main_controller.connection_status.IsWired.Assign(1);
|
||||
main_controller.connection_status.is_connected.Assign(1);
|
||||
main_controller.connection_status.is_wired.Assign(1);
|
||||
main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
|
||||
main_controller.pad.l_stick = pad_state.l_stick;
|
||||
main_controller.pad.r_stick = pad_state.r_stick;
|
||||
|
||||
libnx_entry.connection_status.IsWired.Assign(1);
|
||||
libnx_entry.connection_status.is_wired.Assign(1);
|
||||
break;
|
||||
case NPadControllerType::Handheld:
|
||||
handheld_entry.connection_status.raw = 0;
|
||||
handheld_entry.connection_status.IsConnected.Assign(1);
|
||||
handheld_entry.connection_status.IsWired.Assign(1);
|
||||
handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
||||
handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
|
||||
handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
|
||||
handheld_entry.connection_status.IsRightJoyWired.Assign(1);
|
||||
handheld_entry.connection_status.is_connected.Assign(1);
|
||||
handheld_entry.connection_status.is_wired.Assign(1);
|
||||
handheld_entry.connection_status.is_left_connected.Assign(1);
|
||||
handheld_entry.connection_status.is_right_connected.Assign(1);
|
||||
handheld_entry.connection_status.is_left_wired.Assign(1);
|
||||
handheld_entry.connection_status.is_right_wired.Assign(1);
|
||||
handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
|
||||
handheld_entry.pad.l_stick = pad_state.l_stick;
|
||||
handheld_entry.pad.r_stick = pad_state.r_stick;
|
||||
|
||||
libnx_entry.connection_status.IsWired.Assign(1);
|
||||
libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
||||
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
|
||||
libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
|
||||
libnx_entry.connection_status.IsRightJoyWired.Assign(1);
|
||||
libnx_entry.connection_status.is_wired.Assign(1);
|
||||
libnx_entry.connection_status.is_left_connected.Assign(1);
|
||||
libnx_entry.connection_status.is_right_connected.Assign(1);
|
||||
libnx_entry.connection_status.is_left_wired.Assign(1);
|
||||
libnx_entry.connection_status.is_right_wired.Assign(1);
|
||||
break;
|
||||
case NPadControllerType::JoyDual:
|
||||
dual_entry.connection_status.raw = 0;
|
||||
dual_entry.connection_status.IsConnected.Assign(1);
|
||||
dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
||||
dual_entry.connection_status.IsRightJoyConnected.Assign(1);
|
||||
dual_entry.connection_status.is_connected.Assign(1);
|
||||
dual_entry.connection_status.is_left_connected.Assign(1);
|
||||
dual_entry.connection_status.is_right_connected.Assign(1);
|
||||
dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
|
||||
dual_entry.pad.l_stick = pad_state.l_stick;
|
||||
dual_entry.pad.r_stick = pad_state.r_stick;
|
||||
|
||||
libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
||||
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
|
||||
libnx_entry.connection_status.is_left_connected.Assign(1);
|
||||
libnx_entry.connection_status.is_right_connected.Assign(1);
|
||||
break;
|
||||
case NPadControllerType::JoyLeft:
|
||||
left_entry.connection_status.raw = 0;
|
||||
left_entry.connection_status.IsConnected.Assign(1);
|
||||
left_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
||||
left_entry.connection_status.is_connected.Assign(1);
|
||||
left_entry.connection_status.is_left_connected.Assign(1);
|
||||
left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
|
||||
left_entry.pad.l_stick = pad_state.l_stick;
|
||||
left_entry.pad.r_stick = pad_state.r_stick;
|
||||
|
||||
libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
||||
libnx_entry.connection_status.is_left_connected.Assign(1);
|
||||
break;
|
||||
case NPadControllerType::JoyRight:
|
||||
right_entry.connection_status.raw = 0;
|
||||
right_entry.connection_status.IsConnected.Assign(1);
|
||||
right_entry.connection_status.IsRightJoyConnected.Assign(1);
|
||||
right_entry.connection_status.is_connected.Assign(1);
|
||||
right_entry.connection_status.is_right_connected.Assign(1);
|
||||
right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
|
||||
right_entry.pad.l_stick = pad_state.l_stick;
|
||||
right_entry.pad.r_stick = pad_state.r_stick;
|
||||
|
||||
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
|
||||
libnx_entry.connection_status.is_right_connected.Assign(1);
|
||||
break;
|
||||
case NPadControllerType::Pokeball:
|
||||
pokeball_entry.connection_status.raw = 0;
|
||||
pokeball_entry.connection_status.IsConnected.Assign(1);
|
||||
pokeball_entry.connection_status.is_connected.Assign(1);
|
||||
pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
|
||||
pokeball_entry.pad.l_stick = pad_state.l_stick;
|
||||
pokeball_entry.pad.r_stick = pad_state.r_stick;
|
||||
@@ -554,7 +560,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||
}
|
||||
|
||||
const std::array<SixAxisGeneric*, 6> controller_sixaxes{
|
||||
&npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
|
||||
&npad.sixaxis_fullkey, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
|
||||
&npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right,
|
||||
};
|
||||
|
||||
@@ -592,7 +598,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||
}
|
||||
|
||||
auto& full_sixaxis_entry =
|
||||
npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index];
|
||||
npad.sixaxis_fullkey.sixaxis[npad.sixaxis_fullkey.common.last_entry_index];
|
||||
auto& handheld_sixaxis_entry =
|
||||
npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index];
|
||||
auto& dual_left_sixaxis_entry =
|
||||
@@ -609,7 +615,9 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case NPadControllerType::ProController:
|
||||
full_sixaxis_entry.attribute.raw = 0;
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
full_sixaxis_entry.attribute.is_connected.Assign(1);
|
||||
full_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
full_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
full_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
@@ -617,7 +625,9 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::Handheld:
|
||||
handheld_sixaxis_entry.attribute.raw = 0;
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
handheld_sixaxis_entry.attribute.is_connected.Assign(1);
|
||||
handheld_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
handheld_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
handheld_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
@@ -625,8 +635,11 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::JoyDual:
|
||||
dual_left_sixaxis_entry.attribute.raw = 0;
|
||||
dual_right_sixaxis_entry.attribute.raw = 0;
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
// Set motion for the left joycon
|
||||
dual_left_sixaxis_entry.attribute.is_connected.Assign(1);
|
||||
dual_left_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
dual_left_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
dual_left_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
@@ -634,6 +647,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||
}
|
||||
if (sixaxis_sensors_enabled && motions[i][1]) {
|
||||
// Set motion for the right joycon
|
||||
dual_right_sixaxis_entry.attribute.is_connected.Assign(1);
|
||||
dual_right_sixaxis_entry.accel = motion_devices[1].accel;
|
||||
dual_right_sixaxis_entry.gyro = motion_devices[1].gyro;
|
||||
dual_right_sixaxis_entry.rotation = motion_devices[1].rotation;
|
||||
@@ -641,7 +655,9 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::JoyLeft:
|
||||
left_sixaxis_entry.attribute.raw = 0;
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
left_sixaxis_entry.attribute.is_connected.Assign(1);
|
||||
left_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
left_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
left_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
@@ -649,7 +665,9 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::JoyRight:
|
||||
right_sixaxis_entry.attribute.raw = 0;
|
||||
if (sixaxis_sensors_enabled && motions[i][1]) {
|
||||
right_sixaxis_entry.attribute.is_connected.Assign(1);
|
||||
right_sixaxis_entry.accel = motion_devices[1].accel;
|
||||
right_sixaxis_entry.gyro = motion_devices[1].gyro;
|
||||
right_sixaxis_entry.rotation = motion_devices[1].rotation;
|
||||
@@ -715,8 +733,8 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode
|
||||
void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) {
|
||||
const std::size_t npad_index = NPadIdToIndex(npad_id);
|
||||
ASSERT(npad_index < shared_memory_entries.size());
|
||||
if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) {
|
||||
shared_memory_entries[npad_index].pad_assignment = assignment_mode;
|
||||
if (shared_memory_entries[npad_index].assignment_mode != assignment_mode) {
|
||||
shared_memory_entries[npad_index].assignment_mode = assignment_mode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,13 +890,14 @@ bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_dev
|
||||
return vibration_devices_mounted[npad_index][device_index];
|
||||
}
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
|
||||
std::shared_ptr<Kernel::KReadableEvent> Controller_NPad::GetStyleSetChangedEvent(
|
||||
u32 npad_id) const {
|
||||
const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
|
||||
return styleset_event.readable;
|
||||
return styleset_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
|
||||
styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal();
|
||||
styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent()->Signal();
|
||||
}
|
||||
|
||||
void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
|
||||
@@ -923,9 +942,17 @@ void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
|
||||
connected_controllers[npad_index].is_connected = false;
|
||||
|
||||
auto& controller = shared_memory_entries[npad_index];
|
||||
controller.joy_styles.raw = 0; // Zero out
|
||||
controller.style_set.raw = 0; // Zero out
|
||||
controller.device_type.raw = 0;
|
||||
controller.properties.raw = 0;
|
||||
controller.system_properties.raw = 0;
|
||||
controller.button_properties.raw = 0;
|
||||
controller.battery_level_dual = 0;
|
||||
controller.battery_level_left = 0;
|
||||
controller.battery_level_right = 0;
|
||||
controller.fullkey_color = {};
|
||||
controller.joycon_color = {};
|
||||
controller.assignment_mode = NpadAssignments::Dual;
|
||||
controller.footer_type = AppletFooterUiType::None;
|
||||
|
||||
SignalStyleSetChangedEvent(IndexToNPad(npad_index));
|
||||
}
|
||||
@@ -1101,7 +1128,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
|
||||
[](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) {
|
||||
switch (controller) {
|
||||
case NPadControllerType::ProController:
|
||||
return style.pro_controller;
|
||||
return style.fullkey;
|
||||
case NPadControllerType::JoyDual:
|
||||
return style.joycon_dual;
|
||||
case NPadControllerType::JoyLeft:
|
||||
@@ -1109,7 +1136,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
|
||||
case NPadControllerType::JoyRight:
|
||||
return style.joycon_right;
|
||||
case NPadControllerType::Pokeball:
|
||||
return style.pokeball;
|
||||
return style.palma;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -10,10 +10,14 @@
|
||||
#include "common/common_types.h"
|
||||
#include "core/frontend/input.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
constexpr u32 NPAD_HANDHELD = 32;
|
||||
@@ -90,10 +94,10 @@ public:
|
||||
};
|
||||
|
||||
enum class NpadCommunicationMode : u64 {
|
||||
Unknown0 = 0,
|
||||
Unknown1 = 1,
|
||||
Unknown2 = 2,
|
||||
Unknown3 = 3,
|
||||
Mode_5ms = 0,
|
||||
Mode_10ms = 1,
|
||||
Mode_15ms = 2,
|
||||
Default = 3,
|
||||
};
|
||||
|
||||
struct DeviceHandle {
|
||||
@@ -108,13 +112,18 @@ public:
|
||||
union {
|
||||
u32_le raw{};
|
||||
|
||||
BitField<0, 1, u32> pro_controller;
|
||||
BitField<0, 1, u32> fullkey;
|
||||
BitField<1, 1, u32> handheld;
|
||||
BitField<2, 1, u32> joycon_dual;
|
||||
BitField<3, 1, u32> joycon_left;
|
||||
BitField<4, 1, u32> joycon_right;
|
||||
|
||||
BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible
|
||||
BitField<5, 1, u32> gamecube;
|
||||
BitField<6, 1, u32> palma;
|
||||
BitField<7, 1, u32> lark;
|
||||
BitField<8, 1, u32> handheld_lark;
|
||||
BitField<9, 1, u32> lucia;
|
||||
BitField<29, 1, u32> system_ext;
|
||||
BitField<30, 1, u32> system;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
|
||||
@@ -187,7 +196,7 @@ public:
|
||||
|
||||
bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;
|
||||
|
||||
std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
|
||||
std::shared_ptr<Kernel::KReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
|
||||
void SignalStyleSetChangedEvent(u32 npad_id) const;
|
||||
|
||||
// Adds a new controller at an index.
|
||||
@@ -238,12 +247,32 @@ private:
|
||||
};
|
||||
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
|
||||
|
||||
enum class ColorAttributes : u32_le {
|
||||
Ok = 0,
|
||||
ReadError = 1,
|
||||
NoController = 2,
|
||||
};
|
||||
static_assert(sizeof(ColorAttributes) == 4, "ColorAttributes is an invalid size");
|
||||
|
||||
struct ControllerColor {
|
||||
u32_le body_color;
|
||||
u32_le button_color;
|
||||
u32_le body;
|
||||
u32_le button;
|
||||
};
|
||||
static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size");
|
||||
|
||||
struct FullKeyColor {
|
||||
ColorAttributes attribute;
|
||||
ControllerColor fullkey;
|
||||
};
|
||||
static_assert(sizeof(FullKeyColor) == 0xC, "FullKeyColor is an invalid size");
|
||||
|
||||
struct JoyconColor {
|
||||
ColorAttributes attribute;
|
||||
ControllerColor left;
|
||||
ControllerColor right;
|
||||
};
|
||||
static_assert(sizeof(JoyconColor) == 0x14, "JoyconColor is an invalid size");
|
||||
|
||||
struct ControllerPadState {
|
||||
union {
|
||||
u64_le raw{};
|
||||
@@ -285,6 +314,9 @@ private:
|
||||
|
||||
BitField<26, 1, u64> right_sl;
|
||||
BitField<27, 1, u64> right_sr;
|
||||
|
||||
BitField<28, 1, u64> palma;
|
||||
BitField<30, 1, u64> handheld_left_b;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size");
|
||||
@@ -298,12 +330,12 @@ private:
|
||||
struct ConnectionState {
|
||||
union {
|
||||
u32_le raw{};
|
||||
BitField<0, 1, u32> IsConnected;
|
||||
BitField<1, 1, u32> IsWired;
|
||||
BitField<2, 1, u32> IsLeftJoyConnected;
|
||||
BitField<3, 1, u32> IsLeftJoyWired;
|
||||
BitField<4, 1, u32> IsRightJoyConnected;
|
||||
BitField<5, 1, u32> IsRightJoyWired;
|
||||
BitField<0, 1, u32> is_connected;
|
||||
BitField<1, 1, u32> is_wired;
|
||||
BitField<2, 1, u32> is_left_connected;
|
||||
BitField<3, 1, u32> is_left_wired;
|
||||
BitField<4, 1, u32> is_right_connected;
|
||||
BitField<5, 1, u32> is_right_wired;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
|
||||
@@ -329,6 +361,15 @@ private:
|
||||
};
|
||||
static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size");
|
||||
|
||||
struct SixAxisAttributes {
|
||||
union {
|
||||
u32_le raw{};
|
||||
BitField<0, 1, u32> is_connected;
|
||||
BitField<1, 1, u32> is_interpolated;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(SixAxisAttributes) == 4, "SixAxisAttributes is an invalid size");
|
||||
|
||||
struct SixAxisStates {
|
||||
s64_le timestamp{};
|
||||
INSERT_PADDING_WORDS(2);
|
||||
@@ -337,7 +378,8 @@ private:
|
||||
Common::Vec3f gyro{};
|
||||
Common::Vec3f rotation{};
|
||||
std::array<Common::Vec3f, 3> orientation{};
|
||||
s64_le always_one{1};
|
||||
SixAxisAttributes attribute;
|
||||
INSERT_PADDING_BYTES(4); // Reserved
|
||||
};
|
||||
static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size");
|
||||
|
||||
@@ -347,32 +389,54 @@ private:
|
||||
};
|
||||
static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size");
|
||||
|
||||
enum class ColorReadError : u32_le {
|
||||
ReadOk = 0,
|
||||
ColorDoesntExist = 1,
|
||||
NoController = 2,
|
||||
};
|
||||
|
||||
struct NPadProperties {
|
||||
struct NPadSystemProperties {
|
||||
union {
|
||||
s64_le raw{};
|
||||
BitField<0, 1, s64> is_charging_joy_dual;
|
||||
BitField<1, 1, s64> is_charging_joy_left;
|
||||
BitField<2, 1, s64> is_charging_joy_right;
|
||||
BitField<3, 1, s64> is_powered_joy_dual;
|
||||
BitField<4, 1, s64> is_powered_joy_left;
|
||||
BitField<5, 1, s64> is_powered_joy_right;
|
||||
BitField<9, 1, s64> is_system_unsupported_button;
|
||||
BitField<10, 1, s64> is_system_ext_unsupported_button;
|
||||
BitField<11, 1, s64> is_vertical;
|
||||
BitField<12, 1, s64> is_horizontal;
|
||||
BitField<13, 1, s64> use_plus;
|
||||
BitField<14, 1, s64> use_minus;
|
||||
BitField<15, 1, s64> use_directional_buttons;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
|
||||
|
||||
struct NPadButtonProperties {
|
||||
union {
|
||||
s32_le raw{};
|
||||
BitField<0, 1, s32> is_home_button_protection_enabled;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NPadButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
|
||||
|
||||
struct NPadDevice {
|
||||
union {
|
||||
u32_le raw{};
|
||||
BitField<0, 1, s32> pro_controller;
|
||||
BitField<1, 1, s32> handheld;
|
||||
BitField<0, 1, s32> fullkey;
|
||||
BitField<1, 1, s32> debug_pad;
|
||||
BitField<2, 1, s32> handheld_left;
|
||||
BitField<3, 1, s32> handheld_right;
|
||||
BitField<4, 1, s32> joycon_left;
|
||||
BitField<5, 1, s32> joycon_right;
|
||||
BitField<6, 1, s32> pokeball;
|
||||
BitField<6, 1, s32> palma;
|
||||
BitField<7, 1, s32> lark_hvc_left;
|
||||
BitField<8, 1, s32> lark_hvc_right;
|
||||
BitField<9, 1, s32> lark_nes_left;
|
||||
BitField<10, 1, s32> lark_nes_right;
|
||||
BitField<11, 1, s32> handheld_lark_hvc_left;
|
||||
BitField<12, 1, s32> handheld_lark_hvc_right;
|
||||
BitField<13, 1, s32> handheld_lark_nes_left;
|
||||
BitField<14, 1, s32> handheld_lark_nes_right;
|
||||
BitField<15, 1, s32> lucia;
|
||||
BitField<31, 1, s32> system;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -383,37 +447,69 @@ private:
|
||||
std::array<Common::Vec3f, 3> orientation;
|
||||
};
|
||||
|
||||
struct NfcXcdHandle {
|
||||
INSERT_PADDING_BYTES(0x60);
|
||||
};
|
||||
|
||||
struct AppletFooterUiAttributes {
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
};
|
||||
|
||||
enum class AppletFooterUiType : u8 {
|
||||
None = 0,
|
||||
HandheldNone = 1,
|
||||
HandheldJoyConLeftOnly = 1,
|
||||
HandheldJoyConRightOnly = 3,
|
||||
HandheldJoyConLeftJoyConRight = 4,
|
||||
JoyDual = 5,
|
||||
JoyDualLeftOnly = 6,
|
||||
JoyDualRightOnly = 7,
|
||||
JoyLeftHorizontal = 8,
|
||||
JoyLeftVertical = 9,
|
||||
JoyRightHorizontal = 10,
|
||||
JoyRightVertical = 11,
|
||||
SwitchProController = 12,
|
||||
CompatibleProController = 13,
|
||||
CompatibleJoyCon = 14,
|
||||
LarkHvc1 = 15,
|
||||
LarkHvc2 = 16,
|
||||
LarkNesLeft = 17,
|
||||
LarkNesRight = 18,
|
||||
Lucia = 19,
|
||||
Verification = 20,
|
||||
};
|
||||
|
||||
struct NPadEntry {
|
||||
NpadStyleSet joy_styles;
|
||||
NpadAssignments pad_assignment;
|
||||
NpadStyleSet style_set;
|
||||
NpadAssignments assignment_mode;
|
||||
FullKeyColor fullkey_color;
|
||||
JoyconColor joycon_color;
|
||||
|
||||
ColorReadError single_color_error;
|
||||
ControllerColor single_color;
|
||||
|
||||
ColorReadError dual_color_error;
|
||||
ControllerColor left_color;
|
||||
ControllerColor right_color;
|
||||
|
||||
NPadGeneric main_controller_states;
|
||||
NPadGeneric fullkey_states;
|
||||
NPadGeneric handheld_states;
|
||||
NPadGeneric dual_states;
|
||||
NPadGeneric left_joy_states;
|
||||
NPadGeneric right_joy_states;
|
||||
NPadGeneric pokeball_states;
|
||||
NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be
|
||||
// relying on this for the time being
|
||||
SixAxisGeneric sixaxis_full;
|
||||
NPadGeneric joy_dual_states;
|
||||
NPadGeneric joy_left_states;
|
||||
NPadGeneric joy_right_states;
|
||||
NPadGeneric palma_states;
|
||||
NPadGeneric system_ext_states;
|
||||
SixAxisGeneric sixaxis_fullkey;
|
||||
SixAxisGeneric sixaxis_handheld;
|
||||
SixAxisGeneric sixaxis_dual_left;
|
||||
SixAxisGeneric sixaxis_dual_right;
|
||||
SixAxisGeneric sixaxis_left;
|
||||
SixAxisGeneric sixaxis_right;
|
||||
NPadDevice device_type;
|
||||
NPadProperties properties;
|
||||
INSERT_PADDING_WORDS(1);
|
||||
std::array<u32, 3> battery_level;
|
||||
INSERT_PADDING_BYTES(0x5c);
|
||||
INSERT_PADDING_BYTES(0xdf8);
|
||||
INSERT_PADDING_BYTES(0x4); // reserved
|
||||
NPadSystemProperties system_properties;
|
||||
NPadButtonProperties button_properties;
|
||||
u32 battery_level_dual;
|
||||
u32 battery_level_left;
|
||||
u32 battery_level_right;
|
||||
AppletFooterUiAttributes footer_attributes;
|
||||
AppletFooterUiType footer_type;
|
||||
// nfc_states needs to be checked switchbrew does not match with HW
|
||||
NfcXcdHandle nfc_states;
|
||||
INSERT_PADDING_BYTES(0xdef);
|
||||
};
|
||||
static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
|
||||
|
||||
@@ -449,10 +545,9 @@ private:
|
||||
std::vector<u32> supported_npad_id_types{};
|
||||
NpadHoldType hold_type{NpadHoldType::Vertical};
|
||||
NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
|
||||
// NpadCommunicationMode is unknown, default value is 1
|
||||
NpadCommunicationMode communication_mode{NpadCommunicationMode::Unknown1};
|
||||
NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
|
||||
// Each controller should have their own styleset changed event
|
||||
std::array<Kernel::EventPair, 10> styleset_changed_events;
|
||||
std::array<std::shared_ptr<Kernel::KEvent>, 10> styleset_changed_events;
|
||||
std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints;
|
||||
std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
|
||||
bool permit_vibration_session_enabled{false};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
@@ -28,6 +29,67 @@ public:
|
||||
void OnLoadInputDevices() override;
|
||||
|
||||
private:
|
||||
struct Attributes {
|
||||
union {
|
||||
u32_le raw{};
|
||||
BitField<0, 1, u32> is_connected;
|
||||
BitField<1, 1, u32> is_wired;
|
||||
BitField<2, 1, u32> is_left_connected;
|
||||
BitField<3, 1, u32> is_left_wired;
|
||||
BitField<4, 1, u32> is_right_connected;
|
||||
BitField<5, 1, u32> is_right_wired;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(Attributes) == 4, "Attributes is an invalid size");
|
||||
|
||||
struct Buttons {
|
||||
union {
|
||||
u32_le raw{};
|
||||
// Button states
|
||||
BitField<0, 1, u32> a;
|
||||
BitField<1, 1, u32> b;
|
||||
BitField<2, 1, u32> x;
|
||||
BitField<3, 1, u32> y;
|
||||
BitField<4, 1, u32> l_stick;
|
||||
BitField<5, 1, u32> r_stick;
|
||||
BitField<6, 1, u32> l;
|
||||
BitField<7, 1, u32> r;
|
||||
BitField<8, 1, u32> zl;
|
||||
BitField<9, 1, u32> zr;
|
||||
BitField<10, 1, u32> plus;
|
||||
BitField<11, 1, u32> minus;
|
||||
|
||||
// D-Pad
|
||||
BitField<12, 1, u32> d_left;
|
||||
BitField<13, 1, u32> d_up;
|
||||
BitField<14, 1, u32> d_right;
|
||||
BitField<15, 1, u32> d_down;
|
||||
|
||||
// Left JoyStick
|
||||
BitField<16, 1, u32> l_stick_left;
|
||||
BitField<17, 1, u32> l_stick_up;
|
||||
BitField<18, 1, u32> l_stick_right;
|
||||
BitField<19, 1, u32> l_stick_down;
|
||||
|
||||
// Right JoyStick
|
||||
BitField<20, 1, u32> r_stick_left;
|
||||
BitField<21, 1, u32> r_stick_up;
|
||||
BitField<22, 1, u32> r_stick_right;
|
||||
BitField<23, 1, u32> r_stick_down;
|
||||
|
||||
// Not always active?
|
||||
BitField<24, 1, u32> left_sl;
|
||||
BitField<25, 1, u32> left_sr;
|
||||
|
||||
BitField<26, 1, u32> right_sl;
|
||||
BitField<27, 1, u32> right_sr;
|
||||
|
||||
BitField<28, 1, u32> palma;
|
||||
BitField<30, 1, u32> handheld_left_b;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(Buttons) == 4, "Buttons is an invalid size");
|
||||
|
||||
struct AnalogStick {
|
||||
s32_le x;
|
||||
s32_le y;
|
||||
@@ -37,10 +99,10 @@ private:
|
||||
struct XPadState {
|
||||
s64_le sampling_number;
|
||||
s64_le sampling_number2;
|
||||
s32_le attributes;
|
||||
u32_le pad_states;
|
||||
AnalogStick x_stick;
|
||||
AnalogStick y_stick;
|
||||
Attributes attributes;
|
||||
Buttons pad_states;
|
||||
AnalogStick l_stick;
|
||||
AnalogStick r_stick;
|
||||
};
|
||||
static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size");
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/hid/irs.h"
|
||||
@@ -59,20 +59,26 @@ IAppletResource::IAppletResource(Core::System& system_)
|
||||
MakeController<Controller_Mouse>(HidController::Mouse);
|
||||
MakeController<Controller_Keyboard>(HidController::Keyboard);
|
||||
MakeController<Controller_XPad>(HidController::XPad);
|
||||
MakeController<Controller_Stubbed>(HidController::Unknown1);
|
||||
MakeController<Controller_Stubbed>(HidController::Unknown2);
|
||||
MakeController<Controller_Stubbed>(HidController::Unknown3);
|
||||
MakeController<Controller_Stubbed>(HidController::SixAxisSensor);
|
||||
MakeController<Controller_Stubbed>(HidController::HomeButton);
|
||||
MakeController<Controller_Stubbed>(HidController::SleepButton);
|
||||
MakeController<Controller_Stubbed>(HidController::CaptureButton);
|
||||
MakeController<Controller_Stubbed>(HidController::InputDetector);
|
||||
MakeController<Controller_Stubbed>(HidController::UniquePad);
|
||||
MakeController<Controller_NPad>(HidController::NPad);
|
||||
MakeController<Controller_Gesture>(HidController::Gesture);
|
||||
MakeController<Controller_Stubbed>(HidController::ConsoleSixAxisSensor);
|
||||
|
||||
// Homebrew doesn't try to activate some controllers, so we activate them by default
|
||||
GetController<Controller_NPad>(HidController::NPad).ActivateController();
|
||||
GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
|
||||
|
||||
GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00);
|
||||
GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00);
|
||||
GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
|
||||
GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
|
||||
GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
|
||||
GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
|
||||
GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
|
||||
GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
|
||||
GetController<Controller_Stubbed>(HidController::ConsoleSixAxisSensor)
|
||||
.SetCommonHeaderOffset(0x3C200);
|
||||
|
||||
// Register update callbacks
|
||||
pad_update_event = Core::Timing::CreateEvent(
|
||||
@@ -104,6 +110,7 @@ void IAppletResource::DeactivateController(HidController controller) {
|
||||
|
||||
IAppletResource ::~IAppletResource() {
|
||||
system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
|
||||
}
|
||||
|
||||
void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
@@ -126,14 +133,23 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
|
||||
controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
|
||||
}
|
||||
|
||||
// If ns_late is higher than the update rate ignore the delay
|
||||
if (ns_late > motion_update_ns) {
|
||||
ns_late = {};
|
||||
}
|
||||
|
||||
core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
|
||||
}
|
||||
|
||||
void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
for (const auto& controller : controllers) {
|
||||
controller->OnMotionUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
|
||||
controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(
|
||||
core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
|
||||
|
||||
// If ns_late is higher than the update rate ignore the delay
|
||||
if (ns_late > motion_update_ns) {
|
||||
ns_late = {};
|
||||
}
|
||||
|
||||
core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
|
||||
|
||||
@@ -29,12 +29,14 @@ enum class HidController : std::size_t {
|
||||
Mouse,
|
||||
Keyboard,
|
||||
XPad,
|
||||
Unknown1,
|
||||
Unknown2,
|
||||
Unknown3,
|
||||
SixAxisSensor,
|
||||
HomeButton,
|
||||
SleepButton,
|
||||
CaptureButton,
|
||||
InputDetector,
|
||||
UniquePad,
|
||||
NPad,
|
||||
Gesture,
|
||||
ConsoleSixAxisSensor,
|
||||
|
||||
MaxControllers,
|
||||
};
|
||||
|
||||
@@ -143,17 +143,19 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
u32 ReadLeb128(const std::vector<u8>& data, std::size_t& offset) {
|
||||
u32 result{};
|
||||
u64 ReadLeb128(const std::vector<u8>& data, std::size_t& offset) {
|
||||
u64 result{};
|
||||
u32 shift{};
|
||||
do {
|
||||
result |= (data[offset] & 0x7f) << shift;
|
||||
|
||||
for (std::size_t i = 0; i < sizeof(u64); i++) {
|
||||
const auto v = data[offset];
|
||||
result |= (static_cast<u64>(v & 0x7f) << shift);
|
||||
shift += 7;
|
||||
offset++;
|
||||
if (offset >= data.size()) {
|
||||
if (offset >= data.size() || ((v & 0x80) == 0)) {
|
||||
break;
|
||||
}
|
||||
} while ((data[offset] & 0x80) != 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -262,7 +264,7 @@ private:
|
||||
|
||||
switch (entry.severity) {
|
||||
case LogSeverity::Trace:
|
||||
LOG_DEBUG(Service_LM, "LogManager DEBUG ({}):\n{}", DestinationToString(destination),
|
||||
LOG_DEBUG(Service_LM, "LogManager TRACE ({}):\n{}", DestinationToString(destination),
|
||||
output_log);
|
||||
break;
|
||||
case LogSeverity::Info:
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/service/nfp/nfp.h"
|
||||
#include "core/hle/service/nfp/nfp_user.h"
|
||||
@@ -25,7 +26,8 @@ Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& syst
|
||||
const char* name)
|
||||
: ServiceFramework{system_, name}, module{std::move(module_)} {
|
||||
auto& kernel = system.Kernel();
|
||||
nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:NFCTagDetected");
|
||||
nfc_tag_load = Kernel::KEvent::Create(kernel, "IUser:NFCTagDetected");
|
||||
nfc_tag_load->Initialize();
|
||||
}
|
||||
|
||||
Module::Interface::~Interface() = default;
|
||||
@@ -64,9 +66,10 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
deactivate_event = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:DeactivateEvent");
|
||||
availability_change_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "IUser:AvailabilityChangeEvent");
|
||||
deactivate_event = Kernel::KEvent::Create(kernel, "IUser:DeactivateEvent");
|
||||
deactivate_event->Initialize();
|
||||
availability_change_event = Kernel::KEvent::Create(kernel, "IUser:AvailabilityChangeEvent");
|
||||
availability_change_event->Initialize();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -164,7 +167,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(deactivate_event.readable);
|
||||
rb.PushCopyObjects(deactivate_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void StopDetection(Kernel::HLERequestContext& ctx) {
|
||||
@@ -173,7 +176,7 @@ private:
|
||||
switch (device_state) {
|
||||
case DeviceState::TagFound:
|
||||
case DeviceState::TagNearby:
|
||||
deactivate_event.writable->Signal();
|
||||
deactivate_event->GetWritableEvent()->Signal();
|
||||
device_state = DeviceState::Initialized;
|
||||
break;
|
||||
case DeviceState::SearchingForTag:
|
||||
@@ -262,7 +265,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(availability_change_event.readable);
|
||||
rb.PushCopyObjects(availability_change_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
|
||||
@@ -316,8 +319,8 @@ private:
|
||||
const u32 npad_id{0}; // Player 1 controller
|
||||
State state{State::NonInitialized};
|
||||
DeviceState device_state{DeviceState::Initialized};
|
||||
Kernel::EventPair deactivate_event;
|
||||
Kernel::EventPair availability_change_event;
|
||||
std::shared_ptr<Kernel::KEvent> deactivate_event;
|
||||
std::shared_ptr<Kernel::KEvent> availability_change_event;
|
||||
const Module::Interface& nfp_interface;
|
||||
};
|
||||
|
||||
@@ -336,12 +339,12 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
|
||||
}
|
||||
|
||||
std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
|
||||
nfc_tag_load.writable->Signal();
|
||||
nfc_tag_load->GetWritableEvent()->Signal();
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const {
|
||||
return nfc_tag_load.readable;
|
||||
const std::shared_ptr<Kernel::KReadableEvent>& Module::Interface::GetNFCEvent() const {
|
||||
return nfc_tag_load->GetReadableEvent();
|
||||
}
|
||||
|
||||
const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
|
||||
|
||||
@@ -6,10 +6,13 @@
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
}
|
||||
|
||||
namespace Service::NFP {
|
||||
|
||||
class Module final {
|
||||
@@ -35,11 +38,11 @@ public:
|
||||
|
||||
void CreateUserInterface(Kernel::HLERequestContext& ctx);
|
||||
bool LoadAmiibo(const std::vector<u8>& buffer);
|
||||
const std::shared_ptr<Kernel::ReadableEvent>& GetNFCEvent() const;
|
||||
const std::shared_ptr<Kernel::KReadableEvent>& GetNFCEvent() const;
|
||||
const AmiiboFile& GetAmiiboBuffer() const;
|
||||
|
||||
private:
|
||||
Kernel::EventPair nfc_tag_load{};
|
||||
std::shared_ptr<Kernel::KEvent> nfc_tag_load;
|
||||
AmiiboFile amiibo{};
|
||||
|
||||
protected:
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/nifm/nifm.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/network/network.h"
|
||||
@@ -158,8 +158,11 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
event1 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event1");
|
||||
event2 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event2");
|
||||
|
||||
event1 = Kernel::KEvent::Create(kernel, "IRequest:Event1");
|
||||
event1->Initialize();
|
||||
event2 = Kernel::KEvent::Create(kernel, "IRequest:Event2");
|
||||
event2->Initialize();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -195,7 +198,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(event1.readable, event2.readable);
|
||||
rb.PushCopyObjects(event1->GetReadableEvent(), event2->GetReadableEvent());
|
||||
}
|
||||
|
||||
void Cancel(Kernel::HLERequestContext& ctx) {
|
||||
@@ -226,7 +229,7 @@ private:
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
Kernel::EventPair event1, event2;
|
||||
std::shared_ptr<Kernel::KEvent> event1, event2;
|
||||
};
|
||||
|
||||
class INetworkProfile final : public ServiceFramework<INetworkProfile> {
|
||||
|
||||