Compare commits
430 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e60d4d70bc | ||
|
|
444231a83d | ||
|
|
c1accfefde | ||
|
|
27e5efd265 | ||
|
|
f5ec165e8c | ||
|
|
edd668047c | ||
|
|
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 | ||
|
|
7c6bb8c17f | ||
|
|
215ca770df | ||
|
|
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 | ||
|
|
48a526dba1 | ||
|
|
f2536cafe5 | ||
|
|
9ec9709f68 | ||
|
|
5af0340066 | ||
|
|
2c0f831468 | ||
|
|
56a97647a3 | ||
|
|
a6aa710b84 | ||
|
|
11f990975c | ||
|
|
ceeff8ebfd | ||
|
|
7538fa4a67 | ||
|
|
5bfd810ab5 | ||
|
|
dea1db0414 | ||
|
|
c91d2bac45 | ||
|
|
351f010cfc | ||
|
|
fe3bf4f075 | ||
|
|
6a0e258dde | ||
|
|
dd0b17a5f0 | ||
|
|
c8c8412901 | ||
|
|
cd8924520c | ||
|
|
f5f35caf20 | ||
|
|
1f0c8bfeda | ||
|
|
15501477e7 | ||
|
|
f96bb2520b | ||
|
|
09ffa0cb21 | ||
|
|
244b46af5a | ||
|
|
b4242633ad | ||
|
|
3a8d38be7e | ||
|
|
8769604144 | ||
|
|
205e6d3b97 | ||
|
|
039e58a984 | ||
|
|
a17dd30057 | ||
|
|
776ce5d74c | ||
|
|
387bffda5e | ||
|
|
e5dfbe22ee | ||
|
|
331c252509 | ||
|
|
f80229b676 | ||
|
|
97fb6179b9 | ||
|
|
fa97f50bff | ||
|
|
614de1dba7 | ||
|
|
af51f123fa | ||
|
|
22d4e10664 | ||
|
|
8495f1df2a | ||
|
|
0c5ede492f | ||
|
|
cb930c4b5a | ||
|
|
2020ba06e1 | ||
|
|
af9336df57 | ||
|
|
ef4c4e239d | ||
|
|
45da3be40e | ||
|
|
e00e1fc755 | ||
|
|
32bfa92c71 | ||
|
|
85a3368e6d | ||
|
|
69f622be36 | ||
|
|
4c20a39828 | ||
|
|
621b25b6be | ||
|
|
abbcc8e61e | ||
|
|
94db6e5f3f | ||
|
|
a81ff6f54c | ||
|
|
f80bc712ea | ||
|
|
771431f625 | ||
|
|
19bfbb28ce | ||
|
|
357bc956ae | ||
|
|
9aa68212d9 | ||
|
|
c6da772b24 | ||
|
|
fbeaa330a3 | ||
|
|
9c2d83cb9c | ||
|
|
4d61ac08aa | ||
|
|
08d5663cb8 | ||
|
|
7b9c982d29 | ||
|
|
6d7514ccec | ||
|
|
5102c91256 | ||
|
|
7149332712 | ||
|
|
e0b0947437 | ||
|
|
4a32d92e6e |
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)
|
||||
137
CONTRIBUTING.md
137
CONTRIBUTING.md
@@ -1,136 +1 @@
|
||||
# Reporting Issues
|
||||
|
||||
**The issue tracker is not a support forum.** Unless you can provide precise *technical information* regarding an issue, you *should not post in it*. If you need support, first read the [FAQ](https://github.com/yuzu-emu/yuzu/wiki/FAQ) and then either visit our [Discord server](https://discordapp.com/invite/u77vRWY), [our forum](https://community.citra-emu.org) or ask in a general emulation forum such as [/r/emulation](https://www.reddit.com/r/emulation/). If you post support questions, generic messages to the developers or vague reports without technical details, they will be closed and locked.
|
||||
|
||||
If you believe you have a valid issue report, please post text or a screenshot from the log (the console window that opens alongside yuzu) and build version (hex string visible in the titlebar and zip filename), as well as your hardware and software information if applicable.
|
||||
|
||||
# Contributing
|
||||
yuzu is a brand new project, so we have a great opportunity to keep things clean and well organized early on. As such, coding style is very important when making commits. We run clang-format on our CI to check the code. Please use it to format your code when contributing. However, it doesn't cover all the rules below. Some of them aren't very strict rules since we want to be flexible and we understand that under certain circumstances some of them can be counterproductive. Just try to follow as many of them as possible.
|
||||
|
||||
# Using clang format (version 6.0)
|
||||
When generating the native build script for your toolset, cmake will try to find the correct version of clang format (or will download it on windows). Before running cmake, please install clang format version 6.0 for your platform as follows:
|
||||
|
||||
* Windows: do nothing; cmake will download a pre built binary for MSVC and MINGW. MSVC users can additionally install a clang format Visual Studio extension to add features like format on save.
|
||||
* OSX: run `brew install clang-format`.
|
||||
* Linux: use your package manager to get an appropriate binary.
|
||||
|
||||
If clang format is found, then cmake will add a custom build target that can be run at any time to run clang format against *all* source files and update the formatting in them. This should be used before making a pull request so that the reviewers can spend more time reviewing the code instead of having to worry about minor style violations. On MSVC, you can run clang format by building the clang-format project in the solution. On OSX, you can either use the Makefile target `make clang-format` or by building the clang-format target in XCode. For Makefile builds, you can use the clang-format target with `make clang-format`
|
||||
|
||||
### General Rules
|
||||
* A lot of code was taken from other projects (e.g. Citra, Dolphin, PPSSPP, Gekko). In general, when editing other people's code, follow the style of the module you're in (or better yet, fix the style if it drastically differs from our guide).
|
||||
* Line width is typically 100 characters. Please do not use 80-characters.
|
||||
* Don't ever introduce new external dependencies into Core
|
||||
* Don't use any platform specific code in Core
|
||||
* Use namespaces often
|
||||
* Avoid the use of C-style casts and instead prefer C++-style `static_cast` and `reinterpret_cast`. Try to avoid using `dynamic_cast`. Never use `const_cast`.
|
||||
|
||||
### Naming Rules
|
||||
* Functions: `PascalCase`
|
||||
* Variables: `lower_case_underscored`. Prefix with `g_` if global.
|
||||
* Classes: `PascalCase`
|
||||
* Files and Directories: `lower_case_underscored`
|
||||
* Namespaces: `PascalCase`, `_` may also be used for clarity (e.g. `ARM_InitCore`)
|
||||
|
||||
### Indentation/Whitespace Style
|
||||
Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead.
|
||||
|
||||
### Comments
|
||||
* For regular comments, use C++ style (`//`) comments, even for multi-line ones.
|
||||
* For doc-comments (Doxygen comments), use `/// ` if it's a single line, else use the `/**` `*/` style featured in the example. Start the text on the second line, not the first containing `/**`.
|
||||
* For items that are both defined and declared in two separate files, put the doc-comment only next to the associated declaration. (In a header file, usually.) Otherwise, put it next to the implementation. Never duplicate doc-comments in both places.
|
||||
|
||||
```cpp
|
||||
// Includes should be sorted lexicographically
|
||||
// STD includes first
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
// then, library includes
|
||||
#include <nihstro/shared_binary.h>
|
||||
|
||||
// finally, yuzu includes
|
||||
#include "common/math_util.h"
|
||||
#include "common/vector_math.h"
|
||||
|
||||
// each major module is separated
|
||||
#include "video_core/pica.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace Example {
|
||||
|
||||
// Namespace contents are not indented
|
||||
|
||||
// Declare globals at the top
|
||||
int g_foo{}; // {} can be used to initialize types as 0, false, or nullptr
|
||||
char* g_some_pointer{}; // Pointer * and reference & stick to the type name, and make sure to initialize as nullptr!
|
||||
|
||||
/// A colorful enum.
|
||||
enum SomeEnum {
|
||||
ColorRed, ///< The color of fire.
|
||||
ColorGreen, ///< The color of grass.
|
||||
ColorBlue, ///< Not actually the color of water.
|
||||
};
|
||||
|
||||
/**
|
||||
* Very important struct that does a lot of stuff.
|
||||
* Note that the asterisks are indented by one space to align to the first line.
|
||||
*/
|
||||
struct Position {
|
||||
int x{}, y{}; // Always intitialize member variables!
|
||||
};
|
||||
|
||||
// Use "typename" rather than "class" here
|
||||
template <typename T>
|
||||
void FooBar() {
|
||||
const std::string some_string{ "prefer uniform initialization" };
|
||||
|
||||
int some_array[]{
|
||||
5,
|
||||
25,
|
||||
7,
|
||||
42,
|
||||
};
|
||||
|
||||
if (note == the_space_after_the_if) {
|
||||
CallAfunction();
|
||||
} else {
|
||||
// Use a space after the // when commenting
|
||||
}
|
||||
|
||||
// Place a single space after the for loop semicolons, prefer pre-increment
|
||||
for (int i{}; i != 25; ++i) {
|
||||
// This is how we write loops
|
||||
}
|
||||
|
||||
DoStuff(this, function, call, takes, up, multiple,
|
||||
lines, like, this);
|
||||
|
||||
if (this || condition_takes_up_multiple &&
|
||||
lines && like && this || everything ||
|
||||
alright || then) {
|
||||
|
||||
// Leave a blank space before the if block body if the condition was continued across
|
||||
// several lines.
|
||||
}
|
||||
|
||||
switch (var) {
|
||||
// No indentation for case label
|
||||
case 1: {
|
||||
int case_var{ var + 3 };
|
||||
DoSomething(case_var);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
DoSomething(var);
|
||||
return;
|
||||
|
||||
default:
|
||||
// Yes, even break for the last case
|
||||
break;
|
||||
}
|
||||
|
||||
std::vector<T> you_can_declare, a_few, variables, like_this;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
**The Contributor's Guide has moved to [the Citra wiki](https://github.com/citra-emu/citra/wiki/Contributing).**
|
||||
|
||||
@@ -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\*
|
||||
|
||||
2
externals/fmt
vendored
2
externals/fmt
vendored
Submodule externals/fmt updated: 3e75ad9822...9e554999ce
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
add_library(core STATIC
|
||||
arm/arm_interface.h
|
||||
arm/arm_interface.cpp
|
||||
arm/exclusive_monitor.cpp
|
||||
arm/exclusive_monitor.h
|
||||
arm/unicorn/arm_unicorn.cpp
|
||||
@@ -87,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
|
||||
@@ -135,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
|
||||
@@ -172,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
|
||||
|
||||
27
src/core/arm/arm_interface.cpp
Normal file
27
src/core/arm/arm_interface.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
void ARM_Interface::LogBacktrace() const {
|
||||
VAddr fp = GetReg(29);
|
||||
VAddr lr = GetReg(30);
|
||||
const VAddr sp = GetReg(13);
|
||||
const VAddr pc = GetPC();
|
||||
|
||||
LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc);
|
||||
while (true) {
|
||||
LOG_ERROR(Core_ARM, "{:016X}", lr);
|
||||
if (!fp) {
|
||||
break;
|
||||
}
|
||||
lr = Memory::Read64(fp + 8) - 4;
|
||||
fp = Memory::Read64(fp);
|
||||
}
|
||||
}
|
||||
} // namespace Core
|
||||
@@ -141,6 +141,14 @@ public:
|
||||
|
||||
/// Prepare core for thread reschedule (if needed to correctly handle state)
|
||||
virtual void PrepareReschedule() = 0;
|
||||
|
||||
/// fp (= r29) points to the last frame record.
|
||||
/// Note that this is the frame record for the *previous* frame, not the current one.
|
||||
/// Note we need to subtract 4 from our last read to get the proper address
|
||||
/// Frame records are two words long:
|
||||
/// fp+0 : pointer to previous frame record
|
||||
/// fp+8 : value of lr for frame
|
||||
void LogBacktrace() const;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -94,6 +97,11 @@ struct System::Impl {
|
||||
CoreTiming::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;
|
||||
}
|
||||
@@ -199,6 +210,11 @@ struct System::Impl {
|
||||
// Close app loader
|
||||
app_loader.reset();
|
||||
|
||||
// Clear all applets
|
||||
profile_selector.reset();
|
||||
software_keyboard.reset();
|
||||
web_browser.reset();
|
||||
|
||||
LOG_DEBUG(Core, "Shutdown OK");
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -92,16 +92,20 @@ void ProgramMetadata::Print() const {
|
||||
LOG_DEBUG(Service_FS, " > 64-bit instructions: {}",
|
||||
npdm_header.has_64_bit_instructions ? "YES" : "NO");
|
||||
|
||||
auto address_space = "Unknown";
|
||||
const char* address_space = "Unknown";
|
||||
switch (npdm_header.address_space_type) {
|
||||
case ProgramAddressSpaceType::Is36Bit:
|
||||
address_space = "64-bit (36-bit address space)";
|
||||
break;
|
||||
case ProgramAddressSpaceType::Is39Bit:
|
||||
address_space = "64-bit";
|
||||
address_space = "64-bit (39-bit address space)";
|
||||
break;
|
||||
case ProgramAddressSpaceType::Is32Bit:
|
||||
case ProgramAddressSpaceType::Is32BitNoMap:
|
||||
address_space = "32-bit";
|
||||
break;
|
||||
case ProgramAddressSpaceType::Is32BitNoMap:
|
||||
address_space = "32-bit (no map region)";
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_FS, " > Address space: {}\n", address_space);
|
||||
|
||||
@@ -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}",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/server_port.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/session.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
||||
@@ -22,11 +22,16 @@
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
SessionRequestHandler::SessionRequestHandler() = default;
|
||||
|
||||
SessionRequestHandler::~SessionRequestHandler() = default;
|
||||
|
||||
void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) {
|
||||
server_session->SetHleHandler(shared_from_this());
|
||||
connected_sessions.push_back(std::move(server_session));
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
namespace Service {
|
||||
class ServiceFrameworkBase;
|
||||
@@ -27,9 +25,13 @@ class Domain;
|
||||
class HandleTable;
|
||||
class HLERequestContext;
|
||||
class Process;
|
||||
class ServerSession;
|
||||
class Thread;
|
||||
class ReadableEvent;
|
||||
class WritableEvent;
|
||||
|
||||
enum class ThreadWakeupReason;
|
||||
|
||||
/**
|
||||
* Interface implemented by HLE Session handlers.
|
||||
* This can be provided to a ServerSession in order to hook into several relevant events
|
||||
@@ -37,7 +39,8 @@ class WritableEvent;
|
||||
*/
|
||||
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
|
||||
public:
|
||||
virtual ~SessionRequestHandler() = default;
|
||||
SessionRequestHandler();
|
||||
virtual ~SessionRequestHandler();
|
||||
|
||||
/**
|
||||
* Handles a sync request from the emulated application.
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -19,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"
|
||||
|
||||
@@ -87,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() {
|
||||
@@ -123,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();
|
||||
}
|
||||
|
||||
@@ -147,11 +127,6 @@ struct KernelCore::Impl {
|
||||
CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
|
||||
}
|
||||
|
||||
void InitializeTimers() {
|
||||
timer_callback_handle_table.Clear();
|
||||
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
|
||||
}
|
||||
|
||||
std::atomic<u32> next_object_id{0};
|
||||
std::atomic<u64> next_process_id{Process::ProcessIDMin};
|
||||
std::atomic<u64> next_thread_id{1};
|
||||
@@ -162,12 +137,6 @@ 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;
|
||||
// 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.
|
||||
@@ -199,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));
|
||||
}
|
||||
@@ -248,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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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,15 +88,9 @@ 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;
|
||||
|
||||
/// 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 {
|
||||
|
||||
@@ -20,6 +20,35 @@
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Kernel {
|
||||
namespace {
|
||||
/**
|
||||
* Sets up the primary application thread
|
||||
*
|
||||
* @param owner_process The parent process for the main thread
|
||||
* @param kernel The kernel instance to create the main thread under.
|
||||
* @param entry_point The address at which the thread should start execution
|
||||
* @param priority The priority to give the main thread
|
||||
*/
|
||||
void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_point, u32 priority) {
|
||||
// Setup page table so we can write to memory
|
||||
SetCurrentPageTable(&owner_process.VMManager().page_table);
|
||||
|
||||
// Initialize new "main" thread
|
||||
const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress();
|
||||
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0,
|
||||
owner_process.GetIdealCore(), stack_top, owner_process);
|
||||
|
||||
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
|
||||
|
||||
// Register 1 must be a handle to the main thread
|
||||
const Handle guest_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
|
||||
thread->SetGuestHandle(guest_handle);
|
||||
thread->GetContext().cpu_registers[1] = guest_handle;
|
||||
|
||||
// Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
|
||||
thread->ResumeFromWait();
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
CodeSet::CodeSet() = default;
|
||||
CodeSet::~CodeSet() = default;
|
||||
@@ -64,7 +93,7 @@ ResultCode Process::ClearSignalState() {
|
||||
|
||||
ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
|
||||
program_id = metadata.GetTitleID();
|
||||
ideal_processor = metadata.GetMainThreadCore();
|
||||
ideal_core = metadata.GetMainThreadCore();
|
||||
is_64bit_process = metadata.Is64BitProgram();
|
||||
|
||||
vm_manager.Reset(metadata.GetAddressSpaceType());
|
||||
@@ -86,7 +115,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
|
||||
vm_manager.LogLayout();
|
||||
ChangeStatus(ProcessStatus::Running);
|
||||
|
||||
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
|
||||
SetupMainThread(*this, kernel, entry_point, main_thread_priority);
|
||||
}
|
||||
|
||||
void Process::PrepareForTermination() {
|
||||
@@ -198,22 +227,6 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
|
||||
Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
|
||||
}
|
||||
|
||||
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
|
||||
return vm_manager.HeapAllocate(target, size, perms);
|
||||
}
|
||||
|
||||
ResultCode Process::HeapFree(VAddr target, u32 size) {
|
||||
return vm_manager.HeapFree(target, size);
|
||||
}
|
||||
|
||||
ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) {
|
||||
return vm_manager.MirrorMemory(dst_addr, src_addr, size, state);
|
||||
}
|
||||
|
||||
ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
|
||||
return vm_manager.UnmapRange(dst_addr, size);
|
||||
}
|
||||
|
||||
Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {}
|
||||
Kernel::Process::~Process() {}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/process_capability.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/vm_manager.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
#include "core/hle/result.h"
|
||||
@@ -27,6 +26,7 @@ namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
class ResourceLimit;
|
||||
class Thread;
|
||||
|
||||
struct AddressMapping {
|
||||
// Address and size must be page-aligned
|
||||
@@ -168,18 +168,18 @@ public:
|
||||
/// Gets the resource limit descriptor for this process
|
||||
SharedPtr<ResourceLimit> GetResourceLimit() const;
|
||||
|
||||
/// Gets the default CPU ID for this process
|
||||
u8 GetDefaultProcessorID() const {
|
||||
return ideal_processor;
|
||||
/// Gets the ideal CPU core ID for this process
|
||||
u8 GetIdealCore() const {
|
||||
return ideal_core;
|
||||
}
|
||||
|
||||
/// Gets the bitmask of allowed CPUs that this process' threads can run on.
|
||||
u64 GetAllowedProcessorMask() const {
|
||||
/// Gets the bitmask of allowed cores that this process' threads can run on.
|
||||
u64 GetCoreMask() const {
|
||||
return capabilities.GetCoreMask();
|
||||
}
|
||||
|
||||
/// Gets the bitmask of allowed thread priorities.
|
||||
u64 GetAllowedThreadPriorityMask() const {
|
||||
u64 GetPriorityMask() const {
|
||||
return capabilities.GetPriorityMask();
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ public:
|
||||
void LoadModule(CodeSet module_, VAddr base_addr);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory Management
|
||||
// Thread-local storage management
|
||||
|
||||
// Marks the next available region as used and returns the address of the slot.
|
||||
VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread);
|
||||
@@ -250,13 +250,6 @@ public:
|
||||
// Frees a used TLS slot identified by the given address
|
||||
void FreeTLSSlot(VAddr tls_address);
|
||||
|
||||
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
|
||||
ResultCode HeapFree(VAddr target, u32 size);
|
||||
|
||||
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state);
|
||||
|
||||
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||
|
||||
private:
|
||||
explicit Process(KernelCore& kernel);
|
||||
~Process() override;
|
||||
@@ -287,8 +280,8 @@ private:
|
||||
/// Resource limit descriptor for this process
|
||||
SharedPtr<ResourceLimit> resource_limit;
|
||||
|
||||
/// The default CPU for this process, threads are scheduled on this cpu by default.
|
||||
u8 ideal_processor = 0;
|
||||
/// The ideal CPU core for this process, threads are scheduled on this core by default.
|
||||
u8 ideal_core = 0;
|
||||
u32 is_virtual_address_memory_enabled = 0;
|
||||
|
||||
/// The Thread Local Storage area is allocated as processes create threads,
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
@@ -190,10 +190,16 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
auto& process = *Core::CurrentProcess();
|
||||
const VAddr heap_base = process.VMManager().GetHeapRegionBaseAddress();
|
||||
CASCADE_RESULT(*heap_addr,
|
||||
process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite));
|
||||
auto& vm_manager = Core::CurrentProcess()->VMManager();
|
||||
const VAddr heap_base = vm_manager.GetHeapRegionBaseAddress();
|
||||
const auto alloc_result =
|
||||
vm_manager.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite);
|
||||
|
||||
if (alloc_result.Failed()) {
|
||||
return alloc_result.Code();
|
||||
}
|
||||
|
||||
*heap_addr = *alloc_result;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -307,15 +313,14 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
||||
src_addr, size);
|
||||
|
||||
auto* const current_process = Core::CurrentProcess();
|
||||
const auto& vm_manager = current_process->VMManager();
|
||||
|
||||
auto& vm_manager = Core::CurrentProcess()->VMManager();
|
||||
const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
|
||||
if (result != RESULT_SUCCESS) {
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return current_process->MirrorMemory(dst_addr, src_addr, size, MemoryState::Stack);
|
||||
return vm_manager.MirrorMemory(dst_addr, src_addr, size, MemoryState::Stack);
|
||||
}
|
||||
|
||||
/// Unmaps a region that was previously mapped with svcMapMemory
|
||||
@@ -323,15 +328,14 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
||||
src_addr, size);
|
||||
|
||||
auto* const current_process = Core::CurrentProcess();
|
||||
const auto& vm_manager = current_process->VMManager();
|
||||
|
||||
auto& vm_manager = Core::CurrentProcess()->VMManager();
|
||||
const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
|
||||
if (result != RESULT_SUCCESS) {
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return current_process->UnmapMemory(dst_addr, src_addr, size);
|
||||
return vm_manager.UnmapRange(dst_addr, size);
|
||||
}
|
||||
|
||||
/// Connect to an OS service given the port name, returns the handle to the port to out
|
||||
@@ -593,6 +597,7 @@ enum class BreakType : u32 {
|
||||
PostNROLoad = 4,
|
||||
PreNROUnload = 5,
|
||||
PostNROUnload = 6,
|
||||
CppException = 7,
|
||||
};
|
||||
|
||||
struct BreakReason {
|
||||
@@ -665,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,
|
||||
@@ -680,6 +688,9 @@ static void Break(u32 reason, u64 info1, u64 info2) {
|
||||
"Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
|
||||
reason, info1, info2);
|
||||
handle_debug_buffer(info1, info2);
|
||||
Core::System::GetInstance()
|
||||
.ArmInterface(static_cast<std::size_t>(GetCurrentThread()->GetProcessorID()))
|
||||
.LogBacktrace();
|
||||
ASSERT(false);
|
||||
|
||||
Core::CurrentProcess()->PrepareForTermination();
|
||||
@@ -708,8 +719,8 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||
|
||||
enum class GetInfoType : u64 {
|
||||
// 1.0.0+
|
||||
AllowedCpuIdBitmask = 0,
|
||||
AllowedThreadPrioBitmask = 1,
|
||||
AllowedCPUCoreMask = 0,
|
||||
AllowedThreadPriorityMask = 1,
|
||||
MapRegionBaseAddr = 2,
|
||||
MapRegionSize = 3,
|
||||
HeapRegionBaseAddr = 4,
|
||||
@@ -740,8 +751,8 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||
const auto info_id_type = static_cast<GetInfoType>(info_id);
|
||||
|
||||
switch (info_id_type) {
|
||||
case GetInfoType::AllowedCpuIdBitmask:
|
||||
case GetInfoType::AllowedThreadPrioBitmask:
|
||||
case GetInfoType::AllowedCPUCoreMask:
|
||||
case GetInfoType::AllowedThreadPriorityMask:
|
||||
case GetInfoType::MapRegionBaseAddr:
|
||||
case GetInfoType::MapRegionSize:
|
||||
case GetInfoType::HeapRegionBaseAddr:
|
||||
@@ -767,12 +778,12 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||
}
|
||||
|
||||
switch (info_id_type) {
|
||||
case GetInfoType::AllowedCpuIdBitmask:
|
||||
*result = process->GetAllowedProcessorMask();
|
||||
case GetInfoType::AllowedCPUCoreMask:
|
||||
*result = process->GetCoreMask();
|
||||
return RESULT_SUCCESS;
|
||||
|
||||
case GetInfoType::AllowedThreadPrioBitmask:
|
||||
*result = process->GetAllowedThreadPriorityMask();
|
||||
case GetInfoType::AllowedThreadPriorityMask:
|
||||
*result = process->GetPriorityMask();
|
||||
return RESULT_SUCCESS;
|
||||
|
||||
case GetInfoType::MapRegionBaseAddr:
|
||||
@@ -1212,29 +1223,35 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
|
||||
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
|
||||
entry_point, arg, stack_top, priority, processor_id, *out_handle);
|
||||
|
||||
auto* const current_process = Core::CurrentProcess();
|
||||
|
||||
if (processor_id == THREADPROCESSORID_IDEAL) {
|
||||
// Set the target CPU to the one specified by the process.
|
||||
processor_id = current_process->GetIdealCore();
|
||||
ASSERT(processor_id != THREADPROCESSORID_IDEAL);
|
||||
}
|
||||
|
||||
if (processor_id < THREADPROCESSORID_0 || processor_id > THREADPROCESSORID_3) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id);
|
||||
return ERR_INVALID_PROCESSOR_ID;
|
||||
}
|
||||
|
||||
const u64 core_mask = current_process->GetCoreMask();
|
||||
if ((core_mask | (1ULL << processor_id)) != core_mask) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread core specified ({})", processor_id);
|
||||
return ERR_INVALID_PROCESSOR_ID;
|
||||
}
|
||||
|
||||
if (priority > THREADPRIO_LOWEST) {
|
||||
LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}",
|
||||
THREADPRIO_LOWEST, priority);
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Invalid thread priority specified ({}). Must be within the range 0-64",
|
||||
priority);
|
||||
return ERR_INVALID_THREAD_PRIORITY;
|
||||
}
|
||||
|
||||
auto* const current_process = Core::CurrentProcess();
|
||||
|
||||
if (processor_id == THREADPROCESSORID_DEFAULT) {
|
||||
// Set the target CPU to the one specified in the process' exheader.
|
||||
processor_id = current_process->GetDefaultProcessorID();
|
||||
ASSERT(processor_id != THREADPROCESSORID_DEFAULT);
|
||||
}
|
||||
|
||||
switch (processor_id) {
|
||||
case THREADPROCESSORID_0:
|
||||
case THREADPROCESSORID_1:
|
||||
case THREADPROCESSORID_2:
|
||||
case THREADPROCESSORID_3:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id);
|
||||
return ERR_INVALID_PROCESSOR_ID;
|
||||
if (((1ULL << priority) & current_process->GetPriorityMask()) == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread priority specified ({})", priority);
|
||||
return ERR_INVALID_THREAD_PRIORITY;
|
||||
}
|
||||
|
||||
const std::string name = fmt::format("thread-{:X}", entry_point);
|
||||
@@ -1632,13 +1649,13 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) {
|
||||
const u8 default_processor_id = thread->GetOwnerProcess()->GetDefaultProcessorID();
|
||||
if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) {
|
||||
const u8 ideal_cpu_core = thread->GetOwnerProcess()->GetIdealCore();
|
||||
|
||||
ASSERT(default_processor_id != static_cast<u8>(THREADPROCESSORID_DEFAULT));
|
||||
ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL));
|
||||
|
||||
// Set the target CPU to the one specified in the process' exheader.
|
||||
core = default_processor_id;
|
||||
// Set the target CPU to the ideal core specified by the process.
|
||||
core = ideal_cpu_core;
|
||||
mask = 1ULL << core;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/math_util.h"
|
||||
#include "common/thread_queue_list.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/core.h"
|
||||
@@ -232,29 +231,6 @@ void Thread::BoostPriority(u32 priority) {
|
||||
current_priority = priority;
|
||||
}
|
||||
|
||||
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
|
||||
Process& owner_process) {
|
||||
// Setup page table so we can write to memory
|
||||
SetCurrentPageTable(&owner_process.VMManager().page_table);
|
||||
|
||||
// Initialize new "main" thread
|
||||
const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress();
|
||||
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
|
||||
stack_top, owner_process);
|
||||
|
||||
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
|
||||
|
||||
// Register 1 must be a handle to the main thread
|
||||
const Handle guest_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
|
||||
thread->SetGuestHandle(guest_handle);
|
||||
thread->GetContext().cpu_registers[1] = guest_handle;
|
||||
|
||||
// Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
|
||||
thread->ResumeFromWait();
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
void Thread::SetWaitSynchronizationResult(ResultCode result) {
|
||||
context.cpu_registers[0] = result.raw;
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@ enum ThreadPriority : u32 {
|
||||
};
|
||||
|
||||
enum ThreadProcessorId : s32 {
|
||||
THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader
|
||||
THREADPROCESSORID_0 = 0, ///< Run thread on core 0
|
||||
THREADPROCESSORID_1 = 1, ///< Run thread on core 1
|
||||
THREADPROCESSORID_2 = 2, ///< Run thread on core 2
|
||||
THREADPROCESSORID_3 = 3, ///< Run thread on core 3
|
||||
THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this
|
||||
THREADPROCESSORID_IDEAL = -2, ///< Run thread on the ideal core specified by the process.
|
||||
THREADPROCESSORID_0 = 0, ///< Run thread on core 0
|
||||
THREADPROCESSORID_1 = 1, ///< Run thread on core 1
|
||||
THREADPROCESSORID_2 = 2, ///< Run thread on core 2
|
||||
THREADPROCESSORID_3 = 3, ///< Run thread on core 3
|
||||
THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this
|
||||
|
||||
/// Allowed CPU mask
|
||||
THREADPROCESSORID_DEFAULT_MASK = (1 << THREADPROCESSORID_0) | (1 << THREADPROCESSORID_1) |
|
||||
@@ -455,17 +455,6 @@ private:
|
||||
ThreadActivity activity = ThreadActivity::Normal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets up the primary application thread
|
||||
* @param kernel The kernel instance to create the main thread under.
|
||||
* @param entry_point The address at which the thread should start execution
|
||||
* @param priority The priority to give the main thread
|
||||
* @param owner_process The parent process for the main thread
|
||||
* @return A shared pointer to the main thread
|
||||
*/
|
||||
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
|
||||
Process& owner_process);
|
||||
|
||||
/**
|
||||
* Gets the current thread
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/timer.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <vector>
|
||||
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
namespace Kernel {
|
||||
@@ -34,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.
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/server_port.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -111,7 +111,8 @@ static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
|
||||
}
|
||||
|
||||
static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) {
|
||||
LOG_ERROR(Service_Fatal, "Threw fatal error type {}", static_cast<u32>(fatal_type));
|
||||
LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}",
|
||||
static_cast<u32>(fatal_type), error_code.raw);
|
||||
switch (fatal_type) {
|
||||
case FatalType::ErrorReportAndScreen:
|
||||
GenerateErrorReport(error_code, info);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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<
|
||||
|
||||
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 CoreTiming {
|
||||
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;
|
||||
|
||||
CoreTiming::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();
|
||||
|
||||
|
||||
@@ -318,14 +318,18 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(process->MirrorMemory(*map_address, nro_addr, nro_size,
|
||||
Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
|
||||
ASSERT(process->UnmapMemory(nro_addr, 0, nro_size) == RESULT_SUCCESS);
|
||||
ASSERT(vm_manager
|
||||
.MirrorMemory(*map_address, nro_addr, nro_size,
|
||||
Kernel::MemoryState::ModuleCodeStatic)
|
||||
.IsSuccess());
|
||||
ASSERT(vm_manager.UnmapRange(nro_addr, nro_size).IsSuccess());
|
||||
|
||||
if (bss_size > 0) {
|
||||
ASSERT(process->MirrorMemory(*map_address + nro_size, bss_addr, bss_size,
|
||||
Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
|
||||
ASSERT(process->UnmapMemory(bss_addr, 0, bss_size) == RESULT_SUCCESS);
|
||||
ASSERT(vm_manager
|
||||
.MirrorMemory(*map_address + nro_size, bss_addr, bss_size,
|
||||
Kernel::MemoryState::ModuleCodeStatic)
|
||||
.IsSuccess());
|
||||
ASSERT(vm_manager.UnmapRange(bss_addr, bss_size).IsSuccess());
|
||||
}
|
||||
|
||||
vm_manager.ReprotectRange(*map_address, header.text_size,
|
||||
@@ -380,13 +384,14 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto* process = Core::CurrentProcess();
|
||||
auto& vm_manager = process->VMManager();
|
||||
auto& vm_manager = Core::CurrentProcess()->VMManager();
|
||||
const auto& nro_size = iter->second.size;
|
||||
|
||||
ASSERT(process->MirrorMemory(heap_addr, mapped_addr, nro_size,
|
||||
Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
|
||||
ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS);
|
||||
ASSERT(vm_manager
|
||||
.MirrorMemory(heap_addr, mapped_addr, nro_size,
|
||||
Kernel::MemoryState::ModuleCodeStatic)
|
||||
.IsSuccess());
|
||||
ASSERT(vm_manager.UnmapRange(mapped_addr, nro_size).IsSuccess());
|
||||
|
||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/nfp/nfp.h"
|
||||
#include "core/hle/service/nfp/nfp_user.h"
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace Service::NFP {
|
||||
namespace ErrCodes {
|
||||
constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
|
||||
-1); // TODO(ogniK): Find the actual error code
|
||||
}
|
||||
constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
|
||||
} // namespace ErrCodes
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
|
||||
: ServiceFramework(name), module(std::move(module)) {
|
||||
@@ -292,10 +293,9 @@ private:
|
||||
}
|
||||
|
||||
void OpenApplicationArea(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFP, "called");
|
||||
// We don't need to worry about this since we can just open the file
|
||||
LOG_WARNING(Service_NFP, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(ErrCodes::ERR_NO_APPLICATION_AREA);
|
||||
}
|
||||
|
||||
void GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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,7 +21,6 @@
|
||||
#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 {
|
||||
|
||||
@@ -30,12 +28,6 @@ constexpr std::size_t SCREEN_REFRESH_RATE = 60;
|
||||
constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::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) {
|
||||
@@ -54,66 +46,120 @@ 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>
|
||||
@@ -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.
|
||||
|
||||
@@ -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};
|
||||
@@ -264,14 +269,9 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto unknown_u8 = rp.PopRaw<u8>();
|
||||
const auto initial_type = rp.PopRaw<u8>();
|
||||
|
||||
ClockSnapshot clock_snapshot{};
|
||||
|
||||
const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count()};
|
||||
CalendarTime calendar_time{};
|
||||
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,16 +280,19 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code
|
||||
return;
|
||||
}
|
||||
SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) /
|
||||
1000};
|
||||
|
||||
LocationName location_name{"UTC"};
|
||||
const SteadyClockTimePoint steady_clock_time_point{
|
||||
CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000, {}};
|
||||
|
||||
CalendarTime calendar_time{};
|
||||
calendar_time.year = tm->tm_year + 1900;
|
||||
calendar_time.month = tm->tm_mon + 1;
|
||||
calendar_time.day = tm->tm_mday;
|
||||
calendar_time.hour = tm->tm_hour;
|
||||
calendar_time.minute = tm->tm_min;
|
||||
calendar_time.second = tm->tm_sec;
|
||||
|
||||
ClockSnapshot clock_snapshot{};
|
||||
clock_snapshot.system_posix_time = time_since_epoch;
|
||||
clock_snapshot.network_posix_time = time_since_epoch;
|
||||
clock_snapshot.system_calendar_time = calendar_time;
|
||||
@@ -302,9 +305,10 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
clock_snapshot.network_calendar_info = additional_info;
|
||||
|
||||
clock_snapshot.steady_clock_timepoint = steady_clock_time_point;
|
||||
clock_snapshot.location_name = location_name;
|
||||
clock_snapshot.location_name = LocationName{"UTC"};
|
||||
clock_snapshot.clock_auto_adjustment_enabled = 1;
|
||||
clock_snapshot.ipc_u8 = unknown_u8;
|
||||
clock_snapshot.type = initial_type;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
|
||||
|
||||
@@ -22,7 +22,6 @@ struct CalendarTime {
|
||||
u8 hour;
|
||||
u8 minute;
|
||||
u8 second;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
};
|
||||
static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size");
|
||||
|
||||
@@ -30,7 +29,7 @@ struct CalendarAdditionalInfo {
|
||||
u32_le day_of_week;
|
||||
u32_le day_of_year;
|
||||
std::array<u8, 8> name;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
u8 is_dst;
|
||||
s32_le utc_offset;
|
||||
};
|
||||
static_assert(sizeof(CalendarAdditionalInfo) == 0x18,
|
||||
@@ -42,8 +41,10 @@ struct TimeZoneRule {
|
||||
};
|
||||
|
||||
struct SteadyClockTimePoint {
|
||||
using SourceID = std::array<u8, 16>;
|
||||
|
||||
u64_le value;
|
||||
INSERT_PADDING_WORDS(4);
|
||||
SourceID source_id;
|
||||
};
|
||||
static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
|
||||
|
||||
@@ -66,8 +67,9 @@ struct ClockSnapshot {
|
||||
SteadyClockTimePoint steady_clock_timepoint;
|
||||
LocationName location_name;
|
||||
u8 clock_auto_adjustment_enabled;
|
||||
u8 ipc_u8;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
u8 type;
|
||||
u8 version;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
};
|
||||
static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size");
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
#include "core/hle/service/nvflinger/buffer_queue.h"
|
||||
@@ -31,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");
|
||||
|
||||
@@ -502,12 +518,14 @@ private:
|
||||
|
||||
void TransactParcel(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 id = rp.Pop<u32>();
|
||||
auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
|
||||
u32 flags = rp.Pop<u32>();
|
||||
LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction));
|
||||
const u32 id = rp.Pop<u32>();
|
||||
const auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
|
||||
const u32 flags = rp.Pop<u32>();
|
||||
|
||||
auto buffer_queue = nv_flinger->GetBufferQueue(id);
|
||||
LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
|
||||
static_cast<u32>(transaction), flags);
|
||||
|
||||
auto buffer_queue = nv_flinger->FindBufferQueue(id);
|
||||
|
||||
if (transaction == TransactionId::Connect) {
|
||||
IGBPConnectRequestParcel request{ctx.ReadBuffer()};
|
||||
@@ -541,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.");
|
||||
|
||||
@@ -593,9 +611,10 @@ private:
|
||||
|
||||
void AdjustRefcount(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 id = rp.Pop<u32>();
|
||||
s32 addval = rp.PopRaw<s32>();
|
||||
u32 type = rp.Pop<u32>();
|
||||
const u32 id = rp.Pop<u32>();
|
||||
const s32 addval = rp.PopRaw<s32>();
|
||||
const u32 type = rp.Pop<u32>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval,
|
||||
type);
|
||||
|
||||
@@ -605,11 +624,12 @@ private:
|
||||
|
||||
void GetNativeHandle(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 id = rp.Pop<u32>();
|
||||
u32 unknown = rp.Pop<u32>();
|
||||
const u32 id = rp.Pop<u32>();
|
||||
const u32 unknown = rp.Pop<u32>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
|
||||
|
||||
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};
|
||||
@@ -674,22 +694,25 @@ public:
|
||||
|
||||
private:
|
||||
void SetLayerZ(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
u64 z_value = rp.Pop<u64>();
|
||||
const u64 layer_id = rp.Pop<u64>();
|
||||
const u64 z_value = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}, z_value=0x{:016X}", layer_id,
|
||||
z_value);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
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};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
bool visibility = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
|
||||
visibility);
|
||||
const u64 layer_id = rp.Pop<u64>();
|
||||
const bool visibility = rp.Pop<bool>();
|
||||
|
||||
LOG_DEBUG(Service_VI, "called, layer_id=0x{:08X}, visibility={}", layer_id, visibility);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -796,37 +819,45 @@ public:
|
||||
|
||||
private:
|
||||
void CloseDisplay(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display = rp.Pop<u64>();
|
||||
const u64 display = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. display=0x{:016X}", display);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void CreateManagedLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 unknown = rp.Pop<u32>();
|
||||
const u32 unknown = rp.Pop<u32>();
|
||||
rp.Skip(1, false);
|
||||
u64 display = rp.Pop<u64>();
|
||||
u64 aruid = rp.Pop<u64>();
|
||||
const u64 display = rp.Pop<u64>();
|
||||
const u64 aruid = rp.Pop<u64>();
|
||||
|
||||
u64 layer_id = nv_flinger->CreateLayer(display);
|
||||
LOG_WARNING(Service_VI,
|
||||
"(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
|
||||
unknown, display, aruid);
|
||||
|
||||
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) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 stack = rp.Pop<u32>();
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
const u32 stack = rp.Pop<u32>();
|
||||
const u64 layer_id = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. stack=0x{:08X}, layer_id=0x{:016X}", stack,
|
||||
layer_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -834,8 +865,9 @@ private:
|
||||
|
||||
void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
bool visibility = rp.Pop<bool>();
|
||||
const u64 layer_id = rp.Pop<u64>();
|
||||
const bool visibility = rp.Pop<bool>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
|
||||
visibility);
|
||||
|
||||
@@ -852,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");
|
||||
|
||||
@@ -888,58 +936,98 @@ private:
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
|
||||
auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
const auto name_buf = rp.PopRaw<std::array<char, 0x40>>();
|
||||
|
||||
std::string name(name_buf.begin(), end);
|
||||
OpenDisplayImpl(ctx, std::string_view{name_buf.data(), name_buf.size()});
|
||||
}
|
||||
|
||||
void OpenDefaultDisplay(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_VI, "called");
|
||||
|
||||
OpenDisplayImpl(ctx, "Default");
|
||||
}
|
||||
|
||||
void OpenDisplayImpl(Kernel::HLERequestContext& ctx, std::string_view name) {
|
||||
const auto trim_pos = name.find('\0');
|
||||
|
||||
if (trim_pos != std::string_view::npos) {
|
||||
name.remove_suffix(name.size() - trim_pos);
|
||||
}
|
||||
|
||||
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) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
const u64 display_id = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
// This literally does nothing internally in the actual service itself,
|
||||
// and just returns a successful result code regardless of the input.
|
||||
void SetDisplayEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_VI, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetDisplayResolution(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
const u64 display_id = rp.Pop<u64>();
|
||||
|
||||
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) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 scaling_mode = rp.Pop<u32>();
|
||||
u64 unknown = rp.Pop<u64>();
|
||||
const auto scaling_mode = rp.PopEnum<NintendoScaleMode>();
|
||||
const u64 unknown = rp.Pop<u64>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -957,114 +1045,127 @@ private:
|
||||
}
|
||||
|
||||
void OpenLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_VI, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
|
||||
auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
|
||||
const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
|
||||
std::string display_name(name_buf.begin(), end);
|
||||
const std::string display_name(name_buf.begin(), end);
|
||||
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
u64 aruid = rp.Pop<u64>();
|
||||
const u64 layer_id = rp.Pop<u64>();
|
||||
const u64 aruid = rp.Pop<u64>();
|
||||
|
||||
u64 display_id = nv_flinger->OpenDisplay(display_name);
|
||||
u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id);
|
||||
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
|
||||
|
||||
NativeWindow native_window{buffer_queue_id};
|
||||
const auto display_id = nv_flinger->OpenDisplay(display_name);
|
||||
if (!display_id) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
void CreateStrayLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_VI, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 flags = rp.Pop<u32>();
|
||||
const u32 flags = rp.Pop<u32>();
|
||||
rp.Pop<u32>(); // padding
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
const u64 display_id = rp.Pop<u64>();
|
||||
|
||||
LOG_DEBUG(Service_VI, "called. flags=0x{:08X}, display_id=0x{:016X}", flags, display_id);
|
||||
|
||||
// TODO(Subv): What's the difference between a Stray and a Managed layer?
|
||||
|
||||
u64 layer_id = nv_flinger->CreateLayer(display_id);
|
||||
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()));
|
||||
}
|
||||
|
||||
void DestroyStrayLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
const u64 layer_id = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
const u64 display_id = rp.Pop<u64>();
|
||||
|
||||
auto vsync_event = nv_flinger->GetVsyncEvent(display_id);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1082,9 +1183,9 @@ IApplicationDisplayService::IApplicationDisplayService(
|
||||
"GetIndirectDisplayTransactionService"},
|
||||
{1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
|
||||
{1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
|
||||
{1011, nullptr, "OpenDefaultDisplay"},
|
||||
{1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
|
||||
{1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
|
||||
{1101, nullptr, "SetDisplayEnabled"},
|
||||
{1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
|
||||
{1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
|
||||
{2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
|
||||
{2021, nullptr, "CloseLayer"},
|
||||
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user