Compare commits
249 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7cd5d742e | ||
|
|
56ecafc204 | ||
|
|
92344da20c | ||
|
|
abda366362 | ||
|
|
0ca91ced2d | ||
|
|
b3c8997829 | ||
|
|
3cfd962ef4 | ||
|
|
0890451c55 | ||
|
|
2dc9dbb809 | ||
|
|
70812ec57b | ||
|
|
a78021580d | ||
|
|
b928fca114 | ||
|
|
8ace3959a5 | ||
|
|
e7e8a87927 | ||
|
|
b254d528bc | ||
|
|
ad50209383 | ||
|
|
d8ad2f3484 | ||
|
|
6f5b942897 | ||
|
|
97b2220a82 | ||
|
|
117bdc71e0 | ||
|
|
760a9e8693 | ||
|
|
30e0d1c973 | ||
|
|
91c06dae1a | ||
|
|
978ca65f59 | ||
|
|
e9e1876e82 | ||
|
|
38110dd485 | ||
|
|
d6a41cfc21 | ||
|
|
92fa5257c7 | ||
|
|
373408ae8c | ||
|
|
70f16f1722 | ||
|
|
9b501af8e3 | ||
|
|
652d6766d5 | ||
|
|
e02ef3c3be | ||
|
|
07b81f57ba | ||
|
|
31de52513e | ||
|
|
e3c2749986 | ||
|
|
b92bf51ae1 | ||
|
|
16e2e1c45f | ||
|
|
428ce8ec29 | ||
|
|
0a966e2cac | ||
|
|
ceb7b11f16 | ||
|
|
8f2959f680 | ||
|
|
8ead176639 | ||
|
|
64e174237e | ||
|
|
c0c4ed0d3b | ||
|
|
5cafa70d3b | ||
|
|
484623cd61 | ||
|
|
57d89e291d | ||
|
|
75eaab2e0f | ||
|
|
9d4edd4e88 | ||
|
|
0a50ba3bd1 | ||
|
|
cb826bcee7 | ||
|
|
ce718522bc | ||
|
|
87f220efff | ||
|
|
c22d0d9945 | ||
|
|
c433c0a746 | ||
|
|
945cfe234b | ||
|
|
9b24197ca0 | ||
|
|
8008b5ddc9 | ||
|
|
da7be67daf | ||
|
|
0aad914527 | ||
|
|
a6ecdf42bc | ||
|
|
9efbf5309f | ||
|
|
af1183a993 | ||
|
|
88192af8ac | ||
|
|
7bf9f9ae49 | ||
|
|
9f5facc3aa | ||
|
|
0785796372 | ||
|
|
e829973742 | ||
|
|
1e149dc18b | ||
|
|
dc5396a466 | ||
|
|
af477fb8c5 | ||
|
|
a0d7a2732d | ||
|
|
f6a89edb67 | ||
|
|
00fb79b2f3 | ||
|
|
91a45834fd | ||
|
|
0b75ec5316 | ||
|
|
c0ab5b79dc | ||
|
|
a111a9ae2c | ||
|
|
6f006d051e | ||
|
|
d62d28522b | ||
|
|
087f52e872 | ||
|
|
7aae6d6d2b | ||
|
|
6bbbbe8f85 | ||
|
|
fc6db97a09 | ||
|
|
4bfa411ddc | ||
|
|
46fdc94586 | ||
|
|
ee21b5378b | ||
|
|
222fe75401 | ||
|
|
448e4d5c2a | ||
|
|
4a4b685a04 | ||
|
|
4f0f481f63 | ||
|
|
1089d76736 | ||
|
|
848bdf8a40 | ||
|
|
7d2839d7a3 | ||
|
|
e67b8678f8 | ||
|
|
c6e1c46ac7 | ||
|
|
c64545d07a | ||
|
|
1d4cbb92f2 | ||
|
|
6053b95552 | ||
|
|
66edfd61c6 | ||
|
|
4a3fd97e48 | ||
|
|
d567b7e841 | ||
|
|
bca9591660 | ||
|
|
98f68d06f1 | ||
|
|
a0e5cccb92 | ||
|
|
6db0c0d8d9 | ||
|
|
14a97d082e | ||
|
|
50e52ade85 | ||
|
|
8aa9ae5ba5 | ||
|
|
131a75b65d | ||
|
|
11d0a6e7b8 | ||
|
|
26547d3e3b | ||
|
|
8049b8beb6 | ||
|
|
12eeffcb7c | ||
|
|
0d713cf8eb | ||
|
|
badea3b301 | ||
|
|
f8543249f0 | ||
|
|
5553bd3ba2 | ||
|
|
7dcf4c0018 | ||
|
|
ef29bf4515 | ||
|
|
3620206136 | ||
|
|
2dbb144fc6 | ||
|
|
89199ca215 | ||
|
|
9cfc5fee2f | ||
|
|
1a6b1bf1d7 | ||
|
|
c5134cbf3a | ||
|
|
c6d001c94f | ||
|
|
cf63eacc1a | ||
|
|
5333db91c1 | ||
|
|
c20569ebdf | ||
|
|
156556ddd2 | ||
|
|
475d46bb64 | ||
|
|
94eca09cf6 | ||
|
|
7af2cb4318 | ||
|
|
657771bdcb | ||
|
|
44b552be71 | ||
|
|
663e221f99 | ||
|
|
725fcbb368 | ||
|
|
a1f176ce52 | ||
|
|
1fd22823bc | ||
|
|
978e7897a3 | ||
|
|
55ac6f7a2b | ||
|
|
79da90cea8 | ||
|
|
4a451e5849 | ||
|
|
cdb2480d39 | ||
|
|
3fdb42e0b4 | ||
|
|
020519def8 | ||
|
|
9a44c1ea27 | ||
|
|
65e697de59 | ||
|
|
7d27a7a511 | ||
|
|
eb84e0f63a | ||
|
|
8e673cbb08 | ||
|
|
047e77e2f0 | ||
|
|
cce14b4cd7 | ||
|
|
6291975731 | ||
|
|
00decfbb07 | ||
|
|
111802bbbb | ||
|
|
3b5d5fa86f | ||
|
|
dcc26c54a5 | ||
|
|
c04203b786 | ||
|
|
cd92a94965 | ||
|
|
941563f981 | ||
|
|
d33399e1f4 | ||
|
|
ce69ff2890 | ||
|
|
c7f32931ee | ||
|
|
1828f82000 | ||
|
|
eb67a45ca8 | ||
|
|
9f08cea2c4 | ||
|
|
8bd246032a | ||
|
|
6b5f565324 | ||
|
|
3984bb6def | ||
|
|
54aabb00b0 | ||
|
|
1dd4132eb1 | ||
|
|
2f6ba54483 | ||
|
|
ae3a755d13 | ||
|
|
98f4c5e7b8 | ||
|
|
061a63547f | ||
|
|
fe53ee26ce | ||
|
|
9afbcd9e8a | ||
|
|
ab052cf684 | ||
|
|
6f6d83befa | ||
|
|
3e46934442 | ||
|
|
e7042163c8 | ||
|
|
85b5b816cf | ||
|
|
ea20b5c970 | ||
|
|
2f852f182a | ||
|
|
1fc61d09d3 | ||
|
|
e408bd3b7c | ||
|
|
2e74b79e89 | ||
|
|
3d592972dc | ||
|
|
678d012c2c | ||
|
|
fdd9154069 | ||
|
|
536c51912d | ||
|
|
88d5140cf2 | ||
|
|
940c3bf68d | ||
|
|
ea8345cdcd | ||
|
|
e03dc4d569 | ||
|
|
ff82f3894a | ||
|
|
f21a189148 | ||
|
|
298b50e220 | ||
|
|
acd35e1b60 | ||
|
|
60bd54776a | ||
|
|
e7a26ecec5 | ||
|
|
f1ead11df7 | ||
|
|
598ef6b0b3 | ||
|
|
54b977acaa | ||
|
|
0ab7bfdfce | ||
|
|
2190f1a2b7 | ||
|
|
743fe1aea3 | ||
|
|
be1954e04c | ||
|
|
c1577f3448 | ||
|
|
1eb908bc88 | ||
|
|
cb708631b6 | ||
|
|
363c644730 | ||
|
|
30b1e71066 | ||
|
|
36cfb234d5 | ||
|
|
7b3f5845d2 | ||
|
|
64f967fd49 | ||
|
|
dbd1662ae2 | ||
|
|
046c0c91a3 | ||
|
|
046cc81938 | ||
|
|
1d714c8c7f | ||
|
|
d47ac3ce09 | ||
|
|
1f186f34a2 | ||
|
|
ca416a0fb8 | ||
|
|
b9a9b83bee | ||
|
|
9f9b64d280 | ||
|
|
c5b3c8d06b | ||
|
|
39c8d18feb | ||
|
|
e4e0abc418 | ||
|
|
8db3feae19 | ||
|
|
62c6c9f6a6 | ||
|
|
d291fc1a51 | ||
|
|
b260847218 | ||
|
|
4c348f4069 | ||
|
|
419a59a7b1 | ||
|
|
f250011ba0 | ||
|
|
e1600b0962 | ||
|
|
61b246a3a9 | ||
|
|
0120e5b1d9 | ||
|
|
dffaffaac1 | ||
|
|
a54aee290f | ||
|
|
a220d8799e | ||
|
|
2a24b1c973 | ||
|
|
67af0323f0 | ||
|
|
c5a78f4480 | ||
|
|
29a0ca2391 | ||
|
|
4d4bbe756f |
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -1,15 +1,12 @@
|
||||
[submodule "inih"]
|
||||
path = externals/inih/inih
|
||||
url = https://github.com/svn2github/inih
|
||||
url = https://github.com/benhoyt/inih.git
|
||||
[submodule "cubeb"]
|
||||
path = externals/cubeb
|
||||
url = https://github.com/kinetiknz/cubeb.git
|
||||
[submodule "dynarmic"]
|
||||
path = externals/dynarmic
|
||||
url = https://github.com/MerryMage/dynarmic.git
|
||||
[submodule "unicorn"]
|
||||
path = externals/unicorn
|
||||
url = https://github.com/yuzu-emu/unicorn
|
||||
[submodule "soundtouch"]
|
||||
path = externals/soundtouch
|
||||
url = https://github.com/citra-emu/ext-soundtouch.git
|
||||
|
||||
@@ -4,16 +4,8 @@ cd /yuzu
|
||||
# override Travis CI unreasonable ccache size
|
||||
echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf"
|
||||
|
||||
# Dirty hack to trick unicorn makefile into believing we are in a MINGW system
|
||||
mv /bin/uname /bin/uname1 && echo -e '#!/bin/sh\necho MINGW64' >> /bin/uname
|
||||
chmod +x /bin/uname
|
||||
|
||||
# Dirty hack to trick unicorn makefile into believing we have cmd
|
||||
echo '' >> /bin/cmd
|
||||
chmod +x /bin/cmd
|
||||
|
||||
mkdir build && cd build
|
||||
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
|
||||
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
|
||||
ninja
|
||||
|
||||
# Clean up the dirty hacks
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
cd /yuzu
|
||||
|
||||
mkdir build && cd build
|
||||
cmake .. -G Ninja -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
|
||||
cmake .. -G Ninja -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
|
||||
ninja
|
||||
|
||||
ccache -s
|
||||
|
||||
@@ -4,13 +4,12 @@ set -o pipefail
|
||||
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.14
|
||||
export Qt5_DIR=$(brew --prefix)/opt/qt5
|
||||
export UNICORNDIR=$(pwd)/externals/unicorn
|
||||
export PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||
|
||||
# TODO: Build using ninja instead of make
|
||||
mkdir build && cd build
|
||||
cmake --version
|
||||
cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
|
||||
cmake .. -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
|
||||
make -j4
|
||||
|
||||
ccache -s
|
||||
|
||||
@@ -18,8 +18,6 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "EN
|
||||
|
||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
|
||||
option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON)
|
||||
|
||||
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)
|
||||
@@ -161,7 +159,7 @@ macro(yuzu_find_packages)
|
||||
# Cmake Pkg Prefix Version Conan Pkg
|
||||
"Boost 1.73 boost/1.73.0"
|
||||
"Catch2 2.13 catch2/2.13.0"
|
||||
"fmt 7.0 fmt/7.0.3"
|
||||
"fmt 7.1 fmt/7.1.2"
|
||||
# can't use until https://github.com/bincrafters/community/issues/1173
|
||||
#"libzip 1.5 libzip/1.5.2@bincrafters/stable"
|
||||
"lz4 1.8 lz4/1.9.2"
|
||||
@@ -263,6 +261,7 @@ if (CONAN_REQUIRED_LIBS)
|
||||
libzip:with_openssl=False
|
||||
libzip:enable_windows_crypto=False
|
||||
)
|
||||
|
||||
conan_check(VERSION 1.24.0 REQUIRED)
|
||||
# Add the bincrafters remote
|
||||
conan_add_remote(NAME bincrafters
|
||||
@@ -354,85 +353,23 @@ 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)
|
||||
endif()
|
||||
|
||||
# Prefer the -pthread flag on Linux.
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# If unicorn isn't found, msvc -> download bundled unicorn; everyone else -> build external
|
||||
if (YUZU_USE_BUNDLED_UNICORN)
|
||||
if (MSVC)
|
||||
message(STATUS "unicorn not found, falling back to bundled")
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
|
||||
set(UNICORN_VER "unicorn-yuzu")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
|
||||
endif()
|
||||
|
||||
if (DEFINED UNICORN_VER)
|
||||
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
|
||||
endif()
|
||||
|
||||
if (DEFINED UNICORN_VER)
|
||||
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
|
||||
endif()
|
||||
|
||||
set(UNICORN_FOUND YES)
|
||||
set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
|
||||
set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/lib/x64/unicorn_dynload.lib" CACHE PATH "Path to Unicorn library" FORCE)
|
||||
set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/lib/x64/" CACHE PATH "Path to unicorn.dll" FORCE)
|
||||
else()
|
||||
message(STATUS "unicorn not found, falling back to externals")
|
||||
if (MINGW)
|
||||
set(UNICORN_LIB_NAME "unicorn.a")
|
||||
else()
|
||||
set(UNICORN_LIB_NAME "libunicorn.a")
|
||||
endif()
|
||||
|
||||
set(UNICORN_FOUND YES)
|
||||
set(UNICORN_PREFIX ${PROJECT_SOURCE_DIR}/externals/unicorn)
|
||||
set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/${UNICORN_LIB_NAME}" CACHE PATH "Path to Unicorn library" FORCE)
|
||||
set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
|
||||
set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/" CACHE PATH "Path to unicorn dynamic library" FORCE)
|
||||
|
||||
find_package(PythonInterp 2.7 REQUIRED)
|
||||
|
||||
if (MINGW)
|
||||
# Intentionally call the unicorn makefile directly instead of using make.sh so that we can override the
|
||||
# UNAME_S makefile variable to MINGW. This way we don't have to hack at the uname binary to build
|
||||
# Additionally, overriding DO_WINDOWS_EXPORT prevents unicorn from patching the static unicorn.a by using msvc and cmd,
|
||||
# which are both things we don't have in a mingw cross compiling environment.
|
||||
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
|
||||
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-gcc-ar RANLIB=x86_64-w64-mingw32-gcc-ranlib make UNAME_S=MINGW DO_WINDOWS_EXPORT=0
|
||||
WORKING_DIRECTORY ${UNICORN_PREFIX}
|
||||
)
|
||||
else()
|
||||
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
|
||||
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no
|
||||
WORKING_DIRECTORY ${UNICORN_PREFIX}
|
||||
)
|
||||
endif()
|
||||
|
||||
# ALL makes this custom target build every time
|
||||
# but it won't actually build if LIBUNICORN_LIBRARY is up to date
|
||||
add_custom_target(unicorn-build ALL
|
||||
DEPENDS ${LIBUNICORN_LIBRARY}
|
||||
)
|
||||
unset(UNICORN_LIB_NAME)
|
||||
endif()
|
||||
else()
|
||||
find_package(Unicorn REQUIRED)
|
||||
endif()
|
||||
|
||||
if (UNICORN_FOUND)
|
||||
add_library(unicorn INTERFACE)
|
||||
add_dependencies(unicorn unicorn-build)
|
||||
target_link_libraries(unicorn INTERFACE "${LIBUNICORN_LIBRARY}")
|
||||
target_include_directories(unicorn INTERFACE "${LIBUNICORN_INCLUDE_DIR}")
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find or build unicorn which is required.")
|
||||
endif()
|
||||
|
||||
# Platform-specific library requirements
|
||||
# ======================================
|
||||
|
||||
|
||||
10
CMakeModules/CopyYuzuFFmpegDeps.cmake
Normal file
10
CMakeModules/CopyYuzuFFmpegDeps.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
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}
|
||||
avcodec-58.dll
|
||||
avutil-56.dll
|
||||
swresample-3.dll
|
||||
swscale-5.dll
|
||||
)
|
||||
endfunction(copy_yuzu_FFmpeg_deps)
|
||||
@@ -1,9 +0,0 @@
|
||||
function(copy_yuzu_unicorn_deps target_dir)
|
||||
include(WindowsCopyFiles)
|
||||
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
|
||||
windows_copy_files(${target_dir} ${UNICORN_DLL_DIR} ${DLL_DEST}
|
||||
libgcc_s_seh-1.dll
|
||||
libwinpthread-1.dll
|
||||
unicorn.dll
|
||||
)
|
||||
endfunction(copy_yuzu_unicorn_deps)
|
||||
14
dist/qt_themes/default/style.qss
vendored
14
dist/qt_themes/default/style.qss
vendored
@@ -1,3 +1,7 @@
|
||||
QAbstractSpinBox {
|
||||
min-height: 19px;
|
||||
}
|
||||
|
||||
QPushButton#TogglableStatusBarButton {
|
||||
color: #959595;
|
||||
border: 1px solid transparent;
|
||||
@@ -35,10 +39,10 @@ QPushButton#RendererStatusBarButton:!checked {
|
||||
}
|
||||
|
||||
QPushButton#buttonRefreshDevices {
|
||||
min-width: 20px;
|
||||
min-height: 20px;
|
||||
max-width: 20px;
|
||||
max-height: 20px;
|
||||
min-width: 21px;
|
||||
min-height: 21px;
|
||||
max-width: 21px;
|
||||
max-height: 21px;
|
||||
}
|
||||
|
||||
QWidget#bottomPerGameInput,
|
||||
@@ -71,7 +75,7 @@ QWidget#middleControllerApplet {
|
||||
|
||||
QWidget#topPerGameInput QComboBox,
|
||||
QWidget#middleControllerApplet QComboBox {
|
||||
width: 123px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
QWidget#connectedControllers {
|
||||
|
||||
82
dist/qt_themes/qdarkstyle/style.qss
vendored
82
dist/qt_themes/qdarkstyle/style.qss
vendored
@@ -99,12 +99,19 @@ QGroupBox::indicator:unchecked:disabled {
|
||||
}
|
||||
|
||||
QRadioButton {
|
||||
spacing: 5px;
|
||||
outline: none;
|
||||
color: #eff0f1;
|
||||
spacing: 3px;
|
||||
padding: 0px;
|
||||
border: none;
|
||||
outline: none;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
QGroupBox QRadioButton {
|
||||
padding-left: 0px;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
QRadioButton:disabled {
|
||||
color: #76797C;
|
||||
}
|
||||
@@ -522,13 +529,12 @@ QToolButton#qt_toolbar_ext_button {
|
||||
|
||||
QPushButton {
|
||||
color: #eff0f1;
|
||||
border-width: 1px;
|
||||
border-color: #54575B;
|
||||
border-style: solid;
|
||||
padding: 6px 4px;
|
||||
border: 1px solid #54575B;
|
||||
border-radius: 2px;
|
||||
padding: 5px 0px 5px 0px;
|
||||
outline: none;
|
||||
min-width: 100px;
|
||||
min-height: 13px;
|
||||
background-color: #232629;
|
||||
}
|
||||
|
||||
@@ -553,8 +559,9 @@ QComboBox {
|
||||
selection-background-color: #3daee9;
|
||||
border: 1px solid #54575B;
|
||||
border-radius: 2px;
|
||||
padding: 4px 6px;
|
||||
min-width: 75px;
|
||||
padding: 0px 4px 0px 4px;
|
||||
min-width: 60px;
|
||||
min-height: 23px;
|
||||
background-color: #232629;
|
||||
}
|
||||
|
||||
@@ -608,26 +615,26 @@ QComboBox::down-arrow:focus {
|
||||
}
|
||||
|
||||
QAbstractSpinBox {
|
||||
padding: 4px 6px;
|
||||
border: 1px solid #54575B;
|
||||
background-color: #232629;
|
||||
color: #eff0f1;
|
||||
border-radius: 2px;
|
||||
min-width: 75px;
|
||||
min-width: 52px;
|
||||
min-height: 23px;
|
||||
}
|
||||
|
||||
QAbstractSpinBox:up-button {
|
||||
background-color: transparent;
|
||||
subcontrol-origin: border;
|
||||
subcontrol-position: center right;
|
||||
left: -6px;
|
||||
left: -2px;
|
||||
}
|
||||
|
||||
QAbstractSpinBox:down-button {
|
||||
background-color: transparent;
|
||||
subcontrol-origin: border;
|
||||
subcontrol-position: center left;
|
||||
right: -6px;
|
||||
right: -2px;
|
||||
}
|
||||
|
||||
QAbstractSpinBox::up-arrow,
|
||||
@@ -1277,41 +1284,33 @@ QPushButton#RendererStatusBarButton:!checked {
|
||||
}
|
||||
|
||||
QPushButton#buttonRefreshDevices {
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
max-width: 24px;
|
||||
max-height: 24px;
|
||||
min-width: 23px;
|
||||
min-height: 23px;
|
||||
max-width: 23px;
|
||||
max-height: 23px;
|
||||
padding: 0px 0px;
|
||||
}
|
||||
|
||||
QSpinBox#spinboxLStickRange,
|
||||
QSpinBox#spinboxRStickRange {
|
||||
padding: 4px 0px 5px 0px;
|
||||
min-width: 63px;
|
||||
}
|
||||
|
||||
QSpinBox#vibrationSpin {
|
||||
padding: 4px 0px 5px 0px;
|
||||
min-width: 63px;
|
||||
}
|
||||
|
||||
QSpinBox#spinboxLStickRange:up-button,
|
||||
QSpinBox#spinboxRStickRange:up-button,
|
||||
QSpinBox#vibrationSpin:up-button {
|
||||
left: -2px;
|
||||
}
|
||||
|
||||
QSpinBox#spinboxLStickRange:down-button,
|
||||
QSpinBox#spinboxRStickRange:down-button,
|
||||
QSpinBox#vibrationSpin:down-button {
|
||||
right: -1px;
|
||||
QSpinBox#spinboxRStickRange,
|
||||
QSpinBox#vibrationSpinPlayer1,
|
||||
QSpinBox#vibrationSpinPlayer2,
|
||||
QSpinBox#vibrationSpinPlayer3,
|
||||
QSpinBox#vibrationSpinPlayer4,
|
||||
QSpinBox#vibrationSpinPlayer5,
|
||||
QSpinBox#vibrationSpinPlayer6,
|
||||
QSpinBox#vibrationSpinPlayer7,
|
||||
QSpinBox#vibrationSpinPlayer8 {
|
||||
min-width: 68px;
|
||||
}
|
||||
|
||||
QDialog#ConfigureVibration QGroupBox::indicator,
|
||||
QGroupBox#motionGroup::indicator,
|
||||
QGroupBox#vibrationGroup::indicator {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
QDialog#ConfigureVibration QGroupBox::title,
|
||||
QGroupBox#motionGroup::title,
|
||||
QGroupBox#vibrationGroup::title {
|
||||
spacing: 2px;
|
||||
@@ -1340,16 +1339,7 @@ QWidget#middleControllerApplet {
|
||||
|
||||
QWidget#topPerGameInput QComboBox,
|
||||
QWidget#middleControllerApplet QComboBox {
|
||||
width: 119px;
|
||||
}
|
||||
|
||||
QRadioButton#radioDocked {
|
||||
margin-left: -3px;
|
||||
}
|
||||
|
||||
|
||||
QRadioButton#radioUndocked {
|
||||
margin-right: 5px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
QWidget#connectedControllers {
|
||||
|
||||
@@ -172,8 +172,8 @@ QCheckBox {
|
||||
color: #F0F0F0;
|
||||
spacing: 4px;
|
||||
outline: none;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
QCheckBox:focus {
|
||||
@@ -239,7 +239,7 @@ QGroupBox {
|
||||
border: 1px solid #32414B;
|
||||
border-radius: 4px;
|
||||
margin-top: 12px;
|
||||
padding: 4px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
QGroupBox::title {
|
||||
@@ -247,7 +247,7 @@ QGroupBox::title {
|
||||
subcontrol-position: top left;
|
||||
padding-left: 3px;
|
||||
padding-right: 5px;
|
||||
padding-top: 4px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
QGroupBox::indicator {
|
||||
@@ -298,6 +298,11 @@ QRadioButton {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QGroupBox QRadioButton {
|
||||
padding-left: 0px;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
QRadioButton:focus {
|
||||
border: none;
|
||||
}
|
||||
@@ -321,7 +326,6 @@ QRadioButton QWidget {
|
||||
QRadioButton::indicator {
|
||||
border: none;
|
||||
outline: none;
|
||||
margin-left: 4px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
@@ -785,14 +789,8 @@ QAbstractSpinBox {
|
||||
background-color: #19232D;
|
||||
border: 1px solid #32414B;
|
||||
color: #F0F0F0;
|
||||
/* This fixes 103, 111 */
|
||||
padding-top: 2px;
|
||||
/* This fixes 103, 111 */
|
||||
padding-bottom: 2px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
border-radius: 4px;
|
||||
/* min-width: 5px; removed to fix 109 */
|
||||
min-height: 19px;
|
||||
}
|
||||
|
||||
QAbstractSpinBox:up-button {
|
||||
@@ -997,10 +995,11 @@ QPushButton {
|
||||
border: 1px solid #32414B;
|
||||
color: #F0F0F0;
|
||||
border-radius: 4px;
|
||||
padding: 3px;
|
||||
padding: 3px 0px 3px 0px;
|
||||
outline: none;
|
||||
/* Issue #194 - Special case of QPushButton inside dialogs, for better UI */
|
||||
min-width: 80px;
|
||||
min-height: 13px;
|
||||
}
|
||||
|
||||
QPushButton:disabled {
|
||||
@@ -1008,14 +1007,14 @@ QPushButton:disabled {
|
||||
border: 1px solid #32414B;
|
||||
color: #787878;
|
||||
border-radius: 4px;
|
||||
padding: 3px;
|
||||
padding: 3px 0px 3px 0px;
|
||||
}
|
||||
|
||||
QPushButton:checked {
|
||||
background-color: #32414B;
|
||||
border: 1px solid #32414B;
|
||||
border-radius: 4px;
|
||||
padding: 3px;
|
||||
padding: 3px 0px 3px 0px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -1024,7 +1023,7 @@ QPushButton:checked:disabled {
|
||||
border: 1px solid #32414B;
|
||||
color: #787878;
|
||||
border-radius: 4px;
|
||||
padding: 3px;
|
||||
padding: 3px 0px 3px 0px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -1197,15 +1196,9 @@ QComboBox {
|
||||
border: 1px solid #32414B;
|
||||
border-radius: 4px;
|
||||
selection-background-color: #1464A0;
|
||||
padding-left: 4px;
|
||||
padding-right: 36px;
|
||||
/* 4 + 16*2 See scrollbar size */
|
||||
/* Fixes #103, #111 */
|
||||
min-height: 1.5em;
|
||||
/* padding-top: 2px; removed to fix #132 */
|
||||
/* padding-bottom: 2px; removed to fix #132 */
|
||||
/* min-width: 75px; removed to fix #109 */
|
||||
/* Needed to remove indicator - fix #132 */
|
||||
padding: 0px 4px 0px 4px;
|
||||
min-width: 60px;
|
||||
min-height: 19px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
@@ -2198,29 +2191,40 @@ QPushButton#RendererStatusBarButton:!checked {
|
||||
}
|
||||
|
||||
QPushButton#buttonRefreshDevices {
|
||||
min-width: 20px;
|
||||
min-height: 20px;
|
||||
max-width: 20px;
|
||||
max-height: 20px;
|
||||
min-width: 19px;
|
||||
min-height: 19px;
|
||||
max-width: 19px;
|
||||
max-height: 19px;
|
||||
padding: 0px 0px;
|
||||
}
|
||||
|
||||
QSpinBox#spinboxLStickRange,
|
||||
QSpinBox#spinboxRStickRange {
|
||||
min-width: 38px;
|
||||
QSpinBox#spinboxRStickRange,
|
||||
QSpinBox#vibrationSpinPlayer1,
|
||||
QSpinBox#vibrationSpinPlayer2,
|
||||
QSpinBox#vibrationSpinPlayer3,
|
||||
QSpinBox#vibrationSpinPlayer4,
|
||||
QSpinBox#vibrationSpinPlayer5,
|
||||
QSpinBox#vibrationSpinPlayer6,
|
||||
QSpinBox#vibrationSpinPlayer7,
|
||||
QSpinBox#vibrationSpinPlayer8 {
|
||||
min-width: 68px;
|
||||
}
|
||||
|
||||
QDialog#ConfigureVibration QGroupBox::indicator,
|
||||
QGroupBox#motionGroup::indicator,
|
||||
QGroupBox#vibrationGroup::indicator {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
QDialog#ConfigureVibration QGroupBox,
|
||||
QWidget#bottomPerGameInput QGroupBox#motionGroup,
|
||||
QWidget#bottomPerGameInput QGroupBox#vibrationGroup,
|
||||
QWidget#bottomPerGameInput QGroupBox#inputConfigGroup {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
QDialog#ConfigureVibration QGroupBox::title,
|
||||
QGroupBox#motionGroup::title,
|
||||
QGroupBox#vibrationGroup::title {
|
||||
spacing: 2px;
|
||||
@@ -2260,26 +2264,7 @@ QWidget#middleControllerApplet {
|
||||
|
||||
QWidget#topPerGameInput QComboBox,
|
||||
QWidget#middleControllerApplet QComboBox {
|
||||
padding-right: 2px;
|
||||
width: 127px;
|
||||
}
|
||||
|
||||
QGroupBox#handheldGroup {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
QRadioButton#radioDocked {
|
||||
margin-left: -1px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
QRadioButton#radioDocked::indicator {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
|
||||
QRadioButton#radioUndocked {
|
||||
margin-right: 2px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
QWidget#connectedControllers {
|
||||
@@ -2352,7 +2337,7 @@ QCheckBox#checkboxPlayer5Connected,
|
||||
QCheckBox#checkboxPlayer6Connected,
|
||||
QCheckBox#checkboxPlayer7Connected,
|
||||
QCheckBox#checkboxPlayer8Connected {
|
||||
spacing: 0px;
|
||||
spacing: 0px;
|
||||
}
|
||||
|
||||
QWidget#connectedControllers QLabel {
|
||||
@@ -2427,7 +2412,7 @@ QCheckBox#checkboxPlayer7Connected::indicator,
|
||||
QCheckBox#checkboxPlayer8Connected::indicator {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-left: 2px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
QWidget#Player1LEDs QCheckBox::indicator:checked,
|
||||
|
||||
28
externals/CMakeLists.txt
vendored
28
externals/CMakeLists.txt
vendored
@@ -73,23 +73,29 @@ if (NOT LIBZIP_FOUND)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
# LibreSSL
|
||||
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
|
||||
add_subdirectory(libressl EXCLUDE_FROM_ALL)
|
||||
target_include_directories(ssl INTERFACE ./libressl/include)
|
||||
target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
|
||||
get_directory_property(OPENSSL_LIBRARIES
|
||||
DIRECTORY libressl
|
||||
DEFINITION OPENSSL_LIBS)
|
||||
|
||||
# lurlparser
|
||||
add_subdirectory(lurlparser EXCLUDE_FROM_ALL)
|
||||
find_package(OpenSSL 1.1)
|
||||
if (OPENSSL_FOUND)
|
||||
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
|
||||
else()
|
||||
# LibreSSL
|
||||
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
|
||||
set(OPENSSLDIR "/etc/ssl/")
|
||||
add_subdirectory(libressl EXCLUDE_FROM_ALL)
|
||||
target_include_directories(ssl INTERFACE ./libressl/include)
|
||||
target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
|
||||
get_directory_property(OPENSSL_LIBRARIES
|
||||
DIRECTORY libressl
|
||||
DEFINITION OPENSSL_LIBS)
|
||||
endif()
|
||||
|
||||
# httplib
|
||||
add_library(httplib INTERFACE)
|
||||
target_include_directories(httplib INTERFACE ./httplib)
|
||||
target_compile_definitions(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
|
||||
if (WIN32)
|
||||
target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Opus
|
||||
|
||||
100
externals/find-modules/FindFFmpeg.cmake
vendored
Normal file
100
externals/find-modules/FindFFmpeg.cmake
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
# - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil)
|
||||
# Once done this will define
|
||||
#
|
||||
# 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 (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
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
#
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(FFMPEG
|
||||
FOUND_VAR FFMPEG_FOUND
|
||||
REQUIRED_VARS
|
||||
FFMPEG_LIBRARY
|
||||
FFMPEG_INCLUDE_DIR
|
||||
VERSION_VAR FFMPEG_VERSION
|
||||
)
|
||||
|
||||
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)
|
||||
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()
|
||||
else()
|
||||
if(FFMPEG_FIND_REQUIRED)
|
||||
message(FATAL_ERROR
|
||||
"Could not find libavcodec or libavutil or libswscale")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
2
externals/httplib/README.md
vendored
2
externals/httplib/README.md
vendored
@@ -1,4 +1,4 @@
|
||||
From https://github.com/yhirose/cpp-httplib/tree/fce8e6fefdab4ad48bc5b25c98e5ebfda4f3cf53
|
||||
From https://github.com/yhirose/cpp-httplib/tree/ff5677ad197947177c158fe857caff4f0e242045 with https://github.com/yhirose/cpp-httplib/pull/701
|
||||
|
||||
MIT License
|
||||
|
||||
|
||||
4792
externals/httplib/httplib.h
vendored
4792
externals/httplib/httplib.h
vendored
File diff suppressed because it is too large
Load Diff
2
externals/inih/inih
vendored
2
externals/inih/inih
vendored
Submodule externals/inih/inih updated: 603729dec8...1e80a47dff
2
externals/libressl
vendored
2
externals/libressl
vendored
Submodule externals/libressl updated: 7d01cb01cb...8289d0d07d
8
externals/lurlparser/CMakeLists.txt
vendored
8
externals/lurlparser/CMakeLists.txt
vendored
@@ -1,8 +0,0 @@
|
||||
add_library(lurlparser
|
||||
LUrlParser.cpp
|
||||
LUrlParser.h
|
||||
)
|
||||
|
||||
create_target_directory_groups(lurlparser)
|
||||
|
||||
target_include_directories(lurlparser INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
265
externals/lurlparser/LUrlParser.cpp
vendored
265
externals/lurlparser/LUrlParser.cpp
vendored
@@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Lightweight URL & URI parser (RFC 1738, RFC 3986)
|
||||
* https://github.com/corporateshark/LUrlParser
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "LUrlParser.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <stdlib.h>
|
||||
|
||||
// check if the scheme name is valid
|
||||
static bool IsSchemeValid( const std::string& SchemeName )
|
||||
{
|
||||
for ( auto c : SchemeName )
|
||||
{
|
||||
if ( !isalpha( c ) && c != '+' && c != '-' && c != '.' ) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LUrlParser::clParseURL::GetPort( int* OutPort ) const
|
||||
{
|
||||
if ( !IsValid() ) { return false; }
|
||||
|
||||
int Port = atoi( m_Port.c_str() );
|
||||
|
||||
if ( Port <= 0 || Port > 65535 ) { return false; }
|
||||
|
||||
if ( OutPort ) { *OutPort = Port; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// based on RFC 1738 and RFC 3986
|
||||
LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL )
|
||||
{
|
||||
LUrlParser::clParseURL Result;
|
||||
|
||||
const char* CurrentString = URL.c_str();
|
||||
|
||||
/*
|
||||
* <scheme>:<scheme-specific-part>
|
||||
* <scheme> := [a-z\+\-\.]+
|
||||
* For resiliency, programs interpreting URLs should treat upper case letters as equivalent to lower case in scheme names
|
||||
*/
|
||||
|
||||
// try to read scheme
|
||||
{
|
||||
const char* LocalString = strchr( CurrentString, ':' );
|
||||
|
||||
if ( !LocalString )
|
||||
{
|
||||
return clParseURL( LUrlParserError_NoUrlCharacter );
|
||||
}
|
||||
|
||||
// save the scheme name
|
||||
Result.m_Scheme = std::string( CurrentString, LocalString - CurrentString );
|
||||
|
||||
if ( !IsSchemeValid( Result.m_Scheme ) )
|
||||
{
|
||||
return clParseURL( LUrlParserError_InvalidSchemeName );
|
||||
}
|
||||
|
||||
// scheme should be lowercase
|
||||
std::transform( Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower );
|
||||
|
||||
// skip ':'
|
||||
CurrentString = LocalString+1;
|
||||
}
|
||||
|
||||
/*
|
||||
* //<user>:<password>@<host>:<port>/<url-path>
|
||||
* any ":", "@" and "/" must be normalized
|
||||
*/
|
||||
|
||||
// skip "//"
|
||||
if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash );
|
||||
if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash );
|
||||
|
||||
// check if the user name and password are specified
|
||||
bool bHasUserName = false;
|
||||
|
||||
const char* LocalString = CurrentString;
|
||||
|
||||
while ( *LocalString )
|
||||
{
|
||||
if ( *LocalString == '@' )
|
||||
{
|
||||
// user name and password are specified
|
||||
bHasUserName = true;
|
||||
break;
|
||||
}
|
||||
else if ( *LocalString == '/' )
|
||||
{
|
||||
// end of <host>:<port> specification
|
||||
bHasUserName = false;
|
||||
break;
|
||||
}
|
||||
|
||||
LocalString++;
|
||||
}
|
||||
|
||||
// user name and password
|
||||
LocalString = CurrentString;
|
||||
|
||||
if ( bHasUserName )
|
||||
{
|
||||
// read user name
|
||||
while ( *LocalString && *LocalString != ':' && *LocalString != '@' ) LocalString++;
|
||||
|
||||
Result.m_UserName = std::string( CurrentString, LocalString - CurrentString );
|
||||
|
||||
// proceed with the current pointer
|
||||
CurrentString = LocalString;
|
||||
|
||||
if ( *CurrentString == ':' )
|
||||
{
|
||||
// skip ':'
|
||||
CurrentString++;
|
||||
|
||||
// read password
|
||||
LocalString = CurrentString;
|
||||
|
||||
while ( *LocalString && *LocalString != '@' ) LocalString++;
|
||||
|
||||
Result.m_Password = std::string( CurrentString, LocalString - CurrentString );
|
||||
|
||||
CurrentString = LocalString;
|
||||
}
|
||||
|
||||
// skip '@'
|
||||
if ( *CurrentString != '@' )
|
||||
{
|
||||
return clParseURL( LUrlParserError_NoAtSign );
|
||||
}
|
||||
|
||||
CurrentString++;
|
||||
}
|
||||
|
||||
bool bHasBracket = ( *CurrentString == '[' );
|
||||
|
||||
// go ahead, read the host name
|
||||
LocalString = CurrentString;
|
||||
|
||||
while ( *LocalString )
|
||||
{
|
||||
if ( bHasBracket && *LocalString == ']' )
|
||||
{
|
||||
// end of IPv6 address
|
||||
LocalString++;
|
||||
break;
|
||||
}
|
||||
else if ( !bHasBracket && ( *LocalString == ':' || *LocalString == '/' ) )
|
||||
{
|
||||
// port number is specified
|
||||
break;
|
||||
}
|
||||
|
||||
LocalString++;
|
||||
}
|
||||
|
||||
Result.m_Host = std::string( CurrentString, LocalString - CurrentString );
|
||||
|
||||
CurrentString = LocalString;
|
||||
|
||||
// is port number specified?
|
||||
if ( *CurrentString == ':' )
|
||||
{
|
||||
CurrentString++;
|
||||
|
||||
// read port number
|
||||
LocalString = CurrentString;
|
||||
|
||||
while ( *LocalString && *LocalString != '/' ) LocalString++;
|
||||
|
||||
Result.m_Port = std::string( CurrentString, LocalString - CurrentString );
|
||||
|
||||
CurrentString = LocalString;
|
||||
}
|
||||
|
||||
// end of string
|
||||
if ( !*CurrentString )
|
||||
{
|
||||
Result.m_ErrorCode = LUrlParserError_Ok;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
// skip '/'
|
||||
if ( *CurrentString != '/' )
|
||||
{
|
||||
return clParseURL( LUrlParserError_NoSlash );
|
||||
}
|
||||
|
||||
CurrentString++;
|
||||
|
||||
// parse the path
|
||||
LocalString = CurrentString;
|
||||
|
||||
while ( *LocalString && *LocalString != '#' && *LocalString != '?' ) LocalString++;
|
||||
|
||||
Result.m_Path = std::string( CurrentString, LocalString - CurrentString );
|
||||
|
||||
CurrentString = LocalString;
|
||||
|
||||
// check for query
|
||||
if ( *CurrentString == '?' )
|
||||
{
|
||||
// skip '?'
|
||||
CurrentString++;
|
||||
|
||||
// read query
|
||||
LocalString = CurrentString;
|
||||
|
||||
while ( *LocalString && *LocalString != '#' ) LocalString++;
|
||||
|
||||
Result.m_Query = std::string( CurrentString, LocalString - CurrentString );
|
||||
|
||||
CurrentString = LocalString;
|
||||
}
|
||||
|
||||
// check for fragment
|
||||
if ( *CurrentString == '#' )
|
||||
{
|
||||
// skip '#'
|
||||
CurrentString++;
|
||||
|
||||
// read fragment
|
||||
LocalString = CurrentString;
|
||||
|
||||
while ( *LocalString ) LocalString++;
|
||||
|
||||
Result.m_Fragment = std::string( CurrentString, LocalString - CurrentString );
|
||||
|
||||
CurrentString = LocalString;
|
||||
}
|
||||
|
||||
Result.m_ErrorCode = LUrlParserError_Ok;
|
||||
|
||||
return Result;
|
||||
}
|
||||
78
externals/lurlparser/LUrlParser.h
vendored
78
externals/lurlparser/LUrlParser.h
vendored
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Lightweight URL & URI parser (RFC 1738, RFC 3986)
|
||||
* https://github.com/corporateshark/LUrlParser
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace LUrlParser
|
||||
{
|
||||
enum LUrlParserError
|
||||
{
|
||||
LUrlParserError_Ok = 0,
|
||||
LUrlParserError_Uninitialized = 1,
|
||||
LUrlParserError_NoUrlCharacter = 2,
|
||||
LUrlParserError_InvalidSchemeName = 3,
|
||||
LUrlParserError_NoDoubleSlash = 4,
|
||||
LUrlParserError_NoAtSign = 5,
|
||||
LUrlParserError_UnexpectedEndOfLine = 6,
|
||||
LUrlParserError_NoSlash = 7,
|
||||
};
|
||||
|
||||
class clParseURL
|
||||
{
|
||||
public:
|
||||
LUrlParserError m_ErrorCode;
|
||||
std::string m_Scheme;
|
||||
std::string m_Host;
|
||||
std::string m_Port;
|
||||
std::string m_Path;
|
||||
std::string m_Query;
|
||||
std::string m_Fragment;
|
||||
std::string m_UserName;
|
||||
std::string m_Password;
|
||||
|
||||
clParseURL()
|
||||
: m_ErrorCode( LUrlParserError_Uninitialized )
|
||||
{}
|
||||
|
||||
/// return 'true' if the parsing was successful
|
||||
bool IsValid() const { return m_ErrorCode == LUrlParserError_Ok; }
|
||||
|
||||
/// helper to convert the port number to int, return 'true' if the port is valid (within the 0..65535 range)
|
||||
bool GetPort( int* OutPort ) const;
|
||||
|
||||
/// parse the URL
|
||||
static clParseURL ParseURL( const std::string& URL );
|
||||
|
||||
private:
|
||||
explicit clParseURL( LUrlParserError ErrorCode )
|
||||
: m_ErrorCode( ErrorCode )
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace LUrlParser
|
||||
19
externals/lurlparser/README.md
vendored
19
externals/lurlparser/README.md
vendored
@@ -1,19 +0,0 @@
|
||||
From https://github.com/corporateshark/LUrlParser/commit/455d5e2d27e3946f11ad0328fee9ee2628e6a8e2
|
||||
|
||||
MIT License
|
||||
|
||||
===
|
||||
|
||||
Lightweight URL & URI parser (RFC 1738, RFC 3986)
|
||||
|
||||
(C) Sergey Kosarevsky, 2015
|
||||
|
||||
@corporateshark sk@linderdaum.com
|
||||
|
||||
http://www.linderdaum.com
|
||||
|
||||
http://blog.linderdaum.com
|
||||
|
||||
=============================
|
||||
|
||||
A tiny and lightweight URL & URI parser (RFC 1738, RFC 3986) written in C++.
|
||||
18
externals/microprofile/microprofile.h
vendored
18
externals/microprofile/microprofile.h
vendored
@@ -902,8 +902,10 @@ inline uint16_t MicroProfileGetGroupIndex(MicroProfileToken t)
|
||||
#include <windows.h>
|
||||
#define snprintf _snprintf
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4244)
|
||||
#endif
|
||||
int64_t MicroProfileTicksPerSecondCpu()
|
||||
{
|
||||
static int64_t nTicksPerSecond = 0;
|
||||
@@ -946,7 +948,11 @@ typedef HANDLE MicroProfileThread;
|
||||
DWORD _stdcall ThreadTrampoline(void* pFunc)
|
||||
{
|
||||
MicroProfileThreadFunc F = (MicroProfileThreadFunc)pFunc;
|
||||
return (uint32_t)F(0);
|
||||
|
||||
// The return value of F will always return a void*, however, this is for
|
||||
// compatibility with pthreads. The underlying "address" of the pointer
|
||||
// is always a 32-bit value, so this cast is safe to perform.
|
||||
return static_cast<DWORD>(reinterpret_cast<uint64_t>(F(0)));
|
||||
}
|
||||
|
||||
inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
|
||||
@@ -1742,10 +1748,10 @@ void MicroProfileFlip()
|
||||
}
|
||||
}
|
||||
}
|
||||
for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
|
||||
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
|
||||
{
|
||||
pLog->nGroupTicks[i] += nGroupTicks[i];
|
||||
pFrameGroup[i] += nGroupTicks[i];
|
||||
pLog->nGroupTicks[j] += nGroupTicks[j];
|
||||
pFrameGroup[j] += nGroupTicks[j];
|
||||
}
|
||||
pLog->nStackPos = nStackPos;
|
||||
}
|
||||
@@ -3328,7 +3334,7 @@ bool MicroProfileIsLocalThread(uint32_t nThreadId)
|
||||
#endif
|
||||
#else
|
||||
|
||||
bool MicroProfileIsLocalThread(uint32_t nThreadId){return false;}
|
||||
bool MicroProfileIsLocalThread([[maybe_unused]] uint32_t nThreadId) { return false; }
|
||||
void MicroProfileStopContextSwitchTrace(){}
|
||||
void MicroProfileStartContextSwitchTrace(){}
|
||||
|
||||
@@ -3576,7 +3582,7 @@ int MicroProfileGetGpuTickReference(int64_t* pOutCpu, int64_t* pOutGpu)
|
||||
|
||||
#undef S
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
1
externals/unicorn
vendored
1
externals/unicorn
vendored
Submodule externals/unicorn deleted from 73f4573535
@@ -32,7 +32,6 @@ if (MSVC)
|
||||
# /Zc:inline - Let codegen omit inline functions in object files
|
||||
# /Zc:throwingNew - Let codegen assume `operator new` (without std::nothrow) will never return null
|
||||
add_compile_options(
|
||||
/W3
|
||||
/MP
|
||||
/Zi
|
||||
/Zo
|
||||
@@ -43,6 +42,13 @@ if (MSVC)
|
||||
/Zc:externConstexpr
|
||||
/Zc:inline
|
||||
/Zc:throwingNew
|
||||
|
||||
# Warnings
|
||||
/W3
|
||||
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
|
||||
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
|
||||
/we4555 # Expression has no effect; expected expression with side-effect
|
||||
/we4834 # Discarding return value of function with 'nodiscard' attribute
|
||||
)
|
||||
|
||||
# /GS- - No stack buffer overflow checks
|
||||
@@ -56,6 +62,7 @@ else()
|
||||
-Werror=implicit-fallthrough
|
||||
-Werror=missing-declarations
|
||||
-Werror=reorder
|
||||
-Werror=unused-result
|
||||
-Wextra
|
||||
-Wmissing-declarations
|
||||
-Wno-attributes
|
||||
|
||||
@@ -46,11 +46,17 @@ create_target_directory_groups(audio_core)
|
||||
|
||||
if (NOT MSVC)
|
||||
target_compile_options(audio_core PRIVATE
|
||||
-Werror=conversion
|
||||
-Werror=ignored-qualifiers
|
||||
-Werror=implicit-fallthrough
|
||||
-Werror=reorder
|
||||
-Werror=sign-compare
|
||||
-Werror=unused-variable
|
||||
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
|
||||
|
||||
-Wno-sign-conversion
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ void Filter::Process(std::vector<s16>& signal) {
|
||||
/// @param total_count The total number of biquads to be cascaded.
|
||||
/// @param index 0-index of the biquad to calculate the Q value for.
|
||||
static double CascadingBiquadQ(std::size_t total_count, std::size_t index) {
|
||||
const double pole = M_PI * (2 * index + 1) / (4.0 * total_count);
|
||||
const auto pole =
|
||||
M_PI * static_cast<double>(2 * index + 1) / (4.0 * static_cast<double>(total_count));
|
||||
return 1.0 / (2.0 * std::cos(pole));
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
|
||||
return {};
|
||||
|
||||
if (ratio <= 0) {
|
||||
LOG_CRITICAL(Audio, "Nonsensical interpolation ratio {}", ratio);
|
||||
LOG_ERROR(Audio, "Nonsensical interpolation ratio {}", ratio);
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,8 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
|
||||
const std::size_t num_frames{input.size() / 2};
|
||||
|
||||
std::vector<s16> output;
|
||||
output.reserve(static_cast<std::size_t>(input.size() / ratio + InterpolationState::taps));
|
||||
output.reserve(static_cast<std::size_t>(static_cast<double>(input.size()) / ratio +
|
||||
InterpolationState::taps));
|
||||
|
||||
for (std::size_t frame{}; frame < num_frames; ++frame) {
|
||||
const std::size_t lut_index{(state.fraction >> 8) * InterpolationState::taps};
|
||||
|
||||
@@ -793,7 +793,6 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
|
||||
// Decode entire frame
|
||||
if (remaining_samples >= static_cast<int>(SAMPLES_PER_FRAME)) {
|
||||
for (std::size_t i = 0; i < SAMPLES_PER_FRAME / 2; i++) {
|
||||
|
||||
// Sample 1
|
||||
const s32 s0 = SIGNED_NIBBLES[buffer[buffer_offset] >> 4];
|
||||
const s32 s1 = SIGNED_NIBBLES[buffer[buffer_offset++] & 0xf];
|
||||
@@ -802,7 +801,7 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
|
||||
sample_buffer[cur_mix_offset++] = sample_1;
|
||||
sample_buffer[cur_mix_offset++] = sample_2;
|
||||
}
|
||||
remaining_samples -= SAMPLES_PER_FRAME;
|
||||
remaining_samples -= static_cast<int>(SAMPLES_PER_FRAME);
|
||||
position_in_frame += SAMPLES_PER_FRAME;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -93,8 +93,10 @@ public:
|
||||
constexpr s32 clev{707}; // center mixing level coefficient
|
||||
constexpr s32 slev{707}; // surround mixing level coefficient
|
||||
|
||||
buf.push_back(left + (clev * center / 1000) + (slev * surround_left / 1000));
|
||||
buf.push_back(right + (clev * center / 1000) + (slev * surround_right / 1000));
|
||||
buf.push_back(static_cast<s16>(left + (clev * center / 1000) +
|
||||
(slev * surround_left / 1000)));
|
||||
buf.push_back(static_cast<s16>(right + (clev * center / 1000) +
|
||||
(slev * surround_right / 1000)));
|
||||
}
|
||||
queue.Push(buf);
|
||||
return;
|
||||
|
||||
@@ -128,7 +128,10 @@ void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in,
|
||||
in_params.wave_buffer_count = voice_in.wave_buffer_count;
|
||||
in_params.wave_bufffer_head = voice_in.wave_buffer_head;
|
||||
if (behavior_info.IsFlushVoiceWaveBuffersSupported()) {
|
||||
in_params.wave_buffer_flush_request_count += voice_in.wave_buffer_flush_request_count;
|
||||
const auto in_request_count = in_params.wave_buffer_flush_request_count;
|
||||
const auto voice_request_count = voice_in.wave_buffer_flush_request_count;
|
||||
in_params.wave_buffer_flush_request_count =
|
||||
static_cast<u8>(in_request_count + voice_request_count);
|
||||
}
|
||||
in_params.mix_id = voice_in.mix_id;
|
||||
if (behavior_info.IsSplitterSupported()) {
|
||||
|
||||
@@ -150,6 +150,8 @@ add_library(common STATIC
|
||||
scope_exit.h
|
||||
spin_lock.cpp
|
||||
spin_lock.h
|
||||
stream.cpp
|
||||
stream.h
|
||||
string_util.cpp
|
||||
string_util.h
|
||||
swap.h
|
||||
@@ -188,6 +190,22 @@ if(ARCHITECTURE_x86_64)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
target_compile_definitions(common PRIVATE
|
||||
# The standard library doesn't provide any replacement for codecvt yet
|
||||
# so we can disable this deprecation warning for the time being.
|
||||
_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
|
||||
)
|
||||
target_compile_options(common PRIVATE
|
||||
/W4
|
||||
/WX
|
||||
)
|
||||
else()
|
||||
target_compile_options(common PRIVATE
|
||||
-Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
create_target_directory_groups(common)
|
||||
find_package(Boost 1.71 COMPONENTS context headers REQUIRED)
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/fiber.h"
|
||||
#include "common/spin_lock.h"
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
#include <windows.h>
|
||||
#else
|
||||
@@ -14,18 +16,45 @@ namespace Common {
|
||||
|
||||
constexpr std::size_t default_stack_size = 256 * 1024; // 256kb
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
|
||||
struct Fiber::FiberImpl {
|
||||
SpinLock guard{};
|
||||
std::function<void(void*)> entry_point;
|
||||
std::function<void(void*)> rewind_point;
|
||||
void* rewind_parameter{};
|
||||
void* start_parameter{};
|
||||
std::shared_ptr<Fiber> previous_fiber;
|
||||
bool is_thread_fiber{};
|
||||
bool released{};
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
LPVOID handle = nullptr;
|
||||
LPVOID rewind_handle = nullptr;
|
||||
#else
|
||||
alignas(64) std::array<u8, default_stack_size> stack;
|
||||
alignas(64) std::array<u8, default_stack_size> rewind_stack;
|
||||
u8* stack_limit;
|
||||
u8* rewind_stack_limit;
|
||||
boost::context::detail::fcontext_t context;
|
||||
boost::context::detail::fcontext_t rewind_context;
|
||||
#endif
|
||||
};
|
||||
|
||||
void Fiber::SetStartParameter(void* new_parameter) {
|
||||
impl->start_parameter = new_parameter;
|
||||
}
|
||||
|
||||
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
|
||||
impl->rewind_point = std::move(rewind_func);
|
||||
impl->rewind_parameter = rewind_param;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
|
||||
void Fiber::Start() {
|
||||
ASSERT(previous_fiber != nullptr);
|
||||
previous_fiber->guard.unlock();
|
||||
previous_fiber.reset();
|
||||
entry_point(start_parameter);
|
||||
ASSERT(impl->previous_fiber != nullptr);
|
||||
impl->previous_fiber->impl->guard.unlock();
|
||||
impl->previous_fiber.reset();
|
||||
impl->entry_point(impl->start_parameter);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@@ -34,99 +63,86 @@ void Fiber::OnRewind() {
|
||||
DeleteFiber(impl->handle);
|
||||
impl->handle = impl->rewind_handle;
|
||||
impl->rewind_handle = nullptr;
|
||||
rewind_point(rewind_parameter);
|
||||
impl->rewind_point(impl->rewind_parameter);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void Fiber::FiberStartFunc(void* fiber_parameter) {
|
||||
auto fiber = static_cast<Fiber*>(fiber_parameter);
|
||||
auto* fiber = static_cast<Fiber*>(fiber_parameter);
|
||||
fiber->Start();
|
||||
}
|
||||
|
||||
void Fiber::RewindStartFunc(void* fiber_parameter) {
|
||||
auto fiber = static_cast<Fiber*>(fiber_parameter);
|
||||
auto* fiber = static_cast<Fiber*>(fiber_parameter);
|
||||
fiber->OnRewind();
|
||||
}
|
||||
|
||||
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
|
||||
: entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} {
|
||||
impl = std::make_unique<FiberImpl>();
|
||||
: impl{std::make_unique<FiberImpl>()} {
|
||||
impl->entry_point = std::move(entry_point_func);
|
||||
impl->start_parameter = start_parameter;
|
||||
impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this);
|
||||
}
|
||||
|
||||
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
|
||||
|
||||
Fiber::~Fiber() {
|
||||
if (released) {
|
||||
if (impl->released) {
|
||||
return;
|
||||
}
|
||||
// Make sure the Fiber is not being used
|
||||
const bool locked = guard.try_lock();
|
||||
const bool locked = impl->guard.try_lock();
|
||||
ASSERT_MSG(locked, "Destroying a fiber that's still running");
|
||||
if (locked) {
|
||||
guard.unlock();
|
||||
impl->guard.unlock();
|
||||
}
|
||||
DeleteFiber(impl->handle);
|
||||
}
|
||||
|
||||
void Fiber::Exit() {
|
||||
ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber");
|
||||
if (!is_thread_fiber) {
|
||||
ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
|
||||
if (!impl->is_thread_fiber) {
|
||||
return;
|
||||
}
|
||||
ConvertFiberToThread();
|
||||
guard.unlock();
|
||||
released = true;
|
||||
}
|
||||
|
||||
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) {
|
||||
rewind_point = std::move(rewind_func);
|
||||
rewind_parameter = start_parameter;
|
||||
impl->guard.unlock();
|
||||
impl->released = true;
|
||||
}
|
||||
|
||||
void Fiber::Rewind() {
|
||||
ASSERT(rewind_point);
|
||||
ASSERT(impl->rewind_point);
|
||||
ASSERT(impl->rewind_handle == nullptr);
|
||||
impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this);
|
||||
SwitchToFiber(impl->rewind_handle);
|
||||
}
|
||||
|
||||
void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) {
|
||||
void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
|
||||
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
|
||||
ASSERT_MSG(to != nullptr, "Next fiber is null!");
|
||||
to->guard.lock();
|
||||
to->previous_fiber = from;
|
||||
to->impl->guard.lock();
|
||||
to->impl->previous_fiber = from;
|
||||
SwitchToFiber(to->impl->handle);
|
||||
ASSERT(from->previous_fiber != nullptr);
|
||||
from->previous_fiber->guard.unlock();
|
||||
from->previous_fiber.reset();
|
||||
ASSERT(from->impl->previous_fiber != nullptr);
|
||||
from->impl->previous_fiber->impl->guard.unlock();
|
||||
from->impl->previous_fiber.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
||||
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
|
||||
fiber->guard.lock();
|
||||
fiber->impl->guard.lock();
|
||||
fiber->impl->handle = ConvertThreadToFiber(nullptr);
|
||||
fiber->is_thread_fiber = true;
|
||||
fiber->impl->is_thread_fiber = true;
|
||||
return fiber;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct Fiber::FiberImpl {
|
||||
alignas(64) std::array<u8, default_stack_size> stack;
|
||||
alignas(64) std::array<u8, default_stack_size> rewind_stack;
|
||||
u8* stack_limit;
|
||||
u8* rewind_stack_limit;
|
||||
boost::context::detail::fcontext_t context;
|
||||
boost::context::detail::fcontext_t rewind_context;
|
||||
};
|
||||
|
||||
void Fiber::Start(boost::context::detail::transfer_t& transfer) {
|
||||
ASSERT(previous_fiber != nullptr);
|
||||
previous_fiber->impl->context = transfer.fctx;
|
||||
previous_fiber->guard.unlock();
|
||||
previous_fiber.reset();
|
||||
entry_point(start_parameter);
|
||||
ASSERT(impl->previous_fiber != nullptr);
|
||||
impl->previous_fiber->impl->context = transfer.fctx;
|
||||
impl->previous_fiber->impl->guard.unlock();
|
||||
impl->previous_fiber.reset();
|
||||
impl->entry_point(impl->start_parameter);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@@ -137,23 +153,24 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf
|
||||
u8* tmp = impl->stack_limit;
|
||||
impl->stack_limit = impl->rewind_stack_limit;
|
||||
impl->rewind_stack_limit = tmp;
|
||||
rewind_point(rewind_parameter);
|
||||
impl->rewind_point(impl->rewind_parameter);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) {
|
||||
auto fiber = static_cast<Fiber*>(transfer.data);
|
||||
auto* fiber = static_cast<Fiber*>(transfer.data);
|
||||
fiber->Start(transfer);
|
||||
}
|
||||
|
||||
void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
|
||||
auto fiber = static_cast<Fiber*>(transfer.data);
|
||||
auto* fiber = static_cast<Fiber*>(transfer.data);
|
||||
fiber->OnRewind(transfer);
|
||||
}
|
||||
|
||||
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
|
||||
: entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} {
|
||||
impl = std::make_unique<FiberImpl>();
|
||||
: impl{std::make_unique<FiberImpl>()} {
|
||||
impl->entry_point = std::move(entry_point_func);
|
||||
impl->start_parameter = start_parameter;
|
||||
impl->stack_limit = impl->stack.data();
|
||||
impl->rewind_stack_limit = impl->rewind_stack.data();
|
||||
u8* stack_base = impl->stack_limit + default_stack_size;
|
||||
@@ -161,37 +178,31 @@ Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_paramete
|
||||
boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc);
|
||||
}
|
||||
|
||||
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) {
|
||||
rewind_point = std::move(rewind_func);
|
||||
rewind_parameter = start_parameter;
|
||||
}
|
||||
|
||||
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
|
||||
|
||||
Fiber::~Fiber() {
|
||||
if (released) {
|
||||
if (impl->released) {
|
||||
return;
|
||||
}
|
||||
// Make sure the Fiber is not being used
|
||||
const bool locked = guard.try_lock();
|
||||
const bool locked = impl->guard.try_lock();
|
||||
ASSERT_MSG(locked, "Destroying a fiber that's still running");
|
||||
if (locked) {
|
||||
guard.unlock();
|
||||
impl->guard.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void Fiber::Exit() {
|
||||
|
||||
ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber");
|
||||
if (!is_thread_fiber) {
|
||||
ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
|
||||
if (!impl->is_thread_fiber) {
|
||||
return;
|
||||
}
|
||||
guard.unlock();
|
||||
released = true;
|
||||
impl->guard.unlock();
|
||||
impl->released = true;
|
||||
}
|
||||
|
||||
void Fiber::Rewind() {
|
||||
ASSERT(rewind_point);
|
||||
ASSERT(impl->rewind_point);
|
||||
ASSERT(impl->rewind_context == nullptr);
|
||||
u8* stack_base = impl->rewind_stack_limit + default_stack_size;
|
||||
impl->rewind_context =
|
||||
@@ -199,22 +210,22 @@ void Fiber::Rewind() {
|
||||
boost::context::detail::jump_fcontext(impl->rewind_context, this);
|
||||
}
|
||||
|
||||
void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) {
|
||||
void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
|
||||
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
|
||||
ASSERT_MSG(to != nullptr, "Next fiber is null!");
|
||||
to->guard.lock();
|
||||
to->previous_fiber = from;
|
||||
to->impl->guard.lock();
|
||||
to->impl->previous_fiber = from;
|
||||
auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get());
|
||||
ASSERT(from->previous_fiber != nullptr);
|
||||
from->previous_fiber->impl->context = transfer.fctx;
|
||||
from->previous_fiber->guard.unlock();
|
||||
from->previous_fiber.reset();
|
||||
ASSERT(from->impl->previous_fiber != nullptr);
|
||||
from->impl->previous_fiber->impl->context = transfer.fctx;
|
||||
from->impl->previous_fiber->impl->guard.unlock();
|
||||
from->impl->previous_fiber.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
||||
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
|
||||
fiber->guard.lock();
|
||||
fiber->is_thread_fiber = true;
|
||||
fiber->impl->guard.lock();
|
||||
fiber->impl->is_thread_fiber = true;
|
||||
return fiber;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/spin_lock.h"
|
||||
|
||||
#if !defined(_WIN32) && !defined(WIN32)
|
||||
namespace boost::context::detail {
|
||||
struct transfer_t;
|
||||
@@ -46,10 +43,10 @@ public:
|
||||
|
||||
/// Yields control from Fiber 'from' to Fiber 'to'
|
||||
/// Fiber 'from' must be the currently running fiber.
|
||||
static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to);
|
||||
static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to);
|
||||
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
|
||||
|
||||
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter);
|
||||
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param);
|
||||
|
||||
void Rewind();
|
||||
|
||||
@@ -57,9 +54,7 @@ public:
|
||||
void Exit();
|
||||
|
||||
/// Changes the start parameter of the fiber. Has no effect if the fiber already started
|
||||
void SetStartParameter(void* new_parameter) {
|
||||
start_parameter = new_parameter;
|
||||
}
|
||||
void SetStartParameter(void* new_parameter);
|
||||
|
||||
private:
|
||||
Fiber();
|
||||
@@ -77,16 +72,7 @@ private:
|
||||
#endif
|
||||
|
||||
struct FiberImpl;
|
||||
|
||||
SpinLock guard{};
|
||||
std::function<void(void*)> entry_point;
|
||||
std::function<void(void*)> rewind_point;
|
||||
void* rewind_parameter{};
|
||||
void* start_parameter{};
|
||||
std::shared_ptr<Fiber> previous_fiber;
|
||||
std::unique_ptr<FiberImpl> impl;
|
||||
bool is_thread_fiber{};
|
||||
bool released{};
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -472,13 +472,14 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
|
||||
}
|
||||
|
||||
bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) {
|
||||
const auto callback = [recursion](u64* num_entries_out, const std::string& directory,
|
||||
const std::string& virtual_name) -> bool {
|
||||
std::string new_path = directory + DIR_SEP_CHR + virtual_name;
|
||||
const auto callback = [recursion](u64*, const std::string& directory,
|
||||
const std::string& virtual_name) {
|
||||
const std::string new_path = directory + DIR_SEP_CHR + virtual_name;
|
||||
|
||||
if (IsDirectory(new_path)) {
|
||||
if (recursion == 0)
|
||||
if (recursion == 0) {
|
||||
return false;
|
||||
}
|
||||
return DeleteDirRecursively(new_path, recursion - 1);
|
||||
}
|
||||
return Delete(new_path);
|
||||
@@ -492,7 +493,8 @@ bool DeleteDirRecursively(const std::string& directory, unsigned int recursion)
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path) {
|
||||
void CopyDir([[maybe_unused]] const std::string& source_path,
|
||||
[[maybe_unused]] const std::string& dest_path) {
|
||||
#ifndef _WIN32
|
||||
if (source_path == dest_path) {
|
||||
return;
|
||||
@@ -553,7 +555,7 @@ std::optional<std::string> GetCurrentDir() {
|
||||
std::string strDir = dir;
|
||||
#endif
|
||||
free(dir);
|
||||
return std::move(strDir);
|
||||
return strDir;
|
||||
}
|
||||
|
||||
bool SetCurrentDir(const std::string& directory) {
|
||||
@@ -772,21 +774,23 @@ std::size_t ReadFileToString(bool text_file, const std::string& filename, std::s
|
||||
|
||||
void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,
|
||||
std::array<char, 4>& extension) {
|
||||
const std::string forbidden_characters = ".\"/\\[]:;=, ";
|
||||
static constexpr std::string_view forbidden_characters = ".\"/\\[]:;=, ";
|
||||
|
||||
// On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces.
|
||||
short_name = {{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}};
|
||||
extension = {{' ', ' ', ' ', '\0'}};
|
||||
|
||||
std::string::size_type point = filename.rfind('.');
|
||||
if (point == filename.size() - 1)
|
||||
auto point = filename.rfind('.');
|
||||
if (point == filename.size() - 1) {
|
||||
point = filename.rfind('.', point);
|
||||
}
|
||||
|
||||
// Get short name.
|
||||
int j = 0;
|
||||
for (char letter : filename.substr(0, point)) {
|
||||
if (forbidden_characters.find(letter, 0) != std::string::npos)
|
||||
if (forbidden_characters.find(letter, 0) != std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
if (j == 8) {
|
||||
// TODO(Link Mauve): also do that for filenames containing a space.
|
||||
// TODO(Link Mauve): handle multiple files having the same short name.
|
||||
@@ -794,14 +798,15 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
|
||||
short_name[7] = '1';
|
||||
break;
|
||||
}
|
||||
short_name[j++] = toupper(letter);
|
||||
short_name[j++] = static_cast<char>(std::toupper(letter));
|
||||
}
|
||||
|
||||
// Get extension.
|
||||
if (point != std::string::npos) {
|
||||
j = 0;
|
||||
for (char letter : filename.substr(point + 1, 3))
|
||||
extension[j++] = toupper(letter);
|
||||
for (char letter : filename.substr(point + 1, 3)) {
|
||||
extension[j++] = static_cast<char>(std::toupper(letter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ public:
|
||||
|
||||
void Swap(IOFile& other) noexcept;
|
||||
|
||||
[[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0);
|
||||
bool Open(const std::string& filename, const char openmode[], int flags = 0);
|
||||
bool Close();
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -16,14 +16,14 @@ namespace Common {
|
||||
|
||||
[[nodiscard]] constexpr u8 ToHexNibble(char c) {
|
||||
if (c >= 65 && c <= 70) {
|
||||
return c - 55;
|
||||
return static_cast<u8>(c - 55);
|
||||
}
|
||||
|
||||
if (c >= 97 && c <= 102) {
|
||||
return c - 87;
|
||||
return static_cast<u8>(c - 87);
|
||||
}
|
||||
|
||||
return c - 48;
|
||||
return static_cast<u8>(c - 48);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
|
||||
@@ -33,11 +33,11 @@ template <std::size_t Size, bool le = false>
|
||||
std::array<u8, Size> out{};
|
||||
if constexpr (le) {
|
||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
|
||||
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
|
||||
out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
|
||||
}
|
||||
} else {
|
||||
for (std::size_t i = 0; i < 2 * Size; i += 2) {
|
||||
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
|
||||
out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
|
||||
@@ -274,7 +274,6 @@ const char* GetLogClassName(Class log_class) {
|
||||
case Class::Count:
|
||||
break;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
@@ -293,7 +292,6 @@ const char* GetLevelName(Level log_level) {
|
||||
break;
|
||||
}
|
||||
#undef LVL
|
||||
UNREACHABLE();
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
|
||||
@@ -20,14 +20,14 @@ struct Rectangle {
|
||||
|
||||
constexpr Rectangle() = default;
|
||||
|
||||
constexpr Rectangle(T left, T top, T right, T bottom)
|
||||
: left(left), top(top), right(right), bottom(bottom) {}
|
||||
constexpr Rectangle(T left_, T top_, T right_, T bottom_)
|
||||
: left(left_), top(top_), right(right_), bottom(bottom_) {}
|
||||
|
||||
[[nodiscard]] T GetWidth() const {
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
return std::abs(right - left);
|
||||
} else {
|
||||
return std::abs(static_cast<std::make_signed_t<T>>(right - left));
|
||||
return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(right - left)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ struct Rectangle {
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
return std::abs(bottom - top);
|
||||
} else {
|
||||
return std::abs(static_cast<std::make_signed_t<T>>(bottom - top));
|
||||
return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(bottom - top)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,16 +16,23 @@
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
std::string GetLastErrorMsg() {
|
||||
static const std::size_t buff_size = 255;
|
||||
static constexpr std::size_t buff_size = 255;
|
||||
char err_str[buff_size];
|
||||
|
||||
#ifdef _WIN32
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr);
|
||||
return std::string(err_str, buff_size);
|
||||
#elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
|
||||
// Thread safe (GNU-specific)
|
||||
const char* str = strerror_r(errno, err_str, buff_size);
|
||||
return std::string(str);
|
||||
#else
|
||||
// Thread safe (XSI-compliant)
|
||||
strerror_r(errno, err_str, buff_size);
|
||||
const int success = strerror_r(errno, err_str, buff_size);
|
||||
if (success != 0) {
|
||||
return {};
|
||||
}
|
||||
return std::string(err_str);
|
||||
#endif
|
||||
|
||||
return std::string(err_str, buff_size);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Common {
|
||||
|
||||
PageTable::PageTable() = default;
|
||||
|
||||
PageTable::~PageTable() = default;
|
||||
PageTable::~PageTable() noexcept = default;
|
||||
|
||||
void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits,
|
||||
bool has_attribute) {
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include <tuple>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/memory_hook.h"
|
||||
@@ -51,13 +49,21 @@ struct SpecialRegion {
|
||||
*/
|
||||
struct PageTable {
|
||||
PageTable();
|
||||
~PageTable();
|
||||
~PageTable() noexcept;
|
||||
|
||||
PageTable(const PageTable&) = delete;
|
||||
PageTable& operator=(const PageTable&) = delete;
|
||||
|
||||
PageTable(PageTable&&) noexcept = default;
|
||||
PageTable& operator=(PageTable&&) noexcept = default;
|
||||
|
||||
/**
|
||||
* Resizes the page table to be able to accomodate enough pages within
|
||||
* a given address space.
|
||||
*
|
||||
* @param address_space_width_in_bits The address size width in bits.
|
||||
* @param page_size_in_bits The page size in bits.
|
||||
* @param has_attribute Whether or not this page has any backing attributes.
|
||||
*/
|
||||
void Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits,
|
||||
bool has_attribute);
|
||||
|
||||
@@ -15,6 +15,14 @@ namespace Common {
|
||||
*/
|
||||
class SpinLock {
|
||||
public:
|
||||
SpinLock() = default;
|
||||
|
||||
SpinLock(const SpinLock&) = delete;
|
||||
SpinLock& operator=(const SpinLock&) = delete;
|
||||
|
||||
SpinLock(SpinLock&&) = delete;
|
||||
SpinLock& operator=(SpinLock&&) = delete;
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
[[nodiscard]] bool try_lock();
|
||||
|
||||
47
src/common/stream.cpp
Normal file
47
src/common/stream.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <stdexcept>
|
||||
#include "common/common_types.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
Stream::Stream() = default;
|
||||
Stream::~Stream() = default;
|
||||
|
||||
void Stream::Seek(s32 offset, SeekOrigin origin) {
|
||||
if (origin == SeekOrigin::SetOrigin) {
|
||||
if (offset < 0) {
|
||||
position = 0;
|
||||
} else if (position >= buffer.size()) {
|
||||
position = buffer.size();
|
||||
} else {
|
||||
position = offset;
|
||||
}
|
||||
} else if (origin == SeekOrigin::FromCurrentPos) {
|
||||
Seek(static_cast<s32>(position) + offset, SeekOrigin::SetOrigin);
|
||||
} else if (origin == SeekOrigin::FromEnd) {
|
||||
Seek(static_cast<s32>(buffer.size()) - offset, SeekOrigin::SetOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
u8 Stream::ReadByte() {
|
||||
if (position < buffer.size()) {
|
||||
return buffer[position++];
|
||||
} else {
|
||||
throw std::out_of_range("Attempting to read a byte not within the buffer range");
|
||||
}
|
||||
}
|
||||
|
||||
void Stream::WriteByte(u8 byte) {
|
||||
if (position == buffer.size()) {
|
||||
buffer.push_back(byte);
|
||||
position++;
|
||||
} else {
|
||||
buffer.insert(buffer.begin() + position, byte);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
56
src/common/stream.h
Normal file
56
src/common/stream.h
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
enum class SeekOrigin {
|
||||
SetOrigin,
|
||||
FromCurrentPos,
|
||||
FromEnd,
|
||||
};
|
||||
|
||||
class Stream {
|
||||
public:
|
||||
/// Stream creates a bitstream and provides common functionality on the stream.
|
||||
explicit Stream();
|
||||
~Stream();
|
||||
|
||||
Stream(const Stream&) = delete;
|
||||
Stream& operator=(const Stream&) = delete;
|
||||
|
||||
Stream(Stream&&) = default;
|
||||
Stream& operator=(Stream&&) = default;
|
||||
|
||||
/// Reposition bitstream "cursor" to the specified offset from origin
|
||||
void Seek(s32 offset, SeekOrigin origin);
|
||||
|
||||
/// Reads next byte in the stream buffer and increments position
|
||||
u8 ReadByte();
|
||||
|
||||
/// Writes byte at current position
|
||||
void WriteByte(u8 byte);
|
||||
|
||||
[[nodiscard]] std::size_t GetPosition() const {
|
||||
return position;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<u8>& GetBuffer() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<u8>& GetBuffer() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<u8> buffer;
|
||||
std::size_t position{0};
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <cstdlib>
|
||||
#include <locale>
|
||||
#include <sstream>
|
||||
|
||||
#include "common/common_paths.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
@@ -21,14 +22,14 @@ namespace Common {
|
||||
/// Make a string lowercase
|
||||
std::string ToLower(std::string str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return str;
|
||||
}
|
||||
|
||||
/// Make a string uppercase
|
||||
std::string ToUpper(std::string str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](unsigned char c) { return std::toupper(c); });
|
||||
[](unsigned char c) { return static_cast<char>(std::toupper(c)); });
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
@@ -142,20 +142,18 @@ std::string Timer::GetTimeFormatted() {
|
||||
// ----------------
|
||||
double Timer::GetDoubleTime() {
|
||||
// Get continuous timestamp
|
||||
u64 TmpSeconds = static_cast<u64>(Common::Timer::GetTimeSinceJan1970().count());
|
||||
double ms = static_cast<u64>(GetTimeMs().count()) % 1000;
|
||||
auto tmp_seconds = static_cast<u64>(GetTimeSinceJan1970().count());
|
||||
const auto ms = static_cast<double>(static_cast<u64>(GetTimeMs().count()) % 1000);
|
||||
|
||||
// Remove a few years. We only really want enough seconds to make
|
||||
// sure that we are detecting actual actions, perhaps 60 seconds is
|
||||
// enough really, but I leave a year of seconds anyway, in case the
|
||||
// user's clock is incorrect or something like that.
|
||||
TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60);
|
||||
tmp_seconds = tmp_seconds - (38 * 365 * 24 * 60 * 60);
|
||||
|
||||
// Make a smaller integer that fits in the double
|
||||
u32 Seconds = static_cast<u32>(TmpSeconds);
|
||||
double TmpTime = Seconds + ms;
|
||||
|
||||
return TmpTime;
|
||||
const auto seconds = static_cast<u32>(tmp_seconds);
|
||||
return seconds + ms;
|
||||
}
|
||||
|
||||
} // Namespace Common
|
||||
|
||||
@@ -87,7 +87,13 @@ public:
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return {x * f, y * f};
|
||||
using TV = decltype(T{} * V{});
|
||||
using C = std::common_type_t<T, V>;
|
||||
|
||||
return {
|
||||
static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
|
||||
};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
@@ -98,7 +104,13 @@ public:
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return {x / f, y / f};
|
||||
using TV = decltype(T{} / V{});
|
||||
using C = std::common_type_t<T, V>;
|
||||
|
||||
return {
|
||||
static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
|
||||
};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
@@ -168,7 +180,10 @@ public:
|
||||
|
||||
template <typename T, typename V>
|
||||
[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
|
||||
return Vec2<T>(f * vec.x, f * vec.y);
|
||||
using C = std::common_type_t<T, V>;
|
||||
|
||||
return Vec2<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
|
||||
static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)));
|
||||
}
|
||||
|
||||
using Vec2f = Vec2<float>;
|
||||
@@ -237,7 +252,14 @@ public:
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return {x * f, y * f, z * f};
|
||||
using TV = decltype(T{} * V{});
|
||||
using C = std::common_type_t<T, V>;
|
||||
|
||||
return {
|
||||
static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
|
||||
};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
@@ -247,7 +269,14 @@ public:
|
||||
}
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return {x / f, y / f, z / f};
|
||||
using TV = decltype(T{} / V{});
|
||||
using C = std::common_type_t<T, V>;
|
||||
|
||||
return {
|
||||
static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
|
||||
};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
@@ -367,7 +396,11 @@ public:
|
||||
|
||||
template <typename T, typename V>
|
||||
[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
|
||||
return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
|
||||
using C = std::common_type_t<T, V>;
|
||||
|
||||
return Vec3<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
|
||||
static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)),
|
||||
static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.z)));
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -446,7 +479,15 @@ public:
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return {x * f, y * f, z * f, w * f};
|
||||
using TV = decltype(T{} * V{});
|
||||
using C = std::common_type_t<T, V>;
|
||||
|
||||
return {
|
||||
static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(w) * static_cast<C>(f)),
|
||||
};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
@@ -457,7 +498,15 @@ public:
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return {x / f, y / f, z / f, w / f};
|
||||
using TV = decltype(T{} / V{});
|
||||
using C = std::common_type_t<T, V>;
|
||||
|
||||
return {
|
||||
static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
|
||||
static_cast<TV>(static_cast<C>(w) / static_cast<C>(f)),
|
||||
};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
@@ -582,7 +631,15 @@ public:
|
||||
|
||||
template <typename T, typename V>
|
||||
[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
|
||||
return {f * vec.x, f * vec.y, f * vec.z, f * vec.w};
|
||||
using TV = decltype(V{} * T{});
|
||||
using C = std::common_type_t<T, V>;
|
||||
|
||||
return {
|
||||
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.x)),
|
||||
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.y)),
|
||||
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.z)),
|
||||
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.w)),
|
||||
};
|
||||
}
|
||||
|
||||
using Vec4f = Vec4<float>;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
void* AllocateMemoryPages(std::size_t size) {
|
||||
void* AllocateMemoryPages(std::size_t size) noexcept {
|
||||
#ifdef _WIN32
|
||||
void* base{VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE)};
|
||||
#else
|
||||
@@ -29,7 +29,7 @@ void* AllocateMemoryPages(std::size_t size) {
|
||||
return base;
|
||||
}
|
||||
|
||||
void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) {
|
||||
void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
|
||||
if (!base) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,25 +4,44 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Common {
|
||||
|
||||
void* AllocateMemoryPages(std::size_t size);
|
||||
void FreeMemoryPages(void* base, std::size_t size);
|
||||
void* AllocateMemoryPages(std::size_t size) noexcept;
|
||||
void FreeMemoryPages(void* base, std::size_t size) noexcept;
|
||||
|
||||
template <typename T>
|
||||
class VirtualBuffer final : NonCopyable {
|
||||
class VirtualBuffer final {
|
||||
public:
|
||||
static_assert(
|
||||
std::is_trivially_constructible_v<T>,
|
||||
"T must be trivially constructible, as non-trivial constructors will not be executed "
|
||||
"with the current allocator");
|
||||
|
||||
constexpr VirtualBuffer() = default;
|
||||
explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} {
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
~VirtualBuffer() {
|
||||
~VirtualBuffer() noexcept {
|
||||
FreeMemoryPages(base_ptr, alloc_size);
|
||||
}
|
||||
|
||||
VirtualBuffer(const VirtualBuffer&) = delete;
|
||||
VirtualBuffer& operator=(const VirtualBuffer&) = delete;
|
||||
|
||||
VirtualBuffer(VirtualBuffer&& other) noexcept
|
||||
: alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr),
|
||||
nullptr} {}
|
||||
|
||||
VirtualBuffer& operator=(VirtualBuffer&& other) noexcept {
|
||||
alloc_size = std::exchange(other.alloc_size, 0);
|
||||
base_ptr = std::exchange(other.base_ptr, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void resize(std::size_t count) {
|
||||
FreeMemoryPages(base_ptr, alloc_size);
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
return Common::Divide128On32(temporary, 1000000000).first;
|
||||
}
|
||||
|
||||
void Pause(bool is_paused) override {
|
||||
void Pause([[maybe_unused]] bool is_paused) override {
|
||||
// Do nothing in this clock type.
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ private:
|
||||
/// value used to reduce the native clocks accuracy as some apss rely on
|
||||
/// undefined behavior where the level of accuracy in the clock shouldn't
|
||||
/// be higher.
|
||||
static constexpr u64 inaccuracy_mask = ~(0x400 - 1);
|
||||
static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1);
|
||||
|
||||
SpinLock rtsc_serialize{};
|
||||
u64 last_measure{};
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
if (YUZU_ENABLE_BOXCAT)
|
||||
set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h)
|
||||
else()
|
||||
set(BCAT_BOXCAT_ADDITIONAL_SOURCES)
|
||||
endif()
|
||||
|
||||
add_library(core STATIC
|
||||
arm/arm_interface.h
|
||||
arm/arm_interface.cpp
|
||||
@@ -19,8 +13,6 @@ add_library(core STATIC
|
||||
arm/dynarmic/arm_exclusive_monitor.h
|
||||
arm/exclusive_monitor.cpp
|
||||
arm/exclusive_monitor.h
|
||||
arm/unicorn/arm_unicorn.cpp
|
||||
arm/unicorn/arm_unicorn.h
|
||||
constants.cpp
|
||||
constants.h
|
||||
core.cpp
|
||||
@@ -303,7 +295,6 @@ add_library(core STATIC
|
||||
hle/service/audio/hwopus.h
|
||||
hle/service/bcat/backend/backend.cpp
|
||||
hle/service/bcat/backend/backend.h
|
||||
${BCAT_BOXCAT_ADDITIONAL_SOURCES}
|
||||
hle/service/bcat/bcat.cpp
|
||||
hle/service/bcat/bcat.h
|
||||
hle/service/bcat/module.cpp
|
||||
@@ -446,6 +437,8 @@ add_library(core STATIC
|
||||
hle/service/nvdrv/devices/nvhost_gpu.h
|
||||
hle/service/nvdrv/devices/nvhost_nvdec.cpp
|
||||
hle/service/nvdrv/devices/nvhost_nvdec.h
|
||||
hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
|
||||
hle/service/nvdrv/devices/nvhost_nvdec_common.h
|
||||
hle/service/nvdrv/devices/nvhost_nvjpg.cpp
|
||||
hle/service/nvdrv/devices/nvhost_nvjpg.h
|
||||
hle/service/nvdrv/devices/nvhost_vic.cpp
|
||||
@@ -459,6 +452,8 @@ add_library(core STATIC
|
||||
hle/service/nvdrv/nvdrv.h
|
||||
hle/service/nvdrv/nvmemp.cpp
|
||||
hle/service/nvdrv/nvmemp.h
|
||||
hle/service/nvdrv/syncpoint_manager.cpp
|
||||
hle/service/nvdrv/syncpoint_manager.h
|
||||
hle/service/nvflinger/buffer_queue.cpp
|
||||
hle/service/nvflinger/buffer_queue.h
|
||||
hle/service/nvflinger/nvflinger.cpp
|
||||
@@ -608,6 +603,13 @@ add_library(core STATIC
|
||||
tools/freezer.h
|
||||
)
|
||||
|
||||
if (YUZU_ENABLE_BOXCAT)
|
||||
target_sources(core PRIVATE
|
||||
hle/service/bcat/backend/boxcat.cpp
|
||||
hle/service/bcat/backend/boxcat.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(core PRIVATE
|
||||
# 'expression' : signed/unsigned mismatch
|
||||
@@ -623,12 +625,26 @@ if (MSVC)
|
||||
# 'context' : truncation from 'type1' to 'type2'
|
||||
/we4305
|
||||
)
|
||||
else()
|
||||
target_compile_options(core PRIVATE
|
||||
-Werror=conversion
|
||||
-Werror=ignored-qualifiers
|
||||
-Werror=implicit-fallthrough
|
||||
-Werror=reorder
|
||||
-Werror=sign-compare
|
||||
-Werror=unused-variable
|
||||
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
|
||||
|
||||
-Wno-sign-conversion
|
||||
)
|
||||
endif()
|
||||
|
||||
create_target_directory_groups(core)
|
||||
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus unicorn zip)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip)
|
||||
|
||||
if (YUZU_ENABLE_BOXCAT)
|
||||
target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)
|
||||
|
||||
@@ -147,10 +147,18 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex
|
||||
auto fp = ctx.cpu_registers[29];
|
||||
auto lr = ctx.cpu_registers[30];
|
||||
while (true) {
|
||||
out.push_back({"", 0, lr, 0});
|
||||
if (!fp) {
|
||||
out.push_back({
|
||||
.module = "",
|
||||
.address = 0,
|
||||
.original_address = lr,
|
||||
.offset = 0,
|
||||
.name = {},
|
||||
});
|
||||
|
||||
if (fp == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
lr = memory.Read64(fp + 8) - 4;
|
||||
fp = memory.Read64(fp);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ public:
|
||||
CPUInterruptHandler(const CPUInterruptHandler&) = delete;
|
||||
CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete;
|
||||
|
||||
CPUInterruptHandler(CPUInterruptHandler&&) = default;
|
||||
CPUInterruptHandler& operator=(CPUInterruptHandler&&) = default;
|
||||
CPUInterruptHandler(CPUInterruptHandler&&) = delete;
|
||||
CPUInterruptHandler& operator=(CPUInterruptHandler&&) = delete;
|
||||
|
||||
bool IsInterrupted() const {
|
||||
return is_interrupted;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <dynarmic/A32/a32.h>
|
||||
#include <dynarmic/A32/config.h>
|
||||
#include <dynarmic/A32/context.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/page_table.h"
|
||||
#include "core/arm/cpu_interrupt_handler.h"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <memory>
|
||||
#include <dynarmic/A64/a64.h>
|
||||
#include <dynarmic/A64/config.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/page_table.h"
|
||||
#include "core/arm/cpu_interrupt_handler.h"
|
||||
@@ -13,7 +14,6 @@
|
||||
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hardware_properties.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
@@ -82,16 +82,9 @@ public:
|
||||
}
|
||||
|
||||
void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
|
||||
LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc,
|
||||
num_instructions, MemoryReadCode(pc));
|
||||
|
||||
ARM_Interface::ThreadContext64 ctx;
|
||||
parent.SaveContext(ctx);
|
||||
parent.inner_unicorn.LoadContext(ctx);
|
||||
parent.inner_unicorn.ExecuteInstructions(num_instructions);
|
||||
parent.inner_unicorn.SaveContext(ctx);
|
||||
parent.LoadContext(ctx);
|
||||
num_interpreted_instructions += num_instructions;
|
||||
LOG_ERROR(Core_ARM,
|
||||
"Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
|
||||
num_instructions, MemoryReadCode(pc));
|
||||
}
|
||||
|
||||
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
|
||||
@@ -127,18 +120,17 @@ public:
|
||||
if (parent.uses_wall_clock) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
|
||||
// rough approximation of the amount of executed ticks in the system, it may be thrown off
|
||||
// if not all cores are doing a similar amount of work. Instead of doing this, we should
|
||||
// device a way so that timing is consistent across all cores without increasing the ticks 4
|
||||
// times.
|
||||
u64 amortized_ticks =
|
||||
(ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
|
||||
u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
|
||||
// Always execute at least one tick.
|
||||
amortized_ticks = std::max<u64>(amortized_ticks, 1);
|
||||
|
||||
parent.system.CoreTiming().AddTicks(amortized_ticks);
|
||||
num_interpreted_instructions = 0;
|
||||
}
|
||||
|
||||
u64 GetTicksRemaining() override {
|
||||
@@ -156,7 +148,6 @@ public:
|
||||
}
|
||||
|
||||
ARM_Dynarmic_64& parent;
|
||||
std::size_t num_interpreted_instructions = 0;
|
||||
u64 tpidrro_el0 = 0;
|
||||
u64 tpidr_el0 = 0;
|
||||
static constexpr u64 minimum_run_cycles = 1000U;
|
||||
@@ -248,12 +239,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
|
||||
bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
|
||||
std::size_t core_index)
|
||||
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
|
||||
cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handlers,
|
||||
uses_wall_clock,
|
||||
ARM_Unicorn::Arch::AArch64,
|
||||
core_index},
|
||||
core_index{core_index}, exclusive_monitor{
|
||||
dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
|
||||
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
|
||||
|
||||
ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "common/hash.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/arm/unicorn/arm_unicorn.h"
|
||||
|
||||
namespace Core::Memory {
|
||||
class Memory;
|
||||
@@ -71,7 +70,6 @@ private:
|
||||
std::unique_ptr<DynarmicCallbacks64> cb;
|
||||
JitCacheType jit_cache;
|
||||
std::shared_ptr<Dynarmic::A64::Jit> jit;
|
||||
ARM_Unicorn inner_unicorn;
|
||||
|
||||
std::size_t core_index;
|
||||
DynarmicExclusiveMonitor& exclusive_monitor;
|
||||
|
||||
@@ -1,295 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <unicorn/arm64.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "core/arm/cpu_interrupt_handler.h"
|
||||
#include "core/arm/unicorn/arm_unicorn.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/scheduler.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
// Load Unicorn DLL once on Windows using RAII
|
||||
#ifdef _MSC_VER
|
||||
#include <unicorn_dynload.h>
|
||||
struct LoadDll {
|
||||
private:
|
||||
LoadDll() {
|
||||
ASSERT(uc_dyn_load(NULL, 0));
|
||||
}
|
||||
~LoadDll() {
|
||||
ASSERT(uc_dyn_free());
|
||||
}
|
||||
static LoadDll g_load_dll;
|
||||
};
|
||||
LoadDll LoadDll::g_load_dll;
|
||||
#endif
|
||||
|
||||
#define CHECKED(expr) \
|
||||
do { \
|
||||
if (auto _cerr = (expr)) { \
|
||||
ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", _cerr, \
|
||||
uc_strerror(_cerr)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
|
||||
GDBStub::BreakpointAddress bkpt =
|
||||
GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute);
|
||||
if (GDBStub::IsMemoryBreak() ||
|
||||
(bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) {
|
||||
auto core = static_cast<ARM_Unicorn*>(user_data);
|
||||
core->RecordBreak(bkpt);
|
||||
uc_emu_stop(uc);
|
||||
}
|
||||
}
|
||||
|
||||
static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
|
||||
void* user_data) {
|
||||
auto* const system = static_cast<System*>(user_data);
|
||||
|
||||
ARM_Interface::ThreadContext64 ctx{};
|
||||
system->CurrentArmInterface().SaveContext(ctx);
|
||||
ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr,
|
||||
ctx.pc, ctx.cpu_registers[30]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
|
||||
Arch architecture, std::size_t core_index)
|
||||
: ARM_Interface{system, interrupt_handlers, uses_wall_clock}, core_index{core_index} {
|
||||
const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64;
|
||||
CHECKED(uc_open(arch, UC_MODE_ARM, &uc));
|
||||
|
||||
auto fpv = 3 << 20;
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_CPACR_EL1, &fpv));
|
||||
|
||||
uc_hook hook{};
|
||||
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, UINT64_MAX));
|
||||
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0,
|
||||
UINT64_MAX));
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, UINT64_MAX));
|
||||
last_bkpt_hit = false;
|
||||
}
|
||||
}
|
||||
|
||||
ARM_Unicorn::~ARM_Unicorn() {
|
||||
CHECKED(uc_close(uc));
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetPC(u64 pc) {
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
|
||||
}
|
||||
|
||||
u64 ARM_Unicorn::GetPC() const {
|
||||
u64 val{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &val));
|
||||
return val;
|
||||
}
|
||||
|
||||
u64 ARM_Unicorn::GetReg(int regn) const {
|
||||
u64 val{};
|
||||
auto treg = UC_ARM64_REG_SP;
|
||||
if (regn <= 28) {
|
||||
treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
|
||||
} else if (regn < 31) {
|
||||
treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
|
||||
}
|
||||
CHECKED(uc_reg_read(uc, treg, &val));
|
||||
return val;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetReg(int regn, u64 val) {
|
||||
auto treg = UC_ARM64_REG_SP;
|
||||
if (regn <= 28) {
|
||||
treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
|
||||
} else if (regn < 31) {
|
||||
treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
|
||||
}
|
||||
CHECKED(uc_reg_write(uc, treg, &val));
|
||||
}
|
||||
|
||||
u128 ARM_Unicorn::GetVectorReg(int /*index*/) const {
|
||||
UNIMPLEMENTED();
|
||||
static constexpr u128 res{};
|
||||
return res;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
u32 ARM_Unicorn::GetPSTATE() const {
|
||||
u64 nzcv{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv));
|
||||
return static_cast<u32>(nzcv);
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetPSTATE(u32 pstate) {
|
||||
u64 nzcv = pstate;
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv));
|
||||
}
|
||||
|
||||
VAddr ARM_Unicorn::GetTlsAddress() const {
|
||||
u64 base{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
|
||||
return base;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetTlsAddress(VAddr base) {
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
|
||||
}
|
||||
|
||||
u64 ARM_Unicorn::GetTPIDR_EL0() const {
|
||||
u64 value{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value));
|
||||
return value;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SetTPIDR_EL0(u64 value) {
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value));
|
||||
}
|
||||
|
||||
void ARM_Unicorn::ChangeProcessorID(std::size_t new_core_id) {
|
||||
core_index = new_core_id;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::Run() {
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
ExecuteInstructions(std::max(4000000U, 0U));
|
||||
} else {
|
||||
while (true) {
|
||||
if (interrupt_handlers[core_index].IsInterrupted()) {
|
||||
return;
|
||||
}
|
||||
ExecuteInstructions(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ARM_Unicorn::Step() {
|
||||
ExecuteInstructions(1);
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
|
||||
|
||||
void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) {
|
||||
MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
|
||||
|
||||
// Temporarily map the code page for Unicorn
|
||||
u64 map_addr{GetPC() & ~Memory::PAGE_MASK};
|
||||
std::vector<u8> page_buffer(Memory::PAGE_SIZE);
|
||||
system.Memory().ReadBlock(map_addr, page_buffer.data(), page_buffer.size());
|
||||
|
||||
CHECKED(uc_mem_map_ptr(uc, map_addr, page_buffer.size(),
|
||||
UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, page_buffer.data()));
|
||||
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
|
||||
CHECKED(uc_mem_unmap(uc, map_addr, page_buffer.size()));
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
|
||||
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
|
||||
}
|
||||
|
||||
Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread();
|
||||
SaveContext(thread->GetContext64());
|
||||
if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
|
||||
last_bkpt_hit = false;
|
||||
GDBStub::Break();
|
||||
GDBStub::SendTrap(thread, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ARM_Unicorn::SaveContext(ThreadContext64& ctx) {
|
||||
int uregs[32];
|
||||
void* tregs[32];
|
||||
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp));
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc));
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
|
||||
|
||||
for (auto i = 0; i < 29; ++i) {
|
||||
uregs[i] = UC_ARM64_REG_X0 + i;
|
||||
tregs[i] = &ctx.cpu_registers[i];
|
||||
}
|
||||
uregs[29] = UC_ARM64_REG_X29;
|
||||
tregs[29] = (void*)&ctx.cpu_registers[29];
|
||||
uregs[30] = UC_ARM64_REG_X30;
|
||||
tregs[30] = (void*)&ctx.cpu_registers[30];
|
||||
|
||||
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 31));
|
||||
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
uregs[i] = UC_ARM64_REG_Q0 + i;
|
||||
tregs[i] = &ctx.vector_registers[i];
|
||||
}
|
||||
|
||||
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
|
||||
}
|
||||
|
||||
void ARM_Unicorn::LoadContext(const ThreadContext64& ctx) {
|
||||
int uregs[32];
|
||||
void* tregs[32];
|
||||
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp));
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc));
|
||||
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
|
||||
|
||||
for (int i = 0; i < 29; ++i) {
|
||||
uregs[i] = UC_ARM64_REG_X0 + i;
|
||||
tregs[i] = (void*)&ctx.cpu_registers[i];
|
||||
}
|
||||
uregs[29] = UC_ARM64_REG_X29;
|
||||
tregs[29] = (void*)&ctx.cpu_registers[29];
|
||||
uregs[30] = UC_ARM64_REG_X30;
|
||||
tregs[30] = (void*)&ctx.cpu_registers[30];
|
||||
|
||||
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 31));
|
||||
|
||||
for (auto i = 0; i < 32; ++i) {
|
||||
uregs[i] = UC_ARM64_REG_Q0 + i;
|
||||
tregs[i] = (void*)&ctx.vector_registers[i];
|
||||
}
|
||||
|
||||
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32));
|
||||
}
|
||||
|
||||
void ARM_Unicorn::PrepareReschedule() {
|
||||
CHECKED(uc_emu_stop(uc));
|
||||
}
|
||||
|
||||
void ARM_Unicorn::ClearExclusiveState() {}
|
||||
|
||||
void ARM_Unicorn::ClearInstructionCache() {}
|
||||
|
||||
void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
|
||||
last_bkpt = bkpt;
|
||||
last_bkpt_hit = true;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
|
||||
u32 esr{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
|
||||
|
||||
const auto ec = esr >> 26;
|
||||
const auto iss = esr & 0xFFFFFF;
|
||||
|
||||
auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
|
||||
|
||||
switch (ec) {
|
||||
case 0x15: // SVC
|
||||
Kernel::Svc::Call(arm_instance->system, iss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unicorn/unicorn.h>
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
class System;
|
||||
|
||||
class ARM_Unicorn final : public ARM_Interface {
|
||||
public:
|
||||
enum class Arch {
|
||||
AArch32, // 32-bit ARM
|
||||
AArch64, // 64-bit ARM
|
||||
};
|
||||
|
||||
explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
|
||||
Arch architecture, std::size_t core_index);
|
||||
~ARM_Unicorn() override;
|
||||
|
||||
void SetPC(u64 pc) override;
|
||||
u64 GetPC() const override;
|
||||
u64 GetReg(int index) const override;
|
||||
void SetReg(int index, u64 value) override;
|
||||
u128 GetVectorReg(int index) const override;
|
||||
void SetVectorReg(int index, u128 value) override;
|
||||
u32 GetPSTATE() const override;
|
||||
void SetPSTATE(u32 pstate) override;
|
||||
VAddr GetTlsAddress() const override;
|
||||
void SetTlsAddress(VAddr address) override;
|
||||
void SetTPIDR_EL0(u64 value) override;
|
||||
u64 GetTPIDR_EL0() const override;
|
||||
void ChangeProcessorID(std::size_t new_core_id) override;
|
||||
void PrepareReschedule() override;
|
||||
void ClearExclusiveState() override;
|
||||
void ExecuteInstructions(std::size_t num_instructions);
|
||||
void Run() override;
|
||||
void Step() override;
|
||||
void ClearInstructionCache() override;
|
||||
void PageTableChanged(Common::PageTable&, std::size_t) override {}
|
||||
void RecordBreak(GDBStub::BreakpointAddress bkpt);
|
||||
|
||||
void SaveContext(ThreadContext32& ctx) override {}
|
||||
void SaveContext(ThreadContext64& ctx) override;
|
||||
void LoadContext(const ThreadContext32& ctx) override {}
|
||||
void LoadContext(const ThreadContext64& ctx) override;
|
||||
|
||||
private:
|
||||
static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
|
||||
|
||||
uc_engine* uc{};
|
||||
GDBStub::BreakpointAddress last_bkpt{};
|
||||
bool last_bkpt_hit = false;
|
||||
std::size_t core_index;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "core/hle/service/lm/manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/memory/cheat_engine.h"
|
||||
@@ -121,7 +122,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
struct System::Impl {
|
||||
explicit Impl(System& system)
|
||||
: kernel{system}, fs_controller{system}, memory{system},
|
||||
cpu_manager{system}, reporter{system}, applet_manager{system} {}
|
||||
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
|
||||
|
||||
ResultStatus Run() {
|
||||
status = ResultStatus::Success;
|
||||
@@ -178,16 +179,21 @@ struct System::Impl {
|
||||
arp_manager.ResetAll();
|
||||
|
||||
telemetry_session = std::make_unique<Core::TelemetrySession>();
|
||||
|
||||
gpu_core = VideoCore::CreateGPU(emu_window, system);
|
||||
if (!gpu_core) {
|
||||
return ResultStatus::ErrorVideoCore;
|
||||
}
|
||||
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
|
||||
|
||||
Service::Init(service_manager, system);
|
||||
GDBStub::DeferStart();
|
||||
|
||||
interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system);
|
||||
gpu_core = VideoCore::CreateGPU(emu_window, system);
|
||||
if (!gpu_core) {
|
||||
return ResultStatus::ErrorVideoCore;
|
||||
}
|
||||
|
||||
// Initialize time manager, which must happen after kernel is created
|
||||
time_manager.Initialize();
|
||||
|
||||
is_powered_on = true;
|
||||
exit_lock = false;
|
||||
@@ -387,6 +393,7 @@ struct System::Impl {
|
||||
/// Service State
|
||||
Service::Glue::ARPManager arp_manager;
|
||||
Service::LM::Manager lm_manager{reporter};
|
||||
Service::Time::TimeManager time_manager;
|
||||
|
||||
/// Service manager
|
||||
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
||||
@@ -717,6 +724,14 @@ const Service::LM::Manager& System::GetLogManager() const {
|
||||
return impl->lm_manager;
|
||||
}
|
||||
|
||||
Service::Time::TimeManager& System::GetTimeManager() {
|
||||
return impl->time_manager;
|
||||
}
|
||||
|
||||
const Service::Time::TimeManager& System::GetTimeManager() const {
|
||||
return impl->time_manager;
|
||||
}
|
||||
|
||||
void System::SetExitLock(bool locked) {
|
||||
impl->exit_lock = locked;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,10 @@ namespace SM {
|
||||
class ServiceManager;
|
||||
} // namespace SM
|
||||
|
||||
namespace Time {
|
||||
class TimeManager;
|
||||
} // namespace Time
|
||||
|
||||
} // namespace Service
|
||||
|
||||
namespace Tegra {
|
||||
@@ -361,6 +365,10 @@ public:
|
||||
|
||||
const Service::LM::Manager& GetLogManager() const;
|
||||
|
||||
Service::Time::TimeManager& GetTimeManager();
|
||||
|
||||
const Service::Time::TimeManager& GetTimeManager() const;
|
||||
|
||||
void SetExitLock(bool locked);
|
||||
|
||||
bool GetExitLock() const;
|
||||
|
||||
@@ -365,6 +365,8 @@ void CpuManager::RunThread(std::size_t core) {
|
||||
data.enter_barrier.reset();
|
||||
data.exit_barrier.reset();
|
||||
data.initialized = false;
|
||||
|
||||
MicroProfileOnThreadExit();
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -411,7 +411,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
|
||||
// Combine sources and seed
|
||||
for (auto& source : sd_key_sources) {
|
||||
for (std::size_t i = 0; i < source.size(); ++i) {
|
||||
source[i] ^= sd_seed[i & 0xF];
|
||||
source[i] = static_cast<u8>(source[i] ^ sd_seed[i & 0xF]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -266,8 +266,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
|
||||
cur_file->offset = file_partition_size;
|
||||
file_partition_size += cur_file->size;
|
||||
cur_file->entry_offset = entry_offset;
|
||||
entry_offset += sizeof(RomFSFileEntry) +
|
||||
Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4);
|
||||
entry_offset +=
|
||||
static_cast<u32>(sizeof(RomFSFileEntry) +
|
||||
Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4));
|
||||
prev_file = cur_file;
|
||||
}
|
||||
// Assign deferred parent/sibling ownership.
|
||||
@@ -284,8 +285,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
|
||||
for (const auto& it : directories) {
|
||||
cur_dir = it.second;
|
||||
cur_dir->entry_offset = entry_offset;
|
||||
entry_offset += sizeof(RomFSDirectoryEntry) +
|
||||
Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4);
|
||||
entry_offset +=
|
||||
static_cast<u32>(sizeof(RomFSDirectoryEntry) +
|
||||
Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4));
|
||||
}
|
||||
// Assign deferred parent/sibling ownership.
|
||||
for (auto it = directories.rbegin(); it->second != root; ++it) {
|
||||
|
||||
@@ -299,7 +299,7 @@ void IPSwitchCompiler::Parse() {
|
||||
patch_text->GetName(), offset, Common::HexToString(replace));
|
||||
}
|
||||
|
||||
patch.records.insert_or_assign(offset, std::move(replace));
|
||||
patch.records.insert_or_assign(static_cast<u32>(offset), std::move(replace));
|
||||
}
|
||||
|
||||
patches.push_back(std::move(patch));
|
||||
|
||||
@@ -108,7 +108,7 @@ std::vector<u8> CNMT::Serialize() const {
|
||||
memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader));
|
||||
}
|
||||
|
||||
auto offset = header.table_offset;
|
||||
u64_le offset = header.table_offset;
|
||||
|
||||
for (const auto& rec : content_records) {
|
||||
memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord));
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
namespace FileSys {
|
||||
namespace {
|
||||
|
||||
constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
|
||||
constexpr u32 SINGLE_BYTE_MODULUS = 0x100;
|
||||
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
|
||||
|
||||
constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
|
||||
|
||||
@@ -19,38 +19,6 @@
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace FileSys {
|
||||
namespace {
|
||||
void SetTicketKeys(const std::vector<VirtualFile>& files) {
|
||||
auto& keys = Core::Crypto::KeyManager::Instance();
|
||||
|
||||
for (const auto& ticket_file : files) {
|
||||
if (ticket_file == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ticket_file->GetExtension() != "tik") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ticket_file->GetSize() <
|
||||
Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Core::Crypto::Key128 key{};
|
||||
ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
|
||||
|
||||
// We get the name without the extension in order to create the rights ID.
|
||||
std::string name_only(ticket_file->GetName());
|
||||
name_only.erase(name_only.size() - 4);
|
||||
|
||||
const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
|
||||
u128 rights_id;
|
||||
std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
|
||||
keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
NSP::NSP(VirtualFile file_)
|
||||
: file(std::move(file_)), status{Loader::ResultStatus::Success},
|
||||
@@ -232,6 +200,35 @@ VirtualDir NSP::GetParentDirectory() const {
|
||||
return file->GetContainingDirectory();
|
||||
}
|
||||
|
||||
void NSP::SetTicketKeys(const std::vector<VirtualFile>& files) {
|
||||
for (const auto& ticket_file : files) {
|
||||
if (ticket_file == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ticket_file->GetExtension() != "tik") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ticket_file->GetSize() <
|
||||
Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Core::Crypto::Key128 key{};
|
||||
ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
|
||||
|
||||
// We get the name without the extension in order to create the rights ID.
|
||||
std::string name_only(ticket_file->GetName());
|
||||
name_only.erase(name_only.size() - 4);
|
||||
|
||||
const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
|
||||
u128 rights_id;
|
||||
std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
|
||||
keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
|
||||
exefs = pfs;
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
VirtualDir GetParentDirectory() const override;
|
||||
|
||||
private:
|
||||
void SetTicketKeys(const std::vector<VirtualFile>& files);
|
||||
void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files);
|
||||
void ReadNCAs(const std::vector<VirtualFile>& files);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& se
|
||||
DefaultControllerApplet::~DefaultControllerApplet() = default;
|
||||
|
||||
void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
|
||||
ControllerParameters parameters) const {
|
||||
const ControllerParameters& parameters) const {
|
||||
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
|
||||
|
||||
auto& npad =
|
||||
@@ -27,19 +27,19 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
|
||||
->GetAppletResource()
|
||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
|
||||
|
||||
auto& players = Settings::values.players;
|
||||
auto& players = Settings::values.players.GetValue();
|
||||
|
||||
const std::size_t min_supported_players =
|
||||
parameters.enable_single_mode ? 1 : parameters.min_players;
|
||||
|
||||
// Disconnect Handheld first.
|
||||
npad.DisconnectNPadAtIndex(8);
|
||||
npad.DisconnectNpadAtIndex(8);
|
||||
|
||||
// Deduce the best configuration based on the input parameters.
|
||||
for (std::size_t index = 0; index < players.size() - 2; ++index) {
|
||||
// First, disconnect all controllers regardless of the value of keep_controllers_connected.
|
||||
// This makes it easy to connect the desired controllers.
|
||||
npad.DisconnectNPadAtIndex(index);
|
||||
npad.DisconnectNpadAtIndex(index);
|
||||
|
||||
// Only connect the minimum number of required players.
|
||||
if (index >= min_supported_players) {
|
||||
@@ -66,7 +66,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
|
||||
npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index);
|
||||
}
|
||||
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
|
||||
!Settings::values.use_docked_mode) {
|
||||
!Settings::values.use_docked_mode.GetValue()) {
|
||||
// We should *never* reach here under any normal circumstances.
|
||||
npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld),
|
||||
index);
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
virtual ~ControllerApplet();
|
||||
|
||||
virtual void ReconfigureControllers(std::function<void()> callback,
|
||||
ControllerParameters parameters) const = 0;
|
||||
const ControllerParameters& parameters) const = 0;
|
||||
};
|
||||
|
||||
class DefaultControllerApplet final : public ControllerApplet {
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
~DefaultControllerApplet() override;
|
||||
|
||||
void ReconfigureControllers(std::function<void()> callback,
|
||||
ControllerParameters parameters) const override;
|
||||
const ControllerParameters& parameters) const override;
|
||||
|
||||
private:
|
||||
Service::SM::ServiceManager& service_manager;
|
||||
|
||||
@@ -84,10 +84,12 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
|
||||
return;
|
||||
|
||||
std::lock_guard guard{touch_state->mutex};
|
||||
touch_state->touch_x = static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
|
||||
(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
|
||||
touch_state->touch_y = static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
|
||||
(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
|
||||
touch_state->touch_x =
|
||||
static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
|
||||
static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
|
||||
touch_state->touch_y =
|
||||
static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
|
||||
static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
|
||||
|
||||
touch_state->touch_pressed = true;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace Layout {
|
||||
template <class T>
|
||||
static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area,
|
||||
float screen_aspect_ratio) {
|
||||
float scale = std::min(static_cast<float>(window_area.GetWidth()),
|
||||
window_area.GetHeight() / screen_aspect_ratio);
|
||||
const float scale = std::min(static_cast<float>(window_area.GetWidth()),
|
||||
static_cast<float>(window_area.GetHeight()) / screen_aspect_ratio);
|
||||
return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)),
|
||||
static_cast<T>(std::round(scale * screen_aspect_ratio))};
|
||||
}
|
||||
@@ -27,7 +27,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
|
||||
// so just calculate them both even if the other isn't showing.
|
||||
FramebufferLayout res{width, height, false, {}};
|
||||
|
||||
const float window_aspect_ratio = static_cast<float>(height) / width;
|
||||
const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width);
|
||||
const float emulation_aspect_ratio = EmulationAspectRatio(
|
||||
static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio);
|
||||
|
||||
@@ -47,7 +47,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
|
||||
u32 width, height;
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
if (Settings::values.use_docked_mode.GetValue()) {
|
||||
width = ScreenDocked::Width * res_scale;
|
||||
height = ScreenDocked::Height * res_scale;
|
||||
} else {
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const {
|
||||
return {};
|
||||
}
|
||||
virtual bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const {
|
||||
virtual bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
@@ -121,6 +121,13 @@ using ButtonDevice = InputDevice<bool>;
|
||||
*/
|
||||
using AnalogDevice = InputDevice<std::tuple<float, float>>;
|
||||
|
||||
/**
|
||||
* A vibration device is an input device that returns an unsigned byte as status.
|
||||
* It represents whether the vibration device supports vibration or not.
|
||||
* If the status returns 1, it supports vibration. Otherwise, it does not support vibration.
|
||||
*/
|
||||
using VibrationDevice = InputDevice<u8>;
|
||||
|
||||
/**
|
||||
* A motion status is an object that returns a tuple of accelerometer state vector,
|
||||
* gyroscope state vector, rotation state vector and orientation state matrix.
|
||||
|
||||
@@ -291,11 +291,11 @@ static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr)
|
||||
*/
|
||||
static u8 HexCharToValue(u8 hex) {
|
||||
if (hex >= '0' && hex <= '9') {
|
||||
return hex - '0';
|
||||
return static_cast<u8>(hex - '0');
|
||||
} else if (hex >= 'a' && hex <= 'f') {
|
||||
return hex - 'a' + 0xA;
|
||||
return static_cast<u8>(hex - 'a' + 0xA);
|
||||
} else if (hex >= 'A' && hex <= 'F') {
|
||||
return hex - 'A' + 0xA;
|
||||
return static_cast<u8>(hex - 'A' + 0xA);
|
||||
}
|
||||
|
||||
LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex);
|
||||
@@ -310,9 +310,9 @@ static u8 HexCharToValue(u8 hex) {
|
||||
static u8 NibbleToHex(u8 n) {
|
||||
n &= 0xF;
|
||||
if (n < 0xA) {
|
||||
return '0' + n;
|
||||
return static_cast<u8>('0' + n);
|
||||
} else {
|
||||
return 'a' + n - 0xA;
|
||||
return static_cast<u8>('a' + n - 0xA);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,8 +355,8 @@ static u64 HexToLong(const u8* src, std::size_t len) {
|
||||
*/
|
||||
static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) {
|
||||
while (len-- > 0) {
|
||||
u8 tmp = *src++;
|
||||
*dest++ = NibbleToHex(tmp >> 4);
|
||||
const u8 tmp = *src++;
|
||||
*dest++ = NibbleToHex(static_cast<u8>(tmp >> 4));
|
||||
*dest++ = NibbleToHex(tmp);
|
||||
}
|
||||
}
|
||||
@@ -370,7 +370,7 @@ static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) {
|
||||
*/
|
||||
static void GdbHexToMem(u8* dest, const u8* src, std::size_t len) {
|
||||
while (len-- > 0) {
|
||||
*dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]);
|
||||
*dest++ = static_cast<u8>((HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]));
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
@@ -602,22 +602,22 @@ static void SendReply(const char* reply) {
|
||||
|
||||
memcpy(command_buffer + 1, reply, command_length);
|
||||
|
||||
u8 checksum = CalculateChecksum(command_buffer, command_length + 1);
|
||||
const u8 checksum = CalculateChecksum(command_buffer, command_length + 1);
|
||||
command_buffer[0] = GDB_STUB_START;
|
||||
command_buffer[command_length + 1] = GDB_STUB_END;
|
||||
command_buffer[command_length + 2] = NibbleToHex(checksum >> 4);
|
||||
command_buffer[command_length + 2] = NibbleToHex(static_cast<u8>(checksum >> 4));
|
||||
command_buffer[command_length + 3] = NibbleToHex(checksum);
|
||||
|
||||
u8* ptr = command_buffer;
|
||||
u32 left = command_length + 4;
|
||||
while (left > 0) {
|
||||
int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0);
|
||||
const auto sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0);
|
||||
if (sent_size < 0) {
|
||||
LOG_ERROR(Debug_GDBStub, "gdb: send failed");
|
||||
return Shutdown();
|
||||
}
|
||||
|
||||
left -= sent_size;
|
||||
left -= static_cast<u32>(sent_size);
|
||||
ptr += sent_size;
|
||||
}
|
||||
}
|
||||
@@ -777,10 +777,10 @@ static void ReadCommand() {
|
||||
command_buffer[command_length++] = c;
|
||||
}
|
||||
|
||||
u8 checksum_received = HexCharToValue(ReadByte()) << 4;
|
||||
checksum_received |= HexCharToValue(ReadByte());
|
||||
auto checksum_received = static_cast<u32>(HexCharToValue(ReadByte()) << 4);
|
||||
checksum_received |= static_cast<u32>(HexCharToValue(ReadByte()));
|
||||
|
||||
u8 checksum_calculated = CalculateChecksum(command_buffer, command_length);
|
||||
const u32 checksum_calculated = CalculateChecksum(command_buffer, command_length);
|
||||
|
||||
if (checksum_received != checksum_calculated) {
|
||||
LOG_ERROR(Debug_GDBStub,
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <utility>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
@@ -38,10 +37,11 @@ public:
|
||||
explicit RequestHelperBase(Kernel::HLERequestContext& context)
|
||||
: context(&context), cmdbuf(context.CommandBuffer()) {}
|
||||
|
||||
void Skip(unsigned size_in_words, bool set_to_null) {
|
||||
if (set_to_null)
|
||||
void Skip(u32 size_in_words, bool set_to_null) {
|
||||
if (set_to_null) {
|
||||
memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
|
||||
index += size_in_words;
|
||||
}
|
||||
index += static_cast<ptrdiff_t>(size_in_words);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,15 +49,15 @@ public:
|
||||
*/
|
||||
void AlignWithPadding() {
|
||||
if (index & 3) {
|
||||
Skip(4 - (index & 3), true);
|
||||
Skip(static_cast<u32>(4 - (index & 3)), true);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned GetCurrentOffset() const {
|
||||
return static_cast<unsigned>(index);
|
||||
u32 GetCurrentOffset() const {
|
||||
return static_cast<u32>(index);
|
||||
}
|
||||
|
||||
void SetCurrentOffset(unsigned offset) {
|
||||
void SetCurrentOffset(u32 offset) {
|
||||
index = static_cast<ptrdiff_t>(offset);
|
||||
}
|
||||
};
|
||||
@@ -72,14 +72,12 @@ public:
|
||||
AlwaysMoveHandles = 1,
|
||||
};
|
||||
|
||||
explicit ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {}
|
||||
|
||||
explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size,
|
||||
u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0,
|
||||
Flags flags = Flags::None)
|
||||
|
||||
: RequestHelperBase(context), normal_params_size(normal_params_size),
|
||||
num_handles_to_copy(num_handles_to_copy), num_objects_to_move(num_objects_to_move) {
|
||||
num_handles_to_copy(num_handles_to_copy),
|
||||
num_objects_to_move(num_objects_to_move), kernel{context.kernel} {
|
||||
|
||||
memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
|
||||
|
||||
@@ -89,7 +87,7 @@ public:
|
||||
|
||||
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
|
||||
// padding.
|
||||
u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
|
||||
u64 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
|
||||
|
||||
u32 num_handles_to_move{};
|
||||
u32 num_domain_objects{};
|
||||
@@ -105,7 +103,7 @@ public:
|
||||
raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
|
||||
}
|
||||
|
||||
header.data_size.Assign(raw_data_size);
|
||||
header.data_size.Assign(static_cast<u32>(raw_data_size));
|
||||
if (num_handles_to_copy || num_handles_to_move) {
|
||||
header.enable_handle_descriptor.Assign(1);
|
||||
}
|
||||
@@ -139,7 +137,6 @@ public:
|
||||
if (context->Session()->IsDomain()) {
|
||||
context->AddDomainObject(std::move(iface));
|
||||
} else {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());
|
||||
context->AddMoveObject(std::move(client));
|
||||
iface->ClientConnected(std::move(server));
|
||||
@@ -213,6 +210,7 @@ private:
|
||||
u32 num_handles_to_copy{};
|
||||
u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent
|
||||
std::ptrdiff_t datapayload_index{};
|
||||
Kernel::KernelCore& kernel;
|
||||
};
|
||||
|
||||
/// Push ///
|
||||
|
||||
@@ -118,7 +118,7 @@ std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
|
||||
|
||||
void HandleTable::Clear() {
|
||||
for (u16 i = 0; i < table_size; ++i) {
|
||||
generations[i] = i + 1;
|
||||
generations[i] = static_cast<u16>(i + 1);
|
||||
objects[i] = nullptr;
|
||||
}
|
||||
next_free_slot = 0;
|
||||
|
||||
@@ -24,6 +24,10 @@ namespace Core::Memory {
|
||||
class Memory;
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
class ResponseBuilder;
|
||||
}
|
||||
|
||||
namespace Service {
|
||||
class ServiceFrameworkBase;
|
||||
}
|
||||
@@ -287,6 +291,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
friend class IPC::ResponseBuilder;
|
||||
|
||||
void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
|
||||
|
||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <bitset>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
@@ -87,8 +86,6 @@ struct KernelCore::Impl {
|
||||
}
|
||||
cores.clear();
|
||||
|
||||
registered_core_threads.reset();
|
||||
|
||||
process_list.clear();
|
||||
current_process = nullptr;
|
||||
|
||||
@@ -107,7 +104,11 @@ struct KernelCore::Impl {
|
||||
cores.clear();
|
||||
|
||||
exclusive_monitor.reset();
|
||||
host_thread_ids.clear();
|
||||
|
||||
num_host_threads = 0;
|
||||
std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
|
||||
std::thread::id{});
|
||||
std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
|
||||
}
|
||||
|
||||
void InitializePhysicalCores() {
|
||||
@@ -177,54 +178,58 @@ struct KernelCore::Impl {
|
||||
|
||||
void MakeCurrentProcess(Process* process) {
|
||||
current_process = process;
|
||||
|
||||
if (process == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 core_id = GetCurrentHostThreadID();
|
||||
const u32 core_id = GetCurrentHostThreadID();
|
||||
if (core_id < Core::Hardware::NUM_CPU_CORES) {
|
||||
system.Memory().SetCurrentPageTable(*process, core_id);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterCoreThread(std::size_t core_id) {
|
||||
std::unique_lock lock{register_thread_mutex};
|
||||
if (!is_multicore) {
|
||||
single_core_thread_id = std::this_thread::get_id();
|
||||
}
|
||||
const std::thread::id this_id = std::this_thread::get_id();
|
||||
const auto it = host_thread_ids.find(this_id);
|
||||
if (!is_multicore) {
|
||||
single_core_thread_id = this_id;
|
||||
}
|
||||
const auto end =
|
||||
register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
|
||||
const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
|
||||
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
|
||||
ASSERT(it == host_thread_ids.end());
|
||||
ASSERT(!registered_core_threads[core_id]);
|
||||
host_thread_ids[this_id] = static_cast<u32>(core_id);
|
||||
registered_core_threads.set(core_id);
|
||||
ASSERT(it == end);
|
||||
InsertHostThread(static_cast<u32>(core_id));
|
||||
}
|
||||
|
||||
void RegisterHostThread() {
|
||||
std::unique_lock lock{register_thread_mutex};
|
||||
const std::thread::id this_id = std::this_thread::get_id();
|
||||
const auto it = host_thread_ids.find(this_id);
|
||||
if (it != host_thread_ids.end()) {
|
||||
return;
|
||||
const auto end =
|
||||
register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
|
||||
const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
|
||||
if (it == end) {
|
||||
InsertHostThread(registered_thread_ids++);
|
||||
}
|
||||
host_thread_ids[this_id] = registered_thread_ids++;
|
||||
}
|
||||
|
||||
u32 GetCurrentHostThreadID() const {
|
||||
void InsertHostThread(u32 value) {
|
||||
const size_t index = num_host_threads++;
|
||||
ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads");
|
||||
register_host_thread_values[index] = value;
|
||||
register_host_thread_keys[index] = std::this_thread::get_id();
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 GetCurrentHostThreadID() const {
|
||||
const std::thread::id this_id = std::this_thread::get_id();
|
||||
if (!is_multicore) {
|
||||
if (single_core_thread_id == this_id) {
|
||||
return static_cast<u32>(system.GetCpuManager().CurrentCore());
|
||||
}
|
||||
if (!is_multicore && single_core_thread_id == this_id) {
|
||||
return static_cast<u32>(system.GetCpuManager().CurrentCore());
|
||||
}
|
||||
std::unique_lock lock{register_thread_mutex};
|
||||
const auto it = host_thread_ids.find(this_id);
|
||||
if (it == host_thread_ids.end()) {
|
||||
const auto end =
|
||||
register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
|
||||
const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
|
||||
if (it == end) {
|
||||
return Core::INVALID_HOST_THREAD_ID;
|
||||
}
|
||||
return it->second;
|
||||
return register_host_thread_values[static_cast<size_t>(
|
||||
std::distance(register_host_thread_keys.begin(), it))];
|
||||
}
|
||||
|
||||
Core::EmuThreadHandle GetCurrentEmuThreadID() const {
|
||||
@@ -322,10 +327,14 @@ struct KernelCore::Impl {
|
||||
std::vector<Kernel::PhysicalCore> cores;
|
||||
|
||||
// 0-3 IDs represent core threads, >3 represent others
|
||||
std::unordered_map<std::thread::id, u32> host_thread_ids;
|
||||
u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
|
||||
std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
|
||||
mutable std::mutex register_thread_mutex;
|
||||
std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
|
||||
|
||||
// Number of host threads is a relatively high number to avoid overflowing
|
||||
static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64;
|
||||
std::atomic<size_t> num_host_threads{0};
|
||||
std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS>
|
||||
register_host_thread_keys{};
|
||||
std::array<std::atomic<u32>, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{};
|
||||
|
||||
// Kernel memory management
|
||||
std::unique_ptr<Memory::MemoryManager> memory_manager;
|
||||
|
||||
@@ -2,30 +2,18 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||
#endif
|
||||
#include "core/arm/cpu_interrupt_handler.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/arm/unicorn/arm_unicorn.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/kernel/scheduler.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler,
|
||||
Core::CPUInterruptHandler& interrupt_handler)
|
||||
: interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} {
|
||||
|
||||
guard = std::make_unique<Common::SpinLock>();
|
||||
}
|
||||
: interrupt_handler{interrupt_handler},
|
||||
core_index{id}, scheduler{scheduler}, guard{std::make_unique<Common::SpinLock>()} {}
|
||||
|
||||
PhysicalCore::~PhysicalCore() = default;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include "common/alignment.h"
|
||||
@@ -123,7 +124,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
|
||||
: kernel.CreateNewUserProcessID();
|
||||
process->capabilities.InitializeForMetadatalessProcess();
|
||||
|
||||
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(0));
|
||||
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
|
||||
std::uniform_int_distribution<u64> distribution;
|
||||
std::generate(process->random_entropy.begin(), process->random_entropy.end(),
|
||||
[&] { return distribution(rng); });
|
||||
|
||||
@@ -72,7 +72,7 @@ u32 GlobalScheduler::SelectThreads() {
|
||||
if (top_thread != nullptr) {
|
||||
// TODO(Blinkhawk): Implement Thread Pinning
|
||||
} else {
|
||||
idle_cores |= (1ul << core);
|
||||
idle_cores |= (1U << core);
|
||||
}
|
||||
top_threads[core] = top_thread;
|
||||
}
|
||||
@@ -126,7 +126,7 @@ u32 GlobalScheduler::SelectThreads() {
|
||||
top_threads[core_id] = suggested;
|
||||
}
|
||||
|
||||
idle_cores &= ~(1ul << core_id);
|
||||
idle_cores &= ~(1U << core_id);
|
||||
}
|
||||
u32 cores_needing_context_switch{};
|
||||
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||
@@ -134,7 +134,7 @@ u32 GlobalScheduler::SelectThreads() {
|
||||
ASSERT(top_threads[core] == nullptr ||
|
||||
static_cast<u32>(top_threads[core]->GetProcessorID()) == core);
|
||||
if (update_thread(top_threads[core], sched)) {
|
||||
cores_needing_context_switch |= (1ul << core);
|
||||
cores_needing_context_switch |= (1U << core);
|
||||
}
|
||||
}
|
||||
return cores_needing_context_switch;
|
||||
@@ -364,7 +364,7 @@ void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule,
|
||||
} else {
|
||||
must_context_switch = true;
|
||||
}
|
||||
cores_pending_reschedule &= ~(1ul << core);
|
||||
cores_pending_reschedule &= ~(1U << core);
|
||||
}
|
||||
if (must_context_switch) {
|
||||
auto& core_scheduler = kernel.CurrentScheduler();
|
||||
@@ -767,7 +767,7 @@ void Scheduler::SwitchToCurrent() {
|
||||
current_thread->context_guard.unlock();
|
||||
break;
|
||||
}
|
||||
if (current_thread->GetProcessorID() != core_id) {
|
||||
if (static_cast<u32>(current_thread->GetProcessorID()) != core_id) {
|
||||
current_thread->context_guard.unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/thread_queue_list.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/arm/unicorn/arm_unicorn.h"
|
||||
#include "core/core.h"
|
||||
#include "core/cpu_manager.h"
|
||||
#include "core/hardware_properties.h"
|
||||
@@ -217,8 +216,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
|
||||
} else {
|
||||
thread->tls_address = 0;
|
||||
}
|
||||
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
||||
// to initialize the context
|
||||
|
||||
thread->arm_interface.reset();
|
||||
if ((type_flags & THREADTYPE_HLE) == 0) {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
@@ -231,19 +229,10 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
|
||||
system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(),
|
||||
processor_id);
|
||||
}
|
||||
|
||||
#else
|
||||
if (owner_process && !owner_process->Is64BitProcess()) {
|
||||
thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
|
||||
system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32,
|
||||
processor_id);
|
||||
} else {
|
||||
thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
|
||||
system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64,
|
||||
processor_id);
|
||||
}
|
||||
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||
#error Platform not supported yet.
|
||||
#endif
|
||||
|
||||
ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
|
||||
static_cast<u32>(entry_point), static_cast<u32>(arg));
|
||||
ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "common/string_util.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/constants.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
@@ -496,7 +497,7 @@ public:
|
||||
{3, nullptr, "LoadIdTokenCache"},
|
||||
{130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
|
||||
{150, nullptr, "CreateAuthorizationRequest"},
|
||||
{160, nullptr, "StoreOpenContext"},
|
||||
{160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"},
|
||||
{170, nullptr, "LoadNetworkServiceLicenseKindAsync"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -520,6 +521,12 @@ private:
|
||||
rb.PushRaw<u64>(user_id.GetNintendoID());
|
||||
}
|
||||
|
||||
void StoreOpenContext(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
Common::UUID user_id;
|
||||
};
|
||||
|
||||
|
||||
@@ -751,7 +751,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
if (Settings::values.use_docked_mode.GetValue()) {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor.GetValue()));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
|
||||
@@ -824,7 +824,7 @@ void IStorage::Open(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
|
||||
const bool use_docked_mode{Settings::values.use_docked_mode};
|
||||
const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()};
|
||||
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
@@ -1201,6 +1201,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{151, nullptr, "TryPopFromNotificationStorageChannel"},
|
||||
{160, nullptr, "GetHealthWarningDisappearedSystemEvent"},
|
||||
{170, nullptr, "SetHdcpAuthenticationActivated"},
|
||||
{180, nullptr, "GetLaunchRequiredVersion"},
|
||||
{181, nullptr, "UpgradeLaunchRequiredVersion"},
|
||||
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
|
||||
{1000, nullptr, "CreateMovieMaker"},
|
||||
{1001, nullptr, "PrepareForJit"},
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/nvflinger/nvflinger.h"
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Service::AM::Applets {
|
||||
static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
|
||||
ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
|
||||
std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
|
||||
HID::Controller_NPad::NPadType npad_style_set;
|
||||
HID::Controller_NPad::NpadStyleSet npad_style_set;
|
||||
npad_style_set.raw = private_arg.style_set;
|
||||
|
||||
return {
|
||||
@@ -62,7 +62,7 @@ void Controller::Initialize() {
|
||||
common_args.play_startup_sound, common_args.size, common_args.system_tick,
|
||||
common_args.theme_color);
|
||||
|
||||
library_applet_version = LibraryAppletVersion{common_args.library_version};
|
||||
controller_applet_version = ControllerAppletVersion{common_args.library_version};
|
||||
|
||||
const auto private_arg_storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(private_arg_storage != nullptr);
|
||||
@@ -70,39 +70,78 @@ void Controller::Initialize() {
|
||||
const auto& private_arg = private_arg_storage->GetData();
|
||||
ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate));
|
||||
|
||||
std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate));
|
||||
std::memcpy(&controller_private_arg, private_arg.data(), private_arg.size());
|
||||
ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),
|
||||
"Unknown ControllerSupportArgPrivate revision={} with size={}",
|
||||
library_applet_version, controller_private_arg.arg_private_size);
|
||||
controller_applet_version, controller_private_arg.arg_private_size);
|
||||
|
||||
// Some games such as Cave Story+ set invalid values for the ControllerSupportMode.
|
||||
// Defer to arg_size to set the ControllerSupportMode.
|
||||
if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) {
|
||||
switch (controller_private_arg.arg_size) {
|
||||
case sizeof(ControllerSupportArgOld):
|
||||
case sizeof(ControllerSupportArgNew):
|
||||
controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
|
||||
break;
|
||||
case sizeof(ControllerUpdateFirmwareArg):
|
||||
controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate;
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}",
|
||||
controller_private_arg.mode, controller_private_arg.arg_size);
|
||||
controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Some games such as Cave Story+ set invalid values for the ControllerSupportCaller.
|
||||
// This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem.
|
||||
if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) {
|
||||
if (controller_private_arg.flag_1 &&
|
||||
controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate) {
|
||||
controller_private_arg.caller = ControllerSupportCaller::System;
|
||||
} else {
|
||||
controller_private_arg.caller = ControllerSupportCaller::Application;
|
||||
}
|
||||
}
|
||||
|
||||
switch (controller_private_arg.mode) {
|
||||
case ControllerSupportMode::ShowControllerSupport: {
|
||||
case ControllerSupportMode::ShowControllerSupport:
|
||||
case ControllerSupportMode::ShowControllerStrapGuide: {
|
||||
const auto user_arg_storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(user_arg_storage != nullptr);
|
||||
|
||||
const auto& user_arg = user_arg_storage->GetData();
|
||||
switch (library_applet_version) {
|
||||
case LibraryAppletVersion::Version3:
|
||||
case LibraryAppletVersion::Version4:
|
||||
case LibraryAppletVersion::Version5:
|
||||
switch (controller_applet_version) {
|
||||
case ControllerAppletVersion::Version3:
|
||||
case ControllerAppletVersion::Version4:
|
||||
case ControllerAppletVersion::Version5:
|
||||
ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld));
|
||||
std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld));
|
||||
std::memcpy(&controller_user_arg_old, user_arg.data(), user_arg.size());
|
||||
break;
|
||||
case LibraryAppletVersion::Version7:
|
||||
case ControllerAppletVersion::Version7:
|
||||
ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew));
|
||||
std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
|
||||
std::memcpy(&controller_user_arg_new, user_arg.data(), user_arg.size());
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}",
|
||||
library_applet_version, controller_private_arg.arg_size);
|
||||
controller_applet_version, controller_private_arg.arg_size);
|
||||
ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));
|
||||
std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ControllerSupportMode::ShowControllerStrapGuide:
|
||||
case ControllerSupportMode::ShowControllerFirmwareUpdate:
|
||||
case ControllerSupportMode::ShowControllerFirmwareUpdate: {
|
||||
const auto update_arg_storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(update_arg_storage != nullptr);
|
||||
|
||||
const auto& update_arg = update_arg_storage->GetData();
|
||||
ASSERT(update_arg.size() == sizeof(ControllerUpdateFirmwareArg));
|
||||
|
||||
std::memcpy(&controller_update_arg, update_arg.data(), update_arg.size());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);
|
||||
break;
|
||||
@@ -126,10 +165,10 @@ void Controller::Execute() {
|
||||
switch (controller_private_arg.mode) {
|
||||
case ControllerSupportMode::ShowControllerSupport: {
|
||||
const auto parameters = [this] {
|
||||
switch (library_applet_version) {
|
||||
case LibraryAppletVersion::Version3:
|
||||
case LibraryAppletVersion::Version4:
|
||||
case LibraryAppletVersion::Version5:
|
||||
switch (controller_applet_version) {
|
||||
case ControllerAppletVersion::Version3:
|
||||
case ControllerAppletVersion::Version4:
|
||||
case ControllerAppletVersion::Version5:
|
||||
return ConvertToFrontendParameters(
|
||||
controller_private_arg, controller_user_arg_old.header,
|
||||
controller_user_arg_old.enable_explain_text,
|
||||
@@ -138,7 +177,7 @@ void Controller::Execute() {
|
||||
controller_user_arg_old.identification_colors.end()),
|
||||
std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(),
|
||||
controller_user_arg_old.explain_text.end()));
|
||||
case LibraryAppletVersion::Version7:
|
||||
case ControllerAppletVersion::Version7:
|
||||
default:
|
||||
return ConvertToFrontendParameters(
|
||||
controller_private_arg, controller_user_arg_new.header,
|
||||
@@ -170,6 +209,9 @@ void Controller::Execute() {
|
||||
}
|
||||
case ControllerSupportMode::ShowControllerStrapGuide:
|
||||
case ControllerSupportMode::ShowControllerFirmwareUpdate:
|
||||
UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented",
|
||||
controller_private_arg.mode);
|
||||
[[fallthrough]];
|
||||
default: {
|
||||
ConfigurationComplete();
|
||||
break;
|
||||
@@ -180,7 +222,7 @@ void Controller::Execute() {
|
||||
void Controller::ConfigurationComplete() {
|
||||
ControllerSupportResultInfo result_info{};
|
||||
|
||||
const auto& players = Settings::values.players;
|
||||
const auto& players = Settings::values.players.GetValue();
|
||||
|
||||
// If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
|
||||
// Otherwise, only count connected players from P1-P8.
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Service::AM::Applets {
|
||||
using IdentificationColor = std::array<u8, 4>;
|
||||
using ExplainText = std::array<char, 0x81>;
|
||||
|
||||
enum class LibraryAppletVersion : u32_le {
|
||||
enum class ControllerAppletVersion : u32_le {
|
||||
Version3 = 0x3, // 1.0.0 - 2.3.0
|
||||
Version4 = 0x4, // 3.0.0 - 5.1.0
|
||||
Version5 = 0x5, // 6.0.0 - 7.0.1
|
||||
@@ -29,14 +29,18 @@ enum class LibraryAppletVersion : u32_le {
|
||||
};
|
||||
|
||||
enum class ControllerSupportMode : u8 {
|
||||
ShowControllerSupport = 0,
|
||||
ShowControllerStrapGuide = 1,
|
||||
ShowControllerFirmwareUpdate = 2,
|
||||
ShowControllerSupport,
|
||||
ShowControllerStrapGuide,
|
||||
ShowControllerFirmwareUpdate,
|
||||
|
||||
MaxControllerSupportMode,
|
||||
};
|
||||
|
||||
enum class ControllerSupportCaller : u8 {
|
||||
Application = 0,
|
||||
System = 1,
|
||||
Application,
|
||||
System,
|
||||
|
||||
MaxControllerSupportCaller,
|
||||
};
|
||||
|
||||
struct ControllerSupportArgPrivate {
|
||||
@@ -84,6 +88,13 @@ struct ControllerSupportArgNew {
|
||||
static_assert(sizeof(ControllerSupportArgNew) == 0x430,
|
||||
"ControllerSupportArgNew has incorrect size.");
|
||||
|
||||
struct ControllerUpdateFirmwareArg {
|
||||
bool enable_force_update{};
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(ControllerUpdateFirmwareArg) == 0x4,
|
||||
"ControllerUpdateFirmwareArg has incorrect size.");
|
||||
|
||||
struct ControllerSupportResultInfo {
|
||||
s8 player_count{};
|
||||
INSERT_PADDING_BYTES(3);
|
||||
@@ -110,10 +121,11 @@ public:
|
||||
private:
|
||||
const Core::Frontend::ControllerApplet& frontend;
|
||||
|
||||
LibraryAppletVersion library_applet_version;
|
||||
ControllerAppletVersion controller_applet_version;
|
||||
ControllerSupportArgPrivate controller_private_arg;
|
||||
ControllerSupportArgOld controller_user_arg_old;
|
||||
ControllerSupportArgNew controller_user_arg_new;
|
||||
ControllerUpdateFirmwareArg controller_update_arg;
|
||||
bool complete{false};
|
||||
ResultCode status{RESULT_SUCCESS};
|
||||
bool is_single_mode{false};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/apm/apm.h"
|
||||
#include "core/hle/service/apm/interface.h"
|
||||
|
||||
@@ -69,7 +69,8 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
|
||||
}
|
||||
|
||||
PerformanceMode Controller::GetCurrentPerformanceMode() const {
|
||||
return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld;
|
||||
return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked
|
||||
: PerformanceMode::Handheld;
|
||||
}
|
||||
|
||||
PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) {
|
||||
|
||||
@@ -84,7 +84,7 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
|
||||
|
||||
void ProgressServiceBackend::SignalUpdate() const {
|
||||
if (need_hle_lock) {
|
||||
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
||||
std::lock_guard lock(HLE::g_hle_lock);
|
||||
event.writable->Signal();
|
||||
} else {
|
||||
event.writable->Signal();
|
||||
|
||||
@@ -196,7 +196,9 @@ private:
|
||||
const std::string& content_type_name) {
|
||||
if (client == nullptr) {
|
||||
client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT);
|
||||
client->set_timeout_sec(timeout_seconds);
|
||||
client->set_connection_timeout(timeout_seconds);
|
||||
client->set_read_timeout(timeout_seconds);
|
||||
client->set_write_timeout(timeout_seconds);
|
||||
}
|
||||
|
||||
httplib::Headers headers{
|
||||
@@ -255,7 +257,7 @@ private:
|
||||
return out;
|
||||
}
|
||||
|
||||
std::unique_ptr<httplib::Client> client;
|
||||
std::unique_ptr<httplib::SSLClient> client;
|
||||
std::string path;
|
||||
u64 title_id;
|
||||
u64 build_id;
|
||||
@@ -443,13 +445,25 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
|
||||
Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
|
||||
std::map<std::string, EventStatus>& games) {
|
||||
httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)};
|
||||
client.set_timeout_sec(static_cast<int>(TIMEOUT_SECONDS));
|
||||
client.set_connection_timeout(static_cast<int>(TIMEOUT_SECONDS));
|
||||
client.set_read_timeout(static_cast<int>(TIMEOUT_SECONDS));
|
||||
client.set_write_timeout(static_cast<int>(TIMEOUT_SECONDS));
|
||||
|
||||
httplib::Headers headers{
|
||||
{std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)},
|
||||
{std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
|
||||
};
|
||||
|
||||
if (!client.is_valid()) {
|
||||
LOG_ERROR(Service_BCAT, "Client is invalid, going offline!");
|
||||
return StatusResult::Offline;
|
||||
}
|
||||
|
||||
if (!client.is_socket_open()) {
|
||||
LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!");
|
||||
return StatusResult::Offline;
|
||||
}
|
||||
|
||||
const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers);
|
||||
if (response == nullptr)
|
||||
return StatusResult::Offline;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
|
||||
@@ -41,7 +41,7 @@ CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
|
||||
{130, nullptr, "PrecheckToCreateContentsForApplication"},
|
||||
{140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
|
||||
{141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
|
||||
{142, nullptr, "GetAlbumFileList3AaeAruid"},
|
||||
{142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
|
||||
{143, nullptr, "GetAlbumFileList4AaeUidAruid"},
|
||||
{60002, nullptr, "OpenAccessorSessionForApplication"},
|
||||
};
|
||||
@@ -77,17 +77,24 @@ void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& c
|
||||
|
||||
// TODO: Update this when we implement the album.
|
||||
// Currently we do not have a method of accessing album entries, set this to 0 for now.
|
||||
constexpr s32 total_entries{0};
|
||||
constexpr u32 total_entries_1{};
|
||||
constexpr u32 total_entries_2{};
|
||||
|
||||
LOG_WARNING(Service_Capture,
|
||||
"(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
|
||||
"end_posix_time={}, applet_resource_user_id={}, total_entries={}",
|
||||
pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id,
|
||||
total_entries);
|
||||
LOG_WARNING(
|
||||
Service_Capture,
|
||||
"(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
|
||||
"end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}",
|
||||
pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id,
|
||||
total_entries_1, total_entries_2);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(total_entries);
|
||||
rb.Push(total_entries_1);
|
||||
rb.Push(total_entries_2);
|
||||
}
|
||||
|
||||
void CAPS_U::GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx) {
|
||||
GetAlbumContentsFileListForApplication(ctx);
|
||||
}
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
private:
|
||||
void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
|
||||
void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx);
|
||||
void GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
||||
@@ -79,7 +79,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
|
||||
}
|
||||
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
|
||||
if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
|
||||
@@ -93,8 +93,9 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
|
||||
ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (dir == nullptr && Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty())
|
||||
if (dir == nullptr || Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) {
|
||||
dir = backing;
|
||||
}
|
||||
auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path));
|
||||
if (new_dir == nullptr) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <queue>
|
||||
#include "common/logging/log.h"
|
||||
#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"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user