Compare commits
631 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 473caaff5b | |||
| 787552f832 | |||
| 5f945e2fcd | |||
| c08da2d6ad | |||
| 4458920799 | |||
| 61fed8a3a6 | |||
| efb3165e3d | |||
| a493ba76b4 | |||
| ae60a5657e | |||
| feb60de5c3 | |||
| c67644f1da | |||
| 9343b81afd | |||
| 71f53b4218 | |||
| f131b0faeb | |||
| 6c64d5aff2 | |||
| de594995da | |||
| 4c16a1a26f | |||
| 862e66202c | |||
| 2136a46ab7 | |||
| b9c7e5c2c8 | |||
| d86e88a622 | |||
| 7eac28e410 | |||
| ea4c92f734 | |||
| c9cd938dfd | |||
| 4c5e3d5f7a | |||
| e2be180136 | |||
| c9437e5244 | |||
| 24548b1f5c | |||
| be0ecae108 | |||
| fcd54c6479 | |||
| 08296f151e | |||
| a134e924ff | |||
| 31ed6bae11 | |||
| 9a5ef835cc | |||
| df0d3698ae | |||
| 51fc608f68 | |||
| b30e19ba24 | |||
| ec6b67d862 | |||
| 4d0b7f8496 | |||
| e3b510a4b4 | |||
| 247d66a680 | |||
| 0047d8a01e | |||
| efc0187537 | |||
| b6fe8a0b3f | |||
| ecaa038b4d | |||
| 4aac971864 | |||
| 6c93cdffb1 | |||
| 470714e2d1 | |||
| 6b888b0fa8 | |||
| 1a1393dad7 | |||
| 55412962c0 | |||
| d920da2631 | |||
| ff72bf2cb2 | |||
| 4efb9763d9 | |||
| c600bc8652 | |||
| f1806d237f | |||
| ae57a99d7d | |||
| 767c4b5a99 | |||
| 904d03b01f | |||
| 9f1c9599a2 | |||
| 5f6666a7cd | |||
| 1906e2724f | |||
| 0c032d3f2f | |||
| a6735cba5f | |||
| 3b872b89d1 | |||
| 40d4e9543b | |||
| e588f341ed | |||
| 875246f5b2 | |||
| b16fefa106 | |||
| 2a255b2d61 | |||
| 9e331f9957 | |||
| 9169cbf728 | |||
| 2f9487cd38 | |||
| 1d03a0fa75 | |||
| 09f993899e | |||
| c9038af29e | |||
| f3053920bf | |||
| c7b31d24b9 | |||
| edce713fc9 | |||
| 8d0d0e1c7a | |||
| f75363177e | |||
| 4c6217f09b | |||
| c95f35ea85 | |||
| 40357098a2 | |||
| e7f4110791 | |||
| ca1dd1862b | |||
| 737d1cea62 | |||
| 2f8e237ab7 | |||
| 5191465b0a | |||
| 50c604f37f | |||
| dfbc22c291 | |||
| a5a3167eba | |||
| a423e0f9e0 | |||
| 511c1f0c8b | |||
| 8369fcd71a | |||
| 626916e9a4 | |||
| 507f360a81 | |||
| 5323d9f6b3 | |||
| 770d4b0b72 | |||
| e5fed31009 | |||
| 4b8b223db2 | |||
| 728aca7703 | |||
| f07484bc64 | |||
| 78b9956a04 | |||
| 90aa937593 | |||
| 940618a64d | |||
| 409fa5dda2 | |||
| 211b67668d | |||
| f0cd02b9bd | |||
| 34101d8c5e | |||
| bf8d7bc0da | |||
| 9543adf072 | |||
| 036d2686af | |||
| a80e0e7da5 | |||
| 9631dedea9 | |||
| 75de0cadcf | |||
| 4b321c003c | |||
| 0a83047368 | |||
| 9bb8ac7cb6 | |||
| d6e6ab11b1 | |||
| b3a1f793c3 | |||
| a294beb116 | |||
| eda403388a | |||
| 3032980478 | |||
| 7f96f4db3f | |||
| a0f9a3ab5b | |||
| b36fec486e | |||
| 57cf830862 | |||
| 41701052d3 | |||
| 57c8dcfd77 | |||
| 398e881428 | |||
| 92418e909f | |||
| 7b10ceda02 | |||
| 344162db75 | |||
| 48f913b6e7 | |||
| 0efda40b57 | |||
| 5872c7d420 | |||
| 2b6edd3efd | |||
| b0c6bf497a | |||
| bf16289d77 | |||
| 987b37798a | |||
| 135b645b3d | |||
| 1e468eac94 | |||
| 97b4ca1d01 | |||
| 1d7ff850d6 | |||
| 7e284809de | |||
| 324c93e4aa | |||
| 133788d0d4 | |||
| e8cb8b2668 | |||
| 361dbdddcc | |||
| 6a7123826a | |||
| ab3e3c11af | |||
| db5c24eb66 | |||
| f7755df2af | |||
| c60204e255 | |||
| 5e69769356 | |||
| 22cac3a5e3 | |||
| e867768316 | |||
| 07276cf62a | |||
| f04bc172ae | |||
| 585b6e9d46 | |||
| a9e29a3972 | |||
| 1e61c3e1e7 | |||
| 79d3cef8db | |||
| 3e0da4f698 | |||
| 789c16305d | |||
| 1836e62d33 | |||
| 0bbbe80f75 | |||
| 70be45c992 | |||
| 9b3c64f4a4 | |||
| eec3d356b6 | |||
| a872030a35 | |||
| 79e7d7f4ba | |||
| 2c1d850b46 | |||
| 2581590023 | |||
| adb0900906 | |||
| 2d608cd625 | |||
| 29955de767 | |||
| b0f62d8f24 | |||
| ed2d77ddbc | |||
| 6e883a26da | |||
| 8427b9d49d | |||
| 0bb1c7c804 | |||
| a5aa5876b4 | |||
| 911d2216be | |||
| 4da2105a32 | |||
| 1f9684eaf9 | |||
| 40c97c0549 | |||
| 6aee148b17 | |||
| b5b93e6741 | |||
| 18a4529851 | |||
| 9e4d606c4c | |||
| 6513a356f0 | |||
| 64f60f0acb | |||
| 65d4a16afd | |||
| 21c631b33b | |||
| f26dddf3b5 | |||
| 7f62a48ab5 | |||
| b5415b6872 | |||
| 43be2bfe33 | |||
| 79ba5d9c26 | |||
| ca75c58f43 | |||
| 723df0f368 | |||
| 94b7ac50bb | |||
| 18450ebd78 | |||
| efdb2e8f3d | |||
| 7a84a1a974 | |||
| 789d9c8af9 | |||
| 4df063209b | |||
| 6256e3ca8e | |||
| 008d7e8c5f | |||
| 19e9bde9e0 | |||
| 6eb3a583cb | |||
| e0834ee50b | |||
| 79894152a8 | |||
| 9274eaecd0 | |||
| c733620024 | |||
| 897b411ae7 | |||
| 94836ba3b1 | |||
| b1909b0435 | |||
| 1cc764988f | |||
| da5c49f22d | |||
| 6b93b0b08c | |||
| 68f25217b8 | |||
| 0604b14263 | |||
| a065dcdcd9 | |||
| 3d4a064674 | |||
| e4dfd51337 | |||
| cfe73af6f2 | |||
| d6bd16b2c0 | |||
| a49b146ccc | |||
| fd9e157184 | |||
| 6cbd4020e8 | |||
| 3558b236cd | |||
| 48e82c4138 | |||
| 9eb70aea1d | |||
| 0460fbacc9 | |||
| c73297e840 | |||
| 633d869ff4 | |||
| e03f86cc54 | |||
| a0a3566977 | |||
| 77fb9d415b | |||
| bbdaa62175 | |||
| 31bffc7299 | |||
| 5f8f09d750 | |||
| dcfe674ed4 | |||
| bb195c2c2b | |||
| 8c59543ee3 | |||
| db37e583ff | |||
| d28e826e47 | |||
| 13beb85514 | |||
| 4b06bcc82c | |||
| b76a1d987f | |||
| 12ebc8d9d1 | |||
| 2b85e9e997 | |||
| 59b62c6507 | |||
| 2e760a9833 | |||
| bab4a13a41 | |||
| b56c7397ad | |||
| 689f346e97 | |||
| 249db0a59b | |||
| 9526ce95dd | |||
| 687158fe00 | |||
| d8507332c1 | |||
| 67e983a354 | |||
| f21058a6c0 | |||
| b456af31e6 | |||
| 0441853d0f | |||
| 60a1c6b95b | |||
| 794e6c7a96 | |||
| 22afa2c7a3 | |||
| 85a89ca3e3 | |||
| 26776c0e60 | |||
| e02ee8e59d | |||
| 134ecca9b0 | |||
| ae2130470e | |||
| c5f1ec8040 | |||
| 765ea9b79d | |||
| ac6290bea7 | |||
| 4051bbbed7 | |||
| 2a7edda70a | |||
| 59b6ada7b7 | |||
| c5bdc0054c | |||
| 0b7593d352 | |||
| bd05ace08d | |||
| fa56518f20 | |||
| b577d7a55f | |||
| d9dde7e6f3 | |||
| 2244b613cf | |||
| 9908434c14 | |||
| c73bb33ff1 | |||
| 668a10f9b9 | |||
| bcce184e60 | |||
| fc4b45ebd3 | |||
| 1afe6d51ee | |||
| 1ae0f0f3f6 | |||
| de0b35b974 | |||
| ae88d01d8d | |||
| d759de9f96 | |||
| 89d3e81be8 | |||
| 326ebbb2fa | |||
| 07143ce15c | |||
| dbc73c6c6c | |||
| 71f264c498 | |||
| 26417da5d3 | |||
| b3b458edf9 | |||
| 8becf13e8b | |||
| 9e2ebb24df | |||
| 74961d4dfb | |||
| 9ffa1801c7 | |||
| 90c56f5dc1 | |||
| 4d4fe69223 | |||
| 4b0291172e | |||
| 12e4757cf3 | |||
| 144c0734f5 | |||
| f40f65f5d2 | |||
| 03c3f936cf | |||
| 66f41da365 | |||
| 7a986d731b | |||
| eae0570a1c | |||
| 0a75519ab5 | |||
| 3062a35eb1 | |||
| b57d98f847 | |||
| 762ac5aa9f | |||
| 1a4abd184f | |||
| 9524d7034c | |||
| 36d18e457b | |||
| db562bc08d | |||
| 18672e6a78 | |||
| 32ad99701d | |||
| 63c5340cc4 | |||
| a94371f67b | |||
| 22e4add562 | |||
| b1a7bbd458 | |||
| 27ab2a6e13 | |||
| 68ea0a2b72 | |||
| a8bd02acd8 | |||
| 3e4edbe007 | |||
| 4a9240599a | |||
| 053a16799e | |||
| 82c845dc2f | |||
| 3aa6d4d8ce | |||
| 9b961dddb4 | |||
| 224b6036a4 | |||
| 2c3281c66b | |||
| 1591923f91 | |||
| 56e5d99684 | |||
| ca75c9125d | |||
| 1a4874e178 | |||
| c00b63b9e1 | |||
| c8602e1b1f | |||
| faa6c35e78 | |||
| 8b64878258 | |||
| 519c12da15 | |||
| d74fd9e2fe | |||
| d011d3ff0e | |||
| a5fb9de6fa | |||
| c4ec76edba | |||
| 3f05b8facd | |||
| 65d3300875 | |||
| 7b2ac196d2 | |||
| d9456f0a11 | |||
| 2212c9653d | |||
| fe04a7523a | |||
| 45a76637f5 | |||
| bf7c45e560 | |||
| 48b67fc4a0 | |||
| 6c246f2ac5 | |||
| a34565727b | |||
| 6f4a080b98 | |||
| da6824d9fd | |||
| b36f45b239 | |||
| 07ae6659e7 | |||
| 880b004321 | |||
| 21ebe3e462 | |||
| 98cac9410c | |||
| 7b5d234558 | |||
| 84b0e29b56 | |||
| 5ecdcfa334 | |||
| 5f4857691e | |||
| b50ce645ac | |||
| b6d19329ac | |||
| 8c769b71a1 | |||
| 9512992fe2 | |||
| 6b10f04322 | |||
| c206a04747 | |||
| ec6ddaf766 | |||
| 36ea7565fa | |||
| 00b0938f10 | |||
| ed58445111 | |||
| b28b05e2aa | |||
| 8151a4d301 | |||
| 8ac8d703b9 | |||
| 1c1959eaeb | |||
| c0d152affa | |||
| 85d99f873f | |||
| 21bc2c14bc | |||
| d3997bad9b | |||
| 54fa1115a6 | |||
| 8347e5cdb9 | |||
| dac53b4ba0 | |||
| 0bb7990c49 | |||
| 9ef9ca0927 | |||
| bd42bba71c | |||
| a27f94830a | |||
| bd6f9f1d91 | |||
| bf15aa093c | |||
| 0e9b839b6f | |||
| 15a5bdd979 | |||
| fc4cde7513 | |||
| ff3859d482 | |||
| 10de8f2c60 | |||
| 51b89fddd0 | |||
| f585dec48d | |||
| ad1a9f3d3a | |||
| e797a917a9 | |||
| 71044f6def | |||
| a764f49910 | |||
| a17cde7b2c | |||
| a84c928827 | |||
| 9568d3bc60 | |||
| 0fe935a5de | |||
| c84c35ac74 | |||
| b32940d3ea | |||
| 7a0da729b4 | |||
| 0448eb6f0f | |||
| c334959440 | |||
| 2fa53ec1d9 | |||
| e37ad99f22 | |||
| ff57c66773 | |||
| c6d552f29b | |||
| 7f9b64519d | |||
| d89ef6280c | |||
| 8fb13372c2 | |||
| f9521f5bd4 | |||
| 53f904b740 | |||
| 99e2568304 | |||
| 38394f36d7 | |||
| 26f9d1f122 | |||
| 9cd5c44019 | |||
| 2687a83f6a | |||
| 35f25882e0 | |||
| f1f3d490ef | |||
| ae5c134ac6 | |||
| 03d4fffc70 | |||
| a0d56c855c | |||
| 9007d8c8d4 | |||
| 65bbf708a8 | |||
| 2f0db2708c | |||
| 184ee2d890 | |||
| d6b3e7f195 | |||
| 926e24c642 | |||
| 18a396b53f | |||
| c62e089260 | |||
| 1a246bf135 | |||
| 257a6aa2ba | |||
| 7bae22a3ca | |||
| f24d956ae2 | |||
| 4487c165c8 | |||
| e3f7e02555 | |||
| f782104125 | |||
| 7507a7f89f | |||
| 882859bc78 | |||
| 22284fc504 | |||
| d70f18b87b | |||
| ec388622ff | |||
| 6a425e95cb | |||
| 1fdfedc43e | |||
| 18b240c071 | |||
| 0aa99b8f47 | |||
| 481f91cc34 | |||
| feebdc9779 | |||
| a29e26200f | |||
| 75180bdc9d | |||
| cf44be1de6 | |||
| 95a31b8887 | |||
| c8673a16bb | |||
| 195d0a93b5 | |||
| 3491ba4a06 | |||
| 5326ea63e5 | |||
| e9e6296893 | |||
| 9335cf8857 | |||
| 00a612eaea | |||
| 4e855be38b | |||
| 69ba29e518 | |||
| 3d03e8b806 | |||
| ff9d8dd0b3 | |||
| 38b939b2e9 | |||
| a19f62e636 | |||
| b60013b277 | |||
| 5e4938ab1a | |||
| 854457a392 | |||
| 0d7d3d938c | |||
| 37a4a6751a | |||
| 93a1cd75fe | |||
| b356909212 | |||
| bb28f4a0c4 | |||
| 0993c71335 | |||
| 6e1b113c89 | |||
| c46f54b091 | |||
| 3983ce9b5c | |||
| d2cd08e3e1 | |||
| bb4ae5ee53 | |||
| 57d8cd6c40 | |||
| bf0d6b8806 | |||
| a07c88e686 | |||
| c8237d5c31 | |||
| 2fea1b8407 | |||
| 282ae8fa51 | |||
| aa6587d854 | |||
| 57401589c2 | |||
| f1a2e36711 | |||
| bdc01254a9 | |||
| ace91dd0c0 | |||
| 2921a24268 | |||
| 5269a46399 | |||
| 33e2dce715 | |||
| f3bc7354b1 | |||
| bd5ae33153 | |||
| 16f1592e50 | |||
| fda08cbbb0 | |||
| 1e24d02434 | |||
| a57ca3fb66 | |||
| c619199bb4 | |||
| 703bf7cfce | |||
| 4f69be8169 | |||
| b6ad7e263b | |||
| 9e9cb28471 | |||
| 2ffea42ec8 | |||
| 4a59dc2947 | |||
| c644c1a90a | |||
| 753bc3a448 | |||
| c708643972 | |||
| a85325f56a | |||
| bdb4fd208f | |||
| 1fae4a01a8 | |||
| 8992a62da4 | |||
| 1e740df9b8 | |||
| 02b897ce27 | |||
| df56ecc318 | |||
| 49cb89e324 | |||
| da8cbbf958 | |||
| 55087ab08a | |||
| d7e8926ff6 | |||
| 7dd3d1b8ad | |||
| fd09784231 | |||
| 3b612cff28 | |||
| 32d65fc8de | |||
| 3ff29de4a1 | |||
| 9fef6560f0 | |||
| dca36ebb87 | |||
| f93f31f4ae | |||
| 974380fe10 | |||
| d6cf54dd2f | |||
| 79f0202045 | |||
| 5d7571114e | |||
| 2fb71aecb0 | |||
| 9a878de33f | |||
| a50b50f8b4 | |||
| bd409c3416 | |||
| 2f22b53732 | |||
| 1e8616bd01 | |||
| e3c546a1ed | |||
| e18ff5cb4e | |||
| 77682aabd3 | |||
| 2fe92436b9 | |||
| e1b79610f8 | |||
| 474739a379 | |||
| 67eeb05692 | |||
| 4d28e60694 | |||
| af0c1b0cb7 | |||
| 7282976de3 | |||
| 13a7a297bb | |||
| c484a61515 | |||
| b99f94a7ff | |||
| 6a1ecab2dd | |||
| 67e2d5c28b | |||
| 9912704234 | |||
| fe771b59f4 | |||
| d26c76180d | |||
| 62d473305d | |||
| 13d551846a | |||
| c05ea35f78 | |||
| 7f705870d2 | |||
| 821037e18f | |||
| a3f235f8a2 | |||
| f70bafff1a | |||
| 3ad7eec9de | |||
| 7135bdc3bd | |||
| 260bfc4bd2 | |||
| 8950fe79ad | |||
| c8b9467f50 | |||
| 0d4aa9125e | |||
| aa6afb0cfe | |||
| 832a2fcc69 | |||
| 958bed4545 | |||
| 0c688b0bf5 | |||
| 7e2bd395bc | |||
| 19053ab631 | |||
| 6481f4e937 | |||
| d1deff6b07 | |||
| e8aaab2fc1 | |||
| 21b133de40 | |||
| 0c55248f92 | |||
| 3ef9673360 | |||
| 21ecf01a17 | |||
| 5d52d73c4b | |||
| fea5b758bc | |||
| c656105a6c | |||
| fe70c6f481 | |||
| c2961454fe | |||
| 5ffa1049ae | |||
| 3ae3706c84 | |||
| 2d2c176f03 | |||
| 0eef4a6c94 | |||
| 22be3008f8 | |||
| 7f98f4a38b | |||
| 0098ecb609 | |||
| 85e1754728 | |||
| a2150e456c | |||
| 1b6852a36c | |||
| e69eebb14a | |||
| 0145c89879 | |||
| 667ec28697 | |||
| 5464423667 | |||
| cc4736fa58 | |||
| e3dd78e414 | |||
| b9ab44ed0e | |||
| d31676935e | |||
| 26658c2e93 | |||
| b881949b6d |
@@ -8,8 +8,17 @@ ccache -s
|
||||
|
||||
BUILD_FLAVOR=mainline
|
||||
|
||||
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
|
||||
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
|
||||
base64 --decode <<< "${ANDROID_KEYSTORE_B64}" > "${ANDROID_KEYSTORE_FILE}"
|
||||
fi
|
||||
|
||||
cd src/android
|
||||
chmod +x ./gradlew
|
||||
./gradlew "assemble${BUILD_FLAVOR}Release" "bundle${BUILD_FLAVOR}Release"
|
||||
|
||||
ccache -s
|
||||
|
||||
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
|
||||
rm "${ANDROID_KEYSTORE_FILE}"
|
||||
fi
|
||||
|
||||
@@ -13,15 +13,3 @@ cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/release/app-${BUILD_FLAVOR
|
||||
"artifacts/${REV_NAME}.apk"
|
||||
cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}Release"/"app-${BUILD_FLAVOR}-release.aab" \
|
||||
"artifacts/${REV_NAME}.aab"
|
||||
|
||||
if [ -n "${ANDROID_KEYSTORE_B64}" ]
|
||||
then
|
||||
echo "Signing apk..."
|
||||
base64 --decode <<< "${ANDROID_KEYSTORE_B64}" > ks.jks
|
||||
|
||||
apksigner sign --ks ks.jks \
|
||||
--ks-key-alias "${ANDROID_KEY_ALIAS}" \
|
||||
--ks-pass env:ANDROID_KEYSTORE_PASS "artifacts/${REV_NAME}.apk"
|
||||
else
|
||||
echo "No keystore specified, not signing the APK files."
|
||||
fi
|
||||
|
||||
@@ -19,6 +19,7 @@ cmake .. \
|
||||
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
|
||||
-DENABLE_QT_TRANSLATION=ON \
|
||||
-DUSE_DISCORD_PRESENCE=ON \
|
||||
-DYUZU_CRASH_DUMPS=ON \
|
||||
-DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
|
||||
-DYUZU_USE_BUNDLED_FFMPEG=ON \
|
||||
-GNinja
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
|
||||
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
|
||||
GITREV="`git show -s --format='%h'`"
|
||||
ARTIFACTS_DIR="artifacts"
|
||||
ARTIFACTS_DIR="$PWD/artifacts"
|
||||
|
||||
mkdir -p "${ARTIFACTS_DIR}/"
|
||||
|
||||
@@ -11,7 +11,7 @@ ccache -s
|
||||
mkdir build || true && cd build
|
||||
cmake .. \
|
||||
-DBoost_USE_STATIC_LIBS=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_CXX_FLAGS="-march=x86-64-v2" \
|
||||
-DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \
|
||||
-DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \
|
||||
@@ -23,6 +23,7 @@ cmake .. \
|
||||
-DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
|
||||
-DYUZU_USE_BUNDLED_FFMPEG=ON \
|
||||
-DYUZU_ENABLE_LTO=ON \
|
||||
-DYUZU_CRASH_DUMPS=ON \
|
||||
-GNinja
|
||||
|
||||
ninja
|
||||
@@ -31,6 +32,19 @@ ccache -s
|
||||
|
||||
ctest -VV -C Release
|
||||
|
||||
# Separate debug symbols from specified executables
|
||||
for EXE in yuzu; do
|
||||
EXE_PATH="bin/$EXE"
|
||||
# Copy debug symbols out
|
||||
objcopy --only-keep-debug $EXE_PATH $EXE_PATH.debug
|
||||
# Add debug link and strip debug symbols
|
||||
objcopy -g --add-gnu-debuglink=$EXE_PATH.debug $EXE_PATH $EXE_PATH.out
|
||||
# Overwrite original with stripped copy
|
||||
mv $EXE_PATH.out $EXE_PATH
|
||||
done
|
||||
# Strip debug symbols from all executables
|
||||
find bin/ -type f -not -regex '.*.debug' -exec strip -g {} ';'
|
||||
|
||||
DESTDIR="$PWD/AppDir" ninja install
|
||||
rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
|
||||
|
||||
|
||||
@@ -59,4 +59,9 @@ if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ];
|
||||
cp "build/${APPIMAGE_NAME}" "${DIR_NAME}/yuzu-${RELEASE_NAME}.AppImage"
|
||||
fi
|
||||
|
||||
# Copy debug symbols to artifacts
|
||||
cd build/bin
|
||||
tar $COMPRESSION_FLAGS "${ARTIFACTS_DIR}/${REV_NAME}-debug.tar.xz" *.debug
|
||||
cd -
|
||||
|
||||
. .ci/scripts/common/post-upload.sh
|
||||
|
||||
@@ -17,7 +17,6 @@ cmake .. \
|
||||
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
|
||||
-DENABLE_QT_TRANSLATION=ON \
|
||||
-DUSE_CCACHE=ON \
|
||||
-DYUZU_CRASH_DUMPS=ON \
|
||||
-DYUZU_USE_BUNDLED_SDL2=OFF \
|
||||
-DYUZU_USE_EXTERNAL_SDL2=OFF \
|
||||
-DYUZU_TESTS=OFF \
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@
|
||||
|
||||
[codespell]
|
||||
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res
|
||||
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
|
||||
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,vas,zink
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# CRLF -> LF
|
||||
90aa937593e53a5d5e070fb623b228578b0b225f
|
||||
@@ -40,11 +40,11 @@ jobs:
|
||||
sudo apt-get install -y ccache apksigner glslang-dev glslang-tools
|
||||
- name: Build
|
||||
run: ./.ci/scripts/android/build.sh
|
||||
- name: Copy and sign artifacts
|
||||
env:
|
||||
ANDROID_KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }}
|
||||
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||||
ANDROID_KEYSTORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASS }}
|
||||
- name: Copy artifacts
|
||||
run: ./.ci/scripts/android/upload.sh
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
|
||||
+4
-1
@@ -32,7 +32,7 @@
|
||||
path = externals/xbyak
|
||||
url = https://github.com/herumi/xbyak.git
|
||||
[submodule "opus"]
|
||||
path = externals/opus/opus
|
||||
path = externals/opus
|
||||
url = https://github.com/xiph/opus.git
|
||||
[submodule "SDL"]
|
||||
path = externals/SDL
|
||||
@@ -58,3 +58,6 @@
|
||||
[submodule "VulkanMemoryAllocator"]
|
||||
path = externals/VulkanMemoryAllocator
|
||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
||||
[submodule "breakpad"]
|
||||
path = externals/breakpad
|
||||
url = https://github.com/yuzu-emu/breakpad.git
|
||||
|
||||
@@ -147,3 +147,7 @@ License: GPL-3.0-or-later
|
||||
Files: src/android/gradle/wrapper/*
|
||||
Copyright: 2023 yuzu Emulator Project
|
||||
License: GPL-3.0-or-later
|
||||
|
||||
Files: externals/stb/*
|
||||
Copyright: Sean Barrett
|
||||
License: MIT
|
||||
|
||||
+19
-52
@@ -11,7 +11,6 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modul
|
||||
include(DownloadExternals)
|
||||
include(CMakeDependentOption)
|
||||
include(CTest)
|
||||
include(FetchContent)
|
||||
|
||||
# Set bundled sdl2/qt as dependent options.
|
||||
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
||||
@@ -53,7 +52,7 @@ option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android"
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||
|
||||
option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
|
||||
|
||||
@@ -99,47 +98,8 @@ if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL)
|
||||
DESTINATION "${vvl_lib_path}")
|
||||
endif()
|
||||
|
||||
# On Android, fetch and compile libcxx before doing anything else
|
||||
if (ANDROID)
|
||||
set(CMAKE_SKIP_INSTALL_RULES ON)
|
||||
set(LLVM_VERSION "15.0.6")
|
||||
|
||||
# Note: even though libcxx and libcxxabi have separate releases on the project page,
|
||||
# the separated releases cannot be compiled. Only in-tree builds work. Therefore we
|
||||
# must fetch the source release for the entire llvm tree.
|
||||
FetchContent_Declare(llvm
|
||||
URL "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz"
|
||||
URL_HASH SHA256=9d53ad04dc60cb7b30e810faf64c5ab8157dadef46c8766f67f286238256ff92
|
||||
TLS_VERIFY TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(llvm)
|
||||
|
||||
# libcxx has support for most of the range library, but it's gated behind a flag:
|
||||
add_compile_definitions(_LIBCPP_ENABLE_EXPERIMENTAL)
|
||||
|
||||
# Disable standard header inclusion
|
||||
set(ANDROID_STL "none")
|
||||
|
||||
# libcxxabi
|
||||
set(LIBCXXABI_INCLUDE_TESTS OFF)
|
||||
set(LIBCXXABI_ENABLE_SHARED FALSE)
|
||||
set(LIBCXXABI_ENABLE_STATIC TRUE)
|
||||
set(LIBCXXABI_LIBCXX_INCLUDES "${LIBCXX_TARGET_INCLUDE_DIRECTORY}" CACHE STRING "" FORCE)
|
||||
add_subdirectory("${llvm_SOURCE_DIR}/libcxxabi" "${llvm_BINARY_DIR}/libcxxabi")
|
||||
link_libraries(cxxabi_static)
|
||||
|
||||
# libcxx
|
||||
set(LIBCXX_ABI_NAMESPACE "__ndk1" CACHE STRING "" FORCE)
|
||||
set(LIBCXX_CXX_ABI "libcxxabi")
|
||||
set(LIBCXX_INCLUDE_TESTS OFF)
|
||||
set(LIBCXX_INCLUDE_BENCHMARKS OFF)
|
||||
set(LIBCXX_INCLUDE_DOCS OFF)
|
||||
set(LIBCXX_ENABLE_SHARED FALSE)
|
||||
set(LIBCXX_ENABLE_STATIC TRUE)
|
||||
set(LIBCXX_ENABLE_ASSERTIONS FALSE)
|
||||
add_subdirectory("${llvm_SOURCE_DIR}/libcxx" "${llvm_BINARY_DIR}/libcxx")
|
||||
set_target_properties(cxx-headers PROPERTIES INTERFACE_COMPILE_OPTIONS "-isystem${CMAKE_BINARY_DIR}/${LIBCXX_INSTALL_INCLUDE_DIR}")
|
||||
link_libraries(cxx_static cxx-headers)
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_BUNDLED_VCPKG)
|
||||
@@ -179,9 +139,6 @@ if (YUZU_USE_BUNDLED_VCPKG)
|
||||
if (YUZU_TESTS)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
|
||||
endif()
|
||||
if (YUZU_CRASH_DUMPS)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "dbghelp")
|
||||
endif()
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "web-service")
|
||||
endif()
|
||||
@@ -329,10 +286,12 @@ find_package(Boost 1.79.0 REQUIRED context)
|
||||
find_package(enet 1.3 MODULE)
|
||||
find_package(fmt 9 REQUIRED)
|
||||
find_package(inih 52 MODULE COMPONENTS INIReader)
|
||||
find_package(LLVM 17 MODULE COMPONENTS Demangle)
|
||||
find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle)
|
||||
find_package(lz4 REQUIRED)
|
||||
find_package(nlohmann_json 3.8 REQUIRED)
|
||||
find_package(Opus 1.3 MODULE)
|
||||
find_package(RenderDoc MODULE)
|
||||
find_package(stb MODULE)
|
||||
find_package(VulkanMemoryAllocator CONFIG)
|
||||
find_package(ZLIB 1.2 REQUIRED)
|
||||
find_package(zstd 1.5 REQUIRED)
|
||||
@@ -399,6 +358,9 @@ function(set_yuzu_qt_components)
|
||||
if (ENABLE_QT_TRANSLATION)
|
||||
list(APPEND YUZU_QT_COMPONENTS2 LinguistTools)
|
||||
endif()
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
list(APPEND YUZU_QT_COMPONENTS2 Network)
|
||||
endif()
|
||||
set(YUZU_QT_COMPONENTS ${YUZU_QT_COMPONENTS2} PARENT_SCOPE)
|
||||
endfunction(set_yuzu_qt_components)
|
||||
|
||||
@@ -586,6 +548,18 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
|
||||
endif()
|
||||
|
||||
if (WIN32 AND YUZU_CRASH_DUMPS)
|
||||
set(BREAKPAD_VER "breakpad-c89f9dd")
|
||||
download_bundled_external("breakpad/" ${BREAKPAD_VER} BREAKPAD_PREFIX)
|
||||
|
||||
set(BREAKPAD_CLIENT_INCLUDE_DIR "${BREAKPAD_PREFIX}/include")
|
||||
set(BREAKPAD_CLIENT_LIBRARY "${BREAKPAD_PREFIX}/lib/libbreakpad_client.lib")
|
||||
|
||||
add_library(libbreakpad_client INTERFACE IMPORTED)
|
||||
target_link_libraries(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_LIBRARY}")
|
||||
target_include_directories(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_INCLUDE_DIR}")
|
||||
endif()
|
||||
|
||||
# Prefer the -pthread flag on Linux.
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
@@ -605,13 +579,6 @@ elseif (WIN32)
|
||||
# PSAPI is the Process Status API
|
||||
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
|
||||
endif()
|
||||
|
||||
if (YUZU_CRASH_DUMPS)
|
||||
find_library(DBGHELP_LIBRARY dbghelp)
|
||||
if ("${DBGHELP_LIBRARY}" STREQUAL "DBGHELP_LIBRARY-NOTFOUND")
|
||||
message(FATAL_ERROR "YUZU_CRASH_DUMPS enabled but dbghelp library not found")
|
||||
endif()
|
||||
endif()
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
|
||||
set(PLATFORM_LIBRARIES rt)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2023 Alexandre Bouvier <contact@amb.tf>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
find_path(RenderDoc_INCLUDE_DIR renderdoc_app.h)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(RenderDoc
|
||||
REQUIRED_VARS RenderDoc_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if (RenderDoc_FOUND AND NOT TARGET RenderDoc::API)
|
||||
add_library(RenderDoc::API INTERFACE IMPORTED)
|
||||
set_target_properties(RenderDoc::API PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${RenderDoc_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(RenderDoc_INCLUDE_DIR)
|
||||
@@ -0,0 +1,31 @@
|
||||
# SPDX-FileCopyrightText: 2023 Alexandre Bouvier <contact@amb.tf>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
find_path(stb_image_INCLUDE_DIR stb_image.h PATH_SUFFIXES stb)
|
||||
find_path(stb_image_resize_INCLUDE_DIR stb_image_resize.h PATH_SUFFIXES stb)
|
||||
find_path(stb_image_write_INCLUDE_DIR stb_image_write.h PATH_SUFFIXES stb)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(stb
|
||||
REQUIRED_VARS
|
||||
stb_image_INCLUDE_DIR
|
||||
stb_image_resize_INCLUDE_DIR
|
||||
stb_image_write_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if (stb_FOUND AND NOT TARGET stb::headers)
|
||||
add_library(stb::headers INTERFACE IMPORTED)
|
||||
set_property(TARGET stb::headers PROPERTY
|
||||
INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${stb_image_INCLUDE_DIR}"
|
||||
"${stb_image_resize_INCLUDE_DIR}"
|
||||
"${stb_image_write_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
stb_image_INCLUDE_DIR
|
||||
stb_image_resize_INCLUDE_DIR
|
||||
stb_image_write_INCLUDE_DIR
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# Gets a UTC timstamp and sets the provided variable to it
|
||||
# Gets a UTC timestamp and sets the provided variable to it
|
||||
function(get_timestamp _var)
|
||||
string(TIMESTAMP timestamp UTC)
|
||||
set(${_var} "${timestamp}" PARENT_SCOPE)
|
||||
|
||||
Vendored
+7273
File diff suppressed because it is too large
Load Diff
Vendored
+607
-441
File diff suppressed because it is too large
Load Diff
Vendored
+607
-441
File diff suppressed because it is too large
Load Diff
Vendored
+607
-441
File diff suppressed because it is too large
Load Diff
Vendored
+671
-494
File diff suppressed because it is too large
Load Diff
Vendored
+607
-441
File diff suppressed because it is too large
Load Diff
Vendored
+625
-457
File diff suppressed because it is too large
Load Diff
Vendored
+690
-522
File diff suppressed because it is too large
Load Diff
Vendored
+7288
File diff suppressed because it is too large
Load Diff
Vendored
+607
-441
File diff suppressed because it is too large
Load Diff
Vendored
+613
-445
File diff suppressed because it is too large
Load Diff
Vendored
+654
-486
File diff suppressed because it is too large
Load Diff
Vendored
+608
-442
File diff suppressed because it is too large
Load Diff
Vendored
+612
-444
File diff suppressed because it is too large
Load Diff
Vendored
+640
-471
File diff suppressed because it is too large
Load Diff
Vendored
+608
-442
File diff suppressed because it is too large
Load Diff
Vendored
+697
-525
File diff suppressed because it is too large
Load Diff
Vendored
+695
-524
File diff suppressed because it is too large
Load Diff
Vendored
+608
-442
File diff suppressed because it is too large
Load Diff
Vendored
+607
-441
File diff suppressed because it is too large
Load Diff
Vendored
+608
-442
File diff suppressed because it is too large
Load Diff
Vendored
+608
-442
File diff suppressed because it is too large
Load Diff
Vendored
+611
-443
File diff suppressed because it is too large
Load Diff
Vendored
+611
-443
File diff suppressed because it is too large
Load Diff
Vendored
+618
-450
File diff suppressed because it is too large
Load Diff
Vendored
+610
-442
File diff suppressed because it is too large
Load Diff
Vendored
+1
@@ -13,3 +13,4 @@ Exec=yuzu %f
|
||||
Categories=Game;Emulator;Qt;
|
||||
MimeType=application/x-nx-nro;application/x-nx-nso;application/x-nx-nsp;application/x-nx-xci;
|
||||
Keywords=Nintendo;Switch;
|
||||
StartupWMClass=yuzu
|
||||
|
||||
Vendored
+4
@@ -120,6 +120,10 @@ QWidget#connectedControllers {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#closeButtons {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#playersSupported,
|
||||
QWidget#controllersSupported,
|
||||
QWidget#controllerSupported1,
|
||||
|
||||
Vendored
+4
@@ -1380,6 +1380,10 @@ QWidget#connectedControllers {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#closeButtons {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#playersSupported,
|
||||
QWidget#controllersSupported,
|
||||
QWidget#controllerSupported1,
|
||||
|
||||
@@ -2305,6 +2305,10 @@ QWidget#connectedControllers {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#closeButtons {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#playersSupported,
|
||||
QWidget#controllersSupported,
|
||||
QWidget#controllerSupported1,
|
||||
|
||||
Vendored
+116
@@ -134,6 +134,10 @@ endif()
|
||||
|
||||
# Opus
|
||||
if (NOT TARGET Opus::opus)
|
||||
set(OPUS_BUILD_TESTING OFF)
|
||||
set(OPUS_BUILD_PROGRAMS OFF)
|
||||
set(OPUS_INSTALL_PKG_CONFIG_MODULE OFF)
|
||||
set(OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF)
|
||||
add_subdirectory(opus)
|
||||
endif()
|
||||
|
||||
@@ -171,11 +175,123 @@ endif()
|
||||
add_library(stb stb/stb_dxt.cpp)
|
||||
target_include_directories(stb PUBLIC ./stb)
|
||||
|
||||
if (NOT TARGET stb::headers)
|
||||
add_library(stb::headers ALIAS stb)
|
||||
endif()
|
||||
|
||||
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
||||
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
|
||||
|
||||
if (NOT TARGET RenderDoc::API)
|
||||
add_library(renderdoc INTERFACE)
|
||||
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc)
|
||||
add_library(RenderDoc::API ALIAS renderdoc)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
if (ARCHITECTURE_arm64)
|
||||
add_subdirectory(libadrenotools)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Breakpad
|
||||
# https://github.com/microsoft/vcpkg/blob/master/ports/breakpad/CMakeLists.txt
|
||||
if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
|
||||
set(BREAKPAD_WIN32_DEFINES
|
||||
NOMINMAX
|
||||
UNICODE
|
||||
WIN32_LEAN_AND_MEAN
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
_CRT_SECURE_NO_DEPRECATE
|
||||
_CRT_NONSTDC_NO_DEPRECATE
|
||||
)
|
||||
|
||||
# libbreakpad
|
||||
add_library(libbreakpad STATIC)
|
||||
file(GLOB_RECURSE LIBBREAKPAD_SOURCES breakpad/src/processor/*.cc)
|
||||
file(GLOB_RECURSE LIBDISASM_SOURCES breakpad/src/third_party/libdisasm/*.c)
|
||||
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "_unittest|_selftest|synth_minidump|/tests|/testdata|/solaris|microdump_stackwalk|minidump_dump|minidump_stackwalk")
|
||||
if (WIN32)
|
||||
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/linux|/mac|/android")
|
||||
target_compile_definitions(libbreakpad PRIVATE ${BREAKPAD_WIN32_DEFINES})
|
||||
target_include_directories(libbreakpad PRIVATE "${CMAKE_GENERATOR_INSTANCE}/DIA SDK/include")
|
||||
elseif (APPLE)
|
||||
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/linux|/windows|/android")
|
||||
else()
|
||||
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/mac|/windows|/android")
|
||||
endif()
|
||||
target_sources(libbreakpad PRIVATE ${LIBBREAKPAD_SOURCES} ${LIBDISASM_SOURCES})
|
||||
target_include_directories(libbreakpad
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src/third_party/libdisasm
|
||||
)
|
||||
|
||||
# libbreakpad_client
|
||||
add_library(libbreakpad_client STATIC)
|
||||
file(GLOB LIBBREAKPAD_COMMON_SOURCES breakpad/src/common/*.cc breakpad/src/common/*.c breakpad/src/client/*.cc)
|
||||
|
||||
if (WIN32)
|
||||
file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/windows/*.cc breakpad/src/common/windows/*.cc)
|
||||
list(FILTER LIBBREAKPAD_COMMON_SOURCES EXCLUDE REGEX "language.cc|path_helper.cc|stabs_to_module.cc|stabs_reader.cc|minidump_file_writer.cc")
|
||||
target_include_directories(libbreakpad_client PRIVATE "${CMAKE_GENERATOR_INSTANCE}/DIA SDK/include")
|
||||
target_compile_definitions(libbreakpad_client PRIVATE ${BREAKPAD_WIN32_DEFINES})
|
||||
elseif (APPLE)
|
||||
target_compile_definitions(libbreakpad_client PRIVATE HAVE_MACH_O_NLIST_H)
|
||||
file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/mac/*.cc breakpad/src/common/mac/*.cc)
|
||||
list(APPEND LIBBREAKPAD_CLIENT_SOURCES breakpad/src/common/mac/MachIPC.mm)
|
||||
else()
|
||||
target_compile_definitions(libbreakpad_client PUBLIC -DHAVE_A_OUT_H)
|
||||
file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/linux/*.cc breakpad/src/common/linux/*.cc)
|
||||
endif()
|
||||
list(APPEND LIBBREAKPAD_CLIENT_SOURCES ${LIBBREAKPAD_COMMON_SOURCES})
|
||||
list(FILTER LIBBREAKPAD_CLIENT_SOURCES EXCLUDE REGEX "/sender|/tests|/unittests|/testcases|_unittest|_test")
|
||||
target_sources(libbreakpad_client PRIVATE ${LIBBREAKPAD_CLIENT_SOURCES})
|
||||
target_include_directories(libbreakpad_client PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src)
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(libbreakpad_client PRIVATE wininet.lib)
|
||||
elseif (APPLE)
|
||||
find_library(CoreFoundation_FRAMEWORK CoreFoundation)
|
||||
target_link_libraries(libbreakpad_client PRIVATE ${CoreFoundation_FRAMEWORK})
|
||||
else()
|
||||
find_library(PTHREAD_LIBRARIES pthread)
|
||||
target_compile_definitions(libbreakpad_client PRIVATE HAVE_GETCONTEXT=1)
|
||||
if (PTHREAD_LIBRARIES)
|
||||
target_link_libraries(libbreakpad_client PRIVATE ${PTHREAD_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Host tools for symbol processing
|
||||
if (LINUX)
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
add_executable(minidump_stackwalk breakpad/src/processor/minidump_stackwalk.cc)
|
||||
target_link_libraries(minidump_stackwalk PRIVATE libbreakpad libbreakpad_client)
|
||||
|
||||
add_executable(dump_syms
|
||||
breakpad/src/common/dwarf_cfi_to_module.cc
|
||||
breakpad/src/common/dwarf_cu_to_module.cc
|
||||
breakpad/src/common/dwarf_line_to_module.cc
|
||||
breakpad/src/common/dwarf_range_list_handler.cc
|
||||
breakpad/src/common/language.cc
|
||||
breakpad/src/common/module.cc
|
||||
breakpad/src/common/path_helper.cc
|
||||
breakpad/src/common/stabs_reader.cc
|
||||
breakpad/src/common/stabs_to_module.cc
|
||||
breakpad/src/common/dwarf/bytereader.cc
|
||||
breakpad/src/common/dwarf/dwarf2diehandler.cc
|
||||
breakpad/src/common/dwarf/dwarf2reader.cc
|
||||
breakpad/src/common/dwarf/elf_reader.cc
|
||||
breakpad/src/common/linux/crc32.cc
|
||||
breakpad/src/common/linux/dump_symbols.cc
|
||||
breakpad/src/common/linux/elf_symbols_to_module.cc
|
||||
breakpad/src/common/linux/elfutils.cc
|
||||
breakpad/src/common/linux/file_id.cc
|
||||
breakpad/src/common/linux/linux_libc_support.cc
|
||||
breakpad/src/common/linux/memory_mapped_file.cc
|
||||
breakpad/src/common/linux/safe_readlink.cc
|
||||
breakpad/src/tools/linux/dump_syms/dump_syms.cc)
|
||||
target_link_libraries(dump_syms PRIVATE libbreakpad_client ZLIB::ZLIB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
Vendored
+1
-1
Submodule externals/SDL updated: 031912c4b6...cc016b0046
Vendored
+1
-1
Submodule externals/Vulkan-Headers updated: ed857118e2...df60f03168
Vendored
+1
-1
Submodule externals/VulkanMemoryAllocator updated: 9b0fc3e7b0...2f382df218
+1
Submodule externals/breakpad added at c89f9dddc7
Vendored
+1
-1
Submodule externals/cpp-httplib updated: 6d963fbe8d...a609330e4c
Vendored
+1
-1
Submodule externals/cpp-jwt updated: e12ef06218...10ef5735d8
Vendored
+1
-1
Submodule externals/dynarmic updated: 7da378033a...0df09e2f6b
Vendored
+1
-1
Submodule externals/ffmpeg/ffmpeg updated: 6b6b9e593d...9c1294eadd
Vendored
+1
-1
Submodule externals/inih/inih updated: 1e80a47dff...9cecf0643d
Vendored
-7
@@ -49,11 +49,6 @@ if (MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux") OR APPLE)
|
||||
|
||||
set(LIBUSB_INCLUDE_DIRS "${LIBUSB_SRC_DIR}/libusb" CACHE PATH "libusb headers path" FORCE)
|
||||
|
||||
# MINGW: causes "externals/libusb/libusb/libusb/os/windows_winusb.c:1427:2: error: conversion to non-scalar type requested", so cannot statically link it for now.
|
||||
if (NOT MINGW)
|
||||
set(LIBUSB_CFLAGS "-DGUID_DEVINTERFACE_USB_DEVICE=\\(GUID\\){0xA5DCBF10,0x6530,0x11D2,{0x90,0x1F,0x00,0xC0,0x4F,0xB9,0x51,0xED}}")
|
||||
endif()
|
||||
|
||||
make_directory("${LIBUSB_PREFIX}")
|
||||
|
||||
add_custom_command(
|
||||
@@ -146,8 +141,6 @@ else() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
target_include_directories(usb BEFORE PRIVATE libusb/msvc)
|
||||
endif()
|
||||
|
||||
# Works around other libraries providing their own definition of USB GUIDs (e.g. SDL2)
|
||||
target_compile_definitions(usb PRIVATE "-DGUID_DEVINTERFACE_USB_DEVICE=(GUID){ 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}")
|
||||
else()
|
||||
target_include_directories(usb
|
||||
# turns out other projects also have "config.h", so make sure the
|
||||
|
||||
Vendored
+1
-1
Submodule externals/libusb/libusb updated: c6a35c5601...c060e9ce30
Vendored
+1
-1
@@ -27,7 +27,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID)
|
||||
set(CAN_BUILD_NX_TZDB false)
|
||||
endif()
|
||||
|
||||
set(NX_TZDB_VERSION "220816")
|
||||
set(NX_TZDB_VERSION "221202")
|
||||
set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
|
||||
|
||||
set(NX_TZDB_ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
|
||||
|
||||
Vendored
+1
-1
Submodule externals/nx_tzdb/tzdb_to_nx updated: 212afa2394...0d17dd066d
+1
Submodule externals/opus added at 101a71e03b
Vendored
-259
@@ -1,259 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
|
||||
project(opus)
|
||||
|
||||
option(OPUS_STACK_PROTECTOR "Use stack protection" OFF)
|
||||
option(OPUS_USE_ALLOCA "Use alloca for stack arrays (on non-C99 compilers)" OFF)
|
||||
option(OPUS_CUSTOM_MODES "Enable non-Opus modes, e.g. 44.1 kHz & 2^n frames" OFF)
|
||||
option(OPUS_FIXED_POINT "Compile as fixed-point (for machines without a fast enough FPU)" OFF)
|
||||
option(OPUS_ENABLE_FLOAT_API "Compile with the floating point API (for machines with float library" ON)
|
||||
|
||||
include(opus/opus_functions.cmake)
|
||||
|
||||
if(OPUS_STACK_PROTECTOR)
|
||||
if(NOT MSVC) # GC on by default on MSVC
|
||||
check_and_set_flag(STACK_PROTECTION_STRONG -fstack-protector-strong)
|
||||
endif()
|
||||
else()
|
||||
if(MSVC)
|
||||
check_and_set_flag(BUFFER_SECURITY_CHECK /GS-)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(opus
|
||||
# CELT sources
|
||||
opus/celt/bands.c
|
||||
opus/celt/celt.c
|
||||
opus/celt/celt_decoder.c
|
||||
opus/celt/celt_encoder.c
|
||||
opus/celt/celt_lpc.c
|
||||
opus/celt/cwrs.c
|
||||
opus/celt/entcode.c
|
||||
opus/celt/entdec.c
|
||||
opus/celt/entenc.c
|
||||
opus/celt/kiss_fft.c
|
||||
opus/celt/laplace.c
|
||||
opus/celt/mathops.c
|
||||
opus/celt/mdct.c
|
||||
opus/celt/modes.c
|
||||
opus/celt/pitch.c
|
||||
opus/celt/quant_bands.c
|
||||
opus/celt/rate.c
|
||||
opus/celt/vq.c
|
||||
|
||||
# SILK sources
|
||||
opus/silk/A2NLSF.c
|
||||
opus/silk/CNG.c
|
||||
opus/silk/HP_variable_cutoff.c
|
||||
opus/silk/LPC_analysis_filter.c
|
||||
opus/silk/LPC_fit.c
|
||||
opus/silk/LPC_inv_pred_gain.c
|
||||
opus/silk/LP_variable_cutoff.c
|
||||
opus/silk/NLSF2A.c
|
||||
opus/silk/NLSF_VQ.c
|
||||
opus/silk/NLSF_VQ_weights_laroia.c
|
||||
opus/silk/NLSF_decode.c
|
||||
opus/silk/NLSF_del_dec_quant.c
|
||||
opus/silk/NLSF_encode.c
|
||||
opus/silk/NLSF_stabilize.c
|
||||
opus/silk/NLSF_unpack.c
|
||||
opus/silk/NSQ.c
|
||||
opus/silk/NSQ_del_dec.c
|
||||
opus/silk/PLC.c
|
||||
opus/silk/VAD.c
|
||||
opus/silk/VQ_WMat_EC.c
|
||||
opus/silk/ana_filt_bank_1.c
|
||||
opus/silk/biquad_alt.c
|
||||
opus/silk/bwexpander.c
|
||||
opus/silk/bwexpander_32.c
|
||||
opus/silk/check_control_input.c
|
||||
opus/silk/code_signs.c
|
||||
opus/silk/control_SNR.c
|
||||
opus/silk/control_audio_bandwidth.c
|
||||
opus/silk/control_codec.c
|
||||
opus/silk/dec_API.c
|
||||
opus/silk/decode_core.c
|
||||
opus/silk/decode_frame.c
|
||||
opus/silk/decode_indices.c
|
||||
opus/silk/decode_parameters.c
|
||||
opus/silk/decode_pitch.c
|
||||
opus/silk/decode_pulses.c
|
||||
opus/silk/decoder_set_fs.c
|
||||
opus/silk/enc_API.c
|
||||
opus/silk/encode_indices.c
|
||||
opus/silk/encode_pulses.c
|
||||
opus/silk/gain_quant.c
|
||||
opus/silk/init_decoder.c
|
||||
opus/silk/init_encoder.c
|
||||
opus/silk/inner_prod_aligned.c
|
||||
opus/silk/interpolate.c
|
||||
opus/silk/lin2log.c
|
||||
opus/silk/log2lin.c
|
||||
opus/silk/pitch_est_tables.c
|
||||
opus/silk/process_NLSFs.c
|
||||
opus/silk/quant_LTP_gains.c
|
||||
opus/silk/resampler.c
|
||||
opus/silk/resampler_down2.c
|
||||
opus/silk/resampler_down2_3.c
|
||||
opus/silk/resampler_private_AR2.c
|
||||
opus/silk/resampler_private_IIR_FIR.c
|
||||
opus/silk/resampler_private_down_FIR.c
|
||||
opus/silk/resampler_private_up2_HQ.c
|
||||
opus/silk/resampler_rom.c
|
||||
opus/silk/shell_coder.c
|
||||
opus/silk/sigm_Q15.c
|
||||
opus/silk/sort.c
|
||||
opus/silk/stereo_LR_to_MS.c
|
||||
opus/silk/stereo_MS_to_LR.c
|
||||
opus/silk/stereo_decode_pred.c
|
||||
opus/silk/stereo_encode_pred.c
|
||||
opus/silk/stereo_find_predictor.c
|
||||
opus/silk/stereo_quant_pred.c
|
||||
opus/silk/sum_sqr_shift.c
|
||||
opus/silk/table_LSF_cos.c
|
||||
opus/silk/tables_LTP.c
|
||||
opus/silk/tables_NLSF_CB_NB_MB.c
|
||||
opus/silk/tables_NLSF_CB_WB.c
|
||||
opus/silk/tables_gain.c
|
||||
opus/silk/tables_other.c
|
||||
opus/silk/tables_pitch_lag.c
|
||||
opus/silk/tables_pulses_per_block.c
|
||||
|
||||
# Opus sources
|
||||
opus/src/analysis.c
|
||||
opus/src/mapping_matrix.c
|
||||
opus/src/mlp.c
|
||||
opus/src/mlp_data.c
|
||||
opus/src/opus.c
|
||||
opus/src/opus_decoder.c
|
||||
opus/src/opus_encoder.c
|
||||
opus/src/opus_multistream.c
|
||||
opus/src/opus_multistream_decoder.c
|
||||
opus/src/opus_multistream_encoder.c
|
||||
opus/src/opus_projection_decoder.c
|
||||
opus/src/opus_projection_encoder.c
|
||||
opus/src/repacketizer.c
|
||||
)
|
||||
|
||||
if (DEBUG)
|
||||
target_sources(opus PRIVATE opus/silk/debug.c)
|
||||
endif()
|
||||
|
||||
if (OPUS_FIXED_POINT)
|
||||
target_sources(opus PRIVATE
|
||||
opus/silk/fixed/LTP_analysis_filter_FIX.c
|
||||
opus/silk/fixed/LTP_scale_ctrl_FIX.c
|
||||
opus/silk/fixed/apply_sine_window_FIX.c
|
||||
opus/silk/fixed/autocorr_FIX.c
|
||||
opus/silk/fixed/burg_modified_FIX.c
|
||||
opus/silk/fixed/corrMatrix_FIX.c
|
||||
opus/silk/fixed/encode_frame_FIX.c
|
||||
opus/silk/fixed/find_LPC_FIX.c
|
||||
opus/silk/fixed/find_LTP_FIX.c
|
||||
opus/silk/fixed/find_pitch_lags_FIX.c
|
||||
opus/silk/fixed/find_pred_coefs_FIX.c
|
||||
opus/silk/fixed/k2a_FIX.c
|
||||
opus/silk/fixed/k2a_Q16_FIX.c
|
||||
opus/silk/fixed/noise_shape_analysis_FIX.c
|
||||
opus/silk/fixed/pitch_analysis_core_FIX.c
|
||||
opus/silk/fixed/prefilter_FIX.c
|
||||
opus/silk/fixed/process_gains_FIX.c
|
||||
opus/silk/fixed/regularize_correlations_FIX.c
|
||||
opus/silk/fixed/residual_energy16_FIX.c
|
||||
opus/silk/fixed/residual_energy_FIX.c
|
||||
opus/silk/fixed/schur64_FIX.c
|
||||
opus/silk/fixed/schur_FIX.c
|
||||
opus/silk/fixed/solve_LS_FIX.c
|
||||
opus/silk/fixed/vector_ops_FIX.c
|
||||
opus/silk/fixed/warped_autocorrelation_FIX.c
|
||||
)
|
||||
else()
|
||||
target_sources(opus PRIVATE
|
||||
opus/silk/float/LPC_analysis_filter_FLP.c
|
||||
opus/silk/float/LPC_inv_pred_gain_FLP.c
|
||||
opus/silk/float/LTP_analysis_filter_FLP.c
|
||||
opus/silk/float/LTP_scale_ctrl_FLP.c
|
||||
opus/silk/float/apply_sine_window_FLP.c
|
||||
opus/silk/float/autocorrelation_FLP.c
|
||||
opus/silk/float/burg_modified_FLP.c
|
||||
opus/silk/float/bwexpander_FLP.c
|
||||
opus/silk/float/corrMatrix_FLP.c
|
||||
opus/silk/float/encode_frame_FLP.c
|
||||
opus/silk/float/energy_FLP.c
|
||||
opus/silk/float/find_LPC_FLP.c
|
||||
opus/silk/float/find_LTP_FLP.c
|
||||
opus/silk/float/find_pitch_lags_FLP.c
|
||||
opus/silk/float/find_pred_coefs_FLP.c
|
||||
opus/silk/float/inner_product_FLP.c
|
||||
opus/silk/float/k2a_FLP.c
|
||||
opus/silk/float/noise_shape_analysis_FLP.c
|
||||
opus/silk/float/pitch_analysis_core_FLP.c
|
||||
opus/silk/float/process_gains_FLP.c
|
||||
opus/silk/float/regularize_correlations_FLP.c
|
||||
opus/silk/float/residual_energy_FLP.c
|
||||
opus/silk/float/scale_copy_vector_FLP.c
|
||||
opus/silk/float/scale_vector_FLP.c
|
||||
opus/silk/float/schur_FLP.c
|
||||
opus/silk/float/sort_FLP.c
|
||||
opus/silk/float/warped_autocorrelation_FLP.c
|
||||
opus/silk/float/wrappers_FLP.c
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(opus PRIVATE OPUS_BUILD ENABLE_HARDENING)
|
||||
|
||||
if(NOT MSVC)
|
||||
if(MINGW)
|
||||
target_compile_definitions(opus PRIVATE _FORTIFY_SOURCE=0)
|
||||
else()
|
||||
target_compile_definitions(opus PRIVATE _FORTIFY_SOURCE=2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# It is strongly recommended to uncomment one of these VAR_ARRAYS: Use C99
|
||||
# variable-length arrays for stack allocation USE_ALLOCA: Use alloca() for stack
|
||||
# allocation If none is defined, then the fallback is a non-threadsafe global
|
||||
# array
|
||||
if(OPUS_USE_ALLOCA OR MSVC)
|
||||
target_compile_definitions(opus PRIVATE USE_ALLOCA)
|
||||
else()
|
||||
target_compile_definitions(opus PRIVATE VAR_ARRAYS)
|
||||
endif()
|
||||
|
||||
if(OPUS_CUSTOM_MODES)
|
||||
target_compile_definitions(opus PRIVATE CUSTOM_MODES)
|
||||
endif()
|
||||
|
||||
if(NOT OPUS_ENABLE_FLOAT_API)
|
||||
target_compile_definitions(opus PRIVATE DISABLE_FLOAT_API)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(opus
|
||||
PUBLIC
|
||||
-DOPUS_VERSION="\\"1.3.1\\""
|
||||
|
||||
PRIVATE
|
||||
# Use C99 intrinsics to speed up float-to-int conversion
|
||||
HAVE_LRINTF
|
||||
)
|
||||
|
||||
if (FIXED_POINT)
|
||||
target_compile_definitions(opus PRIVATE -DFIXED_POINT=1 -DDISABLE_FLOAT_API)
|
||||
endif()
|
||||
|
||||
target_include_directories(opus
|
||||
PUBLIC
|
||||
opus/include
|
||||
|
||||
PRIVATE
|
||||
opus/celt
|
||||
opus/silk
|
||||
opus/silk/fixed
|
||||
opus/silk/float
|
||||
opus/src
|
||||
)
|
||||
|
||||
add_library(Opus::opus ALIAS opus)
|
||||
Vendored
-1
Submodule externals/opus/opus deleted from ad8fe90db7
Vendored
+744
@@ -0,0 +1,744 @@
|
||||
// SPDX-FileCopyrightText: Baldur Karlsson
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2023 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Documentation for the API is available at https://renderdoc.org/docs/in_application_api.html
|
||||
//
|
||||
|
||||
#if !defined(RENDERDOC_NO_STDINT)
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
|
||||
#define RENDERDOC_CC __cdecl
|
||||
#elif defined(__linux__)
|
||||
#define RENDERDOC_CC
|
||||
#elif defined(__APPLE__)
|
||||
#define RENDERDOC_CC
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constants not used directly in below API
|
||||
|
||||
// This is a GUID/magic value used for when applications pass a path where shader debug
|
||||
// information can be found to match up with a stripped shader.
|
||||
// the define can be used like so: const GUID RENDERDOC_ShaderDebugMagicValue =
|
||||
// RENDERDOC_ShaderDebugMagicValue_value
|
||||
#define RENDERDOC_ShaderDebugMagicValue_struct \
|
||||
{ \
|
||||
0xeab25520, 0x6670, 0x4865, 0x84, 0x29, 0x6c, 0x8, 0x51, 0x54, 0x00, 0xff \
|
||||
}
|
||||
|
||||
// as an alternative when you want a byte array (assuming x86 endianness):
|
||||
#define RENDERDOC_ShaderDebugMagicValue_bytearray \
|
||||
{ \
|
||||
0x20, 0x55, 0xb2, 0xea, 0x70, 0x66, 0x65, 0x48, 0x84, 0x29, 0x6c, 0x8, 0x51, 0x54, 0x00, 0xff \
|
||||
}
|
||||
|
||||
// truncated version when only a uint64_t is available (e.g. Vulkan tags):
|
||||
#define RENDERDOC_ShaderDebugMagicValue_truncated 0x48656670eab25520ULL
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDoc capture options
|
||||
//
|
||||
|
||||
typedef enum RENDERDOC_CaptureOption
|
||||
{
|
||||
// Allow the application to enable vsync
|
||||
//
|
||||
// Default - enabled
|
||||
//
|
||||
// 1 - The application can enable or disable vsync at will
|
||||
// 0 - vsync is force disabled
|
||||
eRENDERDOC_Option_AllowVSync = 0,
|
||||
|
||||
// Allow the application to enable fullscreen
|
||||
//
|
||||
// Default - enabled
|
||||
//
|
||||
// 1 - The application can enable or disable fullscreen at will
|
||||
// 0 - fullscreen is force disabled
|
||||
eRENDERDOC_Option_AllowFullscreen = 1,
|
||||
|
||||
// Record API debugging events and messages
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Enable built-in API debugging features and records the results into
|
||||
// the capture, which is matched up with events on replay
|
||||
// 0 - no API debugging is forcibly enabled
|
||||
eRENDERDOC_Option_APIValidation = 2,
|
||||
eRENDERDOC_Option_DebugDeviceMode = 2, // deprecated name of this enum
|
||||
|
||||
// Capture CPU callstacks for API events
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Enables capturing of callstacks
|
||||
// 0 - no callstacks are captured
|
||||
eRENDERDOC_Option_CaptureCallstacks = 3,
|
||||
|
||||
// When capturing CPU callstacks, only capture them from actions.
|
||||
// This option does nothing without the above option being enabled
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Only captures callstacks for actions.
|
||||
// Ignored if CaptureCallstacks is disabled
|
||||
// 0 - Callstacks, if enabled, are captured for every event.
|
||||
eRENDERDOC_Option_CaptureCallstacksOnlyDraws = 4,
|
||||
eRENDERDOC_Option_CaptureCallstacksOnlyActions = 4,
|
||||
|
||||
// Specify a delay in seconds to wait for a debugger to attach, after
|
||||
// creating or injecting into a process, before continuing to allow it to run.
|
||||
//
|
||||
// 0 indicates no delay, and the process will run immediately after injection
|
||||
//
|
||||
// Default - 0 seconds
|
||||
//
|
||||
eRENDERDOC_Option_DelayForDebugger = 5,
|
||||
|
||||
// Verify buffer access. This includes checking the memory returned by a Map() call to
|
||||
// detect any out-of-bounds modification, as well as initialising buffers with undefined contents
|
||||
// to a marker value to catch use of uninitialised memory.
|
||||
//
|
||||
// NOTE: This option is only valid for OpenGL and D3D11. Explicit APIs such as D3D12 and Vulkan do
|
||||
// not do the same kind of interception & checking and undefined contents are really undefined.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Verify buffer access
|
||||
// 0 - No verification is performed, and overwriting bounds may cause crashes or corruption in
|
||||
// RenderDoc.
|
||||
eRENDERDOC_Option_VerifyBufferAccess = 6,
|
||||
|
||||
// The old name for eRENDERDOC_Option_VerifyBufferAccess was eRENDERDOC_Option_VerifyMapWrites.
|
||||
// This option now controls the filling of uninitialised buffers with 0xdddddddd which was
|
||||
// previously always enabled
|
||||
eRENDERDOC_Option_VerifyMapWrites = eRENDERDOC_Option_VerifyBufferAccess,
|
||||
|
||||
// Hooks any system API calls that create child processes, and injects
|
||||
// RenderDoc into them recursively with the same options.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Hooks into spawned child processes
|
||||
// 0 - Child processes are not hooked by RenderDoc
|
||||
eRENDERDOC_Option_HookIntoChildren = 7,
|
||||
|
||||
// By default RenderDoc only includes resources in the final capture necessary
|
||||
// for that frame, this allows you to override that behaviour.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - all live resources at the time of capture are included in the capture
|
||||
// and available for inspection
|
||||
// 0 - only the resources referenced by the captured frame are included
|
||||
eRENDERDOC_Option_RefAllResources = 8,
|
||||
|
||||
// **NOTE**: As of RenderDoc v1.1 this option has been deprecated. Setting or
|
||||
// getting it will be ignored, to allow compatibility with older versions.
|
||||
// In v1.1 the option acts as if it's always enabled.
|
||||
//
|
||||
// By default RenderDoc skips saving initial states for resources where the
|
||||
// previous contents don't appear to be used, assuming that writes before
|
||||
// reads indicate previous contents aren't used.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - initial contents at the start of each captured frame are saved, even if
|
||||
// they are later overwritten or cleared before being used.
|
||||
// 0 - unless a read is detected, initial contents will not be saved and will
|
||||
// appear as black or empty data.
|
||||
eRENDERDOC_Option_SaveAllInitials = 9,
|
||||
|
||||
// In APIs that allow for the recording of command lists to be replayed later,
|
||||
// RenderDoc may choose to not capture command lists before a frame capture is
|
||||
// triggered, to reduce overheads. This means any command lists recorded once
|
||||
// and replayed many times will not be available and may cause a failure to
|
||||
// capture.
|
||||
//
|
||||
// NOTE: This is only true for APIs where multithreading is difficult or
|
||||
// discouraged. Newer APIs like Vulkan and D3D12 will ignore this option
|
||||
// and always capture all command lists since the API is heavily oriented
|
||||
// around it and the overheads have been reduced by API design.
|
||||
//
|
||||
// 1 - All command lists are captured from the start of the application
|
||||
// 0 - Command lists are only captured if their recording begins during
|
||||
// the period when a frame capture is in progress.
|
||||
eRENDERDOC_Option_CaptureAllCmdLists = 10,
|
||||
|
||||
// Mute API debugging output when the API validation mode option is enabled
|
||||
//
|
||||
// Default - enabled
|
||||
//
|
||||
// 1 - Mute any API debug messages from being displayed or passed through
|
||||
// 0 - API debugging is displayed as normal
|
||||
eRENDERDOC_Option_DebugOutputMute = 11,
|
||||
|
||||
// Option to allow vendor extensions to be used even when they may be
|
||||
// incompatible with RenderDoc and cause corrupted replays or crashes.
|
||||
//
|
||||
// Default - inactive
|
||||
//
|
||||
// No values are documented, this option should only be used when absolutely
|
||||
// necessary as directed by a RenderDoc developer.
|
||||
eRENDERDOC_Option_AllowUnsupportedVendorExtensions = 12,
|
||||
|
||||
// Define a soft memory limit which some APIs may aim to keep overhead under where
|
||||
// possible. Anything above this limit will where possible be saved directly to disk during
|
||||
// capture.
|
||||
// This will cause increased disk space use (which may cause a capture to fail if disk space is
|
||||
// exhausted) as well as slower capture times.
|
||||
//
|
||||
// Not all memory allocations may be deferred like this so it is not a guarantee of a memory
|
||||
// limit.
|
||||
//
|
||||
// Units are in MBs, suggested values would range from 200MB to 1000MB.
|
||||
//
|
||||
// Default - 0 Megabytes
|
||||
eRENDERDOC_Option_SoftMemoryLimit = 13,
|
||||
} RENDERDOC_CaptureOption;
|
||||
|
||||
// Sets an option that controls how RenderDoc behaves on capture.
|
||||
//
|
||||
// Returns 1 if the option and value are valid
|
||||
// Returns 0 if either is invalid and the option is unchanged
|
||||
typedef int(RENDERDOC_CC *pRENDERDOC_SetCaptureOptionU32)(RENDERDOC_CaptureOption opt, uint32_t val);
|
||||
typedef int(RENDERDOC_CC *pRENDERDOC_SetCaptureOptionF32)(RENDERDOC_CaptureOption opt, float val);
|
||||
|
||||
// Gets the current value of an option as a uint32_t
|
||||
//
|
||||
// If the option is invalid, 0xffffffff is returned
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetCaptureOptionU32)(RENDERDOC_CaptureOption opt);
|
||||
|
||||
// Gets the current value of an option as a float
|
||||
//
|
||||
// If the option is invalid, -FLT_MAX is returned
|
||||
typedef float(RENDERDOC_CC *pRENDERDOC_GetCaptureOptionF32)(RENDERDOC_CaptureOption opt);
|
||||
|
||||
typedef enum RENDERDOC_InputButton
|
||||
{
|
||||
// '0' - '9' matches ASCII values
|
||||
eRENDERDOC_Key_0 = 0x30,
|
||||
eRENDERDOC_Key_1 = 0x31,
|
||||
eRENDERDOC_Key_2 = 0x32,
|
||||
eRENDERDOC_Key_3 = 0x33,
|
||||
eRENDERDOC_Key_4 = 0x34,
|
||||
eRENDERDOC_Key_5 = 0x35,
|
||||
eRENDERDOC_Key_6 = 0x36,
|
||||
eRENDERDOC_Key_7 = 0x37,
|
||||
eRENDERDOC_Key_8 = 0x38,
|
||||
eRENDERDOC_Key_9 = 0x39,
|
||||
|
||||
// 'A' - 'Z' matches ASCII values
|
||||
eRENDERDOC_Key_A = 0x41,
|
||||
eRENDERDOC_Key_B = 0x42,
|
||||
eRENDERDOC_Key_C = 0x43,
|
||||
eRENDERDOC_Key_D = 0x44,
|
||||
eRENDERDOC_Key_E = 0x45,
|
||||
eRENDERDOC_Key_F = 0x46,
|
||||
eRENDERDOC_Key_G = 0x47,
|
||||
eRENDERDOC_Key_H = 0x48,
|
||||
eRENDERDOC_Key_I = 0x49,
|
||||
eRENDERDOC_Key_J = 0x4A,
|
||||
eRENDERDOC_Key_K = 0x4B,
|
||||
eRENDERDOC_Key_L = 0x4C,
|
||||
eRENDERDOC_Key_M = 0x4D,
|
||||
eRENDERDOC_Key_N = 0x4E,
|
||||
eRENDERDOC_Key_O = 0x4F,
|
||||
eRENDERDOC_Key_P = 0x50,
|
||||
eRENDERDOC_Key_Q = 0x51,
|
||||
eRENDERDOC_Key_R = 0x52,
|
||||
eRENDERDOC_Key_S = 0x53,
|
||||
eRENDERDOC_Key_T = 0x54,
|
||||
eRENDERDOC_Key_U = 0x55,
|
||||
eRENDERDOC_Key_V = 0x56,
|
||||
eRENDERDOC_Key_W = 0x57,
|
||||
eRENDERDOC_Key_X = 0x58,
|
||||
eRENDERDOC_Key_Y = 0x59,
|
||||
eRENDERDOC_Key_Z = 0x5A,
|
||||
|
||||
// leave the rest of the ASCII range free
|
||||
// in case we want to use it later
|
||||
eRENDERDOC_Key_NonPrintable = 0x100,
|
||||
|
||||
eRENDERDOC_Key_Divide,
|
||||
eRENDERDOC_Key_Multiply,
|
||||
eRENDERDOC_Key_Subtract,
|
||||
eRENDERDOC_Key_Plus,
|
||||
|
||||
eRENDERDOC_Key_F1,
|
||||
eRENDERDOC_Key_F2,
|
||||
eRENDERDOC_Key_F3,
|
||||
eRENDERDOC_Key_F4,
|
||||
eRENDERDOC_Key_F5,
|
||||
eRENDERDOC_Key_F6,
|
||||
eRENDERDOC_Key_F7,
|
||||
eRENDERDOC_Key_F8,
|
||||
eRENDERDOC_Key_F9,
|
||||
eRENDERDOC_Key_F10,
|
||||
eRENDERDOC_Key_F11,
|
||||
eRENDERDOC_Key_F12,
|
||||
|
||||
eRENDERDOC_Key_Home,
|
||||
eRENDERDOC_Key_End,
|
||||
eRENDERDOC_Key_Insert,
|
||||
eRENDERDOC_Key_Delete,
|
||||
eRENDERDOC_Key_PageUp,
|
||||
eRENDERDOC_Key_PageDn,
|
||||
|
||||
eRENDERDOC_Key_Backspace,
|
||||
eRENDERDOC_Key_Tab,
|
||||
eRENDERDOC_Key_PrtScrn,
|
||||
eRENDERDOC_Key_Pause,
|
||||
|
||||
eRENDERDOC_Key_Max,
|
||||
} RENDERDOC_InputButton;
|
||||
|
||||
// Sets which key or keys can be used to toggle focus between multiple windows
|
||||
//
|
||||
// If keys is NULL or num is 0, toggle keys will be disabled
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetFocusToggleKeys)(RENDERDOC_InputButton *keys, int num);
|
||||
|
||||
// Sets which key or keys can be used to capture the next frame
|
||||
//
|
||||
// If keys is NULL or num is 0, captures keys will be disabled
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureKeys)(RENDERDOC_InputButton *keys, int num);
|
||||
|
||||
typedef enum RENDERDOC_OverlayBits
|
||||
{
|
||||
// This single bit controls whether the overlay is enabled or disabled globally
|
||||
eRENDERDOC_Overlay_Enabled = 0x1,
|
||||
|
||||
// Show the average framerate over several seconds as well as min/max
|
||||
eRENDERDOC_Overlay_FrameRate = 0x2,
|
||||
|
||||
// Show the current frame number
|
||||
eRENDERDOC_Overlay_FrameNumber = 0x4,
|
||||
|
||||
// Show a list of recent captures, and how many captures have been made
|
||||
eRENDERDOC_Overlay_CaptureList = 0x8,
|
||||
|
||||
// Default values for the overlay mask
|
||||
eRENDERDOC_Overlay_Default = (eRENDERDOC_Overlay_Enabled | eRENDERDOC_Overlay_FrameRate |
|
||||
eRENDERDOC_Overlay_FrameNumber | eRENDERDOC_Overlay_CaptureList),
|
||||
|
||||
// Enable all bits
|
||||
eRENDERDOC_Overlay_All = ~0U,
|
||||
|
||||
// Disable all bits
|
||||
eRENDERDOC_Overlay_None = 0,
|
||||
} RENDERDOC_OverlayBits;
|
||||
|
||||
// returns the overlay bits that have been set
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetOverlayBits)();
|
||||
// sets the overlay bits with an and & or mask
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_MaskOverlayBits)(uint32_t And, uint32_t Or);
|
||||
|
||||
// this function will attempt to remove RenderDoc's hooks in the application.
|
||||
//
|
||||
// Note: that this can only work correctly if done immediately after
|
||||
// the module is loaded, before any API work happens. RenderDoc will remove its
|
||||
// injected hooks and shut down. Behaviour is undefined if this is called
|
||||
// after any API functions have been called, and there is still no guarantee of
|
||||
// success.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_RemoveHooks)();
|
||||
|
||||
// DEPRECATED: compatibility for code compiled against pre-1.4.1 headers.
|
||||
typedef pRENDERDOC_RemoveHooks pRENDERDOC_Shutdown;
|
||||
|
||||
// This function will unload RenderDoc's crash handler.
|
||||
//
|
||||
// If you use your own crash handler and don't want RenderDoc's handler to
|
||||
// intercede, you can call this function to unload it and any unhandled
|
||||
// exceptions will pass to the next handler.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_UnloadCrashHandler)();
|
||||
|
||||
// Sets the capture file path template
|
||||
//
|
||||
// pathtemplate is a UTF-8 string that gives a template for how captures will be named
|
||||
// and where they will be saved.
|
||||
//
|
||||
// Any extension is stripped off the path, and captures are saved in the directory
|
||||
// specified, and named with the filename and the frame number appended. If the
|
||||
// directory does not exist it will be created, including any parent directories.
|
||||
//
|
||||
// If pathtemplate is NULL, the template will remain unchanged
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// SetCaptureFilePathTemplate("my_captures/example");
|
||||
//
|
||||
// Capture #1 -> my_captures/example_frame123.rdc
|
||||
// Capture #2 -> my_captures/example_frame456.rdc
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureFilePathTemplate)(const char *pathtemplate);
|
||||
|
||||
// returns the current capture path template, see SetCaptureFileTemplate above, as a UTF-8 string
|
||||
typedef const char *(RENDERDOC_CC *pRENDERDOC_GetCaptureFilePathTemplate)();
|
||||
|
||||
// DEPRECATED: compatibility for code compiled against pre-1.1.2 headers.
|
||||
typedef pRENDERDOC_SetCaptureFilePathTemplate pRENDERDOC_SetLogFilePathTemplate;
|
||||
typedef pRENDERDOC_GetCaptureFilePathTemplate pRENDERDOC_GetLogFilePathTemplate;
|
||||
|
||||
// returns the number of captures that have been made
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetNumCaptures)();
|
||||
|
||||
// This function returns the details of a capture, by index. New captures are added
|
||||
// to the end of the list.
|
||||
//
|
||||
// filename will be filled with the absolute path to the capture file, as a UTF-8 string
|
||||
// pathlength will be written with the length in bytes of the filename string
|
||||
// timestamp will be written with the time of the capture, in seconds since the Unix epoch
|
||||
//
|
||||
// Any of the parameters can be NULL and they'll be skipped.
|
||||
//
|
||||
// The function will return 1 if the capture index is valid, or 0 if the index is invalid
|
||||
// If the index is invalid, the values will be unchanged
|
||||
//
|
||||
// Note: when captures are deleted in the UI they will remain in this list, so the
|
||||
// capture path may not exist anymore.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetCapture)(uint32_t idx, char *filename,
|
||||
uint32_t *pathlength, uint64_t *timestamp);
|
||||
|
||||
// Sets the comments associated with a capture file. These comments are displayed in the
|
||||
// UI program when opening.
|
||||
//
|
||||
// filePath should be a path to the capture file to add comments to. If set to NULL or ""
|
||||
// the most recent capture file created made will be used instead.
|
||||
// comments should be a NULL-terminated UTF-8 string to add as comments.
|
||||
//
|
||||
// Any existing comments will be overwritten.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureFileComments)(const char *filePath,
|
||||
const char *comments);
|
||||
|
||||
// returns 1 if the RenderDoc UI is connected to this application, 0 otherwise
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_IsTargetControlConnected)();
|
||||
|
||||
// DEPRECATED: compatibility for code compiled against pre-1.1.1 headers.
|
||||
// This was renamed to IsTargetControlConnected in API 1.1.1, the old typedef is kept here for
|
||||
// backwards compatibility with old code, it is castable either way since it's ABI compatible
|
||||
// as the same function pointer type.
|
||||
typedef pRENDERDOC_IsTargetControlConnected pRENDERDOC_IsRemoteAccessConnected;
|
||||
|
||||
// This function will launch the Replay UI associated with the RenderDoc library injected
|
||||
// into the running application.
|
||||
//
|
||||
// if connectTargetControl is 1, the Replay UI will be launched with a command line parameter
|
||||
// to connect to this application
|
||||
// cmdline is the rest of the command line, as a UTF-8 string. E.g. a captures to open
|
||||
// if cmdline is NULL, the command line will be empty.
|
||||
//
|
||||
// returns the PID of the replay UI if successful, 0 if not successful.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_LaunchReplayUI)(uint32_t connectTargetControl,
|
||||
const char *cmdline);
|
||||
|
||||
// RenderDoc can return a higher version than requested if it's backwards compatible,
|
||||
// this function returns the actual version returned. If a parameter is NULL, it will be
|
||||
// ignored and the others will be filled out.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_GetAPIVersion)(int *major, int *minor, int *patch);
|
||||
|
||||
// Requests that the replay UI show itself (if hidden or not the current top window). This can be
|
||||
// used in conjunction with IsTargetControlConnected and LaunchReplayUI to intelligently handle
|
||||
// showing the UI after making a capture.
|
||||
//
|
||||
// This will return 1 if the request was successfully passed on, though it's not guaranteed that
|
||||
// the UI will be on top in all cases depending on OS rules. It will return 0 if there is no current
|
||||
// target control connection to make such a request, or if there was another error
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_ShowReplayUI)();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Capturing functions
|
||||
//
|
||||
|
||||
// A device pointer is a pointer to the API's root handle.
|
||||
//
|
||||
// This would be an ID3D11Device, HGLRC/GLXContext, ID3D12Device, etc
|
||||
typedef void *RENDERDOC_DevicePointer;
|
||||
|
||||
// A window handle is the OS's native window handle
|
||||
//
|
||||
// This would be an HWND, GLXDrawable, etc
|
||||
typedef void *RENDERDOC_WindowHandle;
|
||||
|
||||
// A helper macro for Vulkan, where the device handle cannot be used directly.
|
||||
//
|
||||
// Passing the VkInstance to this macro will return the RENDERDOC_DevicePointer to use.
|
||||
//
|
||||
// Specifically, the value needed is the dispatch table pointer, which sits as the first
|
||||
// pointer-sized object in the memory pointed to by the VkInstance. Thus we cast to a void** and
|
||||
// indirect once.
|
||||
#define RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(inst) (*((void **)(inst)))
|
||||
|
||||
// This sets the RenderDoc in-app overlay in the API/window pair as 'active' and it will
|
||||
// respond to keypresses. Neither parameter can be NULL
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetActiveWindow)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// capture the next frame on whichever window and API is currently considered active
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_TriggerCapture)();
|
||||
|
||||
// capture the next N frames on whichever window and API is currently considered active
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_TriggerMultiFrameCapture)(uint32_t numFrames);
|
||||
|
||||
// When choosing either a device pointer or a window handle to capture, you can pass NULL.
|
||||
// Passing NULL specifies a 'wildcard' match against anything. This allows you to specify
|
||||
// any API rendering to a specific window, or a specific API instance rendering to any window,
|
||||
// or in the simplest case of one window and one API, you can just pass NULL for both.
|
||||
//
|
||||
// In either case, if there are two or more possible matching (device,window) pairs it
|
||||
// is undefined which one will be captured.
|
||||
//
|
||||
// Note: for headless rendering you can pass NULL for the window handle and either specify
|
||||
// a device pointer or leave it NULL as above.
|
||||
|
||||
// Immediately starts capturing API calls on the specified device pointer and window handle.
|
||||
//
|
||||
// If there is no matching thing to capture (e.g. no supported API has been initialised),
|
||||
// this will do nothing.
|
||||
//
|
||||
// The results are undefined (including crashes) if two captures are started overlapping,
|
||||
// even on separate devices and/oror windows.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_StartFrameCapture)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// Returns whether or not a frame capture is currently ongoing anywhere.
|
||||
//
|
||||
// This will return 1 if a capture is ongoing, and 0 if there is no capture running
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_IsFrameCapturing)();
|
||||
|
||||
// Ends capturing immediately.
|
||||
//
|
||||
// This will return 1 if the capture succeeded, and 0 if there was an error capturing.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_EndFrameCapture)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// Ends capturing immediately and discard any data stored without saving to disk.
|
||||
//
|
||||
// This will return 1 if the capture was discarded, and 0 if there was an error or no capture
|
||||
// was in progress
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_DiscardFrameCapture)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// Only valid to be called between a call to StartFrameCapture and EndFrameCapture. Gives a custom
|
||||
// title to the capture produced which will be displayed in the UI.
|
||||
//
|
||||
// If multiple captures are ongoing, this title will be applied to the first capture to end after
|
||||
// this call. The second capture to end will have no title, unless this function is called again.
|
||||
//
|
||||
// Calling this function has no effect if no capture is currently running, and if it is called
|
||||
// multiple times only the last title will be used.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureTitle)(const char *title);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDoc API versions
|
||||
//
|
||||
|
||||
// RenderDoc uses semantic versioning (http://semver.org/).
|
||||
//
|
||||
// MAJOR version is incremented when incompatible API changes happen.
|
||||
// MINOR version is incremented when functionality is added in a backwards-compatible manner.
|
||||
// PATCH version is incremented when backwards-compatible bug fixes happen.
|
||||
//
|
||||
// Note that this means the API returned can be higher than the one you might have requested.
|
||||
// e.g. if you are running against a newer RenderDoc that supports 1.0.1, it will be returned
|
||||
// instead of 1.0.0. You can check this with the GetAPIVersion entry point
|
||||
typedef enum RENDERDOC_Version
|
||||
{
|
||||
eRENDERDOC_API_Version_1_0_0 = 10000, // RENDERDOC_API_1_0_0 = 1 00 00
|
||||
eRENDERDOC_API_Version_1_0_1 = 10001, // RENDERDOC_API_1_0_1 = 1 00 01
|
||||
eRENDERDOC_API_Version_1_0_2 = 10002, // RENDERDOC_API_1_0_2 = 1 00 02
|
||||
eRENDERDOC_API_Version_1_1_0 = 10100, // RENDERDOC_API_1_1_0 = 1 01 00
|
||||
eRENDERDOC_API_Version_1_1_1 = 10101, // RENDERDOC_API_1_1_1 = 1 01 01
|
||||
eRENDERDOC_API_Version_1_1_2 = 10102, // RENDERDOC_API_1_1_2 = 1 01 02
|
||||
eRENDERDOC_API_Version_1_2_0 = 10200, // RENDERDOC_API_1_2_0 = 1 02 00
|
||||
eRENDERDOC_API_Version_1_3_0 = 10300, // RENDERDOC_API_1_3_0 = 1 03 00
|
||||
eRENDERDOC_API_Version_1_4_0 = 10400, // RENDERDOC_API_1_4_0 = 1 04 00
|
||||
eRENDERDOC_API_Version_1_4_1 = 10401, // RENDERDOC_API_1_4_1 = 1 04 01
|
||||
eRENDERDOC_API_Version_1_4_2 = 10402, // RENDERDOC_API_1_4_2 = 1 04 02
|
||||
eRENDERDOC_API_Version_1_5_0 = 10500, // RENDERDOC_API_1_5_0 = 1 05 00
|
||||
eRENDERDOC_API_Version_1_6_0 = 10600, // RENDERDOC_API_1_6_0 = 1 06 00
|
||||
} RENDERDOC_Version;
|
||||
|
||||
// API version changelog:
|
||||
//
|
||||
// 1.0.0 - initial release
|
||||
// 1.0.1 - Bugfix: IsFrameCapturing() was returning false for captures that were triggered
|
||||
// by keypress or TriggerCapture, instead of Start/EndFrameCapture.
|
||||
// 1.0.2 - Refactor: Renamed eRENDERDOC_Option_DebugDeviceMode to eRENDERDOC_Option_APIValidation
|
||||
// 1.1.0 - Add feature: TriggerMultiFrameCapture(). Backwards compatible with 1.0.x since the new
|
||||
// function pointer is added to the end of the struct, the original layout is identical
|
||||
// 1.1.1 - Refactor: Renamed remote access to target control (to better disambiguate from remote
|
||||
// replay/remote server concept in replay UI)
|
||||
// 1.1.2 - Refactor: Renamed "log file" in function names to just capture, to clarify that these
|
||||
// are captures and not debug logging files. This is the first API version in the v1.0
|
||||
// branch.
|
||||
// 1.2.0 - Added feature: SetCaptureFileComments() to add comments to a capture file that will be
|
||||
// displayed in the UI program on load.
|
||||
// 1.3.0 - Added feature: New capture option eRENDERDOC_Option_AllowUnsupportedVendorExtensions
|
||||
// which allows users to opt-in to allowing unsupported vendor extensions to function.
|
||||
// Should be used at the user's own risk.
|
||||
// Refactor: Renamed eRENDERDOC_Option_VerifyMapWrites to
|
||||
// eRENDERDOC_Option_VerifyBufferAccess, which now also controls initialisation to
|
||||
// 0xdddddddd of uninitialised buffer contents.
|
||||
// 1.4.0 - Added feature: DiscardFrameCapture() to discard a frame capture in progress and stop
|
||||
// capturing without saving anything to disk.
|
||||
// 1.4.1 - Refactor: Renamed Shutdown to RemoveHooks to better clarify what is happening
|
||||
// 1.4.2 - Refactor: Renamed 'draws' to 'actions' in callstack capture option.
|
||||
// 1.5.0 - Added feature: ShowReplayUI() to request that the replay UI show itself if connected
|
||||
// 1.6.0 - Added feature: SetCaptureTitle() which can be used to set a title for a
|
||||
// capture made with StartFrameCapture() or EndFrameCapture()
|
||||
|
||||
typedef struct RENDERDOC_API_1_6_0
|
||||
{
|
||||
pRENDERDOC_GetAPIVersion GetAPIVersion;
|
||||
|
||||
pRENDERDOC_SetCaptureOptionU32 SetCaptureOptionU32;
|
||||
pRENDERDOC_SetCaptureOptionF32 SetCaptureOptionF32;
|
||||
|
||||
pRENDERDOC_GetCaptureOptionU32 GetCaptureOptionU32;
|
||||
pRENDERDOC_GetCaptureOptionF32 GetCaptureOptionF32;
|
||||
|
||||
pRENDERDOC_SetFocusToggleKeys SetFocusToggleKeys;
|
||||
pRENDERDOC_SetCaptureKeys SetCaptureKeys;
|
||||
|
||||
pRENDERDOC_GetOverlayBits GetOverlayBits;
|
||||
pRENDERDOC_MaskOverlayBits MaskOverlayBits;
|
||||
|
||||
// Shutdown was renamed to RemoveHooks in 1.4.1.
|
||||
// These unions allow old code to continue compiling without changes
|
||||
union
|
||||
{
|
||||
pRENDERDOC_Shutdown Shutdown;
|
||||
pRENDERDOC_RemoveHooks RemoveHooks;
|
||||
};
|
||||
pRENDERDOC_UnloadCrashHandler UnloadCrashHandler;
|
||||
|
||||
// Get/SetLogFilePathTemplate was renamed to Get/SetCaptureFilePathTemplate in 1.1.2.
|
||||
// These unions allow old code to continue compiling without changes
|
||||
union
|
||||
{
|
||||
// deprecated name
|
||||
pRENDERDOC_SetLogFilePathTemplate SetLogFilePathTemplate;
|
||||
// current name
|
||||
pRENDERDOC_SetCaptureFilePathTemplate SetCaptureFilePathTemplate;
|
||||
};
|
||||
union
|
||||
{
|
||||
// deprecated name
|
||||
pRENDERDOC_GetLogFilePathTemplate GetLogFilePathTemplate;
|
||||
// current name
|
||||
pRENDERDOC_GetCaptureFilePathTemplate GetCaptureFilePathTemplate;
|
||||
};
|
||||
|
||||
pRENDERDOC_GetNumCaptures GetNumCaptures;
|
||||
pRENDERDOC_GetCapture GetCapture;
|
||||
|
||||
pRENDERDOC_TriggerCapture TriggerCapture;
|
||||
|
||||
// IsRemoteAccessConnected was renamed to IsTargetControlConnected in 1.1.1.
|
||||
// This union allows old code to continue compiling without changes
|
||||
union
|
||||
{
|
||||
// deprecated name
|
||||
pRENDERDOC_IsRemoteAccessConnected IsRemoteAccessConnected;
|
||||
// current name
|
||||
pRENDERDOC_IsTargetControlConnected IsTargetControlConnected;
|
||||
};
|
||||
pRENDERDOC_LaunchReplayUI LaunchReplayUI;
|
||||
|
||||
pRENDERDOC_SetActiveWindow SetActiveWindow;
|
||||
|
||||
pRENDERDOC_StartFrameCapture StartFrameCapture;
|
||||
pRENDERDOC_IsFrameCapturing IsFrameCapturing;
|
||||
pRENDERDOC_EndFrameCapture EndFrameCapture;
|
||||
|
||||
// new function in 1.1.0
|
||||
pRENDERDOC_TriggerMultiFrameCapture TriggerMultiFrameCapture;
|
||||
|
||||
// new function in 1.2.0
|
||||
pRENDERDOC_SetCaptureFileComments SetCaptureFileComments;
|
||||
|
||||
// new function in 1.4.0
|
||||
pRENDERDOC_DiscardFrameCapture DiscardFrameCapture;
|
||||
|
||||
// new function in 1.5.0
|
||||
pRENDERDOC_ShowReplayUI ShowReplayUI;
|
||||
|
||||
// new function in 1.6.0
|
||||
pRENDERDOC_SetCaptureTitle SetCaptureTitle;
|
||||
} RENDERDOC_API_1_6_0;
|
||||
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_0_0;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_0_1;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_0_2;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_1_0;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_1_1;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_1_2;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_2_0;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_3_0;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_4_0;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_4_1;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_4_2;
|
||||
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_5_0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDoc API entry point
|
||||
//
|
||||
// This entry point can be obtained via GetProcAddress/dlsym if RenderDoc is available.
|
||||
//
|
||||
// The name is the same as the typedef - "RENDERDOC_GetAPI"
|
||||
//
|
||||
// This function is not thread safe, and should not be called on multiple threads at once.
|
||||
// Ideally, call this once as early as possible in your application's startup, before doing
|
||||
// any API work, since some configuration functionality etc has to be done also before
|
||||
// initialising any APIs.
|
||||
//
|
||||
// Parameters:
|
||||
// version is a single value from the RENDERDOC_Version above.
|
||||
//
|
||||
// outAPIPointers will be filled out with a pointer to the corresponding struct of function
|
||||
// pointers.
|
||||
//
|
||||
// Returns:
|
||||
// 1 - if the outAPIPointers has been filled with a pointer to the API struct requested
|
||||
// 0 - if the requested version is not supported or the arguments are invalid.
|
||||
//
|
||||
typedef int(RENDERDOC_CC *pRENDERDOC_GetAPI)(RENDERDOC_Version version, void **outAPIPointers);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
Vendored
+7987
File diff suppressed because it is too large
Load Diff
Vendored
+2634
File diff suppressed because it is too large
Load Diff
Vendored
+1724
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
Submodule externals/vcpkg updated: cbf56573a9...ef2eef1734
+3
-3
@@ -21,7 +21,7 @@ if (MSVC)
|
||||
# Avoid windows.h from including some usually unused libs like winsocks.h, since this might cause some redefinition errors.
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
|
||||
# Ensure that projects build with Unicode support.
|
||||
# Ensure that projects are built with Unicode support.
|
||||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
|
||||
# /W4 - Level 4 warnings
|
||||
@@ -54,11 +54,11 @@ if (MSVC)
|
||||
/GT
|
||||
|
||||
# Modules
|
||||
/experimental:module- # Disable module support explicitly due to conflicts with precompiled headers
|
||||
/experimental:module- # Explicitly disable module support due to conflicts with precompiled headers.
|
||||
|
||||
# External headers diagnostics
|
||||
/external:anglebrackets # Treats all headers included by #include <header>, where the header file is enclosed in angle brackets (< >), as external headers
|
||||
/external:W0 # Sets the default warning level to 0 for external headers, effectively turning off warnings for external headers
|
||||
/external:W0 # Sets the default warning level to 0 for external headers, effectively disabling warnings for them.
|
||||
|
||||
# Warnings
|
||||
/W4
|
||||
|
||||
@@ -63,3 +63,6 @@ fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
# Autogenerated library for vulkan validation layers
|
||||
libVkLayer_khronos_validation.so
|
||||
|
||||
@@ -27,7 +27,7 @@ android {
|
||||
namespace = "org.yuzu.yuzu_emu"
|
||||
|
||||
compileSdkVersion = "android-34"
|
||||
ndkVersion = "25.2.9519653"
|
||||
ndkVersion = "26.1.10909125"
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
@@ -47,6 +47,10 @@ android {
|
||||
jniLibs.useLegacyPackaging = true
|
||||
}
|
||||
|
||||
androidResources {
|
||||
generateLocaleConfig = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO If this is ever modified, change application_id in strings.xml
|
||||
applicationId = "org.yuzu.yuzu_emu"
|
||||
@@ -77,13 +81,30 @@ android {
|
||||
buildConfigField("String", "BRANCH", "\"${getBranch()}\"")
|
||||
}
|
||||
|
||||
val keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE")
|
||||
if (keystoreFile != null) {
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
storeFile = file(keystoreFile)
|
||||
storePassword = System.getenv("ANDROID_KEYSTORE_PASS")
|
||||
keyAlias = System.getenv("ANDROID_KEY_ALIAS")
|
||||
keyPassword = System.getenv("ANDROID_KEYSTORE_PASS")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define build types, which are orthogonal to product flavors.
|
||||
buildTypes {
|
||||
|
||||
// Signed by release key, allowing for upload to Play Store.
|
||||
release {
|
||||
signingConfig = if (keystoreFile != null) {
|
||||
signingConfigs.getByName("release")
|
||||
} else {
|
||||
signingConfigs.getByName("debug")
|
||||
}
|
||||
|
||||
resValue("string", "app_name_suffixed", "yuzu")
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
isMinifyEnabled = true
|
||||
isDebuggable = false
|
||||
proguardFiles(
|
||||
@@ -186,23 +207,23 @@ ktlint {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.core:core-ktx:1.10.1")
|
||||
implementation("androidx.core:core-ktx:1.12.0")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("androidx.recyclerview:recyclerview:1.3.0")
|
||||
implementation("androidx.recyclerview:recyclerview:1.3.1")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation("androidx.fragment:fragment-ktx:1.6.0")
|
||||
implementation("androidx.fragment:fragment-ktx:1.6.1")
|
||||
implementation("androidx.documentfile:documentfile:1.0.1")
|
||||
implementation("com.google.android.material:material:1.9.0")
|
||||
implementation("androidx.preference:preference:1.2.0")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
|
||||
implementation("androidx.preference:preference-ktx:1.2.1")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
|
||||
implementation("io.coil-kt:coil:2.2.2")
|
||||
implementation("androidx.core:core-splashscreen:1.0.1")
|
||||
implementation("androidx.window:window:1.1.0")
|
||||
implementation("androidx.window:window:1.2.0-beta03")
|
||||
implementation("org.ini4j:ini4j:0.5.4")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:2.6.0")
|
||||
implementation("androidx.navigation:navigation-ui-ktx:2.6.0")
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
|
||||
implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
|
||||
implementation("info.debatty:java-string-similarity:2.0.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||
}
|
||||
|
||||
@@ -26,9 +26,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
android:supportsRtl="true"
|
||||
android:isGame="true"
|
||||
android:appCategory="game"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:banner="@drawable/tv_banner"
|
||||
android:extractNativeLibs="true"
|
||||
android:fullBackupContent="@xml/data_extraction_rules"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules_api_31"
|
||||
android:enableOnBackInvokedCallback="true">
|
||||
|
||||
@@ -5,6 +5,7 @@ package org.yuzu.yuzu_emu
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.text.method.LinkMovementMethod
|
||||
@@ -15,13 +16,9 @@ import androidx.annotation.Keep
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import java.lang.ref.WeakReference
|
||||
import org.yuzu.yuzu_emu.YuzuApplication.Companion.appContext
|
||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import org.yuzu.yuzu_emu.utils.DocumentsTree.Companion.isNativePath
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil.exists
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil.getFileSize
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil.isDirectory
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil.openContentUri
|
||||
import org.yuzu.yuzu_emu.utils.DocumentsTree
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
|
||||
|
||||
@@ -72,43 +69,61 @@ object NativeLibrary {
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun openContentUri(path: String?, openmode: String?): Int {
|
||||
return if (isNativePath(path!!)) {
|
||||
return if (DocumentsTree.isNativePath(path!!)) {
|
||||
YuzuApplication.documentsTree!!.openContentUri(path, openmode)
|
||||
} else {
|
||||
openContentUri(appContext, path, openmode)
|
||||
FileUtil.openContentUri(path, openmode)
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun getSize(path: String?): Long {
|
||||
return if (isNativePath(path!!)) {
|
||||
return if (DocumentsTree.isNativePath(path!!)) {
|
||||
YuzuApplication.documentsTree!!.getFileSize(path)
|
||||
} else {
|
||||
getFileSize(appContext, path)
|
||||
FileUtil.getFileSize(path)
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun exists(path: String?): Boolean {
|
||||
return if (isNativePath(path!!)) {
|
||||
return if (DocumentsTree.isNativePath(path!!)) {
|
||||
YuzuApplication.documentsTree!!.exists(path)
|
||||
} else {
|
||||
exists(appContext, path)
|
||||
FileUtil.exists(path, suppressLog = true)
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun isDirectory(path: String?): Boolean {
|
||||
return if (isNativePath(path!!)) {
|
||||
return if (DocumentsTree.isNativePath(path!!)) {
|
||||
YuzuApplication.documentsTree!!.isDirectory(path)
|
||||
} else {
|
||||
isDirectory(appContext, path)
|
||||
FileUtil.isDirectory(path)
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun getParentDirectory(path: String): String =
|
||||
if (DocumentsTree.isNativePath(path)) {
|
||||
YuzuApplication.documentsTree!!.getParentDirectory(path)
|
||||
} else {
|
||||
path
|
||||
}
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun getFilename(path: String): String =
|
||||
if (DocumentsTree.isNativePath(path)) {
|
||||
YuzuApplication.documentsTree!!.getFilename(path)
|
||||
} else {
|
||||
FileUtil.getFilename(Uri.parse(path))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if pro controller isn't available and handheld is
|
||||
*/
|
||||
@@ -219,35 +234,14 @@ object NativeLibrary {
|
||||
|
||||
external fun initGameIni(gameID: String?)
|
||||
|
||||
/**
|
||||
* Gets the embedded icon within the given ROM.
|
||||
*
|
||||
* @param filename the file path to the ROM.
|
||||
* @return a byte array containing the JPEG data for the icon.
|
||||
*/
|
||||
external fun getIcon(filename: String): ByteArray
|
||||
|
||||
/**
|
||||
* Gets the embedded title of the given ISO/ROM.
|
||||
*
|
||||
* @param filename The file path to the ISO/ROM.
|
||||
* @return the embedded title of the ISO/ROM.
|
||||
*/
|
||||
external fun getTitle(filename: String): String
|
||||
|
||||
external fun getDescription(filename: String): String
|
||||
|
||||
external fun getGameId(filename: String): String
|
||||
|
||||
external fun getRegions(filename: String): String
|
||||
|
||||
external fun getCompany(filename: String): String
|
||||
|
||||
external fun isHomebrew(filename: String): Boolean
|
||||
|
||||
external fun setAppDirectory(directory: String)
|
||||
|
||||
external fun installFileToNand(filename: String): Int
|
||||
/**
|
||||
* Installs a nsp or xci file to nand
|
||||
* @param filename String representation of file uri
|
||||
* @param extension Lowercase string representation of file extension without "."
|
||||
*/
|
||||
external fun installFileToNand(filename: String, extension: String): Int
|
||||
|
||||
external fun initializeGpuDriver(
|
||||
hookLibDir: String?,
|
||||
@@ -258,7 +252,7 @@ object NativeLibrary {
|
||||
|
||||
external fun reloadKeys(): Boolean
|
||||
|
||||
external fun initializeEmulation()
|
||||
external fun initializeSystem(reload: Boolean)
|
||||
|
||||
external fun defaultCPUCore(): Int
|
||||
|
||||
@@ -292,11 +286,6 @@ object NativeLibrary {
|
||||
*/
|
||||
external fun stopEmulation()
|
||||
|
||||
/**
|
||||
* Resets the in-memory ROM metadata cache.
|
||||
*/
|
||||
external fun resetRomMetadata()
|
||||
|
||||
/**
|
||||
* Returns true if emulation is running (or is paused).
|
||||
*/
|
||||
@@ -307,21 +296,6 @@ object NativeLibrary {
|
||||
*/
|
||||
external fun isPaused(): Boolean
|
||||
|
||||
/**
|
||||
* Mutes emulation sound
|
||||
*/
|
||||
external fun muteAudio(): Boolean
|
||||
|
||||
/**
|
||||
* Unmutes emulation sound
|
||||
*/
|
||||
external fun unmuteAudio(): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if emulation audio is muted.
|
||||
*/
|
||||
external fun isMuted(): Boolean
|
||||
|
||||
/**
|
||||
* Returns the performance stats for the current game
|
||||
*/
|
||||
@@ -488,12 +462,12 @@ object NativeLibrary {
|
||||
}
|
||||
|
||||
fun setEmulationActivity(emulationActivity: EmulationActivity?) {
|
||||
Log.verbose("[NativeLibrary] Registering EmulationActivity.")
|
||||
Log.debug("[NativeLibrary] Registering EmulationActivity.")
|
||||
sEmulationActivity = WeakReference(emulationActivity)
|
||||
}
|
||||
|
||||
fun clearEmulationActivity() {
|
||||
Log.verbose("[NativeLibrary] Unregistering EmulationActivity.")
|
||||
Log.debug("[NativeLibrary] Unregistering EmulationActivity.")
|
||||
sEmulationActivity.clear()
|
||||
}
|
||||
|
||||
@@ -526,6 +500,41 @@ object NativeLibrary {
|
||||
*/
|
||||
external fun submitInlineKeyboardInput(key_code: Int)
|
||||
|
||||
/**
|
||||
* Creates a generic user directory if it doesn't exist already
|
||||
*/
|
||||
external fun initializeEmptyUserDirectory()
|
||||
|
||||
/**
|
||||
* Gets the launch path for a given applet. It is the caller's responsibility to also
|
||||
* set the system's current applet ID before trying to launch the nca given by this function.
|
||||
*
|
||||
* @param id The applet entry ID
|
||||
* @return The applet's launch path
|
||||
*/
|
||||
external fun getAppletLaunchPath(id: Long): String
|
||||
|
||||
/**
|
||||
* Sets the system's current applet ID before launching.
|
||||
*
|
||||
* @param appletId One of the ids in the Service::AM::Applets::AppletId enum
|
||||
*/
|
||||
external fun setCurrentAppletId(appletId: Int)
|
||||
|
||||
/**
|
||||
* Sets the cabinet mode for launching the cabinet applet.
|
||||
*
|
||||
* @param cabinetMode One of the modes that corresponds to the enum in Service::NFP::CabinetMode
|
||||
*/
|
||||
external fun setCabinetMode(cabinetMode: Int)
|
||||
|
||||
/**
|
||||
* Checks whether NAND contents are available and valid.
|
||||
*
|
||||
* @return 'true' if firmware is available
|
||||
*/
|
||||
external fun isFirmwareAvailable(): Boolean
|
||||
|
||||
/**
|
||||
* Button type for use in onTouchEvent
|
||||
*/
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.io.File
|
||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||
import org.yuzu.yuzu_emu.utils.DocumentsTree
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
|
||||
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
|
||||
|
||||
@@ -47,8 +48,9 @@ class YuzuApplication : Application() {
|
||||
application = this
|
||||
documentsTree = DocumentsTree()
|
||||
DirectoryInitialization.start()
|
||||
GpuDriverHelper.initializeDriverParameters(applicationContext)
|
||||
GpuDriverHelper.initializeDriverParameters()
|
||||
NativeLibrary.logDeviceInfo()
|
||||
Log.logDeviceInfo()
|
||||
|
||||
createNotificationChannels()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.activities
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.app.PictureInPictureParams
|
||||
@@ -44,9 +45,9 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
import org.yuzu.yuzu_emu.model.EmulationViewModel
|
||||
import org.yuzu.yuzu_emu.model.Game
|
||||
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
|
||||
import org.yuzu.yuzu_emu.utils.ForegroundService
|
||||
import org.yuzu.yuzu_emu.utils.InputHandler
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
import org.yuzu.yuzu_emu.utils.MemoryUtil
|
||||
import org.yuzu.yuzu_emu.utils.NfcReader
|
||||
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
||||
@@ -56,17 +57,16 @@ import kotlin.math.roundToInt
|
||||
class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
private lateinit var binding: ActivityEmulationBinding
|
||||
|
||||
private var controllerMappingHelper: ControllerMappingHelper? = null
|
||||
|
||||
var isActivityRecreated = false
|
||||
private lateinit var nfcReader: NfcReader
|
||||
private lateinit var inputHandler: InputHandler
|
||||
|
||||
private val gyro = FloatArray(3)
|
||||
private val accel = FloatArray(3)
|
||||
private var motionTimestamp: Long = 0
|
||||
private var flipMotionOrientation: Boolean = false
|
||||
|
||||
private var controllerIds = InputHandler.getGameControllerIds()
|
||||
|
||||
private val actionPause = "ACTION_EMULATOR_PAUSE"
|
||||
private val actionPlay = "ACTION_EMULATOR_PLAY"
|
||||
private val actionMute = "ACTION_EMULATOR_MUTE"
|
||||
@@ -81,6 +81,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
Log.gameLaunched = true
|
||||
ThemeHelper.setTheme(this)
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -94,8 +95,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
|
||||
isActivityRecreated = savedInstanceState != null
|
||||
|
||||
controllerMappingHelper = ControllerMappingHelper()
|
||||
|
||||
// Set these options now so that the SurfaceView the game renders into is the right size.
|
||||
enableFullscreenImmersive()
|
||||
|
||||
@@ -104,12 +103,11 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
nfcReader = NfcReader(this)
|
||||
nfcReader.initialize()
|
||||
|
||||
inputHandler = InputHandler()
|
||||
inputHandler.initialize()
|
||||
InputHandler.initialize()
|
||||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||
if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) {
|
||||
if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.Gb)) {
|
||||
if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.totalMemory)) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
getString(
|
||||
@@ -161,6 +159,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
super.onResume()
|
||||
nfcReader.startScanning()
|
||||
startMotionSensorListener()
|
||||
InputHandler.updateControllerIds()
|
||||
|
||||
buildPictureInPictureParams()
|
||||
}
|
||||
@@ -194,7 +193,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
return inputHandler.dispatchKeyEvent(event)
|
||||
return InputHandler.dispatchKeyEvent(event)
|
||||
}
|
||||
|
||||
override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean {
|
||||
@@ -209,7 +208,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
return true
|
||||
}
|
||||
|
||||
return inputHandler.dispatchGenericMotionEvent(event)
|
||||
return InputHandler.dispatchGenericMotionEvent(event)
|
||||
}
|
||||
|
||||
override fun onSensorChanged(event: SensorEvent) {
|
||||
@@ -332,7 +331,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
pictureInPictureActions.add(pauseRemoteAction)
|
||||
}
|
||||
|
||||
if (NativeLibrary.isMuted()) {
|
||||
if (BooleanSetting.AUDIO_MUTED.boolean) {
|
||||
val unmuteIcon = Icon.createWithResource(
|
||||
this@EmulationActivity,
|
||||
R.drawable.ic_pip_unmute
|
||||
@@ -374,8 +373,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
|
||||
.getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val isEmulationActive = emulationViewModel.emulationStarted.value &&
|
||||
!emulationViewModel.isEmulationStopping.value
|
||||
pictureInPictureParamsBuilder.setAutoEnterEnabled(
|
||||
BooleanSetting.PICTURE_IN_PICTURE.boolean
|
||||
BooleanSetting.PICTURE_IN_PICTURE.boolean && isEmulationActive
|
||||
)
|
||||
}
|
||||
setPictureInPictureParams(pictureInPictureParamsBuilder.build())
|
||||
@@ -389,14 +390,15 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation()
|
||||
}
|
||||
if (intent.action == actionUnmute) {
|
||||
if (NativeLibrary.isMuted()) NativeLibrary.unmuteAudio()
|
||||
if (BooleanSetting.AUDIO_MUTED.boolean) BooleanSetting.AUDIO_MUTED.setBoolean(false)
|
||||
} else if (intent.action == actionMute) {
|
||||
if (!NativeLibrary.isMuted()) NativeLibrary.muteAudio()
|
||||
if (!BooleanSetting.AUDIO_MUTED.boolean) BooleanSetting.AUDIO_MUTED.setBoolean(true)
|
||||
}
|
||||
buildPictureInPictureParams()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||
override fun onPictureInPictureModeChanged(
|
||||
isInPictureInPictureMode: Boolean,
|
||||
newConfig: Configuration
|
||||
@@ -409,7 +411,11 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
addAction(actionMute)
|
||||
addAction(actionUnmute)
|
||||
}.also {
|
||||
registerReceiver(pictureInPictureReceiver, it)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(pictureInPictureReceiver, it, RECEIVER_EXPORTED)
|
||||
} else {
|
||||
registerReceiver(pictureInPictureReceiver, it)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@@ -417,7 +423,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
// Always resume audio, since there is no UI button
|
||||
if (NativeLibrary.isMuted()) NativeLibrary.unmuteAudio()
|
||||
if (BooleanSetting.AUDIO_MUTED.boolean) BooleanSetting.AUDIO_MUTED.setBoolean(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.databinding.CardAppletOptionBinding
|
||||
import org.yuzu.yuzu_emu.model.Applet
|
||||
import org.yuzu.yuzu_emu.model.AppletInfo
|
||||
import org.yuzu.yuzu_emu.model.Game
|
||||
|
||||
class AppletAdapter(val activity: FragmentActivity, var applets: List<Applet>) :
|
||||
RecyclerView.Adapter<AppletAdapter.AppletViewHolder>(),
|
||||
View.OnClickListener {
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): AppletAdapter.AppletViewHolder {
|
||||
CardAppletOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
.apply { root.setOnClickListener(this@AppletAdapter) }
|
||||
.also { return AppletViewHolder(it) }
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AppletViewHolder, position: Int) =
|
||||
holder.bind(applets[position])
|
||||
|
||||
override fun getItemCount(): Int = applets.size
|
||||
|
||||
override fun onClick(view: View) {
|
||||
val applet = (view.tag as AppletViewHolder).applet
|
||||
val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId)
|
||||
if (appletPath.isEmpty()) {
|
||||
Toast.makeText(
|
||||
YuzuApplication.appContext,
|
||||
R.string.applets_error_applet,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
return
|
||||
}
|
||||
|
||||
if (applet.appletInfo == AppletInfo.Cabinet) {
|
||||
view.findNavController()
|
||||
.navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment)
|
||||
return
|
||||
}
|
||||
|
||||
NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId)
|
||||
val appletGame = Game(
|
||||
title = YuzuApplication.appContext.getString(applet.titleId),
|
||||
path = appletPath
|
||||
)
|
||||
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
|
||||
view.findNavController().navigate(action)
|
||||
}
|
||||
|
||||
inner class AppletViewHolder(val binding: CardAppletOptionBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
lateinit var applet: Applet
|
||||
|
||||
init {
|
||||
itemView.tag = this
|
||||
}
|
||||
|
||||
fun bind(applet: Applet) {
|
||||
this.applet = applet
|
||||
|
||||
binding.title.setText(applet.titleId)
|
||||
binding.description.setText(applet.descriptionId)
|
||||
binding.icon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
binding.icon.context.resources,
|
||||
applet.iconId,
|
||||
binding.icon.context.theme
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.databinding.DialogListItemBinding
|
||||
import org.yuzu.yuzu_emu.model.CabinetMode
|
||||
import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder
|
||||
import org.yuzu.yuzu_emu.model.AppletInfo
|
||||
import org.yuzu.yuzu_emu.model.Game
|
||||
|
||||
class CabinetLauncherDialogAdapter(val fragment: Fragment) :
|
||||
RecyclerView.Adapter<CabinetModeViewHolder>(),
|
||||
View.OnClickListener {
|
||||
private val cabinetModes = CabinetMode.values().copyOfRange(1, CabinetMode.values().size)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder {
|
||||
DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
.apply { root.setOnClickListener(this@CabinetLauncherDialogAdapter) }
|
||||
.also { return CabinetModeViewHolder(it) }
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = cabinetModes.size
|
||||
|
||||
override fun onBindViewHolder(holder: CabinetModeViewHolder, position: Int) =
|
||||
holder.bind(cabinetModes[position])
|
||||
|
||||
override fun onClick(view: View) {
|
||||
val mode = (view.tag as CabinetModeViewHolder).cabinetMode
|
||||
val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId)
|
||||
NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId)
|
||||
NativeLibrary.setCabinetMode(mode.id)
|
||||
val appletGame = Game(
|
||||
title = YuzuApplication.appContext.getString(R.string.cabinet_applet),
|
||||
path = appletPath
|
||||
)
|
||||
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
|
||||
fragment.findNavController().navigate(action)
|
||||
}
|
||||
|
||||
inner class CabinetModeViewHolder(val binding: DialogListItemBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
lateinit var cabinetMode: CabinetMode
|
||||
|
||||
init {
|
||||
itemView.tag = this
|
||||
}
|
||||
|
||||
fun bind(cabinetMode: CabinetMode) {
|
||||
this.cabinetMode = cabinetMode
|
||||
binding.icon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
binding.icon.context.resources,
|
||||
cabinetMode.iconId,
|
||||
binding.icon.context.theme
|
||||
)
|
||||
)
|
||||
binding.title.setText(cabinetMode.titleId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.adapters
|
||||
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding
|
||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
|
||||
|
||||
class DriverAdapter(private val driverViewModel: DriverViewModel) :
|
||||
ListAdapter<Pair<String, GpuDriverMetadata>, DriverAdapter.DriverViewHolder>(
|
||||
AsyncDifferConfig.Builder(DiffCallback()).build()
|
||||
) {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder {
|
||||
val binding =
|
||||
CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return DriverViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = currentList.size
|
||||
|
||||
override fun onBindViewHolder(holder: DriverViewHolder, position: Int) =
|
||||
holder.bind(currentList[position])
|
||||
|
||||
private fun onSelectDriver(position: Int) {
|
||||
driverViewModel.setSelectedDriverIndex(position)
|
||||
notifyItemChanged(driverViewModel.previouslySelectedDriver)
|
||||
notifyItemChanged(driverViewModel.selectedDriver)
|
||||
}
|
||||
|
||||
private fun onDeleteDriver(driverData: Pair<String, GpuDriverMetadata>, position: Int) {
|
||||
if (driverViewModel.selectedDriver > position) {
|
||||
driverViewModel.setSelectedDriverIndex(driverViewModel.selectedDriver - 1)
|
||||
}
|
||||
if (GpuDriverHelper.customDriverData == driverData.second) {
|
||||
driverViewModel.setSelectedDriverIndex(0)
|
||||
}
|
||||
driverViewModel.driversToDelete.add(driverData.first)
|
||||
driverViewModel.removeDriver(driverData)
|
||||
notifyItemRemoved(position)
|
||||
notifyItemChanged(driverViewModel.selectedDriver)
|
||||
}
|
||||
|
||||
inner class DriverViewHolder(val binding: CardDriverOptionBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
private lateinit var driverData: Pair<String, GpuDriverMetadata>
|
||||
|
||||
fun bind(driverData: Pair<String, GpuDriverMetadata>) {
|
||||
this.driverData = driverData
|
||||
val driver = driverData.second
|
||||
|
||||
binding.apply {
|
||||
radioButton.isChecked = driverViewModel.selectedDriver == bindingAdapterPosition
|
||||
root.setOnClickListener {
|
||||
onSelectDriver(bindingAdapterPosition)
|
||||
}
|
||||
buttonDelete.setOnClickListener {
|
||||
onDeleteDriver(driverData, bindingAdapterPosition)
|
||||
}
|
||||
|
||||
// Delay marquee by 3s
|
||||
title.postDelayed(
|
||||
{
|
||||
title.isSelected = true
|
||||
title.ellipsize = TextUtils.TruncateAt.MARQUEE
|
||||
version.isSelected = true
|
||||
version.ellipsize = TextUtils.TruncateAt.MARQUEE
|
||||
description.isSelected = true
|
||||
description.ellipsize = TextUtils.TruncateAt.MARQUEE
|
||||
},
|
||||
3000
|
||||
)
|
||||
if (driver.name == null) {
|
||||
title.setText(R.string.system_gpu_driver)
|
||||
description.text = ""
|
||||
version.text = ""
|
||||
version.visibility = View.GONE
|
||||
description.visibility = View.GONE
|
||||
buttonDelete.visibility = View.GONE
|
||||
} else {
|
||||
title.text = driver.name
|
||||
version.text = driver.version
|
||||
description.text = driver.description
|
||||
version.visibility = View.VISIBLE
|
||||
description.visibility = View.VISIBLE
|
||||
buttonDelete.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DiffCallback : DiffUtil.ItemCallback<Pair<String, GpuDriverMetadata>>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: Pair<String, GpuDriverMetadata>,
|
||||
newItem: Pair<String, GpuDriverMetadata>
|
||||
): Boolean {
|
||||
return oldItem.first == newItem.first
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: Pair<String, GpuDriverMetadata>,
|
||||
newItem: Pair<String, GpuDriverMetadata>
|
||||
): Boolean {
|
||||
return oldItem.second == newItem.second
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@
|
||||
package org.yuzu.yuzu_emu.adapters
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
@@ -15,15 +16,22 @@ import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.pm.ShortcutInfoCompat
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
@@ -87,16 +95,35 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
||||
action = Intent.ACTION_VIEW
|
||||
data = Uri.parse(holder.game.path)
|
||||
}
|
||||
val shortcut = ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path)
|
||||
.setShortLabel(holder.game.title)
|
||||
.setIcon(
|
||||
IconCompat.createWithBitmap(
|
||||
(holder.binding.imageGameScreen.drawable as BitmapDrawable).bitmap
|
||||
|
||||
activity.lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val layerDrawable = ResourcesCompat.getDrawable(
|
||||
YuzuApplication.appContext.resources,
|
||||
R.drawable.shortcut,
|
||||
null
|
||||
) as LayerDrawable
|
||||
layerDrawable.setDrawableByLayerId(
|
||||
R.id.shortcut_foreground,
|
||||
GameIconUtils.getGameIcon(activity, holder.game)
|
||||
.toDrawable(YuzuApplication.appContext.resources)
|
||||
)
|
||||
)
|
||||
.setIntent(openIntent)
|
||||
.build()
|
||||
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
|
||||
val inset = YuzuApplication.appContext.resources
|
||||
.getDimensionPixelSize(R.dimen.icon_inset)
|
||||
layerDrawable.setLayerInset(1, inset, inset, inset, inset)
|
||||
val shortcut =
|
||||
ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path)
|
||||
.setShortLabel(holder.game.title)
|
||||
.setIcon(
|
||||
IconCompat.createWithAdaptiveBitmap(
|
||||
layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
|
||||
)
|
||||
)
|
||||
.setIntent(openIntent)
|
||||
.build()
|
||||
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
|
||||
}
|
||||
}
|
||||
|
||||
val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game)
|
||||
view.findNavController().navigate(action)
|
||||
@@ -130,7 +157,7 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
||||
|
||||
private class DiffCallback : DiffUtil.ItemCallback<Game>() {
|
||||
override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||
return oldItem.gameId == newItem.gameId
|
||||
return oldItem.programId == newItem.programId
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||
|
||||
@@ -49,6 +49,7 @@ class HomeSettingAdapter(
|
||||
holder.option.onClick.invoke()
|
||||
} else {
|
||||
MessageDialogFragment.newInstance(
|
||||
activity,
|
||||
titleId = holder.option.disabledTitleId,
|
||||
descriptionId = holder.option.disabledMessageId
|
||||
).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.yuzu.yuzu_emu.databinding.CardInstallableBinding
|
||||
import org.yuzu.yuzu_emu.model.Installable
|
||||
|
||||
class InstallableAdapter(private val installables: List<Installable>) :
|
||||
RecyclerView.Adapter<InstallableAdapter.InstallableViewHolder>() {
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): InstallableAdapter.InstallableViewHolder {
|
||||
val binding =
|
||||
CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return InstallableViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = installables.size
|
||||
|
||||
override fun onBindViewHolder(holder: InstallableAdapter.InstallableViewHolder, position: Int) =
|
||||
holder.bind(installables[position])
|
||||
|
||||
inner class InstallableViewHolder(val binding: CardInstallableBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
lateinit var installable: Installable
|
||||
|
||||
fun bind(installable: Installable) {
|
||||
this.installable = installable
|
||||
|
||||
binding.title.setText(installable.titleId)
|
||||
binding.description.setText(installable.descriptionId)
|
||||
|
||||
if (installable.install != null) {
|
||||
binding.buttonInstall.visibility = View.VISIBLE
|
||||
binding.buttonInstall.setOnClickListener { installable.install.invoke() }
|
||||
}
|
||||
if (installable.export != null) {
|
||||
binding.buttonExport.visibility = View.VISIBLE
|
||||
binding.buttonExport.setOnClickListener { installable.export.invoke() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -10,6 +10,7 @@ enum class BooleanSetting(
|
||||
override val category: Settings.Category,
|
||||
override val androidDefault: Boolean? = null
|
||||
) : AbstractBooleanSetting {
|
||||
AUDIO_MUTED("audio_muted", Settings.Category.Audio),
|
||||
CPU_DEBUG_MODE("cpu_debug_mode", Settings.Category.Cpu),
|
||||
FASTMEM("cpuopt_fastmem", Settings.Category.Cpu),
|
||||
FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives", Settings.Category.Cpu),
|
||||
|
||||
@@ -82,7 +82,6 @@ object Settings {
|
||||
|
||||
enum class MenuTag(val titleId: Int) {
|
||||
SECTION_ROOT(R.string.advanced_settings),
|
||||
SECTION_GENERAL(R.string.preferences_general),
|
||||
SECTION_SYSTEM(R.string.preferences_system),
|
||||
SECTION_RENDERER(R.string.preferences_graphics),
|
||||
SECTION_AUDIO(R.string.preferences_audio),
|
||||
|
||||
+3
@@ -3,10 +3,13 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
|
||||
class RunnableSetting(
|
||||
titleId: Int,
|
||||
descriptionId: Int,
|
||||
val isRuntimeRunnable: Boolean,
|
||||
@DrawableRes val iconId: Int = 0,
|
||||
val runnable: () -> Unit
|
||||
) : SettingsItem(emptySetting, titleId, descriptionId) {
|
||||
override val type = TYPE_RUNNABLE
|
||||
|
||||
+5
-2
@@ -3,11 +3,14 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
|
||||
class SubmenuSetting(
|
||||
titleId: Int,
|
||||
descriptionId: Int,
|
||||
@StringRes titleId: Int,
|
||||
@StringRes descriptionId: Int,
|
||||
@DrawableRes val iconId: Int,
|
||||
val menuKey: Settings.MenuTag
|
||||
) : SettingsItem(emptySetting, titleId, descriptionId) {
|
||||
override val type = TYPE_SUBMENU
|
||||
|
||||
+8
-5
@@ -21,6 +21,7 @@ import androidx.navigation.navArgs
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import java.io.IOException
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding
|
||||
@@ -168,7 +169,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||
if (!settingsFile.delete()) {
|
||||
throw IOException("Failed to delete $settingsFile")
|
||||
}
|
||||
Settings.settingsList.forEach { it.reset() }
|
||||
NativeLibrary.reloadSettings()
|
||||
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
@@ -181,12 +182,14 @@ class SettingsActivity : AppCompatActivity() {
|
||||
private fun setInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
binding.navigationBarShade
|
||||
) { view: View, windowInsets: WindowInsetsCompat ->
|
||||
) { _: View, windowInsets: WindowInsetsCompat ->
|
||||
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
|
||||
val mlpShade = view.layoutParams as MarginLayoutParams
|
||||
mlpShade.height = barInsets.bottom
|
||||
view.layoutParams = mlpShade
|
||||
// The only situation where we care to have a nav bar shade is when it's at the bottom
|
||||
// of the screen where scrolling list elements can go behind it.
|
||||
val mlpNavShade = binding.navigationBarShade.layoutParams as MarginLayoutParams
|
||||
mlpNavShade.height = barInsets.bottom
|
||||
binding.navigationBarShade.layoutParams = mlpNavShade
|
||||
|
||||
windowInsets
|
||||
}
|
||||
|
||||
+2
-28
@@ -20,7 +20,6 @@ import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.divider.MaterialDividerItemDecoration
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -68,15 +67,9 @@ class SettingsFragment : Fragment() {
|
||||
)
|
||||
|
||||
binding.toolbarSettingsLayout.title = getString(args.menuTag.titleId)
|
||||
val dividerDecoration = MaterialDividerItemDecoration(
|
||||
requireContext(),
|
||||
LinearLayoutManager.VERTICAL
|
||||
)
|
||||
dividerDecoration.isLastItemDecorated = false
|
||||
binding.listSettings.apply {
|
||||
adapter = settingsAdapter
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
addItemDecoration(dividerDecoration)
|
||||
}
|
||||
|
||||
binding.toolbarSettings.setNavigationOnClickListener {
|
||||
@@ -94,17 +87,6 @@ class SettingsFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
settingsViewModel.isUsingSearch.collectLatest {
|
||||
if (it) {
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
|
||||
} else {
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (args.menuTag == Settings.MenuTag.SECTION_ROOT) {
|
||||
@@ -112,8 +94,6 @@ class SettingsFragment : Fragment() {
|
||||
binding.toolbarSettings.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_search -> {
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
|
||||
view.findNavController()
|
||||
.navigate(R.id.action_settingsFragment_to_settingsSearchFragment)
|
||||
true
|
||||
@@ -129,11 +109,6 @@ class SettingsFragment : Fragment() {
|
||||
setInsets()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
settingsViewModel.setIsUsingSearch(false)
|
||||
}
|
||||
|
||||
private fun setInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
binding.root
|
||||
@@ -144,10 +119,9 @@ class SettingsFragment : Fragment() {
|
||||
val leftInsets = barInsets.left + cutoutInsets.left
|
||||
val rightInsets = barInsets.right + cutoutInsets.right
|
||||
|
||||
val sideMargin = resources.getDimensionPixelSize(R.dimen.spacing_medlarge)
|
||||
val mlpSettingsList = binding.listSettings.layoutParams as MarginLayoutParams
|
||||
mlpSettingsList.leftMargin = sideMargin + leftInsets
|
||||
mlpSettingsList.rightMargin = sideMargin + rightInsets
|
||||
mlpSettingsList.leftMargin = leftInsets
|
||||
mlpSettingsList.rightMargin = rightInsets
|
||||
binding.listSettings.layoutParams = mlpSettingsList
|
||||
binding.listSettings.updatePadding(
|
||||
bottom = barInsets.bottom
|
||||
|
||||
+42
-21
@@ -3,7 +3,6 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
@@ -32,8 +31,6 @@ class SettingsFragmentPresenter(
|
||||
private val preferences: SharedPreferences
|
||||
get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||
|
||||
private val context: Context get() = YuzuApplication.appContext
|
||||
|
||||
// Extension for populating settings list based on paired settings
|
||||
fun ArrayList<SettingsItem>.add(key: String) {
|
||||
val item = SettingsItem.settingsItems[key]!!
|
||||
@@ -53,7 +50,6 @@ class SettingsFragmentPresenter(
|
||||
val sl = ArrayList<SettingsItem>()
|
||||
when (menuTag) {
|
||||
Settings.MenuTag.SECTION_ROOT -> addConfigSettings(sl)
|
||||
Settings.MenuTag.SECTION_GENERAL -> addGeneralSettings(sl)
|
||||
Settings.MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
|
||||
Settings.MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
||||
Settings.MenuTag.SECTION_AUDIO -> addAudioSettings(sl)
|
||||
@@ -75,30 +71,53 @@ class SettingsFragmentPresenter(
|
||||
|
||||
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(SubmenuSetting(R.string.preferences_general, 0, Settings.MenuTag.SECTION_GENERAL))
|
||||
add(SubmenuSetting(R.string.preferences_system, 0, Settings.MenuTag.SECTION_SYSTEM))
|
||||
add(SubmenuSetting(R.string.preferences_graphics, 0, Settings.MenuTag.SECTION_RENDERER))
|
||||
add(SubmenuSetting(R.string.preferences_audio, 0, Settings.MenuTag.SECTION_AUDIO))
|
||||
add(SubmenuSetting(R.string.preferences_debug, 0, Settings.MenuTag.SECTION_DEBUG))
|
||||
add(
|
||||
RunnableSetting(R.string.reset_to_default, 0, false) {
|
||||
settingsViewModel.setShouldShowResetSettingsDialog(true)
|
||||
}
|
||||
SubmenuSetting(
|
||||
R.string.preferences_system,
|
||||
R.string.preferences_system_description,
|
||||
R.drawable.ic_system_settings,
|
||||
Settings.MenuTag.SECTION_SYSTEM
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.preferences_graphics,
|
||||
R.string.preferences_graphics_description,
|
||||
R.drawable.ic_graphics,
|
||||
Settings.MenuTag.SECTION_RENDERER
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.preferences_audio,
|
||||
R.string.preferences_audio_description,
|
||||
R.drawable.ic_audio,
|
||||
Settings.MenuTag.SECTION_AUDIO
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.preferences_debug,
|
||||
R.string.preferences_debug_description,
|
||||
R.drawable.ic_code,
|
||||
Settings.MenuTag.SECTION_DEBUG
|
||||
)
|
||||
)
|
||||
add(
|
||||
RunnableSetting(
|
||||
R.string.reset_to_default,
|
||||
R.string.reset_to_default_description,
|
||||
false,
|
||||
R.drawable.ic_restore
|
||||
) { settingsViewModel.setShouldShowResetSettingsDialog(true) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addGeneralSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
|
||||
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
|
||||
add(IntSetting.CPU_ACCURACY.key)
|
||||
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
|
||||
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
|
||||
add(BooleanSetting.USE_DOCKED_MODE.key)
|
||||
add(IntSetting.REGION_INDEX.key)
|
||||
add(IntSetting.LANGUAGE_INDEX.key)
|
||||
@@ -116,6 +135,7 @@ class SettingsFragmentPresenter(
|
||||
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
||||
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
||||
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
||||
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
||||
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||
@@ -249,6 +269,7 @@ class SettingsFragmentPresenter(
|
||||
add(BooleanSetting.RENDERER_DEBUG.key)
|
||||
|
||||
add(HeaderSetting(R.string.cpu))
|
||||
add(IntSetting.CPU_ACCURACY.key)
|
||||
add(BooleanSetting.CPU_DEBUG_MODE.key)
|
||||
add(SettingsItem.FASTMEM_COMBINED)
|
||||
}
|
||||
|
||||
+14
@@ -4,6 +4,7 @@
|
||||
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting
|
||||
@@ -16,6 +17,19 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
|
||||
|
||||
override fun bind(item: SettingsItem) {
|
||||
setting = item as RunnableSetting
|
||||
if (item.iconId != 0) {
|
||||
binding.icon.visibility = View.VISIBLE
|
||||
binding.icon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
binding.icon.resources,
|
||||
item.iconId,
|
||||
binding.icon.context.theme
|
||||
)
|
||||
)
|
||||
} else {
|
||||
binding.icon.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.textSettingName.setText(item.nameId)
|
||||
if (item.descriptionId != 0) {
|
||||
binding.textSettingDescription.setText(item.descriptionId)
|
||||
|
||||
+14
@@ -4,6 +4,7 @@
|
||||
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting
|
||||
@@ -15,6 +16,19 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
|
||||
|
||||
override fun bind(item: SettingsItem) {
|
||||
this.item = item as SubmenuSetting
|
||||
if (item.iconId != 0) {
|
||||
binding.icon.visibility = View.VISIBLE
|
||||
binding.icon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
binding.icon.resources,
|
||||
item.iconId,
|
||||
binding.icon.context.theme
|
||||
)
|
||||
)
|
||||
} else {
|
||||
binding.icon.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.textSettingName.setText(item.nameId)
|
||||
if (item.descriptionId != 0) {
|
||||
binding.textSettingDescription.setText(item.descriptionId)
|
||||
|
||||
@@ -114,10 +114,10 @@ class AboutFragment : Fragment() {
|
||||
val leftInsets = barInsets.left + cutoutInsets.left
|
||||
val rightInsets = barInsets.right + cutoutInsets.right
|
||||
|
||||
val mlpAppBar = binding.appbarAbout.layoutParams as MarginLayoutParams
|
||||
mlpAppBar.leftMargin = leftInsets
|
||||
mlpAppBar.rightMargin = rightInsets
|
||||
binding.appbarAbout.layoutParams = mlpAppBar
|
||||
val mlpToolbar = binding.toolbarAbout.layoutParams as MarginLayoutParams
|
||||
mlpToolbar.leftMargin = leftInsets
|
||||
mlpToolbar.rightMargin = rightInsets
|
||||
binding.toolbarAbout.layoutParams = mlpToolbar
|
||||
|
||||
val mlpScrollAbout = binding.scrollAbout.layoutParams as MarginLayoutParams
|
||||
mlpScrollAbout.leftMargin = leftInsets
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.adapters.AppletAdapter
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentAppletLauncherBinding
|
||||
import org.yuzu.yuzu_emu.model.Applet
|
||||
import org.yuzu.yuzu_emu.model.AppletInfo
|
||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||
|
||||
class AppletLauncherFragment : Fragment() {
|
||||
private var _binding: FragmentAppletLauncherBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val homeViewModel: HomeViewModel by activityViewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentAppletLauncherBinding.inflate(inflater)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
homeViewModel.setNavigationVisibility(visible = false, animated = true)
|
||||
homeViewModel.setStatusBarShadeVisibility(visible = false)
|
||||
|
||||
binding.toolbarApplets.setNavigationOnClickListener {
|
||||
binding.root.findNavController().popBackStack()
|
||||
}
|
||||
|
||||
val applets = listOf(
|
||||
Applet(
|
||||
R.string.album_applet,
|
||||
R.string.album_applet_description,
|
||||
R.drawable.ic_album,
|
||||
AppletInfo.PhotoViewer
|
||||
),
|
||||
Applet(
|
||||
R.string.cabinet_applet,
|
||||
R.string.cabinet_applet_description,
|
||||
R.drawable.ic_nfc,
|
||||
AppletInfo.Cabinet
|
||||
),
|
||||
Applet(
|
||||
R.string.mii_edit_applet,
|
||||
R.string.mii_edit_applet_description,
|
||||
R.drawable.ic_mii,
|
||||
AppletInfo.MiiEdit
|
||||
)
|
||||
)
|
||||
|
||||
binding.listApplets.apply {
|
||||
layoutManager = GridLayoutManager(
|
||||
requireContext(),
|
||||
resources.getInteger(R.integer.grid_columns)
|
||||
)
|
||||
adapter = AppletAdapter(requireActivity(), applets)
|
||||
}
|
||||
|
||||
setInsets()
|
||||
}
|
||||
|
||||
private fun setInsets() =
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
binding.root
|
||||
) { _: View, windowInsets: WindowInsetsCompat ->
|
||||
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||
|
||||
val leftInsets = barInsets.left + cutoutInsets.left
|
||||
val rightInsets = barInsets.right + cutoutInsets.right
|
||||
|
||||
val mlpAppBar = binding.toolbarApplets.layoutParams as ViewGroup.MarginLayoutParams
|
||||
mlpAppBar.leftMargin = leftInsets
|
||||
mlpAppBar.rightMargin = rightInsets
|
||||
binding.toolbarApplets.layoutParams = mlpAppBar
|
||||
|
||||
val mlpListApplets =
|
||||
binding.listApplets.layoutParams as ViewGroup.MarginLayoutParams
|
||||
mlpListApplets.leftMargin = leftInsets
|
||||
mlpListApplets.rightMargin = rightInsets
|
||||
binding.listApplets.layoutParams = mlpListApplets
|
||||
|
||||
binding.listApplets.updatePadding(bottom = barInsets.bottom)
|
||||
|
||||
windowInsets
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter
|
||||
import org.yuzu.yuzu_emu.databinding.DialogListBinding
|
||||
|
||||
class CabinetLauncherDialogFragment : DialogFragment() {
|
||||
private lateinit var binding: DialogListBinding
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
binding = DialogListBinding.inflate(layoutInflater)
|
||||
binding.dialogList.apply {
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
adapter = CabinetLauncherDialogAdapter(this@CabinetLauncherDialogFragment)
|
||||
}
|
||||
|
||||
return MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.cabinet_launcher)
|
||||
.setView(binding.root)
|
||||
.create()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
return binding.root
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.adapters.DriverAdapter
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding
|
||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
class DriverManagerFragment : Fragment() {
|
||||
private var _binding: FragmentDriverManagerBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val homeViewModel: HomeViewModel by activityViewModels()
|
||||
private val driverViewModel: DriverViewModel by activityViewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentDriverManagerBinding.inflate(inflater)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
homeViewModel.setNavigationVisibility(visible = false, animated = true)
|
||||
homeViewModel.setStatusBarShadeVisibility(visible = false)
|
||||
|
||||
if (!driverViewModel.isInteractionAllowed) {
|
||||
DriversLoadingDialogFragment().show(
|
||||
childFragmentManager,
|
||||
DriversLoadingDialogFragment.TAG
|
||||
)
|
||||
}
|
||||
|
||||
binding.toolbarDrivers.setNavigationOnClickListener {
|
||||
binding.root.findNavController().popBackStack()
|
||||
}
|
||||
|
||||
binding.buttonInstall.setOnClickListener {
|
||||
getDriver.launch(arrayOf("application/zip"))
|
||||
}
|
||||
|
||||
binding.listDrivers.apply {
|
||||
layoutManager = GridLayoutManager(
|
||||
requireContext(),
|
||||
resources.getInteger(R.integer.grid_columns)
|
||||
)
|
||||
adapter = DriverAdapter(driverViewModel)
|
||||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.apply {
|
||||
launch {
|
||||
driverViewModel.driverList.collectLatest {
|
||||
(binding.listDrivers.adapter as DriverAdapter).submitList(it)
|
||||
}
|
||||
}
|
||||
launch {
|
||||
driverViewModel.newDriverInstalled.collect {
|
||||
if (_binding != null && it) {
|
||||
(binding.listDrivers.adapter as DriverAdapter).apply {
|
||||
notifyItemChanged(driverViewModel.previouslySelectedDriver)
|
||||
notifyItemChanged(driverViewModel.selectedDriver)
|
||||
driverViewModel.setNewDriverInstalled(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setInsets()
|
||||
}
|
||||
|
||||
// Start installing requested driver
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
driverViewModel.onCloseDriverManager()
|
||||
}
|
||||
|
||||
private fun setInsets() =
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
binding.root
|
||||
) { _: View, windowInsets: WindowInsetsCompat ->
|
||||
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||
|
||||
val leftInsets = barInsets.left + cutoutInsets.left
|
||||
val rightInsets = barInsets.right + cutoutInsets.right
|
||||
|
||||
val mlpAppBar = binding.toolbarDrivers.layoutParams as ViewGroup.MarginLayoutParams
|
||||
mlpAppBar.leftMargin = leftInsets
|
||||
mlpAppBar.rightMargin = rightInsets
|
||||
binding.toolbarDrivers.layoutParams = mlpAppBar
|
||||
|
||||
val mlplistDrivers = binding.listDrivers.layoutParams as ViewGroup.MarginLayoutParams
|
||||
mlplistDrivers.leftMargin = leftInsets
|
||||
mlplistDrivers.rightMargin = rightInsets
|
||||
binding.listDrivers.layoutParams = mlplistDrivers
|
||||
|
||||
val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab)
|
||||
val mlpFab =
|
||||
binding.buttonInstall.layoutParams as ViewGroup.MarginLayoutParams
|
||||
mlpFab.leftMargin = leftInsets + fabSpacing
|
||||
mlpFab.rightMargin = rightInsets + fabSpacing
|
||||
mlpFab.bottomMargin = barInsets.bottom + fabSpacing
|
||||
binding.buttonInstall.layoutParams = mlpFab
|
||||
|
||||
binding.listDrivers.updatePadding(
|
||||
bottom = barInsets.bottom +
|
||||
resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab)
|
||||
)
|
||||
|
||||
windowInsets
|
||||
}
|
||||
|
||||
private val getDriver =
|
||||
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
|
||||
if (result == null) {
|
||||
return@registerForActivityResult
|
||||
}
|
||||
|
||||
IndeterminateProgressDialogFragment.newInstance(
|
||||
requireActivity(),
|
||||
R.string.installing_driver,
|
||||
false
|
||||
) {
|
||||
val driverPath =
|
||||
"${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}"
|
||||
val driverFile = File(driverPath)
|
||||
|
||||
// Ignore file exceptions when a user selects an invalid zip
|
||||
try {
|
||||
if (!GpuDriverHelper.copyDriverToInternalStorage(result)) {
|
||||
throw IOException("Driver failed validation!")
|
||||
}
|
||||
} catch (_: IOException) {
|
||||
if (driverFile.exists()) {
|
||||
driverFile.delete()
|
||||
}
|
||||
return@newInstance getString(R.string.select_gpu_driver_error)
|
||||
}
|
||||
|
||||
val driverData = GpuDriverHelper.getMetadataFromZip(driverFile)
|
||||
val driverInList =
|
||||
driverViewModel.driverList.value.firstOrNull { it.second == driverData }
|
||||
if (driverInList != null) {
|
||||
return@newInstance getString(R.string.driver_already_installed)
|
||||
} else {
|
||||
driverViewModel.addDriver(Pair(driverPath, driverData))
|
||||
driverViewModel.setNewDriverInstalled(true)
|
||||
}
|
||||
return@newInstance Any()
|
||||
}.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.launch
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
|
||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||
|
||||
class DriversLoadingDialogFragment : DialogFragment() {
|
||||
private val driverViewModel: DriverViewModel by activityViewModels()
|
||||
|
||||
private lateinit var binding: DialogProgressBarBinding
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
binding = DialogProgressBarBinding.inflate(layoutInflater)
|
||||
binding.progressBar.isIndeterminate = true
|
||||
|
||||
isCancelable = false
|
||||
|
||||
return MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.loading)
|
||||
.setView(binding.root)
|
||||
.create()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View = binding.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewLifecycleOwner.lifecycleScope.apply {
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
driverViewModel.areDriversLoading.collect { checkForDismiss() }
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
driverViewModel.isDriverReady.collect { checkForDismiss() }
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
driverViewModel.isDeletingDrivers.collect { checkForDismiss() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkForDismiss() {
|
||||
if (driverViewModel.isInteractionAllowed) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "DriversLoadingDialogFragment"
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,14 @@ import android.content.DialogInterface
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Rational
|
||||
import android.os.SystemClock
|
||||
import android.view.*
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
@@ -25,6 +25,7 @@ import androidx.core.graphics.Insets
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
@@ -39,6 +40,7 @@ import androidx.window.layout.WindowLayoutInfo
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.slider.Slider
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||
@@ -50,10 +52,12 @@ import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
|
||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||
import org.yuzu.yuzu_emu.model.Game
|
||||
import org.yuzu.yuzu_emu.model.EmulationViewModel
|
||||
import org.yuzu.yuzu_emu.overlay.InputOverlay
|
||||
import org.yuzu.yuzu_emu.utils.*
|
||||
import java.lang.NullPointerException
|
||||
|
||||
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
private lateinit var preferences: SharedPreferences
|
||||
@@ -69,6 +73,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
private lateinit var game: Game
|
||||
|
||||
private val emulationViewModel: EmulationViewModel by activityViewModels()
|
||||
private val driverViewModel: DriverViewModel by activityViewModels()
|
||||
|
||||
private var isInFoldableLayout = false
|
||||
|
||||
@@ -105,10 +110,21 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
null
|
||||
}
|
||||
}
|
||||
game = if (args.game != null) {
|
||||
args.game!!
|
||||
} else {
|
||||
intentGame ?: error("[EmulationFragment] No bootable game present!")
|
||||
|
||||
try {
|
||||
game = if (args.game != null) {
|
||||
args.game!!
|
||||
} else {
|
||||
intentGame!!
|
||||
}
|
||||
} catch (e: NullPointerException) {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.no_game_present,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
requireActivity().finish()
|
||||
return
|
||||
}
|
||||
|
||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||
@@ -132,10 +148,40 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
// This is using the correct scope, lint is just acting up
|
||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (requireActivity().isFinishing) {
|
||||
return
|
||||
}
|
||||
|
||||
binding.surfaceEmulation.holder.addCallback(this)
|
||||
binding.showFpsText.setTextColor(Color.YELLOW)
|
||||
binding.doneControlConfig.setOnClickListener { stopConfiguringControls() }
|
||||
|
||||
binding.drawerLayout.addDrawerListener(object : DrawerListener {
|
||||
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
|
||||
binding.surfaceInputOverlay.dispatchTouchEvent(
|
||||
MotionEvent.obtain(
|
||||
SystemClock.uptimeMillis(),
|
||||
SystemClock.uptimeMillis() + 100,
|
||||
MotionEvent.ACTION_UP,
|
||||
0f,
|
||||
0f,
|
||||
0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun onDrawerStateChanged(newState: Int) {
|
||||
// No op
|
||||
}
|
||||
})
|
||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
|
||||
game.title
|
||||
@@ -264,6 +310,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
ViewUtils.showView(binding.surfaceInputOverlay)
|
||||
ViewUtils.hideView(binding.loadingIndicator)
|
||||
|
||||
emulationState.updateSurface()
|
||||
|
||||
// Setup overlay
|
||||
updateShowFpsOverlay()
|
||||
}
|
||||
@@ -282,29 +330,43 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
driverViewModel.isDriverReady.collect {
|
||||
if (it && !emulationState.isRunning) {
|
||||
if (!DirectoryInitialization.areDirectoriesReady) {
|
||||
DirectoryInitialization.start()
|
||||
}
|
||||
|
||||
updateScreenLayout()
|
||||
|
||||
emulationState.run(emulationActivity!!.isActivityRecreated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
if (_binding == null) {
|
||||
return
|
||||
}
|
||||
|
||||
updateScreenLayout()
|
||||
if (emulationActivity?.isInPictureInPictureMode == true) {
|
||||
if (binding.drawerLayout.isOpen) {
|
||||
binding.drawerLayout.close()
|
||||
}
|
||||
if (EmulationMenuSettings.showOverlay) {
|
||||
binding.surfaceInputOverlay.post {
|
||||
binding.surfaceInputOverlay.visibility = View.VISIBLE
|
||||
}
|
||||
binding.surfaceInputOverlay.visibility = View.INVISIBLE
|
||||
}
|
||||
} else {
|
||||
if (EmulationMenuSettings.showOverlay && emulationViewModel.emulationStarted.value) {
|
||||
binding.surfaceInputOverlay.post {
|
||||
binding.surfaceInputOverlay.visibility = View.VISIBLE
|
||||
}
|
||||
binding.surfaceInputOverlay.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.surfaceInputOverlay.post {
|
||||
binding.surfaceInputOverlay.visibility = View.INVISIBLE
|
||||
}
|
||||
binding.surfaceInputOverlay.visibility = View.INVISIBLE
|
||||
}
|
||||
if (!isInFoldableLayout) {
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
@@ -316,19 +378,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (!DirectoryInitialization.areDirectoriesReady) {
|
||||
DirectoryInitialization.start()
|
||||
}
|
||||
|
||||
updateScreenLayout()
|
||||
|
||||
emulationState.run(emulationActivity!!.isActivityRecreated)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
if (emulationState.isRunning) {
|
||||
if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) {
|
||||
emulationState.pause()
|
||||
}
|
||||
super.onPause()
|
||||
@@ -361,12 +412,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
val FRAMETIME = 2
|
||||
val SPEED = 3
|
||||
perfStatsUpdater = {
|
||||
if (emulationViewModel.emulationStarted.value == true) {
|
||||
if (emulationViewModel.emulationStarted.value) {
|
||||
val perfStats = NativeLibrary.getPerfStats()
|
||||
if (perfStats[FPS] > 0 && _binding != null) {
|
||||
if (_binding != null) {
|
||||
binding.showFpsText.text = String.format("FPS: %.1f", perfStats[FPS])
|
||||
}
|
||||
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 100)
|
||||
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
|
||||
}
|
||||
}
|
||||
perfStatsUpdateHandler.post(perfStatsUpdater!!)
|
||||
@@ -394,16 +445,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
private fun updateScreenLayout() {
|
||||
binding.surfaceEmulation.setAspectRatio(
|
||||
when (IntSetting.RENDERER_ASPECT_RATIO.int) {
|
||||
0 -> Rational(16, 9)
|
||||
1 -> Rational(4, 3)
|
||||
2 -> Rational(21, 9)
|
||||
3 -> Rational(16, 10)
|
||||
4 -> null // Stretch
|
||||
else -> Rational(16, 9)
|
||||
}
|
||||
)
|
||||
binding.surfaceEmulation.setAspectRatio(null)
|
||||
emulationActivity?.buildPictureInPictureParams()
|
||||
updateOrientation()
|
||||
}
|
||||
@@ -420,7 +462,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
if (it.orientation == FoldingFeature.Orientation.HORIZONTAL) {
|
||||
// Restrict emulation and overlays to the top of the screen
|
||||
binding.emulationContainer.layoutParams.height = it.bounds.top
|
||||
binding.overlayContainer.layoutParams.height = it.bounds.top
|
||||
// Restrict input and menu drawer to the bottom of the screen
|
||||
binding.inputContainer.layoutParams.height = it.bounds.bottom
|
||||
binding.inGameMenu.layoutParams.height = it.bounds.bottom
|
||||
@@ -434,7 +475,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
if (!isFolding) {
|
||||
binding.emulationContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
binding.inputContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
binding.overlayContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
binding.inGameMenu.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
isInFoldableLayout = false
|
||||
updateOrientation()
|
||||
@@ -442,7 +482,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
binding.emulationContainer.requestLayout()
|
||||
binding.inputContainer.requestLayout()
|
||||
binding.overlayContainer.requestLayout()
|
||||
binding.inGameMenu.requestLayout()
|
||||
}
|
||||
|
||||
@@ -668,24 +707,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
v.setPadding(left, cutInsets.top, right, 0)
|
||||
|
||||
// Ensure FPS text doesn't get cut off by rounded display corners
|
||||
val sidePadding = resources.getDimensionPixelSize(R.dimen.spacing_xtralarge)
|
||||
if (cutInsets.left == 0) {
|
||||
binding.showFpsText.setPadding(
|
||||
sidePadding,
|
||||
cutInsets.top,
|
||||
cutInsets.right,
|
||||
cutInsets.bottom
|
||||
)
|
||||
} else {
|
||||
binding.showFpsText.setPadding(
|
||||
cutInsets.left,
|
||||
cutInsets.top,
|
||||
cutInsets.right,
|
||||
cutInsets.bottom
|
||||
)
|
||||
}
|
||||
windowInsets
|
||||
}
|
||||
}
|
||||
@@ -693,7 +714,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
private class EmulationState(private val gamePath: String) {
|
||||
private var state: State
|
||||
private var surface: Surface? = null
|
||||
private var runWhenSurfaceIsValid = false
|
||||
|
||||
init {
|
||||
// Starting state is stopped.
|
||||
@@ -751,8 +771,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
// If the surface is set, run now. Otherwise, wait for it to get set.
|
||||
if (surface != null) {
|
||||
runWithValidSurface()
|
||||
} else {
|
||||
runWhenSurfaceIsValid = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -760,11 +778,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
@Synchronized
|
||||
fun newSurface(surface: Surface?) {
|
||||
this.surface = surface
|
||||
if (runWhenSurfaceIsValid) {
|
||||
if (this.surface != null) {
|
||||
runWithValidSurface()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun updateSurface() {
|
||||
if (surface != null) {
|
||||
NativeLibrary.surfaceChanged(surface)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun clearSurface() {
|
||||
if (surface == null) {
|
||||
@@ -788,10 +813,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
private fun runWithValidSurface() {
|
||||
runWhenSurfaceIsValid = false
|
||||
NativeLibrary.surfaceChanged(surface)
|
||||
when (state) {
|
||||
State.STOPPED -> {
|
||||
NativeLibrary.surfaceChanged(surface)
|
||||
val emulationThread = Thread({
|
||||
Log.debug("[EmulationFragment] Starting emulation thread.")
|
||||
NativeLibrary.run(gamePath)
|
||||
@@ -801,7 +825,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
State.PAUSED -> {
|
||||
Log.debug("[EmulationFragment] Resuming emulation.")
|
||||
NativeLibrary.surfaceChanged(surface)
|
||||
NativeLibrary.unpauseEmulation()
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.Manifest
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
@@ -27,21 +26,23 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.yuzu.yuzu_emu.BuildConfig
|
||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding
|
||||
import org.yuzu.yuzu_emu.features.DocumentProvider
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||
import org.yuzu.yuzu_emu.model.HomeSetting
|
||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
|
||||
class HomeSettingsFragment : Fragment() {
|
||||
private var _binding: FragmentHomeSettingsBinding? = null
|
||||
@@ -50,6 +51,7 @@ class HomeSettingsFragment : Fragment() {
|
||||
private lateinit var mainActivity: MainActivity
|
||||
|
||||
private val homeViewModel: HomeViewModel by activityViewModels()
|
||||
private val driverViewModel: DriverViewModel by activityViewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -85,51 +87,42 @@ class HomeSettingsFragment : Fragment() {
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.open_user_folder,
|
||||
R.string.open_user_folder_description,
|
||||
R.drawable.ic_folder_open,
|
||||
{ openFileManager() }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.preferences_theme,
|
||||
R.string.theme_and_color_description,
|
||||
R.drawable.ic_palette,
|
||||
{
|
||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
||||
null,
|
||||
Settings.MenuTag.SECTION_THEME
|
||||
)
|
||||
binding.root.findNavController().navigate(action)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_gpu_driver,
|
||||
R.string.gpu_driver_manager,
|
||||
R.string.install_gpu_driver_description,
|
||||
R.drawable.ic_exit,
|
||||
{ driverInstaller() },
|
||||
R.drawable.ic_build,
|
||||
{
|
||||
binding.root.findNavController()
|
||||
.navigate(R.id.action_homeSettingsFragment_to_driverManagerFragment)
|
||||
},
|
||||
{ GpuDriverHelper.supportsCustomDriverLoading() },
|
||||
R.string.custom_driver_not_supported,
|
||||
R.string.custom_driver_not_supported_description
|
||||
R.string.custom_driver_not_supported_description,
|
||||
driverViewModel.selectedDriverMetadata
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_amiibo_keys,
|
||||
R.string.install_amiibo_keys_description,
|
||||
R.drawable.ic_nfc,
|
||||
{ mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }
|
||||
R.string.applets,
|
||||
R.string.applets_description,
|
||||
R.drawable.ic_applet,
|
||||
{
|
||||
binding.root.findNavController()
|
||||
.navigate(R.id.action_homeSettingsFragment_to_appletLauncherFragment)
|
||||
},
|
||||
{ NativeLibrary.isFirmwareAvailable() },
|
||||
R.string.applets_error_firmware,
|
||||
R.string.applets_error_description
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_game_content,
|
||||
R.string.install_game_content_description,
|
||||
R.drawable.ic_system_update_alt,
|
||||
{ mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
|
||||
R.string.manage_yuzu_data,
|
||||
R.string.manage_yuzu_data_description,
|
||||
R.drawable.ic_install,
|
||||
{
|
||||
binding.root.findNavController()
|
||||
.navigate(R.id.action_homeSettingsFragment_to_installableFragment)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
@@ -148,35 +141,6 @@ class HomeSettingsFragment : Fragment() {
|
||||
homeViewModel.gamesDir
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.manage_save_data,
|
||||
R.string.import_export_saves_description,
|
||||
R.drawable.ic_save,
|
||||
{
|
||||
ImportExportSavesFragment().show(
|
||||
parentFragmentManager,
|
||||
ImportExportSavesFragment.TAG
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_prod_keys,
|
||||
R.string.install_prod_keys_description,
|
||||
R.drawable.ic_unlock,
|
||||
{ mainActivity.getProdKey.launch(arrayOf("*/*")) }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_firmware,
|
||||
R.string.install_firmware_description,
|
||||
R.drawable.ic_firmware,
|
||||
{ mainActivity.getFirmware.launch(arrayOf("application/zip")) }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.share_log,
|
||||
@@ -185,6 +149,28 @@ class HomeSettingsFragment : Fragment() {
|
||||
{ shareLog() }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.open_user_folder,
|
||||
R.string.open_user_folder_description,
|
||||
R.drawable.ic_folder_open,
|
||||
{ openFileManager() }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.preferences_theme,
|
||||
R.string.theme_and_color_description,
|
||||
R.drawable.ic_palette,
|
||||
{
|
||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
||||
null,
|
||||
Settings.MenuTag.SECTION_THEME
|
||||
)
|
||||
binding.root.findNavController().navigate(action)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.about,
|
||||
@@ -216,7 +202,8 @@ class HomeSettingsFragment : Fragment() {
|
||||
}
|
||||
|
||||
binding.homeSettingsList.apply {
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
layoutManager =
|
||||
GridLayoutManager(requireContext(), resources.getInteger(R.integer.grid_columns))
|
||||
adapter = HomeSettingAdapter(
|
||||
requireActivity() as AppCompatActivity,
|
||||
viewLifecycleOwner,
|
||||
@@ -326,44 +313,32 @@ class HomeSettingsFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun driverInstaller() {
|
||||
// Get the driver name for the dialog message.
|
||||
var driverName = GpuDriverHelper.customDriverName
|
||||
if (driverName == null) {
|
||||
driverName = getString(R.string.system_gpu_driver)
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(getString(R.string.select_gpu_driver_title))
|
||||
.setMessage(driverName)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setNeutralButton(R.string.select_gpu_driver_default) { _: DialogInterface?, _: Int ->
|
||||
GpuDriverHelper.installDefaultDriver(requireContext())
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.select_gpu_driver_use_default,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
.setPositiveButton(R.string.select_gpu_driver_install) { _: DialogInterface?, _: Int ->
|
||||
mainActivity.getDriver.launch(arrayOf("application/zip"))
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
// Share the current log if we just returned from a game but share the old log
|
||||
// if we just started the app and the old log exists.
|
||||
private fun shareLog() {
|
||||
val file = DocumentFile.fromSingleUri(
|
||||
val currentLog = DocumentFile.fromSingleUri(
|
||||
mainActivity,
|
||||
DocumentsContract.buildDocumentUri(
|
||||
DocumentProvider.AUTHORITY,
|
||||
"${DocumentProvider.ROOT_ID}/log/yuzu_log.txt"
|
||||
)
|
||||
)!!
|
||||
if (file.exists()) {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
.setDataAndType(file.uri, FileUtil.TEXT_PLAIN)
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.putExtra(Intent.EXTRA_STREAM, file.uri)
|
||||
val oldLog = DocumentFile.fromSingleUri(
|
||||
mainActivity,
|
||||
DocumentsContract.buildDocumentUri(
|
||||
DocumentProvider.AUTHORITY,
|
||||
"${DocumentProvider.ROOT_ID}/log/yuzu_log.txt.old.txt"
|
||||
)
|
||||
)!!
|
||||
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
.setDataAndType(currentLog.uri, FileUtil.TEXT_PLAIN)
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
if (!Log.gameLaunched && oldLog.exists()) {
|
||||
intent.putExtra(Intent.EXTRA_STREAM, oldLog.uri)
|
||||
startActivity(Intent.createChooser(intent, getText(R.string.share_log)))
|
||||
} else if (currentLog.exists()) {
|
||||
intent.putExtra(Intent.EXTRA_STREAM, currentLog.uri)
|
||||
startActivity(Intent.createChooser(intent, getText(R.string.share_log)))
|
||||
} else {
|
||||
Toast.makeText(
|
||||
|
||||
-213
@@ -1,213 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.DocumentsContract
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.FilenameFilter
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.features.DocumentProvider
|
||||
import org.yuzu.yuzu_emu.getPublicFilesDir
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||
|
||||
class ImportExportSavesFragment : DialogFragment() {
|
||||
private val context = YuzuApplication.appContext
|
||||
private val savesFolder =
|
||||
"${context.getPublicFilesDir().canonicalPath}/nand/user/save/0000000000000000"
|
||||
|
||||
// Get first subfolder in saves folder (should be the user folder)
|
||||
private val savesFolderRoot = File(savesFolder).listFiles()?.firstOrNull()?.canonicalPath ?: ""
|
||||
private var lastZipCreated: File? = null
|
||||
|
||||
private lateinit var startForResultExportSave: ActivityResultLauncher<Intent>
|
||||
private lateinit var documentPicker: ActivityResultLauncher<Array<String>>
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val activity = requireActivity() as AppCompatActivity
|
||||
|
||||
val activityResultRegistry = requireActivity().activityResultRegistry
|
||||
startForResultExportSave = activityResultRegistry.register(
|
||||
"startForResultExportSaveKey",
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) {
|
||||
File(context.getPublicFilesDir().canonicalPath, "temp").deleteRecursively()
|
||||
}
|
||||
documentPicker = activityResultRegistry.register(
|
||||
"documentPickerKey",
|
||||
ActivityResultContracts.OpenDocument()
|
||||
) {
|
||||
it?.let { uri -> importSave(uri, activity) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return if (savesFolderRoot == "") {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.manage_save_data)
|
||||
.setMessage(R.string.import_export_saves_no_profile)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show()
|
||||
} else {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.manage_save_data)
|
||||
.setMessage(R.string.manage_save_data_description)
|
||||
.setNegativeButton(R.string.export_saves) { _, _ ->
|
||||
exportSave()
|
||||
}
|
||||
.setPositiveButton(R.string.import_saves) { _, _ ->
|
||||
documentPicker.launch(arrayOf("application/zip"))
|
||||
}
|
||||
.setNeutralButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zips the save files located in the given folder path and creates a new zip file with the current date and time.
|
||||
* @return true if the zip file is successfully created, false otherwise.
|
||||
*/
|
||||
private fun zipSave(): Boolean {
|
||||
try {
|
||||
val tempFolder = File(requireContext().getPublicFilesDir().canonicalPath, "temp")
|
||||
tempFolder.mkdirs()
|
||||
val saveFolder = File(savesFolderRoot)
|
||||
val outputZipFile = File(
|
||||
tempFolder,
|
||||
"yuzu saves - ${
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
|
||||
}.zip"
|
||||
)
|
||||
outputZipFile.createNewFile()
|
||||
ZipOutputStream(BufferedOutputStream(FileOutputStream(outputZipFile))).use { zos ->
|
||||
saveFolder.walkTopDown().forEach { file ->
|
||||
val zipFileName =
|
||||
file.absolutePath.removePrefix(savesFolderRoot).removePrefix("/")
|
||||
if (zipFileName == "") {
|
||||
return@forEach
|
||||
}
|
||||
val entry = ZipEntry("$zipFileName${(if (file.isDirectory) "/" else "")}")
|
||||
zos.putNextEntry(entry)
|
||||
if (file.isFile) {
|
||||
file.inputStream().use { fis -> fis.copyTo(zos) }
|
||||
}
|
||||
}
|
||||
}
|
||||
lastZipCreated = outputZipFile
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
|
||||
*/
|
||||
private fun exportSave() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val wasZipCreated = zipSave()
|
||||
val lastZipFile = lastZipCreated
|
||||
if (!wasZipCreated || lastZipFile == null) {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(context, "Failed to export save", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
val file = DocumentFile.fromSingleUri(
|
||||
context,
|
||||
DocumentsContract.buildDocumentUri(
|
||||
DocumentProvider.AUTHORITY,
|
||||
"${DocumentProvider.ROOT_ID}/temp/${lastZipFile.name}"
|
||||
)
|
||||
)!!
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
.setDataAndType(file.uri, "application/zip")
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.putExtra(Intent.EXTRA_STREAM, file.uri)
|
||||
startForResultExportSave.launch(Intent.createChooser(intent, "Share save file"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports the save files contained in the zip file, and replaces any existing ones with the new save file.
|
||||
* @param zipUri The Uri of the zip file containing the save file(s) to import.
|
||||
*/
|
||||
private fun importSave(zipUri: Uri, activity: AppCompatActivity) {
|
||||
val inputZip = context.contentResolver.openInputStream(zipUri)
|
||||
// A zip needs to have at least one subfolder named after a TitleId in order to be considered valid.
|
||||
var validZip = false
|
||||
val savesFolder = File(savesFolderRoot)
|
||||
val cacheSaveDir = File("${context.cacheDir.path}/saves/")
|
||||
cacheSaveDir.mkdir()
|
||||
|
||||
if (inputZip == null) {
|
||||
Toast.makeText(context, context.getString(R.string.fatal_error), Toast.LENGTH_LONG)
|
||||
.show()
|
||||
return
|
||||
}
|
||||
|
||||
val filterTitleId =
|
||||
FilenameFilter { _, dirName -> dirName.matches(Regex("^0100[\\dA-Fa-f]{12}$")) }
|
||||
|
||||
try {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
FileUtil.unzip(inputZip, cacheSaveDir)
|
||||
cacheSaveDir.list(filterTitleId)?.forEach { savePath ->
|
||||
File(savesFolder, savePath).deleteRecursively()
|
||||
File(cacheSaveDir, savePath).copyRecursively(File(savesFolder, savePath), true)
|
||||
validZip = true
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
if (!validZip) {
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.save_file_invalid_zip_structure,
|
||||
descriptionId = R.string.save_file_invalid_zip_structure_description
|
||||
).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
|
||||
return@withContext
|
||||
}
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.save_file_imported_success),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
|
||||
cacheSaveDir.deleteRecursively()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(context, context.getString(R.string.fatal_error), Toast.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "ImportExportSavesFragment"
|
||||
}
|
||||
}
|
||||
+83
-26
@@ -5,9 +5,13 @@ package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
@@ -15,63 +19,116 @@ import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.launch
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
|
||||
import org.yuzu.yuzu_emu.model.TaskViewModel
|
||||
|
||||
class IndeterminateProgressDialogFragment : DialogFragment() {
|
||||
private val taskViewModel: TaskViewModel by activityViewModels()
|
||||
|
||||
private lateinit var binding: DialogProgressBarBinding
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val titleId = requireArguments().getInt(TITLE)
|
||||
val cancellable = requireArguments().getBoolean(CANCELLABLE)
|
||||
|
||||
val progressBinding = DialogProgressBarBinding.inflate(layoutInflater)
|
||||
progressBinding.progressBar.isIndeterminate = true
|
||||
binding = DialogProgressBarBinding.inflate(layoutInflater)
|
||||
binding.progressBar.isIndeterminate = true
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(titleId)
|
||||
.setView(progressBinding.root)
|
||||
.create()
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
.setView(binding.root)
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
taskViewModel.isComplete.collect {
|
||||
if (it) {
|
||||
dialog.dismiss()
|
||||
when (val result = taskViewModel.result.value) {
|
||||
is String -> Toast.makeText(requireContext(), result, Toast.LENGTH_LONG)
|
||||
.show()
|
||||
|
||||
is MessageDialogFragment -> result.show(
|
||||
requireActivity().supportFragmentManager,
|
||||
MessageDialogFragment.TAG
|
||||
)
|
||||
}
|
||||
taskViewModel.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cancellable) {
|
||||
dialog.setNegativeButton(android.R.string.cancel, null)
|
||||
}
|
||||
|
||||
val alertDialog = dialog.create()
|
||||
alertDialog.setCanceledOnTouchOutside(false)
|
||||
|
||||
if (!taskViewModel.isRunning.value) {
|
||||
taskViewModel.runTask()
|
||||
}
|
||||
return dialog
|
||||
return alertDialog
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewLifecycleOwner.lifecycleScope.apply {
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
taskViewModel.isComplete.collect {
|
||||
if (it) {
|
||||
dismiss()
|
||||
when (val result = taskViewModel.result.value) {
|
||||
is String -> Toast.makeText(
|
||||
requireContext(),
|
||||
result,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
is MessageDialogFragment -> result.show(
|
||||
requireActivity().supportFragmentManager,
|
||||
MessageDialogFragment.TAG
|
||||
)
|
||||
|
||||
else -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
taskViewModel.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
taskViewModel.cancelled.collect {
|
||||
if (it) {
|
||||
dialog?.setTitle(R.string.cancelling)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// By default, the ProgressDialog will immediately dismiss itself upon a button being pressed.
|
||||
// Setting the OnClickListener again after the dialog is shown overrides this behavior.
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val alertDialog = dialog as AlertDialog
|
||||
val negativeButton = alertDialog.getButton(Dialog.BUTTON_NEGATIVE)
|
||||
negativeButton.setOnClickListener {
|
||||
alertDialog.setTitle(getString(R.string.cancelling))
|
||||
taskViewModel.setCancelled(true)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "IndeterminateProgressDialogFragment"
|
||||
|
||||
private const val TITLE = "Title"
|
||||
private const val CANCELLABLE = "Cancellable"
|
||||
|
||||
fun newInstance(
|
||||
activity: AppCompatActivity,
|
||||
activity: FragmentActivity,
|
||||
titleId: Int,
|
||||
cancellable: Boolean = false,
|
||||
task: () -> Any
|
||||
): IndeterminateProgressDialogFragment {
|
||||
val dialog = IndeterminateProgressDialogFragment()
|
||||
val args = Bundle()
|
||||
ViewModelProvider(activity)[TaskViewModel::class.java].task = task
|
||||
args.putInt(TITLE, titleId)
|
||||
args.putBoolean(CANCELLABLE, cancellable)
|
||||
dialog.arguments = args
|
||||
return dialog
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.adapters.InstallableAdapter
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding
|
||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||
import org.yuzu.yuzu_emu.model.Installable
|
||||
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
||||
|
||||
class InstallableFragment : Fragment() {
|
||||
private var _binding: FragmentInstallablesBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val homeViewModel: HomeViewModel by activityViewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentInstallablesBinding.inflate(layoutInflater)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val mainActivity = requireActivity() as MainActivity
|
||||
|
||||
homeViewModel.setNavigationVisibility(visible = false, animated = true)
|
||||
homeViewModel.setStatusBarShadeVisibility(visible = false)
|
||||
|
||||
binding.toolbarInstallables.setNavigationOnClickListener {
|
||||
binding.root.findNavController().popBackStack()
|
||||
}
|
||||
|
||||
val installables = listOf(
|
||||
Installable(
|
||||
R.string.user_data,
|
||||
R.string.user_data_description,
|
||||
install = { mainActivity.importUserData.launch(arrayOf("application/zip")) },
|
||||
export = { mainActivity.exportUserData.launch("export.zip") }
|
||||
),
|
||||
Installable(
|
||||
R.string.install_game_content,
|
||||
R.string.install_game_content_description,
|
||||
install = { mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
|
||||
),
|
||||
Installable(
|
||||
R.string.install_firmware,
|
||||
R.string.install_firmware_description,
|
||||
install = { mainActivity.getFirmware.launch(arrayOf("application/zip")) }
|
||||
),
|
||||
if (mainActivity.savesFolderRoot != "") {
|
||||
Installable(
|
||||
R.string.manage_save_data,
|
||||
R.string.import_export_saves_description,
|
||||
install = { mainActivity.importSaves.launch(arrayOf("application/zip")) },
|
||||
export = { mainActivity.exportSave() }
|
||||
)
|
||||
} else {
|
||||
Installable(
|
||||
R.string.manage_save_data,
|
||||
R.string.import_export_saves_description,
|
||||
install = { mainActivity.importSaves.launch(arrayOf("application/zip")) }
|
||||
)
|
||||
},
|
||||
Installable(
|
||||
R.string.install_prod_keys,
|
||||
R.string.install_prod_keys_description,
|
||||
install = { mainActivity.getProdKey.launch(arrayOf("*/*")) }
|
||||
),
|
||||
Installable(
|
||||
R.string.install_amiibo_keys,
|
||||
R.string.install_amiibo_keys_description,
|
||||
install = { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }
|
||||
)
|
||||
)
|
||||
|
||||
binding.listInstallables.apply {
|
||||
layoutManager = GridLayoutManager(
|
||||
requireContext(),
|
||||
resources.getInteger(R.integer.grid_columns)
|
||||
)
|
||||
adapter = InstallableAdapter(installables)
|
||||
}
|
||||
|
||||
setInsets()
|
||||
}
|
||||
|
||||
private fun setInsets() =
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
binding.root
|
||||
) { _: View, windowInsets: WindowInsetsCompat ->
|
||||
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||
|
||||
val leftInsets = barInsets.left + cutoutInsets.left
|
||||
val rightInsets = barInsets.right + cutoutInsets.right
|
||||
|
||||
val mlpAppBar = binding.toolbarInstallables.layoutParams as ViewGroup.MarginLayoutParams
|
||||
mlpAppBar.leftMargin = leftInsets
|
||||
mlpAppBar.rightMargin = rightInsets
|
||||
binding.toolbarInstallables.layoutParams = mlpAppBar
|
||||
|
||||
val mlpScrollAbout =
|
||||
binding.listInstallables.layoutParams as ViewGroup.MarginLayoutParams
|
||||
mlpScrollAbout.leftMargin = leftInsets
|
||||
mlpScrollAbout.rightMargin = rightInsets
|
||||
binding.listInstallables.layoutParams = mlpScrollAbout
|
||||
|
||||
binding.listInstallables.updatePadding(bottom = barInsets.bottom)
|
||||
|
||||
windowInsets
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user