Compare commits
391 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f604499702 | ||
|
|
cd542d5aac | ||
|
|
c425a1a857 | ||
|
|
86b55cb6df | ||
|
|
8135f4bfce | ||
|
|
c440ecfafe | ||
|
|
48d9d66dc5 | ||
|
|
444231a83d | ||
|
|
c1accfefde | ||
|
|
27e5efd265 | ||
|
|
f5ec165e8c | ||
|
|
edd668047c | ||
|
|
1ddcd0e6f0 | ||
|
|
dfb0b7beb3 | ||
|
|
60157170cb | ||
|
|
5abf93266e | ||
|
|
a6a73d8892 | ||
|
|
1d98027a0e | ||
|
|
2374471a1e | ||
|
|
e543320129 | ||
|
|
504aafedd2 | ||
|
|
e36e7ae74e | ||
|
|
259e52ccb2 | ||
|
|
889c646ac0 | ||
|
|
d62b0a9e29 | ||
|
|
f09d1dffd1 | ||
|
|
35e1118766 | ||
|
|
dd1aab5446 | ||
|
|
ca482997fe | ||
|
|
e09f1c92fb | ||
|
|
dfd14618f7 | ||
|
|
d0ac624403 | ||
|
|
9f0b247cf6 | ||
|
|
8ff2ce5207 | ||
|
|
e6a2245304 | ||
|
|
e147ed4fc0 | ||
|
|
4ffb487251 | ||
|
|
bd928e70ed | ||
|
|
eb73247433 | ||
|
|
df0f31f44e | ||
|
|
7fefec585c | ||
|
|
2bc6a699dc | ||
|
|
750abcc23d | ||
|
|
8ee3666a3c | ||
|
|
ed956569a4 | ||
|
|
f087639e4a | ||
|
|
cfb20c4c9d | ||
|
|
e78da8dc1f | ||
|
|
be4641c43f | ||
|
|
a3703f5767 | ||
|
|
4039086226 | ||
|
|
a1faed9950 | ||
|
|
57fb15d2a3 | ||
|
|
3435cd8d5e | ||
|
|
b1efceec89 | ||
|
|
98be5a4928 | ||
|
|
145c3ac89e | ||
|
|
c2c5260fd7 | ||
|
|
8b11368671 | ||
|
|
0ed5d728ca | ||
|
|
84412591c9 | ||
|
|
049050856f | ||
|
|
10ab714fe0 | ||
|
|
40ac058557 | ||
|
|
8b800369ea | ||
|
|
c357d8f6f7 | ||
|
|
b34ae2235d | ||
|
|
40cd299f01 | ||
|
|
67c1f31251 | ||
|
|
c82b0afb69 | ||
|
|
ef073ff117 | ||
|
|
7aa7d8f4ff | ||
|
|
f598490b57 | ||
|
|
284536a626 | ||
|
|
7320c667df | ||
|
|
3c02cdcc57 | ||
|
|
72c70d6808 | ||
|
|
b5e685b297 | ||
|
|
bb4549a73d | ||
|
|
a568cd805b | ||
|
|
0306c50339 | ||
|
|
dfa7be5ddf | ||
|
|
0d1d755086 | ||
|
|
42b75e8be8 | ||
|
|
6a6fabea58 | ||
|
|
2bdbb90af7 | ||
|
|
04e68e9738 | ||
|
|
390721a561 | ||
|
|
e01a9de35f | ||
|
|
f61c1ed246 | ||
|
|
9feb68085d | ||
|
|
0be835132c | ||
|
|
eceab45dac | ||
|
|
4076d8fe3e | ||
|
|
2d226ff8ac | ||
|
|
11e7c1244c | ||
|
|
3a6eef27a2 | ||
|
|
26f8a700a7 | ||
|
|
13222f94c0 | ||
|
|
414cc1eb1f | ||
|
|
b0b027d2d0 | ||
|
|
db21ac2627 | ||
|
|
d6f5f5cafa | ||
|
|
3e80b08944 | ||
|
|
911587fb8d | ||
|
|
220df45b7d | ||
|
|
704744bb72 | ||
|
|
3bbaa98c78 | ||
|
|
4b676e7786 | ||
|
|
e597665569 | ||
|
|
a3cdd773c3 | ||
|
|
4596ef5274 | ||
|
|
1a302d4d47 | ||
|
|
35480167b1 | ||
|
|
0b594f3344 | ||
|
|
92b18345a8 | ||
|
|
a897feb21e | ||
|
|
ba14fb42e4 | ||
|
|
1d11def9c4 | ||
|
|
477d616f7d | ||
|
|
07b86dc28c | ||
|
|
44f39bfb68 | ||
|
|
eb1a3c1f4a | ||
|
|
06887c80a5 | ||
|
|
5078106068 | ||
|
|
1710847d08 | ||
|
|
0db8918947 | ||
|
|
c3affdd162 | ||
|
|
09727a6a97 | ||
|
|
c6c1c1b45f | ||
|
|
0c59e6265f | ||
|
|
3c3d9afd61 | ||
|
|
69884d8a8f | ||
|
|
4c818b60e3 | ||
|
|
52c326c301 | ||
|
|
52bb524526 | ||
|
|
9f803299de | ||
|
|
3b84e04af1 | ||
|
|
ba38d91fe2 | ||
|
|
f58a6152fc | ||
|
|
07692230ca | ||
|
|
49a3571e76 | ||
|
|
7e92497402 | ||
|
|
679e63550a | ||
|
|
3d81a8efd5 | ||
|
|
d9f9bb7552 | ||
|
|
f45c25aaba | ||
|
|
2561a79c39 | ||
|
|
ac603cf130 | ||
|
|
8dbb8edcd3 | ||
|
|
c608d3a979 | ||
|
|
932922f67f | ||
|
|
cb2ce9924a | ||
|
|
72c48e01c9 | ||
|
|
5e636d1f6e | ||
|
|
b2b98b2f44 | ||
|
|
62e08c30b7 | ||
|
|
3e1a9a45a6 | ||
|
|
a9268286a4 | ||
|
|
65f3908064 | ||
|
|
6957bac03c | ||
|
|
7842536ddb | ||
|
|
7185d90a53 | ||
|
|
32eb080e02 | ||
|
|
fc6d46c374 | ||
|
|
1f4ca1e841 | ||
|
|
f574d324e7 | ||
|
|
9be3fedcaa | ||
|
|
045b0b70b6 | ||
|
|
a94a828b6c | ||
|
|
d5a4707f65 | ||
|
|
a6f473fd01 | ||
|
|
0fa1ebc349 | ||
|
|
9a82dec74a | ||
|
|
839c4a8a1c | ||
|
|
125599c2d5 | ||
|
|
3049ea45d3 | ||
|
|
372245e0b5 | ||
|
|
3ca0af8bb3 | ||
|
|
3740adb6f5 | ||
|
|
aa427bb2a7 | ||
|
|
636cc2a496 | ||
|
|
ea73ffe202 | ||
|
|
56541b1ae5 | ||
|
|
4bce57b149 | ||
|
|
63783db1b3 | ||
|
|
e8bd6b1fcc | ||
|
|
1c733bf175 | ||
|
|
197d0d9d24 | ||
|
|
cbf8bea9d5 | ||
|
|
eff61c5c42 | ||
|
|
f9e69faf4a | ||
|
|
69da267540 | ||
|
|
08fcf41b0a | ||
|
|
83f8d1aa2e | ||
|
|
966405d64b | ||
|
|
d0e4e43e3c | ||
|
|
96644385ca | ||
|
|
a1b1ea47ed | ||
|
|
faf69a22d4 | ||
|
|
609e98bc63 | ||
|
|
a0f615f232 | ||
|
|
ac754a57d2 | ||
|
|
3629fcf3e6 | ||
|
|
549164d425 | ||
|
|
b8b87ec01f | ||
|
|
5961928543 | ||
|
|
a661025637 | ||
|
|
66978a772d | ||
|
|
e4fa77ef6a | ||
|
|
a63d7c49fc | ||
|
|
b273b19576 | ||
|
|
318bf7c8e3 | ||
|
|
1e40a4b343 | ||
|
|
51de4e00a6 | ||
|
|
1c9c4eefeb | ||
|
|
170c8212bb | ||
|
|
2d6c064e66 | ||
|
|
d911740e5d | ||
|
|
bb12f99b20 | ||
|
|
50195b1704 | ||
|
|
2faad9bf23 | ||
|
|
52223313b1 | ||
|
|
d6b173d5fe | ||
|
|
df74ff3c8b | ||
|
|
af5d7e2c49 | ||
|
|
d9118d324a | ||
|
|
5af82a8ed4 | ||
|
|
c68c13e1aa | ||
|
|
8b5588e776 | ||
|
|
dbed6c6485 | ||
|
|
ea78c78253 | ||
|
|
ab7f52b279 | ||
|
|
55a10d02e5 | ||
|
|
a2e22b4359 | ||
|
|
e1fea1e0c5 | ||
|
|
a1b845b651 | ||
|
|
b11e0b94c7 | ||
|
|
2df55985b6 | ||
|
|
8332482c24 | ||
|
|
3f1136ac6f | ||
|
|
7e13e8bfcb | ||
|
|
dd91650aaf | ||
|
|
d6f76307fe | ||
|
|
027f443e69 | ||
|
|
55e6786254 | ||
|
|
ec98e4d842 | ||
|
|
03e088a4f4 | ||
|
|
2d9136cec6 | ||
|
|
af5c6e4ccb | ||
|
|
4316eaf75c | ||
|
|
fc46ecddb3 | ||
|
|
148a6418ed | ||
|
|
21aff36459 | ||
|
|
59b34b1d76 | ||
|
|
57a900cc45 | ||
|
|
d4fae3a699 | ||
|
|
946c86f0bb | ||
|
|
c9cf899d18 | ||
|
|
4fd06efeb9 | ||
|
|
a40fd07516 | ||
|
|
b184ca9089 | ||
|
|
8d42feb09b | ||
|
|
21f9e9da09 | ||
|
|
68c99d2597 | ||
|
|
cf4a08d950 | ||
|
|
376a837511 | ||
|
|
518a2bd206 | ||
|
|
07944a2345 | ||
|
|
e8235c0215 | ||
|
|
6ca31f544a | ||
|
|
210620ff31 | ||
|
|
b0e7920838 | ||
|
|
becfdb8638 | ||
|
|
8f37531f8e | ||
|
|
8486e7f8c8 | ||
|
|
ccb71bece9 | ||
|
|
faadae5814 | ||
|
|
80183de884 | ||
|
|
078ba28e13 | ||
|
|
acdbbb8885 | ||
|
|
d79c462af0 | ||
|
|
a2819c204f | ||
|
|
39f1c6246a | ||
|
|
501284a81a | ||
|
|
e444a6553f | ||
|
|
3052eae25e | ||
|
|
8abe5ba2c8 | ||
|
|
c849b5b320 | ||
|
|
9118deb990 | ||
|
|
97f33f00cf | ||
|
|
abdbafbc20 | ||
|
|
802c23b8a8 | ||
|
|
2b90637f4b | ||
|
|
878672f371 | ||
|
|
c703f0aee4 | ||
|
|
8215ae942c | ||
|
|
4f95dc950e | ||
|
|
cacb934f21 | ||
|
|
0c049e0a21 | ||
|
|
e3f1233ce1 | ||
|
|
ea358bd4bf | ||
|
|
c9b2a1b051 | ||
|
|
2edee801ce | ||
|
|
06cb910c6d | ||
|
|
5e6a0a08c1 | ||
|
|
964ddeeb90 | ||
|
|
4ccaa1402d | ||
|
|
7c192ec43f | ||
|
|
4c70d5b8eb | ||
|
|
a4f052f6b3 | ||
|
|
0c6fb456e0 | ||
|
|
fbc67a0563 | ||
|
|
a58abbcfc4 | ||
|
|
bf07272695 | ||
|
|
60f044df56 | ||
|
|
e3c55e31d7 | ||
|
|
833d0806f9 | ||
|
|
6b9eea3fe5 | ||
|
|
12a95ff453 | ||
|
|
2f87fd060d | ||
|
|
15f431f0cb | ||
|
|
864e8f55cf | ||
|
|
5e639bfcf6 | ||
|
|
4aaa2192b9 | ||
|
|
15a0e1481d | ||
|
|
294df41b86 | ||
|
|
a0c8c16d07 | ||
|
|
92bd4fc8eb | ||
|
|
7c6bb8c17f | ||
|
|
215ca770df | ||
|
|
865387f3c3 | ||
|
|
f6e998f6ad | ||
|
|
bc879ae880 | ||
|
|
c9ef8b0af1 | ||
|
|
83e8ad2331 | ||
|
|
877a978a22 | ||
|
|
912f2a520a | ||
|
|
3121408a90 | ||
|
|
ac7d8983eb | ||
|
|
05dbb47af5 | ||
|
|
dbb1eb9c29 | ||
|
|
21f1b2889d | ||
|
|
26c9f12271 | ||
|
|
c6016856d8 | ||
|
|
19cf995225 | ||
|
|
23ebd4920e | ||
|
|
b683e41fca | ||
|
|
179ee963db | ||
|
|
0ab17ab406 | ||
|
|
17a68e5ebe | ||
|
|
e04d75f44c | ||
|
|
37ac1bb576 | ||
|
|
5933b3ea96 | ||
|
|
35c095898b | ||
|
|
ea4928393f | ||
|
|
2378ecd0e8 | ||
|
|
fc8a8789da | ||
|
|
59c665b28e | ||
|
|
9e8737b535 | ||
|
|
56e51da1d9 | ||
|
|
40aa1ea9f9 | ||
|
|
a01832b2e0 | ||
|
|
1c7696e0d9 | ||
|
|
bf036b46fc | ||
|
|
54d7b664da | ||
|
|
0f887daa72 | ||
|
|
c5262b1890 | ||
|
|
4f41fd84ff | ||
|
|
de4f931d13 | ||
|
|
548fe0fc62 | ||
|
|
f2536cafe5 | ||
|
|
5af0340066 | ||
|
|
351f010cfc | ||
|
|
fe3bf4f075 | ||
|
|
15501477e7 | ||
|
|
0c5ede492f | ||
|
|
cb930c4b5a | ||
|
|
ef4c4e239d | ||
|
|
45da3be40e | ||
|
|
e00e1fc755 | ||
|
|
32bfa92c71 | ||
|
|
85a3368e6d | ||
|
|
69f622be36 | ||
|
|
4c20a39828 | ||
|
|
621b25b6be | ||
|
|
abbcc8e61e | ||
|
|
94db6e5f3f | ||
|
|
7b9c982d29 | ||
|
|
6d7514ccec | ||
|
|
e0b0947437 |
21
.github/ISSUE_TEMPLATE.md
vendored
21
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,16 +1,27 @@
|
||||
<!--
|
||||
Please keep in mind yuzu is EXPERIMENTAL SOFTWARE.
|
||||
|
||||
Please read the FAQ: https://yuzu-emu.org/wiki/faq/
|
||||
Please read the FAQ:
|
||||
https://yuzu-emu.org/wiki/faq/
|
||||
|
||||
When submitting an issue, please do the following:
|
||||
THIS IS NOT A SUPPORT FORUM, FOR SUPPORT GO TO:
|
||||
https://community.citra-emu.org/
|
||||
|
||||
- Provide the version (commit hash) of yuzu you are using.
|
||||
- Provide sufficient detail for the issue to be reproduced.
|
||||
- Provide:
|
||||
If the FAQ does not answer your question, please go to:
|
||||
https://community.citra-emu.org/
|
||||
|
||||
When submitting an issue, please check the following:
|
||||
|
||||
- You have read the above.
|
||||
- You have provided the version (commit hash) of yuzu you are using.
|
||||
- You have provided sufficient detail for the issue to be reproduced.
|
||||
- You have provided system specs (if relevant).
|
||||
- Please also provide:
|
||||
- For any issues, a log file
|
||||
- For crashes, a backtrace.
|
||||
- For graphical issues, comparison screenshots with real hardware.
|
||||
- For emulation inaccuracies, a test-case (if able).
|
||||
|
||||
-->
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ TRAVIS_BRANCH
|
||||
TRAVIS_BUILD_ID
|
||||
TRAVIS_BUILD_NUMBER
|
||||
TRAVIS_COMMIT
|
||||
TRAVIS_COMMIT_RANGE
|
||||
TRAVIS_EVENT_TYPE
|
||||
TRAVIS_JOB_ID
|
||||
TRAVIS_JOB_NUMBER
|
||||
TRAVIS_REPO_SLUG
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
apt-get update
|
||||
apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget cmake ninja-build ccache
|
||||
apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev qtwebengine5-dev wget cmake ninja-build ccache
|
||||
|
||||
cd /yuzu
|
||||
|
||||
mkdir build && cd build
|
||||
cmake .. -DYUZU_USE_BUNDLED_UNICORN=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 -G Ninja
|
||||
cmake .. -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 -G Ninja
|
||||
ninja
|
||||
|
||||
ccache -s
|
||||
|
||||
@@ -9,7 +9,7 @@ export PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||
|
||||
mkdir build && cd build
|
||||
cmake --version
|
||||
cmake .. -DYUZU_USE_BUNDLED_UNICORN=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_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
|
||||
make -j4
|
||||
|
||||
ccache -s
|
||||
|
||||
@@ -19,6 +19,8 @@ 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(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||
|
||||
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
|
||||
@@ -302,7 +304,7 @@ endif()
|
||||
if (ENABLE_QT)
|
||||
if (YUZU_USE_BUNDLED_QT)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
set(QT_VER qt-5.10.0-msvc2015_64)
|
||||
set(QT_VER qt-5.12.0-msvc2017_64)
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
|
||||
endif()
|
||||
@@ -319,6 +321,10 @@ if (ENABLE_QT)
|
||||
endif()
|
||||
|
||||
find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
|
||||
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets ${QT_PREFIX_HINT})
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
# Platform-specific library requirements
|
||||
@@ -413,19 +419,6 @@ function(create_target_directory_groups target_name)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Gets a UTC timstamp and sets the provided variable to it
|
||||
function(get_timestamp _var)
|
||||
string(TIMESTAMP timestamp UTC)
|
||||
set(${_var} "${timestamp}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# generate git/build information
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
||||
git_describe(GIT_DESC --always --long --dirty)
|
||||
git_branch_name(GIT_BRANCH)
|
||||
get_timestamp(BUILD_DATE)
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(externals)
|
||||
add_subdirectory(src)
|
||||
|
||||
@@ -5,6 +5,7 @@ function(copy_yuzu_Qt5_deps target_dir)
|
||||
set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
|
||||
set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
|
||||
set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")
|
||||
set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/")
|
||||
set(PLATFORMS ${DLL_DEST}platforms/)
|
||||
set(STYLES ${DLL_DEST}styles/)
|
||||
set(IMAGEFORMATS ${DLL_DEST}imageformats/)
|
||||
@@ -17,7 +18,35 @@ function(copy_yuzu_Qt5_deps target_dir)
|
||||
Qt5OpenGL$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Widgets$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
|
||||
Qt5Network$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Positioning$<$<CONFIG:Debug>:d>.*
|
||||
Qt5PrintSupport$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Qml$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Quick$<$<CONFIG:Debug>:d>.*
|
||||
Qt5QuickWidgets$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebChannel$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebEngine$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebEngineCore$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebEngineWidgets$<$<CONFIG:Debug>:d>.*
|
||||
QtWebEngineProcess$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
|
||||
windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${DLL_DEST}
|
||||
qtwebengine_resources.pak
|
||||
qtwebengine_devtools_resources.pak
|
||||
qtwebengine_resources_100p.pak
|
||||
qtwebengine_resources_200p.pak
|
||||
icudtl.dat
|
||||
)
|
||||
endif ()
|
||||
|
||||
windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
|
||||
windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
|
||||
windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*)
|
||||
windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS}
|
||||
qjpeg$<$<CONFIG:Debug>:d>.*
|
||||
qgif$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
endfunction(copy_yuzu_Qt5_deps)
|
||||
|
||||
94
CMakeModules/GenerateSCMRev.cmake
Normal file
94
CMakeModules/GenerateSCMRev.cmake
Normal file
@@ -0,0 +1,94 @@
|
||||
# Gets a UTC timstamp and sets the provided variable to it
|
||||
function(get_timestamp _var)
|
||||
string(TIMESTAMP timestamp UTC)
|
||||
set(${_var} "${timestamp}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/externals/cmake-modules")
|
||||
# generate git/build information
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
||||
git_describe(GIT_DESC --always --long --dirty)
|
||||
git_branch_name(GIT_BRANCH)
|
||||
get_timestamp(BUILD_DATE)
|
||||
|
||||
# Generate cpp with Git revision from template
|
||||
# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
|
||||
set(REPO_NAME "")
|
||||
set(BUILD_VERSION "0")
|
||||
if (BUILD_REPOSITORY)
|
||||
# regex capture the string nightly or canary into CMAKE_MATCH_1
|
||||
string(REGEX MATCH "yuzu-emu/yuzu-?(.*)" OUTVAR ${BUILD_REPOSITORY})
|
||||
if (${CMAKE_MATCH_COUNT} GREATER 0)
|
||||
# capitalize the first letter of each word in the repo name.
|
||||
string(REPLACE "-" ";" REPO_NAME_LIST ${CMAKE_MATCH_1})
|
||||
foreach(WORD ${REPO_NAME_LIST})
|
||||
string(SUBSTRING ${WORD} 0 1 FIRST_LETTER)
|
||||
string(SUBSTRING ${WORD} 1 -1 REMAINDER)
|
||||
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
|
||||
set(REPO_NAME "${REPO_NAME}${FIRST_LETTER}${REMAINDER}")
|
||||
endforeach()
|
||||
if (BUILD_TAG)
|
||||
string(REGEX MATCH "${CMAKE_MATCH_1}-([0-9]+)" OUTVAR ${BUILD_TAG})
|
||||
if (${CMAKE_MATCH_COUNT} GREATER 0)
|
||||
set(BUILD_VERSION ${CMAKE_MATCH_1})
|
||||
endif()
|
||||
if (BUILD_VERSION)
|
||||
# This leaves a trailing space on the last word, but we actually want that
|
||||
# because of how it's styled in the title bar.
|
||||
set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ")
|
||||
else()
|
||||
set(BUILD_FULLNAME "")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# The variable SRC_DIR must be passed into the script (since it uses the current build directory for all values of CMAKE_*_DIR)
|
||||
set(VIDEO_CORE "${SRC_DIR}/src/video_core")
|
||||
set(HASH_FILES
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_cache.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_cache.h"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.h"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_gen.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_gen.h"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_half.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_half_immediate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_immediate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_integer.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_integer_immediate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/bfe.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/bfi.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/conversion.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/ffma.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/float_set.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/float_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/half_set.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/hfma2.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/integer_set.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/memory.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/other.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/predicate_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/predicate_set_register.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/register_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/shift.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/video.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/xmad.cpp"
|
||||
"${VIDEO_CORE}/shader/decode.cpp"
|
||||
"${VIDEO_CORE}/shader/shader_ir.cpp"
|
||||
"${VIDEO_CORE}/shader/shader_ir.h"
|
||||
"${VIDEO_CORE}/shader/track.cpp"
|
||||
)
|
||||
set(COMBINED "")
|
||||
foreach (F IN LISTS HASH_FILES)
|
||||
file(READ ${F} TMP)
|
||||
set(COMBINED "${COMBINED}${TMP}")
|
||||
endforeach()
|
||||
string(MD5 SHADER_CACHE_VERSION "${COMBINED}")
|
||||
configure_file("${SRC_DIR}/src/common/scm_rev.cpp.in" "scm_rev.cpp" @ONLY)
|
||||
@@ -42,7 +42,7 @@ before_build:
|
||||
$COMPAT = if ($env:ENABLE_COMPATIBILITY_REPORTING -eq $null) {0} else {$env:ENABLE_COMPATIBILITY_REPORTING}
|
||||
if ($env:BUILD_TYPE -eq 'msvc') {
|
||||
# redirect stderr and change the exit code to prevent powershell from cancelling the build if cmake prints a warning
|
||||
cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1 && exit 0'
|
||||
cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1 && exit 0'
|
||||
} else {
|
||||
C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DYUZU_BUILD_UNICORN=1 -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1"
|
||||
}
|
||||
@@ -94,6 +94,7 @@ after_build:
|
||||
Copy-Item "$BUILD_DIR\*" -Destination $RELEASE_DIST -Recurse
|
||||
rm "$RELEASE_DIST\*.exe"
|
||||
Get-ChildItem "$BUILD_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
|
||||
Get-ChildItem "$BUILD_DIR" -Recurse -Filter "QtWebEngineProcess*.exe" | Copy-Item -destination $RELEASE_DIST
|
||||
Copy-Item .\license.txt -Destination $RELEASE_DIST
|
||||
Copy-Item .\README.md -Destination $RELEASE_DIST
|
||||
7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\*
|
||||
|
||||
@@ -37,7 +37,7 @@ Stream::Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callbac
|
||||
: sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)},
|
||||
sink_stream{sink_stream}, name{std::move(name_)} {
|
||||
|
||||
release_event = CoreTiming::RegisterEvent(
|
||||
release_event = Core::Timing::RegisterEvent(
|
||||
name, [this](u64 userdata, int cycles_late) { ReleaseActiveBuffer(); });
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ Stream::State Stream::GetState() const {
|
||||
|
||||
s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
|
||||
const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
|
||||
return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
|
||||
return Core::Timing::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
|
||||
}
|
||||
|
||||
static void VolumeAdjustSamples(std::vector<s16>& samples) {
|
||||
@@ -68,7 +68,7 @@ static void VolumeAdjustSamples(std::vector<s16>& samples) {
|
||||
}
|
||||
|
||||
// Implementation of a volume slider with a dynamic range of 60 dB
|
||||
const float volume_scale_factor{std::exp(6.90775f * volume) * 0.001f};
|
||||
const float volume_scale_factor = volume == 0 ? 0 : std::exp(6.90775f * volume) * 0.001f;
|
||||
for (auto& sample : samples) {
|
||||
sample = static_cast<s16>(sample * volume_scale_factor);
|
||||
}
|
||||
@@ -99,7 +99,8 @@ void Stream::PlayNextBuffer() {
|
||||
|
||||
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
|
||||
|
||||
CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
|
||||
Core::Timing::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event,
|
||||
{});
|
||||
}
|
||||
|
||||
void Stream::ReleaseActiveBuffer() {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "audio_core/buffer.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace CoreTiming {
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
@@ -91,16 +91,16 @@ private:
|
||||
/// Gets the number of core cycles when the specified buffer will be released
|
||||
s64 GetBufferReleaseCycles(const Buffer& buffer) const;
|
||||
|
||||
u32 sample_rate; ///< Sample rate of the stream
|
||||
Format format; ///< Format of the stream
|
||||
ReleaseCallback release_callback; ///< Buffer release callback for the stream
|
||||
State state{State::Stopped}; ///< Playback state of the stream
|
||||
CoreTiming::EventType* release_event{}; ///< Core timing release event for the stream
|
||||
BufferPtr active_buffer; ///< Actively playing buffer in the stream
|
||||
std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream
|
||||
std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream
|
||||
SinkStream& sink_stream; ///< Output sink for the stream
|
||||
std::string name; ///< Name of the stream, must be unique
|
||||
u32 sample_rate; ///< Sample rate of the stream
|
||||
Format format; ///< Format of the stream
|
||||
ReleaseCallback release_callback; ///< Buffer release callback for the stream
|
||||
State state{State::Stopped}; ///< Playback state of the stream
|
||||
Core::Timing::EventType* release_event{}; ///< Core timing release event for the stream
|
||||
BufferPtr active_buffer; ///< Actively playing buffer in the stream
|
||||
std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream
|
||||
std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream
|
||||
SinkStream& sink_stream; ///< Output sink for the stream
|
||||
std::string name; ///< Name of the stream, must be unique
|
||||
};
|
||||
|
||||
using StreamPtr = std::shared_ptr<Stream>;
|
||||
|
||||
@@ -53,8 +53,8 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
|
||||
const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale);
|
||||
m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio);
|
||||
|
||||
// Place a lower limit of 5% speed. When a game boots up, there will be
|
||||
// many silence samples. These do not need to be timestretched.
|
||||
// Place a lower limit of 5% speed. When a game boots up, there will be
|
||||
// many silence samples. These do not need to be timestretched.
|
||||
m_stretch_ratio = std::max(m_stretch_ratio, 0.05);
|
||||
m_sound_touch.setTempo(m_stretch_ratio);
|
||||
|
||||
|
||||
@@ -1,42 +1,69 @@
|
||||
# Generate cpp with Git revision from template
|
||||
# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
|
||||
set(REPO_NAME "")
|
||||
set(BUILD_VERSION "0")
|
||||
if ($ENV{CI})
|
||||
if ($ENV{TRAVIS})
|
||||
# Add a custom command to generate a new shader_cache_version hash when any of the following files change
|
||||
# NOTE: This is an approximation of what files affect shader generation, its possible something else
|
||||
# could affect the result, but much more unlikely than the following files. Keeping a list of files
|
||||
# like this allows for much better caching since it doesn't force the user to recompile binary shaders every update
|
||||
set(VIDEO_CORE "${CMAKE_SOURCE_DIR}/src/video_core")
|
||||
if (DEFINED ENV{CI})
|
||||
if (DEFINED ENV{TRAVIS})
|
||||
set(BUILD_REPOSITORY $ENV{TRAVIS_REPO_SLUG})
|
||||
set(BUILD_TAG $ENV{TRAVIS_TAG})
|
||||
elseif($ENV{APPVEYOR})
|
||||
elseif(DEFINED ENV{APPVEYOR})
|
||||
set(BUILD_REPOSITORY $ENV{APPVEYOR_REPO_NAME})
|
||||
set(BUILD_TAG $ENV{APPVEYOR_REPO_TAG_NAME})
|
||||
endif()
|
||||
# regex capture the string nightly or canary into CMAKE_MATCH_1
|
||||
string(REGEX MATCH "yuzu-emu/yuzu-?(.*)" OUTVAR ${BUILD_REPOSITORY})
|
||||
if (${CMAKE_MATCH_COUNT} GREATER 0)
|
||||
# capitalize the first letter of each word in the repo name.
|
||||
string(REPLACE "-" ";" REPO_NAME_LIST ${CMAKE_MATCH_1})
|
||||
foreach(WORD ${REPO_NAME_LIST})
|
||||
string(SUBSTRING ${WORD} 0 1 FIRST_LETTER)
|
||||
string(SUBSTRING ${WORD} 1 -1 REMAINDER)
|
||||
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
|
||||
set(REPO_NAME "${REPO_NAME}${FIRST_LETTER}${REMAINDER}")
|
||||
endforeach()
|
||||
if (BUILD_TAG)
|
||||
string(REGEX MATCH "${CMAKE_MATCH_1}-([0-9]+)" OUTVAR ${BUILD_TAG})
|
||||
if (${CMAKE_MATCH_COUNT} GREATER 0)
|
||||
set(BUILD_VERSION ${CMAKE_MATCH_1})
|
||||
endif()
|
||||
if (BUILD_VERSION)
|
||||
# This leaves a trailing space on the last word, but we actually want that
|
||||
# because of how it's styled in the title bar.
|
||||
set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ")
|
||||
else()
|
||||
set(BUILD_FULLNAME "")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp" @ONLY)
|
||||
add_custom_command(OUTPUT scm_rev.cpp
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DSRC_DIR="${CMAKE_SOURCE_DIR}"
|
||||
-DBUILD_REPOSITORY="${BUILD_REPOSITORY}"
|
||||
-DBUILD_TAG="${BUILD_TAG}"
|
||||
-P "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
|
||||
DEPENDS
|
||||
# WARNING! It was too much work to try and make a common location for this list,
|
||||
# so if you need to change it, please update CMakeModules/GenerateSCMRev.cmake as well
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_cache.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_cache.h"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.h"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_gen.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_gen.h"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_half.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_half_immediate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_immediate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_integer.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/arithmetic_integer_immediate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/bfe.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/bfi.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/conversion.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/ffma.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/float_set.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/float_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/half_set.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/hfma2.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/integer_set.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/memory.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/other.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/predicate_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/predicate_set_register.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/register_set_predicate.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/shift.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/video.cpp"
|
||||
"${VIDEO_CORE}/shader/decode/xmad.cpp"
|
||||
"${VIDEO_CORE}/shader/decode.cpp"
|
||||
"${VIDEO_CORE}/shader/shader_ir.cpp"
|
||||
"${VIDEO_CORE}/shader/shader_ir.h"
|
||||
"${VIDEO_CORE}/shader/track.cpp"
|
||||
# and also check that the scm_rev files haven't changed
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h"
|
||||
# technically we should regenerate if the git version changed, but its not worth the effort imo
|
||||
"${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
|
||||
)
|
||||
|
||||
add_library(common STATIC
|
||||
alignment.h
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#define KEYS_DIR "keys"
|
||||
#define LOAD_DIR "load"
|
||||
#define DUMP_DIR "dump"
|
||||
#define SHADER_DIR "shader"
|
||||
#define LOG_DIR "log"
|
||||
|
||||
// Filenames
|
||||
|
||||
@@ -710,6 +710,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
|
||||
paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::KeysDir, user_path + KEYS_DIR DIR_SEP);
|
||||
// TODO: Put the logs in a better location for each OS
|
||||
|
||||
@@ -31,6 +31,7 @@ enum class UserPath {
|
||||
SDMCDir,
|
||||
LoadDir,
|
||||
DumpDir,
|
||||
ShaderDir,
|
||||
SysDataDir,
|
||||
UserDir,
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define BUILD_DATE "@BUILD_DATE@"
|
||||
#define BUILD_FULLNAME "@BUILD_FULLNAME@"
|
||||
#define BUILD_VERSION "@BUILD_VERSION@"
|
||||
#define SHADER_CACHE_VERSION "@SHADER_CACHE_VERSION@"
|
||||
|
||||
namespace Common {
|
||||
|
||||
@@ -21,6 +22,7 @@ const char g_build_name[] = BUILD_NAME;
|
||||
const char g_build_date[] = BUILD_DATE;
|
||||
const char g_build_fullname[] = BUILD_FULLNAME;
|
||||
const char g_build_version[] = BUILD_VERSION;
|
||||
const char g_shader_cache_version[] = SHADER_CACHE_VERSION;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -13,5 +13,6 @@ extern const char g_build_name[];
|
||||
extern const char g_build_date[];
|
||||
extern const char g_build_fullname[];
|
||||
extern const char g_build_version[];
|
||||
extern const char g_shader_cache_version[];
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -88,11 +88,15 @@ add_library(core STATIC
|
||||
frontend/applets/profile_select.h
|
||||
frontend/applets/software_keyboard.cpp
|
||||
frontend/applets/software_keyboard.h
|
||||
frontend/applets/web_browser.cpp
|
||||
frontend/applets/web_browser.h
|
||||
frontend/emu_window.cpp
|
||||
frontend/emu_window.h
|
||||
frontend/framebuffer_layout.cpp
|
||||
frontend/framebuffer_layout.h
|
||||
frontend/input.h
|
||||
frontend/scope_acquire_window_context.cpp
|
||||
frontend/scope_acquire_window_context.h
|
||||
gdbstub/gdbstub.cpp
|
||||
gdbstub/gdbstub.h
|
||||
hle/ipc.h
|
||||
@@ -136,8 +140,6 @@ add_library(core STATIC
|
||||
hle/kernel/svc_wrap.h
|
||||
hle/kernel/thread.cpp
|
||||
hle/kernel/thread.h
|
||||
hle/kernel/timer.cpp
|
||||
hle/kernel/timer.h
|
||||
hle/kernel/vm_manager.cpp
|
||||
hle/kernel/vm_manager.h
|
||||
hle/kernel/wait_object.cpp
|
||||
@@ -173,6 +175,8 @@ add_library(core STATIC
|
||||
hle/service/am/applets/software_keyboard.h
|
||||
hle/service/am/applets/stub_applet.cpp
|
||||
hle/service/am/applets/stub_applet.h
|
||||
hle/service/am/applets/web_browser.cpp
|
||||
hle/service/am/applets/web_browser.h
|
||||
hle/service/am/idle.cpp
|
||||
hle/service/am/idle.h
|
||||
hle/service/am/omm.cpp
|
||||
|
||||
@@ -112,14 +112,14 @@ public:
|
||||
// Always execute at least one tick.
|
||||
amortized_ticks = std::max<u64>(amortized_ticks, 1);
|
||||
|
||||
CoreTiming::AddTicks(amortized_ticks);
|
||||
Timing::AddTicks(amortized_ticks);
|
||||
num_interpreted_instructions = 0;
|
||||
}
|
||||
u64 GetTicksRemaining() override {
|
||||
return std::max(CoreTiming::GetDowncount(), 0);
|
||||
return std::max(Timing::GetDowncount(), 0);
|
||||
}
|
||||
u64 GetCNTPCT() override {
|
||||
return CoreTiming::GetTicks();
|
||||
return Timing::GetTicks();
|
||||
}
|
||||
|
||||
ARM_Dynarmic& parent;
|
||||
|
||||
@@ -177,7 +177,7 @@ void ARM_Unicorn::Run() {
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
ExecuteInstructions(std::max(4000000, 0));
|
||||
} else {
|
||||
ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0));
|
||||
ExecuteInstructions(std::max(Timing::GetDowncount(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
|
||||
void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
|
||||
MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
|
||||
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
|
||||
CoreTiming::AddTicks(num_instructions);
|
||||
Timing::AddTicks(num_instructions);
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
if (last_bkpt_hit) {
|
||||
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
|
||||
|
||||
@@ -30,8 +30,11 @@
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/perf_stats.h"
|
||||
#include "core/settings.h"
|
||||
#include "core/telemetry_session.h"
|
||||
#include "frontend/applets/profile_select.h"
|
||||
#include "frontend/applets/software_keyboard.h"
|
||||
#include "frontend/applets/web_browser.h"
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
@@ -91,9 +94,14 @@ struct System::Impl {
|
||||
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
|
||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||
|
||||
CoreTiming::Init();
|
||||
Timing::Init();
|
||||
kernel.Initialize();
|
||||
|
||||
const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch());
|
||||
Settings::values.custom_rtc_differential =
|
||||
Settings::values.custom_rtc.value_or(current_time) - current_time;
|
||||
|
||||
// Create a default fs if one doesn't already exist.
|
||||
if (virtual_filesystem == nullptr)
|
||||
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||
@@ -103,6 +111,8 @@ struct System::Impl {
|
||||
profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
|
||||
if (software_keyboard == nullptr)
|
||||
software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
|
||||
if (web_browser == nullptr)
|
||||
web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
|
||||
|
||||
auto main_process = Kernel::Process::Create(kernel, "main");
|
||||
kernel.MakeCurrentProcess(main_process.get());
|
||||
@@ -113,7 +123,7 @@ struct System::Impl {
|
||||
Service::Init(service_manager, *virtual_filesystem);
|
||||
GDBStub::Init();
|
||||
|
||||
renderer = VideoCore::CreateRenderer(emu_window);
|
||||
renderer = VideoCore::CreateRenderer(emu_window, system);
|
||||
if (!renderer->Init()) {
|
||||
return ResultStatus::ErrorVideoCore;
|
||||
}
|
||||
@@ -165,6 +175,7 @@ struct System::Impl {
|
||||
return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
|
||||
static_cast<u32>(load_result));
|
||||
}
|
||||
|
||||
status = ResultStatus::Success;
|
||||
return status;
|
||||
}
|
||||
@@ -194,11 +205,16 @@ struct System::Impl {
|
||||
|
||||
// Shutdown kernel and core timing
|
||||
kernel.Shutdown();
|
||||
CoreTiming::Shutdown();
|
||||
Timing::Shutdown();
|
||||
|
||||
// Close app loader
|
||||
app_loader.reset();
|
||||
|
||||
// Clear all applets
|
||||
profile_selector.reset();
|
||||
software_keyboard.reset();
|
||||
web_browser.reset();
|
||||
|
||||
LOG_DEBUG(Core, "Shutdown OK");
|
||||
}
|
||||
|
||||
@@ -216,7 +232,7 @@ struct System::Impl {
|
||||
}
|
||||
|
||||
PerfStatsResults GetAndResetPerfStats() {
|
||||
return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs());
|
||||
return perf_stats.GetAndResetStats(Timing::GetGlobalTimeUs());
|
||||
}
|
||||
|
||||
Kernel::KernelCore kernel;
|
||||
@@ -233,6 +249,7 @@ struct System::Impl {
|
||||
/// Frontend applets
|
||||
std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector;
|
||||
std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
|
||||
std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser;
|
||||
|
||||
/// Service manager
|
||||
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
||||
@@ -427,22 +444,34 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
|
||||
return impl->virtual_filesystem;
|
||||
}
|
||||
|
||||
void System::SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet) {
|
||||
void System::SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet) {
|
||||
impl->profile_selector = std::move(applet);
|
||||
}
|
||||
|
||||
const Core::Frontend::ProfileSelectApplet& System::GetProfileSelector() const {
|
||||
const Frontend::ProfileSelectApplet& System::GetProfileSelector() const {
|
||||
return *impl->profile_selector;
|
||||
}
|
||||
|
||||
void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) {
|
||||
void System::SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet) {
|
||||
impl->software_keyboard = std::move(applet);
|
||||
}
|
||||
|
||||
const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const {
|
||||
const Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const {
|
||||
return *impl->software_keyboard;
|
||||
}
|
||||
|
||||
void System::SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet) {
|
||||
impl->web_browser = std::move(applet);
|
||||
}
|
||||
|
||||
Frontend::WebBrowserApplet& System::GetWebBrowser() {
|
||||
return *impl->web_browser;
|
||||
}
|
||||
|
||||
const Frontend::WebBrowserApplet& System::GetWebBrowser() const {
|
||||
return *impl->web_browser;
|
||||
}
|
||||
|
||||
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
|
||||
return impl->Init(*this, emu_window);
|
||||
}
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "frontend/applets/profile_select.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
class ProfileSelectApplet;
|
||||
class SoftwareKeyboardApplet;
|
||||
class WebBrowserApplet;
|
||||
} // namespace Core::Frontend
|
||||
|
||||
namespace FileSys {
|
||||
@@ -242,13 +243,18 @@ public:
|
||||
|
||||
std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
|
||||
|
||||
void SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet);
|
||||
void SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet);
|
||||
|
||||
const Core::Frontend::ProfileSelectApplet& GetProfileSelector() const;
|
||||
const Frontend::ProfileSelectApplet& GetProfileSelector() const;
|
||||
|
||||
void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet);
|
||||
void SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet);
|
||||
|
||||
const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
|
||||
const Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
|
||||
|
||||
void SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet);
|
||||
|
||||
Frontend::WebBrowserApplet& GetWebBrowser();
|
||||
const Frontend::WebBrowserApplet& GetWebBrowser() const;
|
||||
|
||||
private:
|
||||
System();
|
||||
|
||||
@@ -93,14 +93,14 @@ void Cpu::RunLoop(bool tight_loop) {
|
||||
|
||||
if (IsMainCore()) {
|
||||
// TODO(Subv): Only let CoreTiming idle if all 4 cores are idling.
|
||||
CoreTiming::Idle();
|
||||
CoreTiming::Advance();
|
||||
Timing::Idle();
|
||||
Timing::Advance();
|
||||
}
|
||||
|
||||
PrepareReschedule();
|
||||
} else {
|
||||
if (IsMainCore()) {
|
||||
CoreTiming::Advance();
|
||||
Timing::Advance();
|
||||
}
|
||||
|
||||
if (tight_loop) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "core/core_timing_util.h"
|
||||
|
||||
namespace CoreTiming {
|
||||
namespace Core::Timing {
|
||||
|
||||
static s64 global_timer;
|
||||
static int slice_length;
|
||||
@@ -242,4 +242,4 @@ int GetDowncount() {
|
||||
return downcount;
|
||||
}
|
||||
|
||||
} // namespace CoreTiming
|
||||
} // namespace Core::Timing
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace CoreTiming {
|
||||
namespace Core::Timing {
|
||||
|
||||
struct EventType;
|
||||
|
||||
@@ -92,4 +92,4 @@ std::chrono::microseconds GetGlobalTimeUs();
|
||||
|
||||
int GetDowncount();
|
||||
|
||||
} // namespace CoreTiming
|
||||
} // namespace Core::Timing
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <limits>
|
||||
#include "common/logging/log.h"
|
||||
|
||||
namespace CoreTiming {
|
||||
namespace Core::Timing {
|
||||
|
||||
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE;
|
||||
|
||||
@@ -60,4 +60,4 @@ s64 nsToCycles(u64 ns) {
|
||||
return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000;
|
||||
}
|
||||
|
||||
} // namespace CoreTiming
|
||||
} // namespace Core::Timing
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace CoreTiming {
|
||||
namespace Core::Timing {
|
||||
|
||||
// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
|
||||
// The exact value used is of course unverified.
|
||||
@@ -61,4 +61,4 @@ inline u64 cyclesToMs(s64 cycles) {
|
||||
return cycles * 1000 / BASE_CLOCK_RATE;
|
||||
}
|
||||
|
||||
} // namespace CoreTiming
|
||||
} // namespace Core::Timing
|
||||
|
||||
@@ -359,6 +359,8 @@ bool NCA::ReadPFS0Section(const NCASectionHeader& section, const NCASectionTable
|
||||
dirs.push_back(std::move(npfs));
|
||||
if (IsDirectoryExeFS(dirs.back()))
|
||||
exefs = dirs.back();
|
||||
else if (IsDirectoryLogoPartition(dirs.back()))
|
||||
logo = dirs.back();
|
||||
} else {
|
||||
if (has_rights_id)
|
||||
status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek;
|
||||
@@ -546,4 +548,8 @@ u64 NCA::GetBaseIVFCOffset() const {
|
||||
return ivfc_offset;
|
||||
}
|
||||
|
||||
VirtualDir NCA::GetLogoPartition() const {
|
||||
return logo;
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -74,6 +74,13 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) {
|
||||
return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr;
|
||||
}
|
||||
|
||||
inline bool IsDirectoryLogoPartition(const VirtualDir& pfs) {
|
||||
// NintendoLogo is the static image in the top left corner while StartupMovie is the animation
|
||||
// in the bottom right corner.
|
||||
return pfs->GetFile("NintendoLogo.png") != nullptr &&
|
||||
pfs->GetFile("StartupMovie.gif") != nullptr;
|
||||
}
|
||||
|
||||
// An implementation of VfsDirectory that represents a Nintendo Content Archive (NCA) conatiner.
|
||||
// After construction, use GetStatus to determine if the file is valid and ready to be used.
|
||||
class NCA : public ReadOnlyVfsDirectory {
|
||||
@@ -102,6 +109,8 @@ public:
|
||||
// Returns the base ivfc offset used in BKTR patching.
|
||||
u64 GetBaseIVFCOffset() const;
|
||||
|
||||
VirtualDir GetLogoPartition() const;
|
||||
|
||||
private:
|
||||
bool CheckSupportedNCA(const NCAHeader& header);
|
||||
bool HandlePotentialHeaderDecryption();
|
||||
@@ -122,6 +131,7 @@ private:
|
||||
|
||||
VirtualFile romfs = nullptr;
|
||||
VirtualDir exefs = nullptr;
|
||||
VirtualDir logo = nullptr;
|
||||
VirtualFile file;
|
||||
VirtualFile bktr_base_romfs;
|
||||
u64 ivfc_offset = 0;
|
||||
|
||||
@@ -39,27 +39,4 @@ static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x31
|
||||
static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry.");
|
||||
static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry.");
|
||||
|
||||
class DirectoryBackend : NonCopyable {
|
||||
public:
|
||||
DirectoryBackend() {}
|
||||
virtual ~DirectoryBackend() {}
|
||||
|
||||
/**
|
||||
* List files contained in the directory
|
||||
* @param count Number of entries to return at once in entries
|
||||
* @param entries Buffer to read data into
|
||||
* @return Number of entries listed
|
||||
*/
|
||||
virtual u64 Read(const u64 count, Entry* entries) = 0;
|
||||
|
||||
/// Returns the number of entries still left to read.
|
||||
virtual u64 GetEntryCount() const = 0;
|
||||
|
||||
/**
|
||||
* Close the directory
|
||||
* @return true if the directory closed correctly
|
||||
*/
|
||||
virtual bool Close() const = 0;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -119,6 +119,9 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) {
|
||||
|
||||
VirtualDir out = std::move(root);
|
||||
|
||||
if (type == RomFSExtractionType::SingleDiscard)
|
||||
return out->GetSubdirectories().front();
|
||||
|
||||
while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) {
|
||||
if (out->GetSubdirectories().front()->GetName() == "data" &&
|
||||
type == RomFSExtractionType::Truncated)
|
||||
|
||||
@@ -33,8 +33,9 @@ struct IVFCHeader {
|
||||
static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size.");
|
||||
|
||||
enum class RomFSExtractionType {
|
||||
Full, // Includes data directory
|
||||
Truncated, // Traverses into data directory
|
||||
Full, // Includes data directory
|
||||
Truncated, // Traverses into data directory
|
||||
SingleDiscard, // Traverses into the first subdirectory of root
|
||||
};
|
||||
|
||||
// Converts a RomFS binary blob to VFS Filesystem
|
||||
|
||||
24
src/core/frontend/applets/web_browser.cpp
Normal file
24
src/core/frontend/applets/web_browser.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
WebBrowserApplet::~WebBrowserApplet() = default;
|
||||
|
||||
DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
|
||||
|
||||
void DefaultWebBrowserApplet::OpenPage(std::string_view filename,
|
||||
std::function<void()> unpack_romfs_callback,
|
||||
std::function<void()> finished_callback) {
|
||||
LOG_INFO(Service_AM,
|
||||
"(STUBBED) called - No suitable web browser implementation found to open website page "
|
||||
"at '{}'!",
|
||||
filename);
|
||||
finished_callback();
|
||||
}
|
||||
|
||||
} // namespace Core::Frontend
|
||||
28
src/core/frontend/applets/web_browser.h
Normal file
28
src/core/frontend/applets/web_browser.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
class WebBrowserApplet {
|
||||
public:
|
||||
virtual ~WebBrowserApplet();
|
||||
|
||||
virtual void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
|
||||
std::function<void()> finished_callback) = 0;
|
||||
};
|
||||
|
||||
class DefaultWebBrowserApplet final : public WebBrowserApplet {
|
||||
public:
|
||||
~DefaultWebBrowserApplet() override;
|
||||
|
||||
void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
|
||||
std::function<void()> finished_callback) override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
18
src/core/frontend/scope_acquire_window_context.cpp
Normal file
18
src/core/frontend/scope_acquire_window_context.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/frontend/scope_acquire_window_context.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
ScopeAcquireWindowContext::ScopeAcquireWindowContext(Core::Frontend::EmuWindow& emu_window_)
|
||||
: emu_window{emu_window_} {
|
||||
emu_window.MakeCurrent();
|
||||
}
|
||||
ScopeAcquireWindowContext::~ScopeAcquireWindowContext() {
|
||||
emu_window.DoneCurrent();
|
||||
}
|
||||
|
||||
} // namespace Core::Frontend
|
||||
23
src/core/frontend/scope_acquire_window_context.h
Normal file
23
src/core/frontend/scope_acquire_window_context.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
class EmuWindow;
|
||||
|
||||
/// Helper class to acquire/release window context within a given scope
|
||||
class ScopeAcquireWindowContext : NonCopyable {
|
||||
public:
|
||||
explicit ScopeAcquireWindowContext(Core::Frontend::EmuWindow& window);
|
||||
~ScopeAcquireWindowContext();
|
||||
|
||||
private:
|
||||
Core::Frontend::EmuWindow& emu_window;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
@@ -507,8 +507,11 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
|
||||
|
||||
LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}",
|
||||
bp->second.len, bp->second.addr, static_cast<int>(type));
|
||||
Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
|
||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||
|
||||
if (type == BreakpointType::Execute) {
|
||||
Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
|
||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||
}
|
||||
p.erase(addr);
|
||||
}
|
||||
|
||||
@@ -1057,9 +1060,12 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
|
||||
breakpoint.addr = addr;
|
||||
breakpoint.len = len;
|
||||
Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
|
||||
|
||||
static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
|
||||
Memory::WriteBlock(addr, btrap.data(), btrap.size());
|
||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||
if (type == BreakpointType::Execute) {
|
||||
Memory::WriteBlock(addr, btrap.data(), btrap.size());
|
||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||
}
|
||||
p.insert({addr, breakpoint});
|
||||
|
||||
LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}",
|
||||
|
||||
@@ -216,6 +216,11 @@ private:
|
||||
|
||||
/// Push ///
|
||||
|
||||
template <>
|
||||
inline void ResponseBuilder::Push(s32 value) {
|
||||
cmdbuf[index++] = static_cast<u32>(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ResponseBuilder::Push(u32 value) {
|
||||
cmdbuf[index++] = value;
|
||||
@@ -234,6 +239,22 @@ inline void ResponseBuilder::Push(ResultCode value) {
|
||||
Push<u32>(0);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ResponseBuilder::Push(s8 value) {
|
||||
PushRaw(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ResponseBuilder::Push(s16 value) {
|
||||
PushRaw(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ResponseBuilder::Push(s64 value) {
|
||||
Push(static_cast<u32>(value));
|
||||
Push(static_cast<u32>(value >> 32));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ResponseBuilder::Push(u8 value) {
|
||||
PushRaw(value);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/timer.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
@@ -86,27 +85,12 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
|
||||
}
|
||||
}
|
||||
|
||||
/// The timer callback event, called when a timer is fired
|
||||
static void TimerCallback(u64 timer_handle, int cycles_late) {
|
||||
const auto proper_handle = static_cast<Handle>(timer_handle);
|
||||
const auto& system = Core::System::GetInstance();
|
||||
SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle);
|
||||
|
||||
if (timer == nullptr) {
|
||||
LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
timer->Signal(cycles_late);
|
||||
}
|
||||
|
||||
struct KernelCore::Impl {
|
||||
void Initialize(KernelCore& kernel) {
|
||||
Shutdown();
|
||||
|
||||
InitializeSystemResourceLimit(kernel);
|
||||
InitializeThreads();
|
||||
InitializeTimers();
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
@@ -122,9 +106,6 @@ struct KernelCore::Impl {
|
||||
thread_wakeup_callback_handle_table.Clear();
|
||||
thread_wakeup_event_type = nullptr;
|
||||
|
||||
timer_callback_handle_table.Clear();
|
||||
timer_callback_event_type = nullptr;
|
||||
|
||||
named_ports.clear();
|
||||
}
|
||||
|
||||
@@ -143,12 +124,7 @@ struct KernelCore::Impl {
|
||||
|
||||
void InitializeThreads() {
|
||||
thread_wakeup_event_type =
|
||||
CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
|
||||
}
|
||||
|
||||
void InitializeTimers() {
|
||||
timer_callback_handle_table.Clear();
|
||||
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
|
||||
Core::Timing::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
|
||||
}
|
||||
|
||||
std::atomic<u32> next_object_id{0};
|
||||
@@ -161,13 +137,7 @@ struct KernelCore::Impl {
|
||||
|
||||
SharedPtr<ResourceLimit> system_resource_limit;
|
||||
|
||||
/// The event type of the generic timer callback event
|
||||
CoreTiming::EventType* timer_callback_event_type = nullptr;
|
||||
// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future,
|
||||
// allowing us to simply use a pool index or similar.
|
||||
Kernel::HandleTable timer_callback_handle_table;
|
||||
|
||||
CoreTiming::EventType* thread_wakeup_event_type = nullptr;
|
||||
Core::Timing::EventType* thread_wakeup_event_type = nullptr;
|
||||
// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
|
||||
// allowing us to simply use a pool index or similar.
|
||||
Kernel::HandleTable thread_wakeup_callback_handle_table;
|
||||
@@ -198,10 +168,6 @@ SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle
|
||||
return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle);
|
||||
}
|
||||
|
||||
SharedPtr<Timer> KernelCore::RetrieveTimerFromCallbackHandleTable(Handle handle) const {
|
||||
return impl->timer_callback_handle_table.Get<Timer>(handle);
|
||||
}
|
||||
|
||||
void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
|
||||
impl->process_list.push_back(std::move(process));
|
||||
}
|
||||
@@ -247,18 +213,10 @@ u64 KernelCore::CreateNewProcessID() {
|
||||
return impl->next_process_id++;
|
||||
}
|
||||
|
||||
ResultVal<Handle> KernelCore::CreateTimerCallbackHandle(const SharedPtr<Timer>& timer) {
|
||||
return impl->timer_callback_handle_table.Create(timer);
|
||||
}
|
||||
|
||||
CoreTiming::EventType* KernelCore::ThreadWakeupCallbackEventType() const {
|
||||
Core::Timing::EventType* KernelCore::ThreadWakeupCallbackEventType() const {
|
||||
return impl->thread_wakeup_event_type;
|
||||
}
|
||||
|
||||
CoreTiming::EventType* KernelCore::TimerCallbackEventType() const {
|
||||
return impl->timer_callback_event_type;
|
||||
}
|
||||
|
||||
Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() {
|
||||
return impl->thread_wakeup_callback_handle_table;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
template <typename T>
|
||||
class ResultVal;
|
||||
|
||||
namespace CoreTiming {
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ class HandleTable;
|
||||
class Process;
|
||||
class ResourceLimit;
|
||||
class Thread;
|
||||
class Timer;
|
||||
|
||||
/// Represents a single instance of the kernel.
|
||||
class KernelCore {
|
||||
@@ -51,9 +50,6 @@ public:
|
||||
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
|
||||
SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
|
||||
|
||||
/// Retrieves a shared pointer to a Timer instance within the timer callback handle table.
|
||||
SharedPtr<Timer> RetrieveTimerFromCallbackHandleTable(Handle handle) const;
|
||||
|
||||
/// Adds the given shared pointer to an internal list of active processes.
|
||||
void AppendNewProcess(SharedPtr<Process> process);
|
||||
|
||||
@@ -82,7 +78,6 @@ private:
|
||||
friend class Object;
|
||||
friend class Process;
|
||||
friend class Thread;
|
||||
friend class Timer;
|
||||
|
||||
/// Creates a new object ID, incrementing the internal object ID counter.
|
||||
u32 CreateNewObjectID();
|
||||
@@ -93,14 +88,8 @@ private:
|
||||
/// Creates a new thread ID, incrementing the internal thread ID counter.
|
||||
u64 CreateNewThreadID();
|
||||
|
||||
/// Creates a timer callback handle for the given timer.
|
||||
ResultVal<Handle> CreateTimerCallbackHandle(const SharedPtr<Timer>& timer);
|
||||
|
||||
/// Retrieves the event type used for thread wakeup callbacks.
|
||||
CoreTiming::EventType* ThreadWakeupCallbackEventType() const;
|
||||
|
||||
/// Retrieves the event type used for timer callbacks.
|
||||
CoreTiming::EventType* TimerCallbackEventType() const;
|
||||
Core::Timing::EventType* ThreadWakeupCallbackEventType() const;
|
||||
|
||||
/// Provides a reference to the thread wakeup callback handle table.
|
||||
Kernel::HandleTable& ThreadWakeupCallbackHandleTable();
|
||||
|
||||
@@ -16,7 +16,6 @@ bool Object::IsWaitable() const {
|
||||
case HandleType::ReadableEvent:
|
||||
case HandleType::Thread:
|
||||
case HandleType::Process:
|
||||
case HandleType::Timer:
|
||||
case HandleType::ServerPort:
|
||||
case HandleType::ServerSession:
|
||||
return true;
|
||||
|
||||
@@ -25,7 +25,6 @@ enum class HandleType : u32 {
|
||||
Thread,
|
||||
Process,
|
||||
AddressArbiter,
|
||||
Timer,
|
||||
ResourceLimit,
|
||||
ClientPort,
|
||||
ServerPort,
|
||||
@@ -36,7 +35,6 @@ enum class HandleType : u32 {
|
||||
enum class ResetType {
|
||||
OneShot, ///< Reset automatically on object acquisition
|
||||
Sticky, ///< Never reset automatically
|
||||
Pulse, ///< Reset automatically on wakeup
|
||||
};
|
||||
|
||||
class Object : NonCopyable {
|
||||
|
||||
@@ -44,11 +44,4 @@ ResultCode ReadableEvent::Reset() {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void ReadableEvent::WakeupAllWaitingThreads() {
|
||||
WaitObject::WakeupAllWaitingThreads();
|
||||
|
||||
if (reset_type == ResetType::Pulse)
|
||||
signaled = false;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -39,8 +39,6 @@ public:
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
void WakeupAllWaitingThreads() override;
|
||||
|
||||
/// Unconditionally clears the readable event's state.
|
||||
void Clear();
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
|
||||
|
||||
void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
|
||||
const u64 prev_switch_ticks = last_context_switch_time;
|
||||
const u64 most_recent_switch_ticks = CoreTiming::GetTicks();
|
||||
const u64 most_recent_switch_ticks = Core::Timing::GetTicks();
|
||||
const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
|
||||
|
||||
if (thread != nullptr) {
|
||||
|
||||
@@ -597,6 +597,7 @@ enum class BreakType : u32 {
|
||||
PostNROLoad = 4,
|
||||
PreNROUnload = 5,
|
||||
PostNROUnload = 6,
|
||||
CppException = 7,
|
||||
};
|
||||
|
||||
struct BreakReason {
|
||||
@@ -669,6 +670,9 @@ static void Break(u32 reason, u64 info1, u64 info2) {
|
||||
"Signalling debugger, Unloaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
|
||||
info2);
|
||||
break;
|
||||
case BreakType::CppException:
|
||||
LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered.");
|
||||
break;
|
||||
default:
|
||||
LOG_WARNING(
|
||||
Debug_Emulated,
|
||||
@@ -923,9 +927,9 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
|
||||
const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
|
||||
|
||||
out_ticks = thread_ticks + (CoreTiming::GetTicks() - prev_ctx_ticks);
|
||||
out_ticks = thread_ticks + (Core::Timing::GetTicks() - prev_ctx_ticks);
|
||||
} else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
|
||||
out_ticks = CoreTiming::GetTicks() - prev_ctx_ticks;
|
||||
out_ticks = Core::Timing::GetTicks() - prev_ctx_ticks;
|
||||
}
|
||||
|
||||
*result = out_ticks;
|
||||
@@ -1542,10 +1546,10 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
|
||||
static u64 GetSystemTick() {
|
||||
LOG_TRACE(Kernel_SVC, "called");
|
||||
|
||||
const u64 result{CoreTiming::GetTicks()};
|
||||
const u64 result{Core::Timing::GetTicks()};
|
||||
|
||||
// Advance time to defeat dumb games that busy-wait for the frame to end.
|
||||
CoreTiming::AddTicks(400);
|
||||
Core::Timing::AddTicks(400);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ Thread::~Thread() = default;
|
||||
|
||||
void Thread::Stop() {
|
||||
// Cancel any outstanding wakeup events for this thread
|
||||
CoreTiming::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle);
|
||||
Core::Timing::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle);
|
||||
kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
|
||||
callback_handle = 0;
|
||||
|
||||
@@ -85,12 +85,13 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
|
||||
|
||||
// This function might be called from any thread so we have to be cautious and use the
|
||||
// thread-safe version of ScheduleEvent.
|
||||
CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds),
|
||||
kernel.ThreadWakeupCallbackEventType(), callback_handle);
|
||||
Core::Timing::ScheduleEventThreadsafe(Core::Timing::nsToCycles(nanoseconds),
|
||||
kernel.ThreadWakeupCallbackEventType(), callback_handle);
|
||||
}
|
||||
|
||||
void Thread::CancelWakeupTimer() {
|
||||
CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle);
|
||||
Core::Timing::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(),
|
||||
callback_handle);
|
||||
}
|
||||
|
||||
static std::optional<s32> GetNextProcessorId(u64 mask) {
|
||||
@@ -197,7 +198,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
|
||||
thread->stack_top = stack_top;
|
||||
thread->tpidr_el0 = 0;
|
||||
thread->nominal_priority = thread->current_priority = priority;
|
||||
thread->last_running_ticks = CoreTiming::GetTicks();
|
||||
thread->last_running_ticks = Core::Timing::GetTicks();
|
||||
thread->processor_id = processor_id;
|
||||
thread->ideal_core = processor_id;
|
||||
thread->affinity_mask = 1ULL << processor_id;
|
||||
@@ -257,7 +258,7 @@ void Thread::SetStatus(ThreadStatus new_status) {
|
||||
}
|
||||
|
||||
if (status == ThreadStatus::Running) {
|
||||
last_running_ticks = CoreTiming::GetTicks();
|
||||
last_running_ticks = Core::Timing::GetTicks();
|
||||
}
|
||||
|
||||
status = new_status;
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/timer.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Timer::Timer(KernelCore& kernel) : WaitObject{kernel} {}
|
||||
Timer::~Timer() = default;
|
||||
|
||||
SharedPtr<Timer> Timer::Create(KernelCore& kernel, ResetType reset_type, std::string name) {
|
||||
SharedPtr<Timer> timer(new Timer(kernel));
|
||||
|
||||
timer->reset_type = reset_type;
|
||||
timer->signaled = false;
|
||||
timer->name = std::move(name);
|
||||
timer->initial_delay = 0;
|
||||
timer->interval_delay = 0;
|
||||
timer->callback_handle = kernel.CreateTimerCallbackHandle(timer).Unwrap();
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
bool Timer::ShouldWait(Thread* thread) const {
|
||||
return !signaled;
|
||||
}
|
||||
|
||||
void Timer::Acquire(Thread* thread) {
|
||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||
|
||||
if (reset_type == ResetType::OneShot)
|
||||
signaled = false;
|
||||
}
|
||||
|
||||
void Timer::Set(s64 initial, s64 interval) {
|
||||
// Ensure we get rid of any previous scheduled event
|
||||
Cancel();
|
||||
|
||||
initial_delay = initial;
|
||||
interval_delay = interval;
|
||||
|
||||
if (initial == 0) {
|
||||
// Immediately invoke the callback
|
||||
Signal(0);
|
||||
} else {
|
||||
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(initial), kernel.TimerCallbackEventType(),
|
||||
callback_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::Cancel() {
|
||||
CoreTiming::UnscheduleEvent(kernel.TimerCallbackEventType(), callback_handle);
|
||||
}
|
||||
|
||||
void Timer::Clear() {
|
||||
signaled = false;
|
||||
}
|
||||
|
||||
void Timer::WakeupAllWaitingThreads() {
|
||||
WaitObject::WakeupAllWaitingThreads();
|
||||
|
||||
if (reset_type == ResetType::Pulse)
|
||||
signaled = false;
|
||||
}
|
||||
|
||||
void Timer::Signal(int cycles_late) {
|
||||
LOG_TRACE(Kernel, "Timer {} fired", GetObjectId());
|
||||
|
||||
signaled = true;
|
||||
|
||||
// Resume all waiting threads
|
||||
WakeupAllWaitingThreads();
|
||||
|
||||
if (interval_delay != 0) {
|
||||
// Reschedule the timer with the interval delay
|
||||
CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(interval_delay) - cycles_late,
|
||||
kernel.TimerCallbackEventType(), callback_handle);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
|
||||
class Timer final : public WaitObject {
|
||||
public:
|
||||
/**
|
||||
* Creates a timer
|
||||
* @param kernel The kernel instance to create the timer callback handle for.
|
||||
* @param reset_type ResetType describing how to create the timer
|
||||
* @param name Optional name of timer
|
||||
* @return The created Timer
|
||||
*/
|
||||
static SharedPtr<Timer> Create(KernelCore& kernel, ResetType reset_type,
|
||||
std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "Timer";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Timer;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
ResetType GetResetType() const {
|
||||
return reset_type;
|
||||
}
|
||||
|
||||
u64 GetInitialDelay() const {
|
||||
return initial_delay;
|
||||
}
|
||||
|
||||
u64 GetIntervalDelay() const {
|
||||
return interval_delay;
|
||||
}
|
||||
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
void WakeupAllWaitingThreads() override;
|
||||
|
||||
/**
|
||||
* Starts the timer, with the specified initial delay and interval.
|
||||
* @param initial Delay until the timer is first fired
|
||||
* @param interval Delay until the timer is fired after the first time
|
||||
*/
|
||||
void Set(s64 initial, s64 interval);
|
||||
|
||||
void Cancel();
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* Signals the timer, waking up any waiting threads and rescheduling it
|
||||
* for the next interval.
|
||||
* This method should not be called from outside the timer callback handler,
|
||||
* lest multiple callback events get scheduled.
|
||||
*/
|
||||
void Signal(int cycles_late);
|
||||
|
||||
private:
|
||||
explicit Timer(KernelCore& kernel);
|
||||
~Timer() override;
|
||||
|
||||
ResetType reset_type; ///< The ResetType of this timer
|
||||
|
||||
u64 initial_delay; ///< The delay until the timer fires for the first time
|
||||
u64 interval_delay; ///< The delay until the timer fires after the first time
|
||||
|
||||
bool signaled; ///< Whether the timer has been signaled or not
|
||||
std::string name; ///< Name of timer (optional)
|
||||
|
||||
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
|
||||
Handle callback_handle;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -33,19 +33,19 @@ public:
|
||||
* Add a thread to wait on this object
|
||||
* @param thread Pointer to thread to add
|
||||
*/
|
||||
virtual void AddWaitingThread(SharedPtr<Thread> thread);
|
||||
void AddWaitingThread(SharedPtr<Thread> thread);
|
||||
|
||||
/**
|
||||
* Removes a thread from waiting on this object (e.g. if it was resumed already)
|
||||
* @param thread Pointer to thread to remove
|
||||
*/
|
||||
virtual void RemoveWaitingThread(Thread* thread);
|
||||
void RemoveWaitingThread(Thread* thread);
|
||||
|
||||
/**
|
||||
* Wake up all threads waiting on this object that can be awoken, in priority order,
|
||||
* and set the synchronization result and output of the thread.
|
||||
*/
|
||||
virtual void WakeupAllWaitingThreads();
|
||||
void WakeupAllWaitingThreads();
|
||||
|
||||
/**
|
||||
* Wakes up a single thread waiting on this object.
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "core/hle/service/am/applets/profile_select.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/stub_applet.h"
|
||||
#include "core/hle/service/am/applets/web_browser.h"
|
||||
#include "core/hle/service/am/idle.h"
|
||||
#include "core/hle/service/am/omm.h"
|
||||
#include "core/hle/service/am/spsm.h"
|
||||
@@ -38,11 +39,13 @@
|
||||
namespace Service::AM {
|
||||
|
||||
constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2};
|
||||
constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3};
|
||||
constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
|
||||
|
||||
enum class AppletId : u32 {
|
||||
ProfileSelect = 0x10,
|
||||
SoftwareKeyboard = 0x11,
|
||||
LibAppletOff = 0x17,
|
||||
};
|
||||
|
||||
constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA;
|
||||
@@ -319,14 +322,15 @@ void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& c
|
||||
|
||||
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
u64 display_id = nvflinger->OpenDisplay("Default");
|
||||
u64 layer_id = nvflinger->CreateLayer(display_id);
|
||||
const auto display_id = nvflinger->OpenDisplay("Default");
|
||||
const auto layer_id = nvflinger->CreateLayer(*display_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(layer_id);
|
||||
rb.Push(*layer_id);
|
||||
}
|
||||
|
||||
void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
|
||||
@@ -460,9 +464,17 @@ void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
const auto message = msg_queue->PopMessage();
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
||||
if (message == AppletMessageQueue::AppletMessage::NoMessage) {
|
||||
LOG_ERROR(Service_AM, "Message queue is empty");
|
||||
rb.Push(ERR_NO_MESSAGES);
|
||||
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
|
||||
return;
|
||||
}
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage());
|
||||
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
|
||||
@@ -721,10 +733,10 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const u64 offset{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
|
||||
const std::vector<u8> data{ctx.ReadBuffer()};
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
|
||||
|
||||
if (data.size() > backing.buffer.size() - offset) {
|
||||
LOG_ERROR(Service_AM,
|
||||
"offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
|
||||
@@ -744,10 +756,10 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const u64 offset{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
|
||||
const std::size_t size{ctx.GetWriteBufferSize()};
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
|
||||
|
||||
if (size > backing.buffer.size() - offset) {
|
||||
LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
|
||||
backing.buffer.size(), size, offset);
|
||||
@@ -782,6 +794,8 @@ static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
|
||||
return std::make_shared<Applets::ProfileSelect>();
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return std::make_shared<Applets::SoftwareKeyboard>();
|
||||
case AppletId::LibAppletOff:
|
||||
return std::make_shared<Applets::WebBrowser>();
|
||||
default:
|
||||
LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!",
|
||||
static_cast<u32>(id));
|
||||
|
||||
@@ -249,7 +249,8 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
{300, nullptr, "OpenOverlayAppletProxy"},
|
||||
{350, nullptr, "OpenSystemApplicationProxy"},
|
||||
{400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
|
||||
{401, nullptr, "GetSystemAppletControllerForDebug"},
|
||||
{410, nullptr, "GetSystemAppletControllerForDebug"},
|
||||
{1000, nullptr, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/profile_select.h"
|
||||
|
||||
|
||||
190
src/core/hle/service/am/applets/web_browser.cpp
Normal file
190
src/core/hle/service/am/applets/web_browser.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_paths.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/mode.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/romfs.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/service/am/applets/web_browser.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not
|
||||
// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant,
|
||||
// but some may be worth an implementation.
|
||||
constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6;
|
||||
|
||||
struct WebBufferHeader {
|
||||
u16 count;
|
||||
INSERT_PADDING_BYTES(6);
|
||||
};
|
||||
static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size.");
|
||||
|
||||
struct WebArgumentHeader {
|
||||
u16 type;
|
||||
u16 size;
|
||||
u32 offset;
|
||||
};
|
||||
static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size.");
|
||||
|
||||
struct WebArgumentResult {
|
||||
u32 result_code;
|
||||
std::array<char, 0x1000> last_url;
|
||||
u64 last_url_size;
|
||||
};
|
||||
static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size.");
|
||||
|
||||
static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) {
|
||||
WebBufferHeader header;
|
||||
ASSERT(sizeof(WebBufferHeader) <= data.size());
|
||||
std::memcpy(&header, data.data(), sizeof(WebBufferHeader));
|
||||
|
||||
u64 offset = sizeof(WebBufferHeader);
|
||||
for (u16 i = 0; i < header.count; ++i) {
|
||||
WebArgumentHeader arg;
|
||||
ASSERT(offset + sizeof(WebArgumentHeader) <= data.size());
|
||||
std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader));
|
||||
offset += sizeof(WebArgumentHeader);
|
||||
|
||||
if (arg.type == type) {
|
||||
std::vector<u8> out(arg.size);
|
||||
offset += arg.offset;
|
||||
ASSERT(offset + arg.size <= data.size());
|
||||
std::memcpy(out.data(), data.data() + offset, out.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
offset += arg.offset + arg.size;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static FileSys::VirtualFile GetManualRomFS() {
|
||||
auto& loader{Core::System::GetInstance().GetAppLoader()};
|
||||
|
||||
FileSys::VirtualFile out;
|
||||
if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success)
|
||||
return out;
|
||||
|
||||
const auto& installed{FileSystem::GetUnionContents()};
|
||||
const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(),
|
||||
FileSys::ContentRecordType::Manual);
|
||||
|
||||
if (res != nullptr)
|
||||
return res->GetRomFS();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WebBrowser::WebBrowser() = default;
|
||||
|
||||
WebBrowser::~WebBrowser() = default;
|
||||
|
||||
void WebBrowser::Initialize() {
|
||||
Applet::Initialize();
|
||||
|
||||
complete = false;
|
||||
temporary_dir.clear();
|
||||
filename.clear();
|
||||
status = RESULT_SUCCESS;
|
||||
|
||||
const auto web_arg_storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(web_arg_storage != nullptr);
|
||||
const auto& web_arg = web_arg_storage->GetData();
|
||||
|
||||
const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE);
|
||||
filename = Common::StringFromFixedZeroTerminatedBuffer(
|
||||
reinterpret_cast<const char*>(url_data.data()), url_data.size());
|
||||
|
||||
temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
|
||||
"web_applet_manual",
|
||||
FileUtil::DirectorySeparator::PlatformDefault);
|
||||
FileUtil::DeleteDirRecursively(temporary_dir);
|
||||
|
||||
manual_romfs = GetManualRomFS();
|
||||
if (manual_romfs == nullptr) {
|
||||
status = ResultCode(-1);
|
||||
LOG_ERROR(Service_AM, "Failed to find manual for current process!");
|
||||
}
|
||||
|
||||
filename =
|
||||
FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename,
|
||||
FileUtil::DirectorySeparator::PlatformDefault);
|
||||
}
|
||||
|
||||
bool WebBrowser::TransactionComplete() const {
|
||||
return complete;
|
||||
}
|
||||
|
||||
ResultCode WebBrowser::GetStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
void WebBrowser::ExecuteInteractive() {
|
||||
UNIMPLEMENTED_MSG("Unexpected interactive data recieved!");
|
||||
}
|
||||
|
||||
void WebBrowser::Execute() {
|
||||
if (complete)
|
||||
return;
|
||||
|
||||
if (status != RESULT_SUCCESS) {
|
||||
complete = true;
|
||||
return;
|
||||
}
|
||||
|
||||
auto& frontend{Core::System::GetInstance().GetWebBrowser()};
|
||||
|
||||
frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
|
||||
}
|
||||
|
||||
void WebBrowser::UnpackRomFS() {
|
||||
if (unpacked)
|
||||
return;
|
||||
|
||||
ASSERT(manual_romfs != nullptr);
|
||||
const auto dir =
|
||||
FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard);
|
||||
const auto& vfs{Core::System::GetInstance().GetFilesystem()};
|
||||
const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);
|
||||
FileSys::VfsRawCopyD(dir, temp_dir);
|
||||
|
||||
unpacked = true;
|
||||
}
|
||||
|
||||
void WebBrowser::Finalize() {
|
||||
complete = true;
|
||||
|
||||
WebArgumentResult out{};
|
||||
out.result_code = 0;
|
||||
out.last_url_size = 0;
|
||||
|
||||
std::vector<u8> data(sizeof(WebArgumentResult));
|
||||
std::memcpy(data.data(), &out, sizeof(WebArgumentResult));
|
||||
|
||||
broker.PushNormalDataFromApplet(IStorage{data});
|
||||
broker.SignalStateChanged();
|
||||
|
||||
FileUtil::DeleteDirRecursively(temporary_dir);
|
||||
}
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
44
src/core/hle/service/am/applets/web_browser.h
Normal file
44
src/core/hle/service/am/applets/web_browser.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
class WebBrowser final : public Applet {
|
||||
public:
|
||||
WebBrowser();
|
||||
~WebBrowser() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
ResultCode GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
||||
// Callback to be fired when the frontend needs the manual RomFS unpacked to temporary
|
||||
// directory. This is a blocking call and may take a while as some manuals can be up to 100MB in
|
||||
// size. Attempting to access files at filename before invocation is likely to not work.
|
||||
void UnpackRomFS();
|
||||
|
||||
// Callback to be fired when the frontend is finished browsing. This will delete the temporary
|
||||
// manual RomFS extracted files, so ensure this is only called at actual finalization.
|
||||
void Finalize();
|
||||
|
||||
private:
|
||||
bool complete = false;
|
||||
bool unpacked = false;
|
||||
ResultCode status = RESULT_SUCCESS;
|
||||
|
||||
FileSys::VirtualFile manual_romfs;
|
||||
std::string temporary_dir;
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
@@ -12,6 +12,7 @@ namespace Service::Audio {
|
||||
class IAudioIn final : public ServiceFramework<IAudioIn> {
|
||||
public:
|
||||
IAudioIn() : ServiceFramework("IAudioIn") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetAudioInState"},
|
||||
{1, nullptr, "StartAudioIn"},
|
||||
@@ -28,16 +29,24 @@ public:
|
||||
{12, nullptr, "SetAudioInDeviceGain"},
|
||||
{13, nullptr, "GetAudioInDeviceGain"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~IAudioIn() = default;
|
||||
};
|
||||
|
||||
AudInU::AudInU() : ServiceFramework("audin:u") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "ListAudioIns"}, {1, nullptr, "OpenAudioIn"}, {2, nullptr, "Unknown"},
|
||||
{3, nullptr, "OpenAudioInAuto"}, {4, nullptr, "ListAudioInsAuto"},
|
||||
{0, nullptr, "ListAudioIns"},
|
||||
{1, nullptr, "OpenAudioIn"},
|
||||
{2, nullptr, "Unknown"},
|
||||
{3, nullptr, "OpenAudioInAuto"},
|
||||
{4, nullptr, "ListAudioInsAuto"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Service::Audio {
|
||||
class IFinalOutputRecorder final : public ServiceFramework<IFinalOutputRecorder> {
|
||||
public:
|
||||
IFinalOutputRecorder() : ServiceFramework("IFinalOutputRecorder") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetFinalOutputRecorderState"},
|
||||
{1, nullptr, "StartFinalOutputRecorder"},
|
||||
@@ -20,10 +21,13 @@ public:
|
||||
{4, nullptr, "RegisterBufferEvent"},
|
||||
{5, nullptr, "GetReleasedFinalOutputRecorderBuffer"},
|
||||
{6, nullptr, "ContainsFinalOutputRecorderBuffer"},
|
||||
{7, nullptr, "Unknown"},
|
||||
{7, nullptr, "GetFinalOutputRecorderBufferEndTime"},
|
||||
{8, nullptr, "AppendFinalOutputRecorderBufferAuto"},
|
||||
{9, nullptr, "GetReleasedFinalOutputRecorderBufferAuto"},
|
||||
{10, nullptr, "FlushFinalOutputRecorderBuffers"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~IFinalOutputRecorder() = default;
|
||||
|
||||
@@ -229,14 +229,16 @@ private:
|
||||
}; // namespace Audio
|
||||
|
||||
AudRenU::AudRenU() : ServiceFramework("audren:u") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
|
||||
{1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
|
||||
{2, &AudRenU::GetAudioDevice, "GetAudioDevice"},
|
||||
{2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
|
||||
{3, nullptr, "OpenAudioRendererAuto"},
|
||||
{4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo,
|
||||
"GetAudioDeviceServiceWithRevisionInfo"},
|
||||
{4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -313,7 +315,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", output_sz);
|
||||
}
|
||||
|
||||
void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
|
||||
void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
private:
|
||||
void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
|
||||
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
|
||||
void GetAudioDevice(Kernel::HLERequestContext& ctx);
|
||||
void GetAudioDeviceService(Kernel::HLERequestContext& ctx);
|
||||
void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx);
|
||||
|
||||
enum class AudioFeatures : u32 {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <opus.h>
|
||||
@@ -30,48 +29,66 @@ public:
|
||||
u32 channel_count)
|
||||
: ServiceFramework("IHardwareOpusDecoderManager"), decoder(std::move(decoder)),
|
||||
sample_rate(sample_rate), channel_count(channel_count) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
|
||||
{0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"},
|
||||
{1, nullptr, "SetContext"},
|
||||
{2, nullptr, "DecodeInterleavedForMultiStream"},
|
||||
{2, nullptr, "DecodeInterleavedForMultiStreamOld"},
|
||||
{3, nullptr, "SetContextForMultiStream"},
|
||||
{4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerformance,
|
||||
"DecodeInterleavedWithPerformance"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
|
||||
{5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"},
|
||||
{6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
|
||||
{7, nullptr, "DecodeInterleavedForMultiStream"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Describes extra behavior that may be asked of the decoding context.
|
||||
enum class ExtraBehavior {
|
||||
/// No extra behavior.
|
||||
None,
|
||||
|
||||
/// Resets the decoder context back to a freshly initialized state.
|
||||
ResetContext,
|
||||
};
|
||||
|
||||
void DecodeInterleavedOld(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called");
|
||||
|
||||
DecodeInterleavedHelper(ctx, nullptr, ExtraBehavior::None);
|
||||
}
|
||||
|
||||
void DecodeInterleavedWithPerfOld(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called");
|
||||
|
||||
u64 performance = 0;
|
||||
DecodeInterleavedHelper(ctx, &performance, ExtraBehavior::None);
|
||||
}
|
||||
|
||||
void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called");
|
||||
|
||||
u32 consumed = 0;
|
||||
u32 sample_count = 0;
|
||||
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
|
||||
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) {
|
||||
LOG_ERROR(Audio, "Failed to decode opus data");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(ogniK): Use correct error code
|
||||
rb.Push(ResultCode(-1));
|
||||
return;
|
||||
}
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(consumed);
|
||||
rb.Push<u32>(sample_count);
|
||||
ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto extra_behavior =
|
||||
rp.Pop<bool>() ? ExtraBehavior::ResetContext : ExtraBehavior::None;
|
||||
|
||||
u64 performance = 0;
|
||||
DecodeInterleavedHelper(ctx, &performance, extra_behavior);
|
||||
}
|
||||
|
||||
void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called");
|
||||
|
||||
void DecodeInterleavedHelper(Kernel::HLERequestContext& ctx, u64* performance,
|
||||
ExtraBehavior extra_behavior) {
|
||||
u32 consumed = 0;
|
||||
u32 sample_count = 0;
|
||||
u64 performance = 0;
|
||||
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
|
||||
|
||||
if (extra_behavior == ExtraBehavior::ResetContext) {
|
||||
ResetDecoderContext();
|
||||
}
|
||||
|
||||
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples,
|
||||
performance)) {
|
||||
LOG_ERROR(Audio, "Failed to decode opus data");
|
||||
@@ -80,25 +97,28 @@ private:
|
||||
rb.Push(ResultCode(-1));
|
||||
return;
|
||||
}
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
|
||||
const u32 param_size = performance != nullptr ? 6 : 4;
|
||||
IPC::ResponseBuilder rb{ctx, param_size};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(consumed);
|
||||
rb.Push<u32>(sample_count);
|
||||
rb.Push<u64>(performance);
|
||||
if (performance) {
|
||||
rb.Push<u64>(*performance);
|
||||
}
|
||||
ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
|
||||
}
|
||||
|
||||
bool Decoder_DecodeInterleaved(
|
||||
u32& consumed, u32& sample_count, const std::vector<u8>& input,
|
||||
std::vector<opus_int16>& output,
|
||||
std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) {
|
||||
bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input,
|
||||
std::vector<opus_int16>& output, u64* out_performance_time) {
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
|
||||
const std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
|
||||
if (sizeof(OpusHeader) > input.size()) {
|
||||
LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}",
|
||||
sizeof(OpusHeader), input.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
OpusHeader hdr{};
|
||||
std::memcpy(&hdr, input.data(), sizeof(OpusHeader));
|
||||
if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) {
|
||||
@@ -106,8 +126,9 @@ private:
|
||||
sizeof(OpusHeader) + static_cast<u32>(hdr.sz), input.size());
|
||||
return false;
|
||||
}
|
||||
auto frame = input.data() + sizeof(OpusHeader);
|
||||
auto decoded_sample_count = opus_packet_get_nb_samples(
|
||||
|
||||
const auto frame = input.data() + sizeof(OpusHeader);
|
||||
const auto decoded_sample_count = opus_packet_get_nb_samples(
|
||||
frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)),
|
||||
static_cast<opus_int32>(sample_rate));
|
||||
if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) {
|
||||
@@ -117,8 +138,9 @@ private:
|
||||
decoded_sample_count * channel_count * sizeof(u16), raw_output_sz);
|
||||
return false;
|
||||
}
|
||||
|
||||
const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count));
|
||||
auto out_sample_count =
|
||||
const auto out_sample_count =
|
||||
opus_decode(decoder.get(), frame, hdr.sz, output.data(), frame_size, 0);
|
||||
if (out_sample_count < 0) {
|
||||
LOG_ERROR(Audio,
|
||||
@@ -127,16 +149,24 @@ private:
|
||||
out_sample_count, frame_size, static_cast<u32>(hdr.sz));
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto end_time = std::chrono::high_resolution_clock::now() - start_time;
|
||||
sample_count = out_sample_count;
|
||||
consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz);
|
||||
if (performance_time.has_value()) {
|
||||
performance_time->get() =
|
||||
if (out_performance_time != nullptr) {
|
||||
*out_performance_time =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(end_time).count();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResetDecoderContext() {
|
||||
ASSERT(decoder != nullptr);
|
||||
|
||||
opus_decoder_ctl(decoder.get(), OPUS_RESET_STATE);
|
||||
}
|
||||
|
||||
struct OpusHeader {
|
||||
u32_be sz; // Needs to be BE for some odd reason
|
||||
INSERT_PADDING_WORDS(1);
|
||||
@@ -157,6 +187,7 @@ void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto sample_rate = rp.Pop<u32>();
|
||||
const auto channel_count = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Audio, "called with sample_rate={}, channel_count={}", sample_rate, channel_count);
|
||||
|
||||
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
|
||||
@@ -174,9 +205,10 @@ void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto sample_rate = rp.Pop<u32>();
|
||||
auto channel_count = rp.Pop<u32>();
|
||||
auto buffer_sz = rp.Pop<u32>();
|
||||
const auto sample_rate = rp.Pop<u32>();
|
||||
const auto channel_count = rp.Pop<u32>();
|
||||
const auto buffer_sz = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate,
|
||||
channel_count, buffer_sz);
|
||||
|
||||
@@ -185,8 +217,9 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
|
||||
"Invalid sample rate");
|
||||
ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
|
||||
|
||||
std::size_t worker_sz = WorkerBufferSize(channel_count);
|
||||
const std::size_t worker_sz = WorkerBufferSize(channel_count);
|
||||
ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
|
||||
|
||||
std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
|
||||
static_cast<OpusDecoder*>(operator new(worker_sz))};
|
||||
if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
|
||||
|
||||
@@ -19,16 +19,16 @@ public:
|
||||
explicit Bt() : ServiceFramework{"bt"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown0"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "Unknown8"},
|
||||
{9, &Bt::RegisterEvent, "RegisterEvent"},
|
||||
{0, nullptr, "LeClientReadCharacteristic"},
|
||||
{1, nullptr, "LeClientReadDescriptor"},
|
||||
{2, nullptr, "LeClientWriteCharacteristic"},
|
||||
{3, nullptr, "LeClientWriteDescriptor"},
|
||||
{4, nullptr, "LeClientRegisterNotification"},
|
||||
{5, nullptr, "LeClientDeregisterNotification"},
|
||||
{6, nullptr, "SetLeResponse"},
|
||||
{7, nullptr, "LeSendIndication"},
|
||||
{8, nullptr, "GetLeEventInfo"},
|
||||
{9, &Bt::RegisterBleEvent, "RegisterBleEvent"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void RegisterEvent(Kernel::HLERequestContext& ctx) {
|
||||
void RegisterBleEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
@@ -55,11 +55,11 @@ public:
|
||||
explicit BtDrv() : ServiceFramework{"btdrv"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown"},
|
||||
{1, nullptr, "Init"},
|
||||
{2, nullptr, "Enable"},
|
||||
{3, nullptr, "Disable"},
|
||||
{4, nullptr, "CleanupAndShutdown"},
|
||||
{0, nullptr, "InitializeBluetoothDriver"},
|
||||
{1, nullptr, "InitializeBluetooth"},
|
||||
{2, nullptr, "EnableBluetooth"},
|
||||
{3, nullptr, "DisableBluetooth"},
|
||||
{4, nullptr, "CleanupBluetooth"},
|
||||
{5, nullptr, "GetAdapterProperties"},
|
||||
{6, nullptr, "GetAdapterProperty"},
|
||||
{7, nullptr, "SetAdapterProperty"},
|
||||
@@ -70,36 +70,91 @@ public:
|
||||
{12, nullptr, "CancelBond"},
|
||||
{13, nullptr, "PinReply"},
|
||||
{14, nullptr, "SspReply"},
|
||||
{15, nullptr, "Unknown2"},
|
||||
{16, nullptr, "InitInterfaces"},
|
||||
{17, nullptr, "HidHostInterface_Connect"},
|
||||
{18, nullptr, "HidHostInterface_Disconnect"},
|
||||
{19, nullptr, "HidHostInterface_SendData"},
|
||||
{20, nullptr, "HidHostInterface_SendData2"},
|
||||
{21, nullptr, "HidHostInterface_SetReport"},
|
||||
{22, nullptr, "HidHostInterface_GetReport"},
|
||||
{23, nullptr, "HidHostInterface_WakeController"},
|
||||
{24, nullptr, "HidHostInterface_AddPairedDevice"},
|
||||
{25, nullptr, "HidHostInterface_GetPairedDevice"},
|
||||
{26, nullptr, "HidHostInterface_CleanupAndShutdown"},
|
||||
{27, nullptr, "Unknown3"},
|
||||
{28, nullptr, "ExtInterface_SetTSI"},
|
||||
{29, nullptr, "ExtInterface_SetBurstMode"},
|
||||
{30, nullptr, "ExtInterface_SetZeroRetran"},
|
||||
{31, nullptr, "ExtInterface_SetMcMode"},
|
||||
{32, nullptr, "ExtInterface_StartLlrMode"},
|
||||
{33, nullptr, "ExtInterface_ExitLlrMode"},
|
||||
{34, nullptr, "ExtInterface_SetRadio"},
|
||||
{35, nullptr, "ExtInterface_SetVisibility"},
|
||||
{36, nullptr, "Unknown4"},
|
||||
{37, nullptr, "Unknown5"},
|
||||
{38, nullptr, "HidHostInterface_GetLatestPlr"},
|
||||
{39, nullptr, "ExtInterface_GetPendingConnections"},
|
||||
{40, nullptr, "HidHostInterface_GetChannelMap"},
|
||||
{41, nullptr, "SetIsBluetoothBoostEnabled"},
|
||||
{42, nullptr, "GetIsBluetoothBoostEnabled"},
|
||||
{43, nullptr, "SetIsBluetoothAfhEnabled"},
|
||||
{44, nullptr, "GetIsBluetoothAfhEnabled"},
|
||||
{15, nullptr, "GetEventInfo"},
|
||||
{16, nullptr, "InitializeHid"},
|
||||
{17, nullptr, "HidConnect"},
|
||||
{18, nullptr, "HidDisconnect"},
|
||||
{19, nullptr, "HidSendData"},
|
||||
{20, nullptr, "HidSendData2"},
|
||||
{21, nullptr, "HidSetReport"},
|
||||
{22, nullptr, "HidGetReport"},
|
||||
{23, nullptr, "HidWakeController"},
|
||||
{24, nullptr, "HidAddPairedDevice"},
|
||||
{25, nullptr, "HidGetPairedDevice"},
|
||||
{26, nullptr, "CleanupHid"},
|
||||
{27, nullptr, "HidGetEventInfo"},
|
||||
{28, nullptr, "ExtSetTsi"},
|
||||
{29, nullptr, "ExtSetBurstMode"},
|
||||
{30, nullptr, "ExtSetZeroRetran"},
|
||||
{31, nullptr, "ExtSetMcMode"},
|
||||
{32, nullptr, "ExtStartLlrMode"},
|
||||
{33, nullptr, "ExtExitLlrMode"},
|
||||
{34, nullptr, "ExtSetRadio"},
|
||||
{35, nullptr, "ExtSetVisibility"},
|
||||
{36, nullptr, "ExtSetTbfcScan"},
|
||||
{37, nullptr, "RegisterHidReportEvent"},
|
||||
{38, nullptr, "HidGetReportEventInfo"},
|
||||
{39, nullptr, "GetLatestPlr"},
|
||||
{40, nullptr, "ExtGetPendingConnections"},
|
||||
{41, nullptr, "GetChannelMap"},
|
||||
{42, nullptr, "EnableBluetoothBoostSetting"},
|
||||
{43, nullptr, "IsBluetoothBoostSettingEnabled"},
|
||||
{44, nullptr, "EnableBluetoothAfhSetting"},
|
||||
{45, nullptr, "IsBluetoothAfhSettingEnabled"},
|
||||
{46, nullptr, "InitializeBluetoothLe"},
|
||||
{47, nullptr, "EnableBluetoothLe"},
|
||||
{48, nullptr, "DisableBluetoothLe"},
|
||||
{49, nullptr, "CleanupBluetoothLe"},
|
||||
{50, nullptr, "SetLeVisibility"},
|
||||
{51, nullptr, "SetLeConnectionParameter"},
|
||||
{52, nullptr, "SetLeDefaultConnectionParameter"},
|
||||
{53, nullptr, "SetLeAdvertiseData"},
|
||||
{54, nullptr, "SetLeAdvertiseParameter"},
|
||||
{55, nullptr, "StartLeScan"},
|
||||
{56, nullptr, "StopLeScan"},
|
||||
{57, nullptr, "AddLeScanFilterCondition"},
|
||||
{58, nullptr, "DeleteLeScanFilterCondition"},
|
||||
{59, nullptr, "DeleteLeScanFilter"},
|
||||
{60, nullptr, "ClearLeScanFilters"},
|
||||
{61, nullptr, "EnableLeScanFilter"},
|
||||
{62, nullptr, "RegisterLeClient"},
|
||||
{63, nullptr, "UnregisterLeClient"},
|
||||
{64, nullptr, "UnregisterLeClientAll"},
|
||||
{65, nullptr, "LeClientConnect"},
|
||||
{66, nullptr, "LeClientCancelConnection"},
|
||||
{67, nullptr, "LeClientDisconnect"},
|
||||
{68, nullptr, "LeClientGetAttributes"},
|
||||
{69, nullptr, "LeClientDiscoverService"},
|
||||
{70, nullptr, "LeClientConfigureMtu"},
|
||||
{71, nullptr, "RegisterLeServer"},
|
||||
{72, nullptr, "UnregisterLeServer"},
|
||||
{73, nullptr, "LeServerConnect"},
|
||||
{74, nullptr, "LeServerDisconnect"},
|
||||
{75, nullptr, "CreateLeService"},
|
||||
{76, nullptr, "StartLeService"},
|
||||
{77, nullptr, "AddLeCharacteristic"},
|
||||
{78, nullptr, "AddLeDescriptor"},
|
||||
{79, nullptr, "GetLeCoreEventInfo"},
|
||||
{80, nullptr, "LeGetFirstCharacteristic"},
|
||||
{81, nullptr, "LeGetNextCharacteristic"},
|
||||
{82, nullptr, "LeGetFirstDescriptor"},
|
||||
{83, nullptr, "LeGetNextDescriptor"},
|
||||
{84, nullptr, "RegisterLeCoreDataPath"},
|
||||
{85, nullptr, "UnregisterLeCoreDataPath"},
|
||||
{86, nullptr, "RegisterLeHidDataPath"},
|
||||
{87, nullptr, "UnregisterLeHidDataPath"},
|
||||
{88, nullptr, "RegisterLeDataPath"},
|
||||
{89, nullptr, "UnregisterLeDataPath"},
|
||||
{90, nullptr, "LeClientReadCharacteristic"},
|
||||
{91, nullptr, "LeClientReadDescriptor"},
|
||||
{92, nullptr, "LeClientWriteCharacteristic"},
|
||||
{93, nullptr, "LeClientWriteDescriptor"},
|
||||
{94, nullptr, "LeClientRegisterNotification"},
|
||||
{95, nullptr, "LeClientDeregisterNotification"},
|
||||
{96, nullptr, "GetLeHidEventInfo"},
|
||||
{97, nullptr, "RegisterBleHidEvent"},
|
||||
{98, nullptr, "SetLeScanParameter"},
|
||||
{256, nullptr, "GetIsManufacturingMode"}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -20,38 +20,38 @@ public:
|
||||
explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IBtmUserCore::GetScanEvent, "GetScanEvent"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "Unknown8"},
|
||||
{9, nullptr, "Unknown9"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{17, &IBtmUserCore::GetConnectionEvent, "GetConnectionEvent"},
|
||||
{18, nullptr, "Unknown18"},
|
||||
{19, nullptr, "Unknown19"},
|
||||
{20, nullptr, "Unknown20"},
|
||||
{21, nullptr, "Unknown21"},
|
||||
{22, nullptr, "Unknown22"},
|
||||
{23, nullptr, "Unknown23"},
|
||||
{24, nullptr, "Unknown24"},
|
||||
{25, nullptr, "Unknown25"},
|
||||
{26, &IBtmUserCore::GetDiscoveryEvent, "AcquireBleServiceDiscoveryEventImpl"},
|
||||
{27, nullptr, "Unknown27"},
|
||||
{28, nullptr, "Unknown28"},
|
||||
{29, nullptr, "Unknown29"},
|
||||
{30, nullptr, "Unknown30"},
|
||||
{31, nullptr, "Unknown31"},
|
||||
{32, nullptr, "Unknown32"},
|
||||
{33, &IBtmUserCore::GetConfigEvent, "GetConfigEvent"},
|
||||
{34, nullptr, "Unknown34"},
|
||||
{35, nullptr, "Unknown35"},
|
||||
{36, nullptr, "Unknown36"},
|
||||
{37, nullptr, "Unknown37"},
|
||||
{0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
|
||||
{1, nullptr, "GetBleScanFilterParameter"},
|
||||
{2, nullptr, "GetBleScanFilterParameter2"},
|
||||
{3, nullptr, "StartBleScanForGeneral"},
|
||||
{4, nullptr, "StopBleScanForGeneral"},
|
||||
{5, nullptr, "GetBleScanResultsForGeneral"},
|
||||
{6, nullptr, "StartBleScanForPaired"},
|
||||
{7, nullptr, "StopBleScanForPaired"},
|
||||
{8, nullptr, "StartBleScanForSmartDevice"},
|
||||
{9, nullptr, "StopBleScanForSmartDevice"},
|
||||
{10, nullptr, "GetBleScanResultsForSmartDevice"},
|
||||
{17, &IBtmUserCore::AcquireBleConnectionEvent, "AcquireBleConnectionEvent"},
|
||||
{18, nullptr, "BleConnect"},
|
||||
{19, nullptr, "BleDisconnect"},
|
||||
{20, nullptr, "BleGetConnectionState"},
|
||||
{21, nullptr, "AcquireBlePairingEvent"},
|
||||
{22, nullptr, "BlePairDevice"},
|
||||
{23, nullptr, "BleUnPairDevice"},
|
||||
{24, nullptr, "BleUnPairDevice2"},
|
||||
{25, nullptr, "BleGetPairedDevices"},
|
||||
{26, &IBtmUserCore::AcquireBleServiceDiscoveryEvent, "AcquireBleServiceDiscoveryEvent"},
|
||||
{27, nullptr, "GetGattServices"},
|
||||
{28, nullptr, "GetGattService"},
|
||||
{29, nullptr, "GetGattIncludedServices"},
|
||||
{30, nullptr, "GetBelongingGattService"},
|
||||
{31, nullptr, "GetGattCharacteristics"},
|
||||
{32, nullptr, "GetGattDescriptors"},
|
||||
{33, &IBtmUserCore::AcquireBleMtuConfigEvent, "AcquireBleMtuConfigEvent"},
|
||||
{34, nullptr, "ConfigureBleMtu"},
|
||||
{35, nullptr, "GetBleMtu"},
|
||||
{36, nullptr, "RegisterBleGattDataPath"},
|
||||
{37, nullptr, "UnregisterBleGattDataPath"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void GetScanEvent(Kernel::HLERequestContext& ctx) {
|
||||
void AcquireBleScanEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
@@ -76,7 +76,7 @@ private:
|
||||
rb.PushCopyObjects(scan_event.readable);
|
||||
}
|
||||
|
||||
void GetConnectionEvent(Kernel::HLERequestContext& ctx) {
|
||||
void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
rb.PushCopyObjects(connection_event.readable);
|
||||
}
|
||||
|
||||
void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) {
|
||||
void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
@@ -92,7 +92,7 @@ private:
|
||||
rb.PushCopyObjects(service_discovery.readable);
|
||||
}
|
||||
|
||||
void GetConfigEvent(Kernel::HLERequestContext& ctx) {
|
||||
void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
@@ -111,14 +111,14 @@ public:
|
||||
explicit BTM_USR() : ServiceFramework{"btm:u"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &BTM_USR::GetCoreImpl, "GetCoreImpl"},
|
||||
{0, &BTM_USR::GetCore, "GetCore"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void GetCoreImpl(Kernel::HLERequestContext& ctx) {
|
||||
void GetCore(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
@@ -134,26 +134,64 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown1"},
|
||||
{1, nullptr, "Unknown2"},
|
||||
{2, nullptr, "RegisterSystemEventForConnectedDeviceConditionImpl"},
|
||||
{2, nullptr, "RegisterSystemEventForConnectedDeviceCondition"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "RegisterSystemEventForRegisteredDeviceInfoImpl"},
|
||||
{8, nullptr, "RegisterSystemEventForRegisteredDeviceInfo"},
|
||||
{9, nullptr, "Unknown8"},
|
||||
{10, nullptr, "Unknown9"},
|
||||
{11, nullptr, "Unknown10"},
|
||||
{12, nullptr, "Unknown11"},
|
||||
{13, nullptr, "Unknown12"},
|
||||
{14, nullptr, "EnableRadioImpl"},
|
||||
{15, nullptr, "DisableRadioImpl"},
|
||||
{14, nullptr, "EnableRadio"},
|
||||
{15, nullptr, "DisableRadio"},
|
||||
{16, nullptr, "Unknown13"},
|
||||
{17, nullptr, "Unknown14"},
|
||||
{18, nullptr, "Unknown15"},
|
||||
{19, nullptr, "Unknown16"},
|
||||
{20, nullptr, "Unknown17"},
|
||||
{21, nullptr, "Unknown18"},
|
||||
{22, nullptr, "Unknown19"},
|
||||
{23, nullptr, "Unknown20"},
|
||||
{24, nullptr, "Unknown21"},
|
||||
{25, nullptr, "Unknown22"},
|
||||
{26, nullptr, "Unknown23"},
|
||||
{27, nullptr, "Unknown24"},
|
||||
{28, nullptr, "Unknown25"},
|
||||
{29, nullptr, "Unknown26"},
|
||||
{30, nullptr, "Unknown27"},
|
||||
{31, nullptr, "Unknown28"},
|
||||
{32, nullptr, "Unknown29"},
|
||||
{33, nullptr, "Unknown30"},
|
||||
{34, nullptr, "Unknown31"},
|
||||
{35, nullptr, "Unknown32"},
|
||||
{36, nullptr, "Unknown33"},
|
||||
{37, nullptr, "Unknown34"},
|
||||
{38, nullptr, "Unknown35"},
|
||||
{39, nullptr, "Unknown36"},
|
||||
{40, nullptr, "Unknown37"},
|
||||
{41, nullptr, "Unknown38"},
|
||||
{42, nullptr, "Unknown39"},
|
||||
{43, nullptr, "Unknown40"},
|
||||
{44, nullptr, "Unknown41"},
|
||||
{45, nullptr, "Unknown42"},
|
||||
{46, nullptr, "Unknown43"},
|
||||
{47, nullptr, "Unknown44"},
|
||||
{48, nullptr, "Unknown45"},
|
||||
{49, nullptr, "Unknown46"},
|
||||
{50, nullptr, "Unknown47"},
|
||||
{51, nullptr, "Unknown48"},
|
||||
{52, nullptr, "Unknown49"},
|
||||
{53, nullptr, "Unknown50"},
|
||||
{54, nullptr, "Unknown51"},
|
||||
{55, nullptr, "Unknown52"},
|
||||
{56, nullptr, "Unknown53"},
|
||||
{57, nullptr, "Unknown54"},
|
||||
{58, nullptr, "Unknown55"},
|
||||
{59, nullptr, "Unknown56"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -166,7 +204,7 @@ public:
|
||||
explicit BTM_DBG() : ServiceFramework{"btm:dbg"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "RegisterSystemEventForDiscoveryImpl"},
|
||||
{0, nullptr, "RegisterSystemEventForDiscovery"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
@@ -175,6 +213,10 @@ public:
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "Unknown8"},
|
||||
{9, nullptr, "Unknown9"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{11, nullptr, "Unknown11"},
|
||||
{12, nullptr, "Unknown11"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -187,16 +229,16 @@ public:
|
||||
explicit IBtmSystemCore() : ServiceFramework{"IBtmSystemCore"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "StartGamepadPairingImpl"},
|
||||
{1, nullptr, "CancelGamepadPairingImpl"},
|
||||
{2, nullptr, "ClearGamepadPairingDatabaseImpl"},
|
||||
{3, nullptr, "GetPairedGamepadCountImpl"},
|
||||
{4, nullptr, "EnableRadioImpl"},
|
||||
{5, nullptr, "DisableRadioImpl"},
|
||||
{6, nullptr, "GetRadioOnOffImpl"},
|
||||
{7, nullptr, "AcquireRadioEventImpl"},
|
||||
{8, nullptr, "AcquireGamepadPairingEventImpl"},
|
||||
{9, nullptr, "IsGamepadPairingStartedImpl"},
|
||||
{0, nullptr, "StartGamepadPairing"},
|
||||
{1, nullptr, "CancelGamepadPairing"},
|
||||
{2, nullptr, "ClearGamepadPairingDatabase"},
|
||||
{3, nullptr, "GetPairedGamepadCount"},
|
||||
{4, nullptr, "EnableRadio"},
|
||||
{5, nullptr, "DisableRadio"},
|
||||
{6, nullptr, "GetRadioOnOff"},
|
||||
{7, nullptr, "AcquireRadioEvent"},
|
||||
{8, nullptr, "AcquireGamepadPairingEvent"},
|
||||
{9, nullptr, "IsGamepadPairingStarted"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -209,7 +251,7 @@ public:
|
||||
explicit BTM_SYS() : ServiceFramework{"btm:sys"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &BTM_SYS::GetCoreImpl, "GetCoreImpl"},
|
||||
{0, &BTM_SYS::GetCore, "GetCore"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -217,7 +259,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void GetCoreImpl(Kernel::HLERequestContext& ctx) {
|
||||
void GetCore(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
@@ -627,8 +627,8 @@ private:
|
||||
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "MountContent"},
|
||||
{1, &FSP_SRV::Initialize, "Initialize"},
|
||||
{0, nullptr, "OpenFileSystem"},
|
||||
{1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"},
|
||||
{2, nullptr, "OpenDataFileSystemByCurrentProcess"},
|
||||
{7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"},
|
||||
{8, nullptr, "OpenFileSystemWithId"},
|
||||
@@ -637,10 +637,10 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
{12, nullptr, "OpenBisStorage"},
|
||||
{13, nullptr, "InvalidateBisCache"},
|
||||
{17, nullptr, "OpenHostFileSystem"},
|
||||
{18, &FSP_SRV::MountSdCard, "MountSdCard"},
|
||||
{18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"},
|
||||
{19, nullptr, "FormatSdCardFileSystem"},
|
||||
{21, nullptr, "DeleteSaveDataFileSystem"},
|
||||
{22, &FSP_SRV::CreateSaveData, "CreateSaveData"},
|
||||
{22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"},
|
||||
{23, nullptr, "CreateSaveDataFileSystemBySystemSaveDataId"},
|
||||
{24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
|
||||
{25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
|
||||
@@ -652,7 +652,8 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
{32, nullptr, "ExtendSaveDataFileSystem"},
|
||||
{33, nullptr, "DeleteCacheStorage"},
|
||||
{34, nullptr, "GetCacheStorageSize"},
|
||||
{51, &FSP_SRV::MountSaveData, "MountSaveData"},
|
||||
{35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
|
||||
{51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"},
|
||||
{52, nullptr, "OpenSaveDataFileSystemBySystemSaveDataId"},
|
||||
{53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"},
|
||||
{57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
|
||||
@@ -664,21 +665,26 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
{64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
|
||||
{65, nullptr, "UpdateSaveDataMacForDebug"},
|
||||
{66, nullptr, "WriteSaveDataFileSystemExtraData2"},
|
||||
{67, nullptr, "FindSaveDataWithFilter"},
|
||||
{68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
|
||||
{80, nullptr, "OpenSaveDataMetaFile"},
|
||||
{81, nullptr, "OpenSaveDataTransferManager"},
|
||||
{82, nullptr, "OpenSaveDataTransferManagerVersion2"},
|
||||
{83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"},
|
||||
{84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
|
||||
{100, nullptr, "OpenImageDirectoryFileSystem"},
|
||||
{110, nullptr, "OpenContentStorageFileSystem"},
|
||||
{120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
|
||||
{200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
|
||||
{201, nullptr, "OpenDataStorageByProgramId"},
|
||||
{202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
|
||||
{203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"},
|
||||
{203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"},
|
||||
{400, nullptr, "OpenDeviceOperator"},
|
||||
{500, nullptr, "OpenSdCardDetectionEventNotifier"},
|
||||
{501, nullptr, "OpenGameCardDetectionEventNotifier"},
|
||||
{510, nullptr, "OpenSystemDataUpdateEventNotifier"},
|
||||
{511, nullptr, "NotifySystemDataUpdateEvent"},
|
||||
{520, nullptr, "SimulateGameCardDetectionEvent"},
|
||||
{600, nullptr, "SetCurrentPosixTime"},
|
||||
{601, nullptr, "QuerySaveDataTotalSize"},
|
||||
{602, nullptr, "VerifySaveDataFileSystem"},
|
||||
@@ -717,6 +723,8 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
{1008, nullptr, "OpenRegisteredUpdatePartition"},
|
||||
{1009, nullptr, "GetAndClearMemoryReportInfo"},
|
||||
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
|
||||
{1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
|
||||
{1200, nullptr, "OpenMultiCommitManager"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
@@ -724,7 +732,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
|
||||
FSP_SRV::~FSP_SRV() = default;
|
||||
|
||||
void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::SetCurrentProcess(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -743,7 +751,7 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(ResultCode(-1));
|
||||
}
|
||||
|
||||
void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
IFileSystem filesystem(OpenSDMC().Unwrap());
|
||||
@@ -753,7 +761,7 @@ void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
|
||||
rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
|
||||
}
|
||||
|
||||
void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
|
||||
@@ -767,7 +775,7 @@ void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
|
||||
@@ -793,7 +801,7 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
|
||||
MountSaveData(ctx);
|
||||
OpenSaveDataFileSystem(ctx);
|
||||
}
|
||||
|
||||
void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
|
||||
@@ -881,7 +889,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
|
||||
rb.PushIpcInterface<IStorage>(std::move(storage));
|
||||
}
|
||||
|
||||
void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto storage_id = rp.PopRaw<FileSys::StorageId>();
|
||||
|
||||
@@ -19,17 +19,17 @@ public:
|
||||
~FSP_SRV() override;
|
||||
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx);
|
||||
void SetCurrentProcess(Kernel::HLERequestContext& ctx);
|
||||
void OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx);
|
||||
void MountSdCard(Kernel::HLERequestContext& ctx);
|
||||
void CreateSaveData(Kernel::HLERequestContext& ctx);
|
||||
void MountSaveData(Kernel::HLERequestContext& ctx);
|
||||
void OpenSdCardFileSystem(Kernel::HLERequestContext& ctx);
|
||||
void CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx);
|
||||
void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx);
|
||||
void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
|
||||
void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
|
||||
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
|
||||
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
|
||||
void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
|
||||
void OpenRomStorage(Kernel::HLERequestContext& ctx);
|
||||
void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
|
||||
|
||||
FileSys::VirtualFile romfs;
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ void Controller_DebugPad::OnInit() {}
|
||||
void Controller_DebugPad::OnRelease() {}
|
||||
|
||||
void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) {
|
||||
shared_memory.header.timestamp = CoreTiming::GetTicks();
|
||||
shared_memory.header.timestamp = Core::Timing::GetTicks();
|
||||
shared_memory.header.total_entry_count = 17;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
|
||||
@@ -18,7 +18,7 @@ void Controller_Gesture::OnInit() {}
|
||||
void Controller_Gesture::OnRelease() {}
|
||||
|
||||
void Controller_Gesture::OnUpdate(u8* data, std::size_t size) {
|
||||
shared_memory.header.timestamp = CoreTiming::GetTicks();
|
||||
shared_memory.header.timestamp = Core::Timing::GetTicks();
|
||||
shared_memory.header.total_entry_count = 17;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
|
||||
@@ -20,7 +20,7 @@ void Controller_Keyboard::OnInit() {}
|
||||
void Controller_Keyboard::OnRelease() {}
|
||||
|
||||
void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) {
|
||||
shared_memory.header.timestamp = CoreTiming::GetTicks();
|
||||
shared_memory.header.timestamp = Core::Timing::GetTicks();
|
||||
shared_memory.header.total_entry_count = 17;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
|
||||
@@ -18,7 +18,7 @@ void Controller_Mouse::OnInit() {}
|
||||
void Controller_Mouse::OnRelease() {}
|
||||
|
||||
void Controller_Mouse::OnUpdate(u8* data, std::size_t size) {
|
||||
shared_memory.header.timestamp = CoreTiming::GetTicks();
|
||||
shared_memory.header.timestamp = Core::Timing::GetTicks();
|
||||
shared_memory.header.total_entry_count = 17;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
|
||||
@@ -308,7 +308,7 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
|
||||
const auto& last_entry =
|
||||
main_controller->npad[main_controller->common.last_entry_index];
|
||||
|
||||
main_controller->common.timestamp = CoreTiming::GetTicks();
|
||||
main_controller->common.timestamp = Core::Timing::GetTicks();
|
||||
main_controller->common.last_entry_index =
|
||||
(main_controller->common.last_entry_index + 1) % 17;
|
||||
|
||||
@@ -410,6 +410,8 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
|
||||
libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
|
||||
libnx_entry.pad.l_stick = pad_state.l_stick;
|
||||
libnx_entry.pad.r_stick = pad_state.r_stick;
|
||||
|
||||
press_state |= static_cast<u32>(pad_state.pad_states.raw);
|
||||
}
|
||||
std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
|
||||
shared_memory_entries.size() * sizeof(NPadEntry));
|
||||
@@ -636,6 +638,10 @@ void Controller_NPad::ClearAllControllers() {
|
||||
});
|
||||
}
|
||||
|
||||
u32 Controller_NPad::GetAndResetPressState() {
|
||||
return std::exchange(press_state, 0);
|
||||
}
|
||||
|
||||
bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
|
||||
const bool support_handheld =
|
||||
std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) !=
|
||||
|
||||
@@ -124,6 +124,10 @@ public:
|
||||
void ConnectAllDisconnectedControllers();
|
||||
void ClearAllControllers();
|
||||
|
||||
// Logical OR for all buttons presses on all controllers
|
||||
// Specifically for cheat engine and other features.
|
||||
u32 GetAndResetPressState();
|
||||
|
||||
static std::size_t NPadIdToIndex(u32 npad_id);
|
||||
static u32 IndexToNPad(std::size_t index);
|
||||
|
||||
@@ -292,6 +296,8 @@ private:
|
||||
bool is_connected;
|
||||
};
|
||||
|
||||
u32 press_state{};
|
||||
|
||||
NPadType style{};
|
||||
std::array<NPadEntry, 10> shared_memory_entries{};
|
||||
std::array<
|
||||
|
||||
@@ -22,7 +22,7 @@ void Controller_Stubbed::OnUpdate(u8* data, std::size_t size) {
|
||||
}
|
||||
|
||||
CommonHeader header{};
|
||||
header.timestamp = CoreTiming::GetTicks();
|
||||
header.timestamp = Core::Timing::GetTicks();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
|
||||
@@ -21,7 +21,7 @@ void Controller_Touchscreen::OnInit() {}
|
||||
void Controller_Touchscreen::OnRelease() {}
|
||||
|
||||
void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
|
||||
shared_memory.header.timestamp = CoreTiming::GetTicks();
|
||||
shared_memory.header.timestamp = Core::Timing::GetTicks();
|
||||
shared_memory.header.total_entry_count = 17;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
@@ -48,7 +48,7 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
|
||||
touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
|
||||
touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
|
||||
touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
|
||||
const u64 tick = CoreTiming::GetTicks();
|
||||
const u64 tick = Core::Timing::GetTicks();
|
||||
touch_entry.delta_time = tick - last_touch;
|
||||
last_touch = tick;
|
||||
touch_entry.finger = Settings::values.touchscreen.finger;
|
||||
|
||||
@@ -19,7 +19,7 @@ void Controller_XPad::OnRelease() {}
|
||||
|
||||
void Controller_XPad::OnUpdate(u8* data, std::size_t size) {
|
||||
for (auto& xpad_entry : shared_memory.shared_memory_entries) {
|
||||
xpad_entry.header.timestamp = CoreTiming::GetTicks();
|
||||
xpad_entry.header.timestamp = Core::Timing::GetTicks();
|
||||
xpad_entry.header.total_entry_count = 17;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,12 +4,122 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "controllers/controller_base.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class SharedMemory;
|
||||
}
|
||||
|
||||
namespace SM {
|
||||
class ServiceManager;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
enum class HidController : std::size_t {
|
||||
DebugPad,
|
||||
Touchscreen,
|
||||
Mouse,
|
||||
Keyboard,
|
||||
XPad,
|
||||
Unknown1,
|
||||
Unknown2,
|
||||
Unknown3,
|
||||
SixAxisSensor,
|
||||
NPad,
|
||||
Gesture,
|
||||
|
||||
MaxControllers,
|
||||
};
|
||||
|
||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||
public:
|
||||
IAppletResource();
|
||||
~IAppletResource() override;
|
||||
|
||||
void ActivateController(HidController controller);
|
||||
void DeactivateController(HidController controller);
|
||||
|
||||
template <typename T>
|
||||
T& GetController(HidController controller) {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& GetController(HidController controller) const {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void MakeController(HidController controller) {
|
||||
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>();
|
||||
}
|
||||
|
||||
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
|
||||
void UpdateControllers(u64 userdata, int cycles_late);
|
||||
|
||||
Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
|
||||
|
||||
Core::Timing::EventType* pad_update_event;
|
||||
|
||||
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
|
||||
controllers{};
|
||||
};
|
||||
|
||||
class Hid final : public ServiceFramework<Hid> {
|
||||
public:
|
||||
Hid();
|
||||
~Hid() override;
|
||||
|
||||
std::shared_ptr<IAppletResource> GetAppletResource();
|
||||
|
||||
private:
|
||||
void CreateAppletResource(Kernel::HLERequestContext& ctx);
|
||||
void ActivateXpad(Kernel::HLERequestContext& ctx);
|
||||
void ActivateDebugPad(Kernel::HLERequestContext& ctx);
|
||||
void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
|
||||
void ActivateMouse(Kernel::HLERequestContext& ctx);
|
||||
void ActivateKeyboard(Kernel::HLERequestContext& ctx);
|
||||
void ActivateGesture(Kernel::HLERequestContext& ctx);
|
||||
void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
|
||||
void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
|
||||
void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
|
||||
void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
|
||||
void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx);
|
||||
void ActivateNpad(Kernel::HLERequestContext& ctx);
|
||||
void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx);
|
||||
void DisconnectNpad(Kernel::HLERequestContext& ctx);
|
||||
void GetPlayerLedPattern(Kernel::HLERequestContext& ctx);
|
||||
void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
|
||||
void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx);
|
||||
void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
|
||||
void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
|
||||
void SendVibrationValue(Kernel::HLERequestContext& ctx);
|
||||
void SendVibrationValues(Kernel::HLERequestContext& ctx);
|
||||
void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx);
|
||||
void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx);
|
||||
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
|
||||
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
|
||||
void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx);
|
||||
void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
|
||||
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<IAppletResource> applet_resource;
|
||||
};
|
||||
|
||||
/// Reload input devices. Used when input configuration changed
|
||||
void ReloadInputDevices();
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u64>(CoreTiming::GetTicks());
|
||||
rb.PushRaw<u64>(Core::Timing::GetTicks());
|
||||
rb.PushRaw<u32>(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,10 +40,10 @@ public:
|
||||
{6, nullptr, "CloseContentStorageForcibly"},
|
||||
{7, nullptr, "CloseContentMetaDatabaseForcibly"},
|
||||
{8, nullptr, "CleanupContentMetaDatabase"},
|
||||
{9, nullptr, "OpenContentStorage2"},
|
||||
{10, nullptr, "CloseContentStorage"},
|
||||
{11, nullptr, "OpenContentMetaDatabase2"},
|
||||
{12, nullptr, "CloseContentMetaDatabase"},
|
||||
{9, nullptr, "ActivateContentStorage"},
|
||||
{10, nullptr, "InactivateContentStorage"},
|
||||
{11, nullptr, "ActivateContentMetaDatabase"},
|
||||
{12, nullptr, "InactivateContentMetaDatabase"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
{11, nullptr, "CalculateApplicationOccupiedSize"},
|
||||
{16, nullptr, "PushApplicationRecord"},
|
||||
{17, nullptr, "ListApplicationRecordContentMeta"},
|
||||
{19, nullptr, "LaunchApplication"},
|
||||
{19, nullptr, "LaunchApplicationOld"},
|
||||
{21, nullptr, "GetApplicationContentPath"},
|
||||
{22, nullptr, "TerminateApplication"},
|
||||
{23, nullptr, "ResolveApplicationContentPath"},
|
||||
@@ -96,10 +96,10 @@ public:
|
||||
{86, nullptr, "EnableApplicationCrashReport"},
|
||||
{87, nullptr, "IsApplicationCrashReportEnabled"},
|
||||
{90, nullptr, "BoostSystemMemoryResourceLimit"},
|
||||
{91, nullptr, "Unknown1"},
|
||||
{92, nullptr, "Unknown2"},
|
||||
{91, nullptr, "DeprecatedLaunchApplication"},
|
||||
{92, nullptr, "GetRunningApplicationProgramId"},
|
||||
{93, nullptr, "GetMainApplicationProgramIndex"},
|
||||
{94, nullptr, "LaunchApplication2"},
|
||||
{94, nullptr, "LaunchApplication"},
|
||||
{95, nullptr, "GetApplicationLaunchInfo"},
|
||||
{96, nullptr, "AcquireApplicationLaunchInfo"},
|
||||
{97, nullptr, "GetMainApplicationProgramIndex2"},
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
{907, nullptr, "WithdrawApplicationUpdateRequest"},
|
||||
{908, nullptr, "ListApplicationRecordInstalledContentMeta"},
|
||||
{909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
|
||||
{910, nullptr, "Unknown3"},
|
||||
{910, nullptr, "HasApplicationRecord"},
|
||||
{911, nullptr, "SetPreInstalledApplication"},
|
||||
{912, nullptr, "ClearPreInstalledApplicationFlag"},
|
||||
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
|
||||
@@ -219,10 +219,10 @@ public:
|
||||
{2015, nullptr, "CompareSystemDeliveryInfo"},
|
||||
{2016, nullptr, "ListNotCommittedContentMeta"},
|
||||
{2017, nullptr, "CreateDownloadTask"},
|
||||
{2018, nullptr, "Unknown4"},
|
||||
{2050, nullptr, "Unknown5"},
|
||||
{2100, nullptr, "Unknown6"},
|
||||
{2101, nullptr, "Unknown7"},
|
||||
{2018, nullptr, "GetApplicationDeliveryInfoHash"},
|
||||
{2050, nullptr, "GetApplicationRightsOnClient"},
|
||||
{2100, nullptr, "GetApplicationTerminateResult"},
|
||||
{2101, nullptr, "GetRawApplicationTerminateResult"},
|
||||
{2150, nullptr, "CreateRightsEnvironment"},
|
||||
{2151, nullptr, "DestroyRightsEnvironment"},
|
||||
{2152, nullptr, "ActivateRightsEnvironment"},
|
||||
@@ -237,10 +237,10 @@ public:
|
||||
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
|
||||
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
|
||||
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
|
||||
{2200, nullptr, "Unknown8"},
|
||||
{2201, nullptr, "Unknown9"},
|
||||
{2250, nullptr, "Unknown10"},
|
||||
{2300, nullptr, "Unknown11"},
|
||||
{2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
|
||||
{2201, nullptr, "GetInstalledApplicationCopyIdentifier"},
|
||||
{2250, nullptr, "RequestReportActiveELicence"},
|
||||
{2300, nullptr, "ListEventLog"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -355,6 +355,7 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{21, nullptr, "GetApplicationContentPath"},
|
||||
{23, nullptr, "ResolveApplicationContentPath"},
|
||||
{93, nullptr, "GetRunningApplicationProgramId"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -389,6 +390,11 @@ public:
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "RequestLinkDevice"},
|
||||
{1, nullptr, "RequestCleanupAllPreInstalledApplications"},
|
||||
{2, nullptr, "RequestCleanupPreInstalledApplication"},
|
||||
{3, nullptr, "RequestSyncRights"},
|
||||
{4, nullptr, "RequestUnlinkDevice"},
|
||||
{5, nullptr, "RequestRevokeAllELicense"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -403,7 +409,7 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{100, nullptr, "ResetToFactorySettings"},
|
||||
{101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
|
||||
{102, nullptr, "ResetToFactorySettingsForRefurbishment "},
|
||||
{102, nullptr, "ResetToFactorySettingsForRefurbishment"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
|
||||
u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform,
|
||||
const MathUtil::Rectangle<int>& crop_rect) {
|
||||
VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
|
||||
LOG_WARNING(Service,
|
||||
"Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
|
||||
addr, offset, width, height, stride, format);
|
||||
LOG_TRACE(Service,
|
||||
"Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
|
||||
addr, offset, width, height, stride, format);
|
||||
|
||||
using PixelFormat = Tegra::FramebufferConfig::PixelFormat;
|
||||
const Tegra::FramebufferConfig framebuffer{
|
||||
|
||||
@@ -184,7 +184,7 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& o
|
||||
|
||||
IoctlGetGpuTime params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks());
|
||||
params.gpu_time = Core::Timing::cyclesToNs(Core::Timing::GetTicks());
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
|
||||
namespace CoreTiming {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace Service::NVFlinger {
|
||||
|
||||
struct IGBPBuffer {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
@@ -22,98 +21,145 @@
|
||||
#include "core/hle/service/nvflinger/nvflinger.h"
|
||||
#include "core/perf_stats.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace Service::NVFlinger {
|
||||
|
||||
constexpr std::size_t SCREEN_REFRESH_RATE = 60;
|
||||
constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
|
||||
constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
|
||||
|
||||
NVFlinger::NVFlinger() {
|
||||
// Add the different displays to the list of displays.
|
||||
displays.emplace_back(0, "Default");
|
||||
displays.emplace_back(1, "External");
|
||||
displays.emplace_back(2, "Edid");
|
||||
displays.emplace_back(3, "Internal");
|
||||
|
||||
// Schedule the screen composition events
|
||||
composition_event =
|
||||
CoreTiming::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) {
|
||||
Core::Timing::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) {
|
||||
Compose();
|
||||
CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event);
|
||||
Core::Timing::ScheduleEvent(frame_ticks - cycles_late, composition_event);
|
||||
});
|
||||
|
||||
CoreTiming::ScheduleEvent(frame_ticks, composition_event);
|
||||
Core::Timing::ScheduleEvent(frame_ticks, composition_event);
|
||||
}
|
||||
|
||||
NVFlinger::~NVFlinger() {
|
||||
CoreTiming::UnscheduleEvent(composition_event, 0);
|
||||
Core::Timing::UnscheduleEvent(composition_event, 0);
|
||||
}
|
||||
|
||||
void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
|
||||
nvdrv = std::move(instance);
|
||||
}
|
||||
|
||||
u64 NVFlinger::OpenDisplay(std::string_view name) {
|
||||
LOG_WARNING(Service, "Opening display {}", name);
|
||||
std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
|
||||
LOG_DEBUG(Service, "Opening \"{}\" display", name);
|
||||
|
||||
// TODO(Subv): Currently we only support the Default display.
|
||||
ASSERT(name == "Default");
|
||||
|
||||
auto itr = std::find_if(displays.begin(), displays.end(),
|
||||
[&](const Display& display) { return display.name == name; });
|
||||
|
||||
ASSERT(itr != displays.end());
|
||||
const auto itr = std::find_if(displays.begin(), displays.end(),
|
||||
[&](const Display& display) { return display.name == name; });
|
||||
if (itr == displays.end()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return itr->id;
|
||||
}
|
||||
|
||||
u64 NVFlinger::CreateLayer(u64 display_id) {
|
||||
auto& display = GetDisplay(display_id);
|
||||
std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
|
||||
auto* const display = FindDisplay(display_id);
|
||||
|
||||
ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment");
|
||||
if (display == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
u64 layer_id = next_layer_id++;
|
||||
u32 buffer_queue_id = next_buffer_queue_id++;
|
||||
ASSERT_MSG(display->layers.empty(), "Only one layer is supported per display at the moment");
|
||||
|
||||
const u64 layer_id = next_layer_id++;
|
||||
const u32 buffer_queue_id = next_buffer_queue_id++;
|
||||
auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id);
|
||||
display.layers.emplace_back(layer_id, buffer_queue);
|
||||
display->layers.emplace_back(layer_id, buffer_queue);
|
||||
buffer_queues.emplace_back(std::move(buffer_queue));
|
||||
return layer_id;
|
||||
}
|
||||
|
||||
u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) {
|
||||
const auto& layer = GetLayer(display_id, layer_id);
|
||||
return layer.buffer_queue->GetId();
|
||||
std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const {
|
||||
const auto* const layer = FindLayer(display_id, layer_id);
|
||||
|
||||
if (layer == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return layer->buffer_queue->GetId();
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id) {
|
||||
return GetDisplay(display_id).vsync_event.readable;
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const {
|
||||
auto* const display = FindDisplay(display_id);
|
||||
|
||||
if (display == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return display->vsync_event.readable;
|
||||
}
|
||||
|
||||
std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const {
|
||||
auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
|
||||
[&](const auto& queue) { return queue->GetId() == id; });
|
||||
std::shared_ptr<BufferQueue> NVFlinger::FindBufferQueue(u32 id) const {
|
||||
const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
|
||||
[&](const auto& queue) { return queue->GetId() == id; });
|
||||
|
||||
ASSERT(itr != buffer_queues.end());
|
||||
return *itr;
|
||||
}
|
||||
|
||||
Display& NVFlinger::GetDisplay(u64 display_id) {
|
||||
auto itr = std::find_if(displays.begin(), displays.end(),
|
||||
[&](const Display& display) { return display.id == display_id; });
|
||||
Display* NVFlinger::FindDisplay(u64 display_id) {
|
||||
const auto itr = std::find_if(displays.begin(), displays.end(),
|
||||
[&](const Display& display) { return display.id == display_id; });
|
||||
|
||||
ASSERT(itr != displays.end());
|
||||
return *itr;
|
||||
if (itr == displays.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &*itr;
|
||||
}
|
||||
|
||||
Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) {
|
||||
auto& display = GetDisplay(display_id);
|
||||
const Display* NVFlinger::FindDisplay(u64 display_id) const {
|
||||
const auto itr = std::find_if(displays.begin(), displays.end(),
|
||||
[&](const Display& display) { return display.id == display_id; });
|
||||
|
||||
auto itr = std::find_if(display.layers.begin(), display.layers.end(),
|
||||
[&](const Layer& layer) { return layer.id == layer_id; });
|
||||
if (itr == displays.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASSERT(itr != display.layers.end());
|
||||
return *itr;
|
||||
return &*itr;
|
||||
}
|
||||
|
||||
Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
|
||||
auto* const display = FindDisplay(display_id);
|
||||
|
||||
if (display == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto itr = std::find_if(display->layers.begin(), display->layers.end(),
|
||||
[&](const Layer& layer) { return layer.id == layer_id; });
|
||||
|
||||
if (itr == display->layers.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &*itr;
|
||||
}
|
||||
|
||||
const Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
|
||||
const auto* const display = FindDisplay(display_id);
|
||||
|
||||
if (display == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto itr = std::find_if(display->layers.begin(), display->layers.end(),
|
||||
[&](const Layer& layer) { return layer.id == layer_id; });
|
||||
|
||||
if (itr == display->layers.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &*itr;
|
||||
}
|
||||
|
||||
void NVFlinger::Compose() {
|
||||
@@ -145,7 +191,7 @@ void NVFlinger::Compose() {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& igbp_buffer = buffer->get().igbp_buffer;
|
||||
const auto& igbp_buffer = buffer->get().igbp_buffer;
|
||||
|
||||
// Now send the buffer to the GPU for drawing.
|
||||
// TODO(Subv): Support more than just disp0. The display device selection is probably based
|
||||
@@ -166,7 +212,7 @@ Layer::~Layer() = default;
|
||||
|
||||
Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse,
|
||||
vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
fmt::format("Display VSync Event {}", id));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -12,7 +14,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
namespace CoreTiming {
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
@@ -56,35 +58,55 @@ public:
|
||||
/// Sets the NVDrv module instance to use to send buffers to the GPU.
|
||||
void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance);
|
||||
|
||||
/// Opens the specified display and returns the id.
|
||||
u64 OpenDisplay(std::string_view name);
|
||||
/// Opens the specified display and returns the ID.
|
||||
///
|
||||
/// If an invalid display name is provided, then an empty optional is returned.
|
||||
std::optional<u64> OpenDisplay(std::string_view name);
|
||||
|
||||
/// Creates a layer on the specified display and returns the layer id.
|
||||
u64 CreateLayer(u64 display_id);
|
||||
/// Creates a layer on the specified display and returns the layer ID.
|
||||
///
|
||||
/// If an invalid display ID is specified, then an empty optional is returned.
|
||||
std::optional<u64> CreateLayer(u64 display_id);
|
||||
|
||||
/// Gets the buffer queue id of the specified layer in the specified display.
|
||||
u32 GetBufferQueueId(u64 display_id, u64 layer_id);
|
||||
/// Finds the buffer queue ID of the specified layer in the specified display.
|
||||
///
|
||||
/// If an invalid display ID or layer ID is provided, then an empty optional is returned.
|
||||
std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id) const;
|
||||
|
||||
/// Gets the vsync event for the specified display.
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> GetVsyncEvent(u64 display_id);
|
||||
///
|
||||
/// If an invalid display ID is provided, then nullptr is returned.
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
|
||||
|
||||
/// Obtains a buffer queue identified by the id.
|
||||
std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const;
|
||||
/// Obtains a buffer queue identified by the ID.
|
||||
std::shared_ptr<BufferQueue> FindBufferQueue(u32 id) const;
|
||||
|
||||
/// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
|
||||
/// finished.
|
||||
void Compose();
|
||||
|
||||
private:
|
||||
/// Returns the display identified by the specified id.
|
||||
Display& GetDisplay(u64 display_id);
|
||||
/// Finds the display identified by the specified ID.
|
||||
Display* FindDisplay(u64 display_id);
|
||||
|
||||
/// Returns the layer identified by the specified id in the desired display.
|
||||
Layer& GetLayer(u64 display_id, u64 layer_id);
|
||||
/// Finds the display identified by the specified ID.
|
||||
const Display* FindDisplay(u64 display_id) const;
|
||||
|
||||
/// Finds the layer identified by the specified ID in the desired display.
|
||||
Layer* FindLayer(u64 display_id, u64 layer_id);
|
||||
|
||||
/// Finds the layer identified by the specified ID in the desired display.
|
||||
const Layer* FindLayer(u64 display_id, u64 layer_id) const;
|
||||
|
||||
std::shared_ptr<Nvidia::Module> nvdrv;
|
||||
|
||||
std::vector<Display> displays;
|
||||
std::array<Display, 5> displays{{
|
||||
{0, "Default"},
|
||||
{1, "External"},
|
||||
{2, "Edid"},
|
||||
{3, "Internal"},
|
||||
{4, "Null"},
|
||||
}};
|
||||
std::vector<std::shared_ptr<BufferQueue>> buffer_queues;
|
||||
|
||||
/// Id to use for the next layer that is created, this counter is shared among all displays.
|
||||
@@ -93,8 +115,8 @@ private:
|
||||
/// layers.
|
||||
u32 next_buffer_queue_id = 1;
|
||||
|
||||
/// CoreTiming event that handles screen composition.
|
||||
CoreTiming::EventType* composition_event;
|
||||
/// Event that handles screen composition.
|
||||
Core::Timing::EventType* composition_event;
|
||||
};
|
||||
|
||||
} // namespace Service::NVFlinger
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
explicit BootMode() : ServiceFramework{"pm:bm"} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &BootMode::GetBootMode, "GetBootMode"},
|
||||
{1, nullptr, "SetMaintenanceBoot"},
|
||||
{1, &BootMode::SetMaintenanceBoot, "SetMaintenanceBoot"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -24,8 +24,19 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode
|
||||
rb.PushEnum(boot_mode);
|
||||
}
|
||||
|
||||
void SetMaintenanceBoot(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PM, "called");
|
||||
|
||||
boot_mode = SystemBootMode::Maintenance;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
SystemBootMode boot_mode = SystemBootMode::Normal;
|
||||
};
|
||||
|
||||
class DebugMonitor final : public ServiceFramework<DebugMonitor> {
|
||||
|
||||
@@ -9,7 +9,12 @@ class ServiceManager;
|
||||
}
|
||||
|
||||
namespace Service::PM {
|
||||
enum class SystemBootMode : u32 { Normal = 0, Maintenance = 1 };
|
||||
|
||||
enum class SystemBootMode {
|
||||
Normal,
|
||||
Maintenance,
|
||||
};
|
||||
|
||||
/// Registers all PM services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager);
|
||||
|
||||
|
||||
@@ -17,13 +17,13 @@ public:
|
||||
explicit PSC_C() : ServiceFramework{"psc:c"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown1"},
|
||||
{1, nullptr, "Unknown2"},
|
||||
{2, nullptr, "Unknown3"},
|
||||
{3, nullptr, "Unknown4"},
|
||||
{4, nullptr, "Unknown5"},
|
||||
{5, nullptr, "Unknown6"},
|
||||
{6, nullptr, "Unknown7"},
|
||||
{0, nullptr, "Initialize"},
|
||||
{1, nullptr, "DispatchRequest"},
|
||||
{2, nullptr, "GetResult"},
|
||||
{3, nullptr, "GetState"},
|
||||
{4, nullptr, "Cancel"},
|
||||
{5, nullptr, "PrintModuleInformation"},
|
||||
{6, nullptr, "GetModuleInformation"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -39,7 +39,8 @@ public:
|
||||
{0, nullptr, "Initialize"},
|
||||
{1, nullptr, "GetRequest"},
|
||||
{2, nullptr, "Acknowledge"},
|
||||
{3, nullptr, "Unknown1"},
|
||||
{3, nullptr, "Finalize"},
|
||||
{4, nullptr, "AcknowledgeEx"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -12,9 +12,16 @@
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/service/time/interface.h"
|
||||
#include "core/hle/service/time/time.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service::Time {
|
||||
|
||||
static std::chrono::seconds GetSecondsSinceEpoch() {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()) +
|
||||
Settings::values.custom_rtc_differential;
|
||||
}
|
||||
|
||||
static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
|
||||
CalendarAdditionalInfo& additional_info,
|
||||
[[maybe_unused]] const TimeZoneRule& /*rule*/) {
|
||||
@@ -68,9 +75,7 @@ public:
|
||||
|
||||
private:
|
||||
void GetCurrentTime(Kernel::HLERequestContext& ctx) {
|
||||
const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count()};
|
||||
const s64 time_since_epoch{GetSecondsSinceEpoch().count()};
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
@@ -101,8 +106,8 @@ private:
|
||||
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
SteadyClockTimePoint steady_clock_time_point{
|
||||
CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000};
|
||||
const SteadyClockTimePoint steady_clock_time_point{
|
||||
Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000};
|
||||
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw(steady_clock_time_point);
|
||||
@@ -266,10 +271,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto initial_type = rp.PopRaw<u8>();
|
||||
|
||||
const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count()};
|
||||
|
||||
const s64 time_since_epoch{GetSecondsSinceEpoch().count()};
|
||||
const std::time_t time(time_since_epoch);
|
||||
const std::tm* tm = std::localtime(&time);
|
||||
if (tm == nullptr) {
|
||||
@@ -280,7 +282,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
const SteadyClockTimePoint steady_clock_time_point{
|
||||
CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000, {}};
|
||||
Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000, {}};
|
||||
|
||||
CalendarTime calendar_time{};
|
||||
calendar_time.year = tm->tm_year + 1900;
|
||||
|
||||
@@ -32,12 +32,27 @@
|
||||
|
||||
namespace Service::VI {
|
||||
|
||||
constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::VI, 1};
|
||||
constexpr ResultCode ERR_UNSUPPORTED{ErrorModule::VI, 6};
|
||||
constexpr ResultCode ERR_NOT_FOUND{ErrorModule::VI, 7};
|
||||
|
||||
struct DisplayInfo {
|
||||
/// The name of this particular display.
|
||||
char display_name[0x40]{"Default"};
|
||||
u64 unknown_1{1};
|
||||
u64 unknown_2{1};
|
||||
u64 width{1280};
|
||||
u64 height{720};
|
||||
|
||||
/// Whether or not the display has a limited number of layers.
|
||||
u8 has_limited_layers{1};
|
||||
INSERT_PADDING_BYTES(7){};
|
||||
|
||||
/// Indicates the total amount of layers supported by the display.
|
||||
/// @note This is only valid if has_limited_layers is set.
|
||||
u64 max_layers{1};
|
||||
|
||||
/// Maximum width in pixels.
|
||||
u64 width{1920};
|
||||
|
||||
/// Maximum height in pixels.
|
||||
u64 height{1080};
|
||||
};
|
||||
static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
|
||||
|
||||
@@ -510,7 +525,7 @@ private:
|
||||
LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
|
||||
static_cast<u32>(transaction), flags);
|
||||
|
||||
auto buffer_queue = nv_flinger->GetBufferQueue(id);
|
||||
auto buffer_queue = nv_flinger->FindBufferQueue(id);
|
||||
|
||||
if (transaction == TransactionId::Connect) {
|
||||
IGBPConnectRequestParcel request{ctx.ReadBuffer()};
|
||||
@@ -544,7 +559,7 @@ private:
|
||||
[=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
|
||||
Kernel::ThreadWakeupReason reason) {
|
||||
// Repeat TransactParcel DequeueBuffer when a buffer is available
|
||||
auto buffer_queue = nv_flinger->GetBufferQueue(id);
|
||||
auto buffer_queue = nv_flinger->FindBufferQueue(id);
|
||||
std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
|
||||
ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer.");
|
||||
|
||||
@@ -614,7 +629,7 @@ private:
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
|
||||
|
||||
const auto buffer_queue = nv_flinger->GetBufferQueue(id);
|
||||
const auto buffer_queue = nv_flinger->FindBufferQueue(id);
|
||||
|
||||
// TODO(Subv): Find out what this actually is.
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
@@ -690,13 +705,14 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
// This function currently does nothing but return a success error code in
|
||||
// the vi library itself, so do the same thing, but log out the passed in values.
|
||||
void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 layer_id = rp.Pop<u64>();
|
||||
const bool visibility = rp.Pop<bool>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
|
||||
visibility);
|
||||
LOG_DEBUG(Service_VI, "called, layer_id=0x{:08X}, visibility={}", layer_id, visibility);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -823,11 +839,16 @@ private:
|
||||
"(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
|
||||
unknown, display, aruid);
|
||||
|
||||
const u64 layer_id = nv_flinger->CreateLayer(display);
|
||||
const auto layer_id = nv_flinger->CreateLayer(display);
|
||||
if (!layer_id) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(layer_id);
|
||||
rb.Push(*layer_id);
|
||||
}
|
||||
|
||||
void AddToLayerStack(Kernel::HLERequestContext& ctx) {
|
||||
@@ -863,6 +884,22 @@ public:
|
||||
~IApplicationDisplayService() = default;
|
||||
|
||||
private:
|
||||
enum class ConvertedScaleMode : u64 {
|
||||
Freeze = 0,
|
||||
ScaleToWindow = 1,
|
||||
ScaleAndCrop = 2,
|
||||
None = 3,
|
||||
PreserveAspectRatio = 4,
|
||||
};
|
||||
|
||||
enum class NintendoScaleMode : u32 {
|
||||
None = 0,
|
||||
Freeze = 1,
|
||||
ScaleToWindow = 2,
|
||||
ScaleAndCrop = 3,
|
||||
PreserveAspectRatio = 4,
|
||||
};
|
||||
|
||||
void GetRelayService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
@@ -919,9 +956,16 @@ private:
|
||||
|
||||
ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
|
||||
|
||||
const auto display_id = nv_flinger->OpenDisplay(name);
|
||||
if (!display_id) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(nv_flinger->OpenDisplay(name));
|
||||
rb.Push<u64>(*display_id);
|
||||
}
|
||||
|
||||
void CloseDisplay(Kernel::HLERequestContext& ctx) {
|
||||
@@ -947,33 +991,43 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 display_id = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id);
|
||||
LOG_DEBUG(Service_VI, "called. display_id=0x{:016X}", display_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
} else {
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
}
|
||||
// This only returns the fixed values of 1280x720 and makes no distinguishing
|
||||
// between docked and undocked dimensions. We take the liberty of applying
|
||||
// the resolution scaling factor here.
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
}
|
||||
|
||||
void SetLayerScalingMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u32 scaling_mode = rp.Pop<u32>();
|
||||
const auto scaling_mode = rp.PopEnum<NintendoScaleMode>();
|
||||
const u64 unknown = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. scaling_mode=0x{:08X}, unknown=0x{:016X}",
|
||||
scaling_mode, unknown);
|
||||
LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}",
|
||||
static_cast<u32>(scaling_mode), unknown);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
if (scaling_mode > NintendoScaleMode::PreserveAspectRatio) {
|
||||
LOG_ERROR(Service_VI, "Invalid scaling mode provided.");
|
||||
rb.Push(ERR_OPERATION_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scaling_mode != NintendoScaleMode::ScaleToWindow &&
|
||||
scaling_mode != NintendoScaleMode::PreserveAspectRatio) {
|
||||
LOG_ERROR(Service_VI, "Unsupported scaling mode supplied.");
|
||||
rb.Push(ERR_UNSUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -1002,10 +1056,21 @@ private:
|
||||
|
||||
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
|
||||
|
||||
const u64 display_id = nv_flinger->OpenDisplay(display_name);
|
||||
const u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id);
|
||||
const auto display_id = nv_flinger->OpenDisplay(display_name);
|
||||
if (!display_id) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
NativeWindow native_window{buffer_queue_id};
|
||||
const auto buffer_queue_id = nv_flinger->FindBufferQueueId(*display_id, layer_id);
|
||||
if (!buffer_queue_id) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
NativeWindow native_window{*buffer_queue_id};
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
|
||||
@@ -1021,13 +1086,24 @@ private:
|
||||
|
||||
// TODO(Subv): What's the difference between a Stray and a Managed layer?
|
||||
|
||||
const u64 layer_id = nv_flinger->CreateLayer(display_id);
|
||||
const u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id);
|
||||
const auto layer_id = nv_flinger->CreateLayer(display_id);
|
||||
if (!layer_id) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
NativeWindow native_window{buffer_queue_id};
|
||||
const auto buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, *layer_id);
|
||||
if (!buffer_queue_id) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
NativeWindow native_window{*buffer_queue_id};
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(layer_id);
|
||||
rb.Push(*layer_id);
|
||||
rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
|
||||
}
|
||||
|
||||
@@ -1047,58 +1123,49 @@ private:
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id);
|
||||
|
||||
const auto vsync_event = nv_flinger->GetVsyncEvent(display_id);
|
||||
const auto vsync_event = nv_flinger->FindVsyncEvent(display_id);
|
||||
if (!vsync_event) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(vsync_event);
|
||||
}
|
||||
|
||||
enum class ConvertedScaleMode : u64 {
|
||||
None = 0, // VI seems to name this as "Unknown" but lots of games pass it, assume it's no
|
||||
// scaling/default
|
||||
Freeze = 1,
|
||||
ScaleToWindow = 2,
|
||||
Crop = 3,
|
||||
NoCrop = 4,
|
||||
};
|
||||
|
||||
// This struct is different, currently it's 1:1 but this might change in the future.
|
||||
enum class NintendoScaleMode : u32 {
|
||||
None = 0,
|
||||
Freeze = 1,
|
||||
ScaleToWindow = 2,
|
||||
Crop = 3,
|
||||
NoCrop = 4,
|
||||
};
|
||||
|
||||
void ConvertScalingMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto mode = rp.PopEnum<NintendoScaleMode>();
|
||||
const auto mode = rp.PopEnum<NintendoScaleMode>();
|
||||
LOG_DEBUG(Service_VI, "called mode={}", static_cast<u32>(mode));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
const auto converted_mode = ConvertScalingModeImpl(mode);
|
||||
|
||||
if (converted_mode.Succeeded()) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(*converted_mode);
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(converted_mode.Code());
|
||||
}
|
||||
}
|
||||
|
||||
static ResultVal<ConvertedScaleMode> ConvertScalingModeImpl(NintendoScaleMode mode) {
|
||||
switch (mode) {
|
||||
case NintendoScaleMode::None:
|
||||
rb.PushEnum(ConvertedScaleMode::None);
|
||||
break;
|
||||
return MakeResult(ConvertedScaleMode::None);
|
||||
case NintendoScaleMode::Freeze:
|
||||
rb.PushEnum(ConvertedScaleMode::Freeze);
|
||||
break;
|
||||
return MakeResult(ConvertedScaleMode::Freeze);
|
||||
case NintendoScaleMode::ScaleToWindow:
|
||||
rb.PushEnum(ConvertedScaleMode::ScaleToWindow);
|
||||
break;
|
||||
case NintendoScaleMode::Crop:
|
||||
rb.PushEnum(ConvertedScaleMode::Crop);
|
||||
break;
|
||||
case NintendoScaleMode::NoCrop:
|
||||
rb.PushEnum(ConvertedScaleMode::NoCrop);
|
||||
break;
|
||||
return MakeResult(ConvertedScaleMode::ScaleToWindow);
|
||||
case NintendoScaleMode::ScaleAndCrop:
|
||||
return MakeResult(ConvertedScaleMode::ScaleAndCrop);
|
||||
case NintendoScaleMode::PreserveAspectRatio:
|
||||
return MakeResult(ConvertedScaleMode::PreserveAspectRatio);
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unknown scaling mode {}", static_cast<u32>(mode));
|
||||
rb.PushEnum(ConvertedScaleMode::None);
|
||||
break;
|
||||
return ERR_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -178,6 +178,8 @@ public:
|
||||
|
||||
/**
|
||||
* Get the banner (typically banner section) of the application
|
||||
* In the context of NX, this is the animation that displays in the bottom right of the screen
|
||||
* when a game boots. Stored in GIF format.
|
||||
* @param buffer Reference to buffer to store data
|
||||
* @return ResultStatus result of function
|
||||
*/
|
||||
@@ -187,6 +189,8 @@ public:
|
||||
|
||||
/**
|
||||
* Get the logo (typically logo section) of the application
|
||||
* In the context of NX, this is the static image that displays in the top left of the screen
|
||||
* when a game boots. Stored in JPEG format.
|
||||
* @param buffer Reference to buffer to store data
|
||||
* @return ResultStatus result of function
|
||||
*/
|
||||
@@ -259,6 +263,15 @@ public:
|
||||
return ResultStatus::ErrorNotImplemented;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the RomFS of the manual of the application
|
||||
* @param file The raw manual RomFS of the game
|
||||
* @return ResultStatus result of function
|
||||
*/
|
||||
virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) {
|
||||
return ResultStatus::ErrorNotImplemented;
|
||||
}
|
||||
|
||||
protected:
|
||||
FileSys::VirtualFile file;
|
||||
bool is_loaded = false;
|
||||
|
||||
@@ -79,4 +79,13 @@ u64 AppLoader_NAX::ReadRomFSIVFCOffset() const {
|
||||
ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) {
|
||||
return nca_loader->ReadProgramId(out_program_id);
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NAX::ReadBanner(std::vector<u8>& buffer) {
|
||||
return nca_loader->ReadBanner(buffer);
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NAX::ReadLogo(std::vector<u8>& buffer) {
|
||||
return nca_loader->ReadLogo(buffer);
|
||||
}
|
||||
|
||||
} // namespace Loader
|
||||
|
||||
@@ -39,6 +39,9 @@ public:
|
||||
u64 ReadRomFSIVFCOffset() const override;
|
||||
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||
|
||||
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
|
||||
ResultStatus ReadLogo(std::vector<u8>& buffer) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<FileSys::NAX> nax;
|
||||
std::unique_ptr<AppLoader_NCA> nca_loader;
|
||||
|
||||
@@ -84,4 +84,23 @@ ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NCA::ReadBanner(std::vector<u8>& buffer) {
|
||||
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
|
||||
return ResultStatus::ErrorNotInitialized;
|
||||
const auto logo = nca->GetLogoPartition();
|
||||
if (logo == nullptr)
|
||||
return ResultStatus::ErrorNoIcon;
|
||||
buffer = logo->GetFile("StartupMovie.gif")->ReadAllBytes();
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NCA::ReadLogo(std::vector<u8>& buffer) {
|
||||
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
|
||||
return ResultStatus::ErrorNotInitialized;
|
||||
const auto logo = nca->GetLogoPartition();
|
||||
if (logo == nullptr)
|
||||
return ResultStatus::ErrorNoIcon;
|
||||
buffer = logo->GetFile("NintendoLogo.png")->ReadAllBytes();
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
} // namespace Loader
|
||||
|
||||
@@ -39,6 +39,9 @@ public:
|
||||
u64 ReadRomFSIVFCOffset() const override;
|
||||
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||
|
||||
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
|
||||
ResultStatus ReadLogo(std::vector<u8>& buffer) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<FileSys::NCA> nca;
|
||||
std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;
|
||||
|
||||
@@ -158,4 +158,21 @@ ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) {
|
||||
nacp = *nacp_file;
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) {
|
||||
const auto nca = nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Manual);
|
||||
if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr)
|
||||
return ResultStatus::ErrorNoRomFS;
|
||||
file = nca->GetRomFS();
|
||||
return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NSP::ReadBanner(std::vector<u8>& buffer) {
|
||||
return secondary_loader->ReadBanner(buffer);
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NSP::ReadLogo(std::vector<u8>& buffer) {
|
||||
return secondary_loader->ReadLogo(buffer);
|
||||
}
|
||||
|
||||
} // namespace Loader
|
||||
|
||||
@@ -44,6 +44,10 @@ public:
|
||||
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
||||
ResultStatus ReadTitle(std::string& title) override;
|
||||
ResultStatus ReadControlData(FileSys::NACP& nacp) override;
|
||||
ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
|
||||
|
||||
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
|
||||
ResultStatus ReadLogo(std::vector<u8>& buffer) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<FileSys::NSP> nsp;
|
||||
|
||||
@@ -128,4 +128,21 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) {
|
||||
const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(),
|
||||
FileSys::ContentRecordType::Manual);
|
||||
if (xci->GetStatus() != ResultStatus::Success || nca == nullptr)
|
||||
return ResultStatus::ErrorXCIMissingPartition;
|
||||
file = nca->GetRomFS();
|
||||
return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_XCI::ReadBanner(std::vector<u8>& buffer) {
|
||||
return nca_loader->ReadBanner(buffer);
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_XCI::ReadLogo(std::vector<u8>& buffer) {
|
||||
return nca_loader->ReadLogo(buffer);
|
||||
}
|
||||
|
||||
} // namespace Loader
|
||||
|
||||
@@ -44,6 +44,10 @@ public:
|
||||
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
||||
ResultStatus ReadTitle(std::string& title) override;
|
||||
ResultStatus ReadControlData(FileSys::NACP& control) override;
|
||||
ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
|
||||
|
||||
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
|
||||
ResultStatus ReadLogo(std::vector<u8>& buffer) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<FileSys::XCI> xci;
|
||||
|
||||
@@ -74,4 +74,33 @@ void Apply() {
|
||||
Service::HID::ReloadInputDevices();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void LogSetting(const std::string& name, const T& value) {
|
||||
LOG_INFO(Config, "{}: {}", name, value);
|
||||
}
|
||||
|
||||
void LogSettings() {
|
||||
LOG_INFO(Config, "yuzu Configuration:");
|
||||
LogSetting("System_UseDockedMode", Settings::values.use_docked_mode);
|
||||
LogSetting("System_EnableNfc", Settings::values.enable_nfc);
|
||||
LogSetting("System_RngSeed", Settings::values.rng_seed.value_or(0));
|
||||
LogSetting("System_CurrentUser", Settings::values.current_user);
|
||||
LogSetting("System_LanguageIndex", Settings::values.language_index);
|
||||
LogSetting("Core_UseCpuJit", Settings::values.use_cpu_jit);
|
||||
LogSetting("Core_UseMultiCore", Settings::values.use_multi_core);
|
||||
LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor);
|
||||
LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit);
|
||||
LogSetting("Renderer_FrameLimit", Settings::values.frame_limit);
|
||||
LogSetting("Renderer_UseAccurateGpuEmulation", Settings::values.use_accurate_gpu_emulation);
|
||||
LogSetting("Audio_OutputEngine", Settings::values.sink_id);
|
||||
LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching);
|
||||
LogSetting("Audio_OutputDevice", Settings::values.audio_device_id);
|
||||
LogSetting("DataStorage_UseVirtualSd", Settings::values.use_virtual_sd);
|
||||
LogSetting("DataStorage_NandDir", Settings::values.nand_dir);
|
||||
LogSetting("DataStorage_SdmcDir", Settings::values.sdmc_dir);
|
||||
LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub);
|
||||
LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port);
|
||||
LogSetting("Debugging_ProgramArgs", Settings::values.program_args);
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -350,6 +351,11 @@ struct Values {
|
||||
bool use_docked_mode;
|
||||
bool enable_nfc;
|
||||
std::optional<u32> rng_seed;
|
||||
// Measured in seconds since epoch
|
||||
std::optional<std::chrono::seconds> custom_rtc;
|
||||
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
|
||||
std::chrono::seconds custom_rtc_differential;
|
||||
|
||||
s32 current_user;
|
||||
s32 language_index;
|
||||
|
||||
@@ -385,6 +391,7 @@ struct Values {
|
||||
float resolution_factor;
|
||||
bool use_frame_limit;
|
||||
u16 frame_limit;
|
||||
bool use_disk_shader_cache;
|
||||
bool use_accurate_gpu_emulation;
|
||||
|
||||
float bg_red;
|
||||
@@ -419,4 +426,5 @@ struct Values {
|
||||
} extern values;
|
||||
|
||||
void Apply();
|
||||
void LogSettings();
|
||||
} // namespace Settings
|
||||
|
||||
@@ -158,6 +158,8 @@ TelemetrySession::TelemetrySession() {
|
||||
AddField(Telemetry::FieldType::UserConfig, "Renderer_UseFrameLimit",
|
||||
Settings::values.use_frame_limit);
|
||||
AddField(Telemetry::FieldType::UserConfig, "Renderer_FrameLimit", Settings::values.frame_limit);
|
||||
AddField(Telemetry::FieldType::UserConfig, "Renderer_UseDiskShaderCache",
|
||||
Settings::values.use_disk_shader_cache);
|
||||
AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAccurateGpuEmulation",
|
||||
Settings::values.use_accurate_gpu_emulation);
|
||||
AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user