Compare commits
554 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 09a9d08466 | |||
| 1b8bf081b5 | |||
| 06ecc2ae68 | |||
| 46d3066c62 | |||
| 8d12816001 | |||
| fe03b55046 | |||
| ca57f25f26 | |||
| 3c639ff8e1 | |||
| 78c986b5dd | |||
| a42663b09b | |||
| 36149fd986 | |||
| c2c559f8d9 | |||
| 5e8419af0d | |||
| 86fc842c89 | |||
| 80530e8aef | |||
| ba26e16411 | |||
| 2cee26c3e7 | |||
| 5d55e509ec | |||
| 4984e87776 | |||
| c65b7d0aea | |||
| 54fd224fd8 | |||
| 5ca2b1200d | |||
| b5014d56ab | |||
| c4e89f8bb4 | |||
| 7dd85b207f | |||
| cb0431d960 | |||
| 58adb6a1aa | |||
| 13c564f2af | |||
| 95aeebe4b5 | |||
| 605d57c541 | |||
| f972fa26a4 | |||
| 150e18539c | |||
| f03d4cf8fd | |||
| 3419d15878 | |||
| 0da24f21d6 | |||
| e794109a67 | |||
| 006c783aba | |||
| 4378a09867 | |||
| fb24b06a5d | |||
| 425fce5070 | |||
| d5667a859a | |||
| 95dbcf2fd7 | |||
| 8ce0819b42 | |||
| 688a456642 | |||
| 59b3a3d26b | |||
| ea1cdbfdd8 | |||
| 3641926333 | |||
| 280958ee74 | |||
| f4070731a8 | |||
| e791678dfc | |||
| 6f5bbf550a | |||
| ff550b5c3c | |||
| d6daa0d05b | |||
| 86785dffa4 | |||
| c491b73f3a | |||
| c50233cc92 | |||
| 13de773486 | |||
| 4966f6de73 | |||
| 6806e3d5c7 | |||
| 0a121e9d26 | |||
| 15e8cba398 | |||
| b32eecb5a7 | |||
| 8ce0eaa9d0 | |||
| 8307f82f86 | |||
| 2b6a56c21c | |||
| f1e66085cd | |||
| d344701fd5 | |||
| 130a0ef20e | |||
| 18ca3ed449 | |||
| af6fcb19a8 | |||
| eec2dfad7b | |||
| 0fcf767ee9 | |||
| 1e7bf218e0 | |||
| 4ea7628204 | |||
| 7db77a5580 | |||
| 97ae5ab561 | |||
| 89d9813a45 | |||
| 2b52b4a749 | |||
| c479d431a4 | |||
| 8628fc441d | |||
| d48d67767a | |||
| 10caa2981f | |||
| 49610f52f5 | |||
| 27643cb715 | |||
| fe3c7926f7 | |||
| 552d8e6aec | |||
| 0bb3609cad | |||
| b56bc7e087 | |||
| abcf265bc7 | |||
| 6d3c421823 | |||
| e70f430b5a | |||
| 8c927d3cc8 | |||
| b998852385 | |||
| 59d9e7ce98 | |||
| 306593a0c5 | |||
| 3b8bce1bed | |||
| f0fd7e2e19 | |||
| 4384ae15b4 | |||
| dc8252bb9f | |||
| 182a998cb6 | |||
| ea8e435b32 | |||
| 72d1ac22aa | |||
| 8ce5392390 | |||
| 311682b341 | |||
| 44c90c060a | |||
| a5eb11d79f | |||
| 120849c734 | |||
| adf50b7c4b | |||
| f5c575961f | |||
| a90801e2aa | |||
| 402e8b12a6 | |||
| 701f7f39d6 | |||
| 6590366f8e | |||
| fa0b02ed30 | |||
| 15efb73aae | |||
| d0057c92e4 | |||
| 4078f43984 | |||
| 3d980a9f66 | |||
| a0d95a823e | |||
| 9e14d240a8 | |||
| 1393bb2caf | |||
| e9914f3004 | |||
| 073772a801 | |||
| 2babe4c236 | |||
| bbda618beb | |||
| 344c813eb1 | |||
| abaa8f855f | |||
| ea1171f624 | |||
| 1e83d2a4e9 | |||
| 443c2b920d | |||
| 953663e00b | |||
| 5185ddb8b5 | |||
| 583ed61712 | |||
| 492ed27495 | |||
| facde63460 | |||
| 494953997e | |||
| 1b89ad00e7 | |||
| 40558e7ac1 | |||
| 3bddba0c7a | |||
| 97cd641da9 | |||
| 91db4b724c | |||
| dcff8c2637 | |||
| 7a76fb1469 | |||
| 17f805ae64 | |||
| 1606f97177 | |||
| dc39a9b84f | |||
| 4ff23a9943 | |||
| a806be8bc4 | |||
| b57a9c31f0 | |||
| 95c1443e30 | |||
| 5bd5a382c0 | |||
| 1885e4345c | |||
| 2f329cf7b5 | |||
| f2d2a6b605 | |||
| 3c935f7834 | |||
| 2c8b3f05ac | |||
| e8e3a3b2a2 | |||
| ec7d243ee9 | |||
| b74c5e04f5 | |||
| 050c3e1d6b | |||
| 6d83c9cc0e | |||
| 346a1d4433 | |||
| d962bb018d | |||
| bca3a3f4ed | |||
| ffea52dc36 | |||
| 865464f607 | |||
| 73f96f48ee | |||
| 89f1248140 | |||
| 59be63167f | |||
| c628147521 | |||
| a5cff8b186 | |||
| 983547af7e | |||
| d5f7e7b179 | |||
| 2a258dc21e | |||
| ec1244bb82 | |||
| ac6e042223 | |||
| a0b387e0a9 | |||
| 4cafd5a31c | |||
| 888b520b31 | |||
| 493e57837b | |||
| bddfa76b2e | |||
| ee00fdb61b | |||
| 9b22661c19 | |||
| 0ac3dbfec9 | |||
| 56cebd99c2 | |||
| 04c3d8d1bb | |||
| 7fdf3dd760 | |||
| 1f28bee86a | |||
| aed560b630 | |||
| 871b15f6e1 | |||
| ef0faf03fd | |||
| 5226076676 | |||
| 046923d9f7 | |||
| 531eb04fd7 | |||
| f4ca6f02a1 | |||
| 3f7eba19c8 | |||
| 04ff7913b4 | |||
| 09cddc84be | |||
| 9baef8c705 | |||
| a14a358b73 | |||
| 259844f4f3 | |||
| 264df11132 | |||
| 53c8ed6a63 | |||
| f22348a9f9 | |||
| 83d71519e0 | |||
| 8ad36e2526 | |||
| 0f67c68993 | |||
| b79d236bfa | |||
| 92efaf0bba | |||
| 3b11f22062 | |||
| 6164b3d2e2 | |||
| c806da51f8 | |||
| 183aa31319 | |||
| 7b3c0a69f3 | |||
| 6b11d82dd0 | |||
| d0f1b29b39 | |||
| b8fa6fb4c4 | |||
| 22269ca0d7 | |||
| 9ea478008c | |||
| 20f1eb865b | |||
| 53212ba7a9 | |||
| 3372409590 | |||
| 4fe2951509 | |||
| ff8a94714f | |||
| b45d6fee2d | |||
| f44e696edf | |||
| 5a049322ed | |||
| 04deb97f94 | |||
| 0c3c34179e | |||
| e938ddda2c | |||
| 97e26f9d6c | |||
| bfa78870cb | |||
| ad37259ccc | |||
| 418968d974 | |||
| 89905bc1c4 | |||
| 3a96d99187 | |||
| a50ea09053 | |||
| d012abd924 | |||
| 7ed82c0791 | |||
| cf61198fe3 | |||
| 5d50602397 | |||
| 34eff440eb | |||
| 0b42cf06f8 | |||
| 4c4be331f5 | |||
| 511e9920c2 | |||
| 75c3fdcb6f | |||
| 9031c5a6e0 | |||
| 5ac6f090fc | |||
| 0d183a24be | |||
| a21790b992 | |||
| 762ceaf87e | |||
| 2620a51cc9 | |||
| f1e8739608 | |||
| b31a0115b2 | |||
| ed032dc985 | |||
| c436ef0c6f | |||
| 9db97278f3 | |||
| d3898fda57 | |||
| 36ac68b436 | |||
| cdc3ee6c1c | |||
| 6540393df5 | |||
| 3f534b33ec | |||
| 9a6aac1662 | |||
| 4c70864588 | |||
| 17c8b34088 | |||
| 7900780cea | |||
| 0eb739756e | |||
| 05364908f3 | |||
| 92d65ff3c2 | |||
| a52a16807f | |||
| 8df1d74395 | |||
| f84697ad5c | |||
| a2da187615 | |||
| d0ffbbfc4d | |||
| 460a933267 | |||
| fe9c61fe73 | |||
| 3206378ae6 | |||
| 7ce790f369 | |||
| 5db1427923 | |||
| 81eceb1728 | |||
| 639650c65a | |||
| 9d034ea4a2 | |||
| 9ff0b460a2 | |||
| 4f0125a0e9 | |||
| 54493747a8 | |||
| b48c036636 | |||
| d489b02fc1 | |||
| 595fdb2f57 | |||
| 8d56dd1969 | |||
| 44371dedd9 | |||
| fb62c297fa | |||
| 676fed7cfc | |||
| d9d354c981 | |||
| 8c8048f037 | |||
| da6760ed98 | |||
| 1d04f14a53 | |||
| 570eee3202 | |||
| ca07605835 | |||
| 46e8b4f561 | |||
| 1e4655aef6 | |||
| 3e1b76258e | |||
| a845a0395a | |||
| f0053bfc1a | |||
| 22dc2947b3 | |||
| 43fce92aa9 | |||
| 6380e67af9 | |||
| dc465df3bc | |||
| 2e88924cb9 | |||
| fee96ec92d | |||
| c39ad1ee12 | |||
| 5669c7497d | |||
| 60f8fc293d | |||
| 9134388f94 | |||
| 10820fa135 | |||
| 2f3e0044f1 | |||
| 5060c779da | |||
| 6d2cb94e3e | |||
| 85e5b077f7 | |||
| 85dd1b4ea9 | |||
| 220e86bbd1 | |||
| abc715bc5c | |||
| e1adb18491 | |||
| 2688081656 | |||
| e4abd3dc5a | |||
| c7a185d4e7 | |||
| baf96b3eb6 | |||
| 8e2b07ba9e | |||
| 0b023d4e28 | |||
| 4ffc58a8ce | |||
| c5c9ea1b21 | |||
| 3c43d8fe05 | |||
| 21f06e1074 | |||
| 875e252db3 | |||
| 610e71b71b | |||
| 73d23eb6e6 | |||
| ddfa077c3e | |||
| 006f546e7c | |||
| 1dac01498c | |||
| ae0e454fc2 | |||
| ca3ee019cc | |||
| a86a3d2fee | |||
| a917f55ef8 | |||
| 21b535b5c5 | |||
| af9e217fa4 | |||
| 9a51f22265 | |||
| 144b185802 | |||
| 3c0f6a2919 | |||
| 22c33d4fb4 | |||
| e9cdb248a0 | |||
| e8274d5a59 | |||
| 6952be5ce4 | |||
| 4317291827 | |||
| bd40430d2b | |||
| ebc4a0188a | |||
| bfa4fcf584 | |||
| 48f70fbf10 | |||
| 019d2d5dcf | |||
| 17f7f329a8 | |||
| 933737e8f0 | |||
| 47b545282e | |||
| 190822c2b2 | |||
| d000d648b0 | |||
| d257ba5156 | |||
| 9828d6146b | |||
| 9e4bec8cec | |||
| 65ead08880 | |||
| f6c6c04648 | |||
| 794378d5e9 | |||
| a5ac5a9861 | |||
| faaf28b41d | |||
| 700c540434 | |||
| c177bf7480 | |||
| bccfb1cda7 | |||
| c099bb817f | |||
| 7fe98d8d66 | |||
| d356e0d1e7 | |||
| 3ce7fd7894 | |||
| 6f42297b58 | |||
| c5aebe4564 | |||
| 841b8fad38 | |||
| ab0df0a0f5 | |||
| 27e3317449 | |||
| edc09e22b4 | |||
| b487c09d34 | |||
| 4a40ef6a19 | |||
| bcddbc15f0 | |||
| 2a19d0a579 | |||
| 9af66e22da | |||
| 715f4f0669 | |||
| e6e753f37f | |||
| e958c3cc6a | |||
| 19500ac9ad | |||
| 25dee4a78e | |||
| ee953f7953 | |||
| acee590733 | |||
| cd94d9849d | |||
| c3709fa744 | |||
| 853e2b90a3 | |||
| 995cb8125e | |||
| 01d3585bf3 | |||
| a11afe05bf | |||
| 9e4f43f4d1 | |||
| 8cdfe5952a | |||
| 0f8ca1f7c5 | |||
| fd2607ad52 | |||
| 7e1b24224d | |||
| 56c63170b9 | |||
| b41349546c | |||
| 6850533b50 | |||
| 4ce2ad54a8 | |||
| 0c85d4c0d0 | |||
| 57471f8c94 | |||
| 7e11855330 | |||
| f188589685 | |||
| 96428a7555 | |||
| d3585e1f80 | |||
| c0c86521a2 | |||
| 22f5e7a9be | |||
| 06c42bba5d | |||
| ada6db2df4 | |||
| eee5e812f7 | |||
| eb5ae94c24 | |||
| 7109fe9889 | |||
| 17557df9f4 | |||
| fab1f7d939 | |||
| 815d6f4223 | |||
| 25d73f5a70 | |||
| d633a266c1 | |||
| 938bf8624c | |||
| 2cdb46b167 | |||
| 8799eebfe1 | |||
| 70fb5712e5 | |||
| 6a51c27fde | |||
| 17f965c171 | |||
| bd21930d1a | |||
| 4df933275b | |||
| 107129f95a | |||
| e11734f971 | |||
| 3bba9708d9 | |||
| dd497625a5 | |||
| f6764767f6 | |||
| e52dd9dc6f | |||
| 03ae1481fb | |||
| 82068cf802 | |||
| ebf832214e | |||
| 4315363f4b | |||
| f073ff8fe8 | |||
| 47040be3ad | |||
| d0bb9d2b62 | |||
| cb6e536fbd | |||
| f820a7a205 | |||
| 16212854b4 | |||
| 1c6003acd5 | |||
| ef3e8d26ce | |||
| 21a1072117 | |||
| 2ce49e3674 | |||
| e58e1ebfd9 | |||
| 609182b131 | |||
| 7898ae6fe6 | |||
| a9d0ffcac1 | |||
| 824be77bba | |||
| 74c8a44d84 | |||
| 9f829b375a | |||
| da44d5f10d | |||
| be4b71b805 | |||
| b0c7ca6d1f | |||
| 4d8de282f9 | |||
| c5d39ace2b | |||
| de80a4b6c7 | |||
| 917069e31a | |||
| 3354c800d7 | |||
| bb3ac62126 | |||
| 6e25fea16a | |||
| 5e7c6853c2 | |||
| f76a011ba0 | |||
| d854a39500 | |||
| a00ebacef3 | |||
| c2f4244c4d | |||
| 7437c324c6 | |||
| 54b87b6dbb | |||
| a029a94c73 | |||
| 3157a10428 | |||
| f8d2d8ca11 | |||
| 0d8152cd4e | |||
| c37bc3c55c | |||
| 6cc0fe4221 | |||
| af1ceb1151 | |||
| c1a80b8146 | |||
| 268bcd1c7b | |||
| 42a9ac9e6c | |||
| 182b20c33d | |||
| 58e2465369 | |||
| 07a44d0ff9 | |||
| d00f882c23 | |||
| e70e534bfa | |||
| d345916241 | |||
| fe8bcac270 | |||
| 60f05fdbf3 | |||
| ad0f12c742 | |||
| 2f2a03b37b | |||
| 881e8e4723 | |||
| e1af6dc4af | |||
| 4d9533ea54 | |||
| d6623e0f22 | |||
| ab3d36f0f3 | |||
| 632af8d723 | |||
| 282b00674a | |||
| 235d12aa6b | |||
| 5d1fc546a8 | |||
| eb993781ef | |||
| 0756fd9c7e | |||
| a3e79fc105 | |||
| 84470c34db | |||
| f8dbfa1d1e | |||
| d9750e8f9f | |||
| e09c4b72c8 | |||
| 53b95fea19 | |||
| e2fd4e46f7 | |||
| 20d6664dc1 | |||
| 8ee953ef8e | |||
| 5b7ee43352 | |||
| 8add57f8e9 | |||
| bb0aaea92d | |||
| 987ede2e6c | |||
| 5fae1b3637 | |||
| cb08c53f2f | |||
| 171e4fafed | |||
| 8d2ce2815c | |||
| d91551c277 | |||
| 332f9cae77 | |||
| dc25a3fa2a | |||
| c98ec4d014 | |||
| 05dc6ad610 | |||
| 3fe8499956 | |||
| f1b1c9053c | |||
| ea4cc0b395 | |||
| be8980fc23 | |||
| e4a9c177e6 | |||
| 99be645fcc | |||
| f8920edb2e | |||
| acf51f0ead | |||
| ddd202b5ff | |||
| 78eb7e73bc | |||
| 72337f2678 | |||
| 14200c1a1f | |||
| c495ef10b0 | |||
| 3bdce6050b | |||
| c9c0d7361d | |||
| d7ffc8b4ac | |||
| b5f01372ee | |||
| bec6bde919 | |||
| 1f25924384 | |||
| 36cf5dca82 | |||
| eea12bad07 |
@@ -48,6 +48,7 @@ cmake .. \
|
||||
-DCMAKE_CXX_FLAGS="$CFLAGS" \
|
||||
-DCMAKE_AR="$AR" \
|
||||
-DCMAKE_RANLIB="$RANLIB" \
|
||||
-DUSE_SYSTEM_CURL=ON \
|
||||
-G Ninja
|
||||
|
||||
ninja; build_status=$?;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
ARTIFACT_DIR="$BUILD_ARTIFACTSTAGINGDIRECTORY"
|
||||
generate_post_data()
|
||||
{
|
||||
body=$(cat GitHubReleaseMessage.txt)
|
||||
cat <<EOF
|
||||
{
|
||||
"tag_name": "build-${BUILD_SOURCEVERSION}",
|
||||
"target_commitish": "7d09e3be30805911226241afbb14f8cdc2eb054e",
|
||||
"name": "${AVVER}",
|
||||
"body": "$body",
|
||||
"draft": false,
|
||||
"prerelease": false
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
repo_full_name="RPCS3/rpcs3-binaries-win"
|
||||
|
||||
curl -s \
|
||||
-H "Authorization: token ${RPCS3_TOKEN}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
--data "$(generate_post_data)" "https://api.github.com/repos/$repo_full_name/releases" >> release.json
|
||||
|
||||
cat release.json
|
||||
id=$(grep '"id"' release.json | cut -d ':' -f2 | head -n1 | awk '{$1=$1;print}')
|
||||
id=${id%?}
|
||||
echo ${id:?}
|
||||
|
||||
upload_file()
|
||||
{
|
||||
curl -s \
|
||||
-H "Authorization: token ${RPCS3_TOKEN}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary @"$2"/"$3" \
|
||||
"https://uploads.github.com/repos/$repo_full_name/releases/$1/assets?name=$3"
|
||||
}
|
||||
|
||||
for file in "$ARTIFACT_DIR"/*; do
|
||||
name=$(basename "$file")
|
||||
upload_file "$id" "$ARTIFACT_DIR" "$name"
|
||||
done
|
||||
@@ -18,7 +18,7 @@ QT_DECL_URL="${QT_HOST}${QT_PREFIX}qtdeclarative${QT_SUFFIX}"
|
||||
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}qttools${QT_SUFFIX}"
|
||||
LLVMLIBS_URL='https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win/llvmlibs_mt.7z'
|
||||
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/download/custom-build-win/glslanglibs_mt.7z'
|
||||
VULKAN_SDK_URL="https://www.dropbox.com/s/4xppf4rz8v2gd8x/VulkanSDK-${VULKAN_VER}-Installer.exe"
|
||||
VULKAN_SDK_URL="https://www.dropbox.com/s/kn005de7gsv5whe/VulkanSDK-1.2.154.1-Installer.exe"
|
||||
|
||||
DEP_URLS=" \
|
||||
$QT_BASE_URL \
|
||||
|
||||
+6
-3
@@ -65,10 +65,13 @@
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/curl"]
|
||||
path = 3rdparty/curl
|
||||
url = https://github.com/RipleyTom/curl.git
|
||||
url = https://github.com/curl/curl.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/wolfssl"]
|
||||
path = 3rdparty/wolfssl
|
||||
url = https://github.com/RipleyTom/wolfssl.git
|
||||
url = https://github.com/wolfSSL/wolfssl.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/flatbuffers"]
|
||||
path = 3rdparty/flatbuffers
|
||||
url = https://github.com/google/flatbuffers.git
|
||||
ignore = dirty
|
||||
|
||||
|
||||
+4
-4
@@ -10,8 +10,8 @@ jobs:
|
||||
services: docker
|
||||
cache: ccache
|
||||
compiler: gcc
|
||||
install: "docker pull rpcs3/rpcs3-travis-xenial:1.4"
|
||||
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .ci/travis.env rpcs3/rpcs3-travis-xenial:1.4 /rpcs3/.ci/build-linux.sh'
|
||||
install: "docker pull rpcs3/rpcs3-travis-xenial:1.6"
|
||||
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .ci/travis.env rpcs3/rpcs3-travis-xenial:1.6 /rpcs3/.ci/build-linux.sh'
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env:
|
||||
@@ -20,8 +20,8 @@ jobs:
|
||||
services: docker
|
||||
cache: ccache
|
||||
compiler: clang
|
||||
install: "docker pull rpcs3/rpcs3-travis-xenial:1.4"
|
||||
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .ci/travis.env rpcs3/rpcs3-travis-xenial:1.4 /rpcs3/.ci/build-linux.sh'
|
||||
install: "docker pull rpcs3/rpcs3-travis-xenial:1.6"
|
||||
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .ci/travis.env rpcs3/rpcs3-travis-xenial:1.6 /rpcs3/.ci/build-linux.sh'
|
||||
# - os: freebsd
|
||||
# compiler: clang
|
||||
# cache: ccache
|
||||
|
||||
Vendored
+3
@@ -111,6 +111,9 @@
|
||||
</PropertyGroup>
|
||||
<Import Project="..\common_default.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\common_default_macros.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
|
||||
Vendored
+73
-18
@@ -74,6 +74,9 @@ else()
|
||||
add_library(3rdparty_7z INTERFACE)
|
||||
endif()
|
||||
|
||||
add_library(3rdparty_flatbuffers INTERFACE)
|
||||
target_include_directories(3rdparty_flatbuffers INTERFACE flatbuffers/include)
|
||||
|
||||
# libPNG
|
||||
# Select the version of libpng to use, default is builtin
|
||||
if (NOT USE_SYSTEM_LIBPNG)
|
||||
@@ -103,6 +106,36 @@ endif()
|
||||
add_subdirectory(pugixml EXCLUDE_FROM_ALL)
|
||||
|
||||
|
||||
# libusb
|
||||
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
|
||||
pkg_check_modules(LIBUSB REQUIRED IMPORTED_TARGET libusb-1.0>=1.0 )
|
||||
CMAKE_DEPENDENT_OPTION( USE_SYS_LIBUSB "Use system libusb-1.0 as shared library" ON
|
||||
"LIBUSB_FOUND" OFF)
|
||||
else()
|
||||
pkg_check_modules(LIBUSB IMPORTED_TARGET libusb-1.0>=1.0 )
|
||||
CMAKE_DEPENDENT_OPTION( USE_SYS_LIBUSB "Use system libusb-1.0 as shared library" OFF
|
||||
"LIBUSB_FOUND" OFF)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
|
||||
# Always use system libusb as reference implementation isn't supported
|
||||
add_library(usb-1.0-shared INTERFACE)
|
||||
target_link_libraries(usb-1.0-shared INTERFACE PkgConfig::LIBUSB)
|
||||
elseif(MSVC)
|
||||
# Windows time.h defines timespec but doesn't add any flag for it, which makes libusb attempt to define it again
|
||||
add_definitions(-DHAVE_STRUCT_TIMESPEC=1)
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
if(USE_SYS_LIBUSB)
|
||||
# we have the system libusb and have selected to use it
|
||||
add_library(usb-1.0-shared INTERFACE)
|
||||
target_link_libraries(usb-1.0-shared INTERFACE PkgConfig::LIBUSB)
|
||||
else()
|
||||
# we don't have the system libusb, so we compile from submodule
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# hidapi
|
||||
add_library(3rdparty_hidapi INTERFACE)
|
||||
target_include_directories(3rdparty_hidapi INTERFACE hidapi/hidapi)
|
||||
@@ -130,24 +163,11 @@ else()
|
||||
endif()
|
||||
|
||||
|
||||
# libusb
|
||||
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
|
||||
# Always use system libusb as reference implementation isn't supported
|
||||
add_library(usb-1.0-static INTERFACE)
|
||||
target_link_libraries(usb-1.0-static INTERFACE usb)
|
||||
elseif(MSVC)
|
||||
# Windows time.h defines timespec but doesn't add any flag for it, which makes libusb attempt to define it again
|
||||
add_definitions(-DHAVE_STRUCT_TIMESPEC=1)
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
|
||||
# yaml-cpp
|
||||
# We don't want to install yaml-cpp but its cmake file doesn't have option
|
||||
# to disable it...
|
||||
# So we just install it to a different directory
|
||||
set(YAML_CPP_INSTALL OFF CACHE BOOL "Don't install YAML")
|
||||
set(CMAKE_INSTALL_PREFIX_OLD ${CMAKE_INSTALL_PREFIX})
|
||||
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/yaml-cpp_install)
|
||||
|
||||
@@ -161,6 +181,7 @@ set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX_OLD})
|
||||
|
||||
# xxHash
|
||||
set(XXHASH_BUNDLED_MODE ON)
|
||||
set(XXHASH_BUILD_XXHSUM OFF)
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Make xxHash build static libs")
|
||||
add_subdirectory(xxHash/cmake_unofficial EXCLUDE_FROM_ALL)
|
||||
target_include_directories(xxhash INTERFACE xxHash)
|
||||
@@ -413,23 +434,57 @@ endif()
|
||||
# LLVM
|
||||
include(llvm.cmake)
|
||||
|
||||
# WOLFSSL
|
||||
if(USE_SYSTEM_WOLFSSL)
|
||||
message("-- RPCS3: using shared wolfssl")
|
||||
find_package(WolfSSL REQUIRED)
|
||||
add_library(wolfssl INTERFACE)
|
||||
target_link_libraries(wolfssl INTERFACE WolfSSL_LIBRARIES)
|
||||
target_include_directories(wolfssl INTERFACE WolfSSL_INCLUDE_DIRS)
|
||||
else()
|
||||
SET(BUILD_TESTS NO CACHE BOOL "Build test applications")
|
||||
add_compile_definitions(HAVE_FFDHE_2048 TFM_TIMING_RESISTANT ECC_TIMING_RESISTANT
|
||||
WC_RSA_BLINDING HAVE_AESGCM WOLFSSL_SHA512 WOLFSSL_SHA384 NO_DSA HAVE_ECC TFM_ECC256 ECC_SHAMIR
|
||||
NO_RC4 NO_HC128 NO_RABBIT WOLFSSL_SHA224 WOLFSSL_SHA3 WOLFSSL_SHAKE256 HAVE_POLY1305
|
||||
HAVE_ONE_TIME_AUTH HAVE_CHACHA HAVE_HASHDRBG HAVE_TLS_EXTENSIONS HAVE_SNI HAVE_SUPPORTED_CURVES
|
||||
HAVE_EXTENDED_MASTER NO_RC4 HAVE_ENCRYPT_THEN_MAC NO_PSK NO_MD4
|
||||
WC_NO_ASYNC_THREADING OPENSSL_EXTRA WOLFSSL_DES_ECB WC_NO_HARDEN)
|
||||
set(ENABLED_HARDEN OFF CACHE BOOL "Disable Harden")
|
||||
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
|
||||
target_include_directories(wolfssl INTERFACE "wolfssl/")
|
||||
# This is needed for CURL
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfssl/options.h.in ${CMAKE_CURRENT_BINARY_DIR}/wolfssl/wolfssl/options.h)
|
||||
set(WolfSSL_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/libwolfssl.a")
|
||||
set(WolfSSL_LIBRARIES "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/libwolfssl.a")
|
||||
set(WolfSSL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/" "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/")
|
||||
set(WolfSSL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/" "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/")
|
||||
endif()
|
||||
|
||||
# CURL
|
||||
if(USE_SYSTEM_CURL)
|
||||
message("-- RPCS3: using shared libcurl")
|
||||
find_package(CURL REQUIRED)
|
||||
add_library(wolfssl-3-static INTERFACE)
|
||||
add_library(libcurl INTERFACE)
|
||||
target_link_libraries(libcurl INTERFACE CURL::libcurl)
|
||||
else()
|
||||
message("-- RPCS3: building libcurl + wolfssl submodules")
|
||||
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
|
||||
option(BUILD_CURL_EXE "Set to ON to build curl executable." OFF)
|
||||
option(CMAKE_USE_WOLFSSL "enable wolfSSL for SSL/TLS" ON)
|
||||
option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" ON)
|
||||
option(CURL_ZLIB "Set to ON to enable building curl with zlib support." OFF)
|
||||
set(CURL_CA_PATH "none" CACHE STRING "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
|
||||
add_subdirectory(curl EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# add nice ALIAS targets for ease of use
|
||||
add_library(3rdparty::libusb ALIAS usb-1.0-static)
|
||||
if(USE_SYS_LIBUSB)
|
||||
add_library(3rdparty::libusb ALIAS usb-1.0-shared)
|
||||
else()
|
||||
add_library(3rdparty::libusb ALIAS usb-1.0-static)
|
||||
endif()
|
||||
add_library(3rdparty::zlib ALIAS 3rdparty_zlib)
|
||||
add_library(3rdparty::7z ALIAS 3rdparty_7z)
|
||||
add_library(3rdparty::flatbuffers ALIAS 3rdparty_flatbuffers)
|
||||
add_library(3rdparty::pugixml ALIAS pugixml)
|
||||
add_library(3rdparty::yaml-cpp ALIAS yaml-cpp)
|
||||
add_library(3rdparty::xxhash ALIAS xxhash)
|
||||
@@ -448,5 +503,5 @@ add_library(3rdparty::vulkan ALIAS ${VULKAN_TARGET})
|
||||
add_library(3rdparty::openal ALIAS 3rdparty_openal)
|
||||
add_library(3rdparty::ffmpeg ALIAS 3rdparty_ffmpeg)
|
||||
add_library(3rdparty::glew ALIAS 3rdparty_glew)
|
||||
add_library(3rdparty::wolfssl ALIAS wolfssl-3-static)
|
||||
add_library(3rdparty::wolfssl ALIAS wolfssl)
|
||||
add_library(3rdparty::libcurl ALIAS libcurl)
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/curl updated: aa1a12cb23...9d954e49bc
+40
@@ -0,0 +1,40 @@
|
||||
/* options.h.in
|
||||
*
|
||||
* Copyright (C) 2006-2020 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
|
||||
/* default blank options for autoconf */
|
||||
|
||||
#ifndef WOLFSSL_OPTIONS_H
|
||||
#define WOLFSSL_OPTIONS_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* WOLFSSL_OPTIONS_H */
|
||||
|
||||
+1
Submodule 3rdparty/flatbuffers added at 9e7e8cbe9f
Vendored
+3
@@ -27,6 +27,9 @@
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
|
||||
Vendored
+16
-2
@@ -31,6 +31,9 @@
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
@@ -48,8 +51,8 @@
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<AdditionalIncludeDirectories>curl\include;curl\lib;wolfssl;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>HAVE_SNI;NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>curl\include;curl\lib;curl_extra;wolfssl;wolfssl\wolfssl;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>HAVE_SNI;NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;SIZEOF_LONG=4;SIZEOF_LONG_LONG=8;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
@@ -94,6 +97,7 @@
|
||||
<ClCompile Include="curl\lib\dict.c" />
|
||||
<ClCompile Include="curl\lib\doh.c" />
|
||||
<ClCompile Include="curl\lib\dotdot.c" />
|
||||
<ClCompile Include="curl\lib\dynbuf.c" />
|
||||
<ClCompile Include="curl\lib\easy.c" />
|
||||
<ClCompile Include="curl\lib\escape.c" />
|
||||
<ClCompile Include="curl\lib\file.c" />
|
||||
@@ -132,6 +136,7 @@
|
||||
<ClCompile Include="curl\lib\memdebug.c" />
|
||||
<ClCompile Include="curl\lib\mime.c" />
|
||||
<ClCompile Include="curl\lib\mprintf.c" />
|
||||
<ClCompile Include="curl\lib\mqtt.c" />
|
||||
<ClCompile Include="curl\lib\multi.c" />
|
||||
<ClCompile Include="curl\lib\netrc.c" />
|
||||
<ClCompile Include="curl\lib\non-ascii.c" />
|
||||
@@ -175,6 +180,7 @@
|
||||
<ClCompile Include="curl\lib\url.c" />
|
||||
<ClCompile Include="curl\lib\urlapi.c" />
|
||||
<ClCompile Include="curl\lib\version.c" />
|
||||
<ClCompile Include="curl\lib\version_win32.c" />
|
||||
<ClCompile Include="curl\lib\warnless.c" />
|
||||
<ClCompile Include="curl\lib\wildcard.c" />
|
||||
<ClCompile Include="curl\lib\x509asn1.c" />
|
||||
@@ -192,12 +198,14 @@
|
||||
<ClCompile Include="curl\lib\vauth\vauth.c" />
|
||||
<ClCompile Include="curl\lib\vquic\ngtcp2.c" />
|
||||
<ClCompile Include="curl\lib\vquic\quiche.c" />
|
||||
<ClCompile Include="curl\lib\vquic\vquic.c" />
|
||||
<ClCompile Include="curl\lib\vssh\libssh.c" />
|
||||
<ClCompile Include="curl\lib\vssh\libssh2.c" />
|
||||
<ClCompile Include="curl\lib\vssh\wolfssh.c" />
|
||||
<ClCompile Include="curl\lib\vtls\bearssl.c" />
|
||||
<ClCompile Include="curl\lib\vtls\gskit.c" />
|
||||
<ClCompile Include="curl\lib\vtls\gtls.c" />
|
||||
<ClCompile Include="curl\lib\vtls\keylog.c" />
|
||||
<ClCompile Include="curl\lib\vtls\mbedtls.c" />
|
||||
<ClCompile Include="curl\lib\vtls\mbedtls_threadlock.c" />
|
||||
<ClCompile Include="curl\lib\vtls\mesalink.c" />
|
||||
@@ -271,6 +279,7 @@
|
||||
<ClInclude Include="curl\lib\dict.h" />
|
||||
<ClInclude Include="curl\lib\doh.h" />
|
||||
<ClInclude Include="curl\lib\dotdot.h" />
|
||||
<ClInclude Include="curl\lib\dynbuf.h" />
|
||||
<ClInclude Include="curl\lib\easyif.h" />
|
||||
<ClInclude Include="curl\lib\escape.h" />
|
||||
<ClInclude Include="curl\lib\file.h" />
|
||||
@@ -297,6 +306,7 @@
|
||||
<ClInclude Include="curl\lib\llist.h" />
|
||||
<ClInclude Include="curl\lib\memdebug.h" />
|
||||
<ClInclude Include="curl\lib\mime.h" />
|
||||
<ClInclude Include="curl\lib\mqtt.h" />
|
||||
<ClInclude Include="curl\lib\multihandle.h" />
|
||||
<ClInclude Include="curl\lib\multiif.h" />
|
||||
<ClInclude Include="curl\lib\netrc.h" />
|
||||
@@ -316,6 +326,7 @@
|
||||
<ClInclude Include="curl\lib\setopt.h" />
|
||||
<ClInclude Include="curl\lib\setup-os400.h" />
|
||||
<ClInclude Include="curl\lib\setup-vms.h" />
|
||||
<ClInclude Include="curl\lib\setup-win32.h" />
|
||||
<ClInclude Include="curl\lib\share.h" />
|
||||
<ClInclude Include="curl\lib\sigpipe.h" />
|
||||
<ClInclude Include="curl\lib\slist.h" />
|
||||
@@ -339,6 +350,7 @@
|
||||
<ClInclude Include="curl\lib\url.h" />
|
||||
<ClInclude Include="curl\lib\urlapi-int.h" />
|
||||
<ClInclude Include="curl\lib\urldata.h" />
|
||||
<ClInclude Include="curl\lib\version_win32.h" />
|
||||
<ClInclude Include="curl\lib\warnless.h" />
|
||||
<ClInclude Include="curl\lib\wildcard.h" />
|
||||
<ClInclude Include="curl\lib\x509asn1.h" />
|
||||
@@ -347,11 +359,13 @@
|
||||
<ClInclude Include="curl\lib\vauth\vauth.h" />
|
||||
<ClInclude Include="curl\lib\vquic\ngtcp2.h" />
|
||||
<ClInclude Include="curl\lib\vquic\quiche.h" />
|
||||
<ClInclude Include="curl\lib\vquic\vquic.h" />
|
||||
<ClInclude Include="curl\lib\vssh\ssh.h" />
|
||||
<ClInclude Include="curl\lib\vssh\wolfssh.h" />
|
||||
<ClInclude Include="curl\lib\vtls\bearssl.h" />
|
||||
<ClInclude Include="curl\lib\vtls\gskit.h" />
|
||||
<ClInclude Include="curl\lib\vtls\gtls.h" />
|
||||
<ClInclude Include="curl\lib\vtls\keylog.h" />
|
||||
<ClInclude Include="curl\lib\vtls\mbedtls.h" />
|
||||
<ClInclude Include="curl\lib\vtls\mbedtls_threadlock.h" />
|
||||
<ClInclude Include="curl\lib\vtls\mesalink.h" />
|
||||
|
||||
Vendored
+4
-1
@@ -28,6 +28,9 @@
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'" Label="PropertySheets">
|
||||
@@ -97,7 +100,7 @@
|
||||
<DisableSpecificWarnings>$(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<AdditionalIncludeDirectories>$(ZLibSrcDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>$(TreatWarningAsError)</TreatWarningAsError>
|
||||
<Optimization>Full</Optimization>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/libusb updated: e782eeb251...c33990a300
Vendored
+7
-4
@@ -6,6 +6,7 @@ if (CMAKE_USE_PTHREADS_INIT)
|
||||
endif()
|
||||
|
||||
if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
add_compile_definitions(PLATFORM_WINDOWS=1)
|
||||
set(OS_WINDOWS 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
|
||||
# Enable MingW support for RC language (for CMake pre-2.8)
|
||||
@@ -22,9 +23,9 @@ if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
endif()
|
||||
|
||||
list(APPEND PLATFORM_SRC
|
||||
poll_windows.c
|
||||
events_windows.c
|
||||
windows_usbdk.c
|
||||
windows_nt_common.c
|
||||
windows_common.c
|
||||
windows_winusb.c
|
||||
threads_windows.c
|
||||
)
|
||||
@@ -36,13 +37,14 @@ if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
endif()
|
||||
elseif (APPLE)
|
||||
# Apple != OSX alone
|
||||
add_compile_definitions(PLATFORM_POSIX=1 HAVE_CLOCK_GETTIME)
|
||||
set(OS_DARWIN 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
||||
set(PLATFORM_SRC
|
||||
darwin_usb.c
|
||||
threads_posix.c
|
||||
poll_posix.c
|
||||
events_posix.c
|
||||
)
|
||||
|
||||
find_package(IOKit REQUIRED)
|
||||
@@ -72,6 +74,7 @@ int main()
|
||||
endif()
|
||||
elseif (UNIX)
|
||||
# Unix is for all *NIX systems including OSX
|
||||
add_compile_definitions(PLATFORM_POSIX=1 HAVE_CLOCK_GETTIME)
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
set(OS_LINUX 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
|
||||
@@ -79,7 +82,7 @@ elseif (UNIX)
|
||||
linux_usbfs.c
|
||||
linux_netlink.c
|
||||
threads_posix.c
|
||||
poll_posix.c
|
||||
events_posix.c
|
||||
)
|
||||
|
||||
list(APPEND LIBUSB_LIBRARIES rt)
|
||||
|
||||
Vendored
+8
-6
@@ -24,6 +24,9 @@
|
||||
<WholeProgramOptimization Condition="'$(Configuration)'=='Release'">true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
@@ -38,8 +41,9 @@
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>libusb\msvc;libusb\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WINVER=0x0600;_WIN32_WINNT=0x0600;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
</ClCompile>
|
||||
@@ -61,11 +65,11 @@
|
||||
<ClCompile Include="libusb\libusb\descriptor.c" />
|
||||
<ClCompile Include="libusb\libusb\hotplug.c" />
|
||||
<ClCompile Include="libusb\libusb\io.c" />
|
||||
<ClCompile Include="libusb\libusb\os\poll_windows.c" />
|
||||
<ClCompile Include="libusb\libusb\os\events_windows.c" />
|
||||
<ClCompile Include="libusb\libusb\strerror.c" />
|
||||
<ClCompile Include="libusb\libusb\sync.c" />
|
||||
<ClCompile Include="libusb\libusb\os\threads_windows.c" />
|
||||
<ClCompile Include="libusb\libusb\os\windows_nt_common.c" />
|
||||
<ClCompile Include="libusb\libusb\os\windows_common.c" />
|
||||
<ClCompile Include="libusb\libusb\os\windows_usbdk.c" />
|
||||
<ClCompile Include="libusb\libusb\os\windows_winusb.c" />
|
||||
</ItemGroup>
|
||||
@@ -74,13 +78,11 @@
|
||||
<ClInclude Include="libusb\libusb\hotplug.h" />
|
||||
<ClInclude Include="libusb\libusb\libusb.h" />
|
||||
<ClInclude Include="libusb\libusb\libusbi.h" />
|
||||
<ClInclude Include="libusb\libusb\os\poll_windows.h" />
|
||||
<ClInclude Include="libusb\libusb\os\events_windows.h" />
|
||||
<ClInclude Include="libusb\libusb\os\threads_windows.h" />
|
||||
<ClInclude Include="libusb\libusb\version.h" />
|
||||
<ClInclude Include="libusb\libusb\version_nano.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_common.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_nt_common.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_nt_shared_types.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_usbdk.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_winusb.h" />
|
||||
</ItemGroup>
|
||||
|
||||
Vendored
-1
@@ -11,7 +11,6 @@ if(WITH_LLVM)
|
||||
option(LLVM_INCLUDE_TESTS OFF)
|
||||
option(LLVM_INCLUDE_TOOLS OFF)
|
||||
option(LLVM_INCLUDE_UTILS OFF)
|
||||
option(WITH_POLLY OFF)
|
||||
option(LLVM_CCACHE_BUILD ON)
|
||||
|
||||
set(CXX_FLAGS_OLD ${CMAKE_CXX_FLAGS})
|
||||
|
||||
Vendored
+3
@@ -21,6 +21,9 @@
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)\3rdparty\zlib.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/wolfssl updated: f7130a4e43...39b5448601
Vendored
+5
-2
@@ -28,6 +28,9 @@
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
@@ -45,7 +48,7 @@
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>./wolfssl;./wolfssl/IDE/WIN;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_USER_SETTINGS;CYASSL_USER_SETTINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_DES_ECB;HAVE_FFDHE_2048;TFM_TIMING_RESISTANT;ECC_TIMING_RESISTANT;WC_RSA_BLINDING;HAVE_AESGCM;WOLFSSL_SHA512;WOLFSSL_SHA384;NO_DSA;HAVE_ECC;TFM_ECC256;ECC_SHAMIR;NO_RC4;NO_HC128;NO_RABBIT;WOLFSSL_SHA224;WOLFSSL_SHA3;WOLFSSL_SHAKE256;HAVE_POLY1305;HAVE_ONE_TIME_AUTH;HAVE_CHACHA;HAVE_HASHDRBG;HAVE_TLS_EXTENSIONS;HAVE_SNI;HAVE_SUPPORTED_CURVES;HAVE_EXTENDED_MASTER;NO_RC4;HAVE_ENCRYPT_THEN_MAC;NO_PSK;NO_MD4;WC_NO_ASYNC_THREADING;OPENSSL_EXTRA;WOLFSSL_USER_SETTINGS;CYASSL_USER_SETTINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
@@ -59,7 +62,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>./wolfssl;./wolfssl/IDE/WIN;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_USER_SETTINGS;CYASSL_USER_SETTINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_DES_ECB;HAVE_FFDHE_2048;TFM_TIMING_RESISTANT;NO_DSA;TFM_ECC256;NO_RC4;NO_HC128;NO_RABBIT;WOLFSSL_SHA224;WOLFSSL_SHA3;WOLFSSL_SHAKE256;HAVE_POLY1305;HAVE_ONE_TIME_AUTH;HAVE_CHACHA;HAVE_HASHDRBG;HAVE_SNI;HAVE_ENCRYPT_THEN_MAC;NO_MD4;WC_NO_ASYNC_THREADING;WOLFSSL_USER_SETTINGS;CYASSL_USER_SETTINGS;WC_NO_HARDEN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/xxHash updated: 7cc9639699...94e5f23e73
Vendored
+7
-1
@@ -27,6 +27,9 @@
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
@@ -41,7 +44,10 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="xxHash/xxhash.c" />
|
||||
|
||||
Vendored
+4
@@ -22,6 +22,9 @@
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
@@ -40,6 +43,7 @@
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
Vendored
+4
-1
@@ -31,6 +31,9 @@
|
||||
<Import Project="$(SolutionDir)\3rdparty\zlib.props" />
|
||||
<Import Project="..\common_default.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\common_default_macros.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
@@ -79,7 +82,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>$(WarningLevel)</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<Optimization>Full</Optimization>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
|
||||
+9
-9
@@ -13,7 +13,7 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
|
||||
* [Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
|
||||
* [Vulkan SDK 1.1.126+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html))
|
||||
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.14.2\msvc2017_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools-19123)**
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.14.2\msvc2017_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
|
||||
|
||||
### Linux
|
||||
|
||||
@@ -40,11 +40,11 @@ Ubuntu is usually horrendously out of date, and some packages need to be downloa
|
||||
|
||||
Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is a PPA available to work around this. Run the following:
|
||||
```
|
||||
ucodename=$(lsb_release -sc)
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.14.2-$ucodename
|
||||
. /etc/os-release
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.14.2-$UBUNTU_CODENAME
|
||||
sudo apt-get update
|
||||
. /opt/qt514/bin/qt514-env.sh >/dev/null 2>&1
|
||||
sudo apt-get install qt514-meta-minimal qt514svg
|
||||
. /opt/qt514/bin/qt514-env.sh >/dev/null 2>&1
|
||||
```
|
||||
|
||||
##### GCC 9.x installation
|
||||
@@ -62,22 +62,22 @@ You can either use `update-alternatives` to setup `gcc-9`/`g++-9` as your defaul
|
||||
|
||||
For Ubuntu systems, it is strongly recommended to use the PPA from [LunarG](https://packages.lunarg.com/) which will provide a compatible Vulkan SDK to compile RPCS3. If your Vulkan SDK is older, it can lead to compilation errors.
|
||||
```
|
||||
ucodename=$(lsb_release -sc)
|
||||
wget -qO - http://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.1.126-$ucodename.list http://packages.lunarg.com/vulkan/1.1.126/lunarg-vulkan-1.1.126-$ucodename.list
|
||||
. /etc/os-release
|
||||
wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.2.148-$UBUNTU_CODENAME.list https://packages.lunarg.com/vulkan/1.2.148/lunarg-vulkan-1.2.148-$UBUNTU_CODENAME.list
|
||||
sudo apt update
|
||||
sudo apt install vulkan-sdk
|
||||
```
|
||||
|
||||
##### CMake
|
||||
```
|
||||
. /etc/os-release
|
||||
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -
|
||||
sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -sc) main"
|
||||
sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $UBUNTU_CODENAME main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install kitware-archive-keyring
|
||||
sudo apt-key --keyring /etc/apt/trusted.gpg del C1F34CDD40CD72DA
|
||||
sudo apt-get install cmake
|
||||
|
||||
```
|
||||
|
||||
#### Fedora
|
||||
|
||||
+4
-4
@@ -492,10 +492,10 @@ template <typename T>
|
||||
using to_le_t = typename to_se<T, std::endian::big == std::endian::native>::type;
|
||||
|
||||
// BE/LE aliases for atomic_t
|
||||
template <typename T>
|
||||
using atomic_be_t = atomic_t<be_t<T>>;
|
||||
template <typename T>
|
||||
using atomic_le_t = atomic_t<le_t<T>>;
|
||||
template <typename T, std::size_t Align = alignof(T)>
|
||||
using atomic_be_t = atomic_t<be_t<T>, Align>;
|
||||
template <typename T, std::size_t Align = alignof(T)>
|
||||
using atomic_le_t = atomic_t<le_t<T>, Align>;
|
||||
|
||||
template <typename T, bool Se, std::size_t Align>
|
||||
struct fmt_unveil<se_t<T, Se, Align>, void>
|
||||
|
||||
@@ -147,7 +147,7 @@ struct bf_t : bf_base<T, N>
|
||||
|
||||
bf_t& operator &=(vtype right)
|
||||
{
|
||||
this->m_data &= static_cast<vtype>((static_cast<utype>(right) & bf_t::vmask) << bitpos);
|
||||
this->m_data &= static_cast<vtype>(((static_cast<utype>(right) & bf_t::vmask) << bitpos) | ~(bf_t::vmask << bitpos));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -203,6 +203,11 @@ namespace cfg
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void set(T value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
void from_default() override
|
||||
{
|
||||
m_value = def;
|
||||
@@ -384,7 +389,7 @@ namespace cfg
|
||||
using uint64 = uint<0, UINT64_MAX>;
|
||||
|
||||
// Simple string entry with mutex
|
||||
class string final : public _base
|
||||
class string : public _base
|
||||
{
|
||||
const std::string m_name;
|
||||
|
||||
|
||||
+190
-118
@@ -322,26 +322,12 @@ std::shared_ptr<fs::device_base> fs::set_virtual_device(const std::string& name,
|
||||
|
||||
std::string fs::get_parent_dir(const std::string& path)
|
||||
{
|
||||
// Search upper bound (set to the last character, npos for empty string)
|
||||
auto last = path.size() - 1;
|
||||
// Get (basically) processed path
|
||||
const auto real_path = fs::escape_path(path);
|
||||
|
||||
#ifdef _WIN32
|
||||
const auto& delim = "/\\";
|
||||
#else
|
||||
const auto& delim = "/";
|
||||
#endif
|
||||
const auto pos = real_path.find_last_of(delim);
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto pos = path.find_last_of(delim, last, sizeof(delim) - 1);
|
||||
|
||||
// Contiguous slashes are ignored at the end
|
||||
if (std::exchange(last, pos - 1) != pos)
|
||||
{
|
||||
// Return empty string if the path doesn't contain at least 2 elements
|
||||
return path.substr(0, pos != umax && path.find_last_not_of(delim, pos, sizeof(delim) - 1) != umax ? pos : 0);
|
||||
}
|
||||
}
|
||||
return real_path.substr(0, pos == umax ? 0 : pos);
|
||||
}
|
||||
|
||||
bool fs::stat(const std::string& path, stat_t& info)
|
||||
@@ -352,16 +338,83 @@ bool fs::stat(const std::string& path, stat_t& info)
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
||||
if (!GetFileAttributesExW(to_wchar(path).get(), GetFileExInfoStandard, &attrs))
|
||||
std::string_view epath = path;
|
||||
|
||||
// '/' and '\\' Not allowed by FindFirstFileExW at the end of path but we should allow it
|
||||
if (auto not_del = epath.find_last_not_of(delim); not_del != umax && not_del != epath.size() - 1)
|
||||
{
|
||||
epath.remove_suffix(epath.size() - 1 - not_del);
|
||||
}
|
||||
|
||||
// Handle drives specially
|
||||
if (epath.find_first_of(delim) == umax && epath.ends_with(':'))
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
||||
|
||||
// Must end with a delimiter
|
||||
if (!GetFileAttributesExW(to_wchar(std::string(epath) + '/').get(), GetFileExInfoStandard, &attrs))
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
info.is_directory = true; // Handle drives as directories
|
||||
info.is_writable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
info.size = attrs.nFileSizeLow | (u64{attrs.nFileSizeHigh} << 32);
|
||||
info.atime = to_time(attrs.ftLastAccessTime);
|
||||
info.mtime = to_time(attrs.ftLastWriteTime);
|
||||
info.ctime = info.mtime;
|
||||
|
||||
if (info.atime < info.mtime)
|
||||
info.atime = info.mtime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WIN32_FIND_DATA attrs;
|
||||
|
||||
// Allowed by FindFirstFileExW but we should not allow it
|
||||
if (epath.ends_with("*"))
|
||||
{
|
||||
g_tls_error = fs::error::noent;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto wchar_ptr = to_wchar(std::string(epath));
|
||||
const std::wstring_view wpath_view = wchar_ptr.get();
|
||||
|
||||
const HANDLE handle = FindFirstFileExW(wpath_view.data(), FindExInfoStandard, &attrs, FindExSearchNameMatch, nullptr, FIND_FIRST_EX_CASE_SENSITIVE);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
struct close_t
|
||||
{
|
||||
HANDLE handle;
|
||||
~close_t() { FindClose(handle); }
|
||||
};
|
||||
|
||||
for (close_t find_manage{handle}; attrs.cFileName != wpath_view.substr(wpath_view.find_last_of(wdelim) + 1);)
|
||||
{
|
||||
if (!FindNextFileW(handle, &attrs))
|
||||
{
|
||||
if (const DWORD err = GetLastError(); err != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
g_tls_error = to_error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_tls_error = fs::error::noent;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
info.is_directory = (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
info.is_writable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
info.size = (u64)attrs.nFileSizeLow | ((u64)attrs.nFileSizeHigh << 32);
|
||||
info.size = attrs.nFileSizeLow | (u64{attrs.nFileSizeHigh} << 32);
|
||||
info.atime = to_time(attrs.ftLastAccessTime);
|
||||
info.mtime = to_time(attrs.ftLastWriteTime);
|
||||
info.ctime = info.mtime;
|
||||
@@ -389,73 +442,19 @@ bool fs::stat(const std::string& path, stat_t& info)
|
||||
|
||||
bool fs::exists(const std::string& path)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
{
|
||||
stat_t info;
|
||||
return device->stat(path, info);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (GetFileAttributesW(to_wchar(path).get()) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
struct ::stat file_info;
|
||||
if (::stat(path.c_str(), &file_info) != 0)
|
||||
{
|
||||
g_tls_error = to_error(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
fs::stat_t info{};
|
||||
return fs::stat(path, info);
|
||||
}
|
||||
|
||||
bool fs::is_file(const std::string& path)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
fs::stat_t info{};
|
||||
if (!fs::stat(path, info))
|
||||
{
|
||||
stat_t info;
|
||||
if (!device->stat(path, info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.is_directory)
|
||||
{
|
||||
g_tls_error = error::exist;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const DWORD attrs = GetFileAttributesW(to_wchar(path).get());
|
||||
if (attrs == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
struct ::stat file_info;
|
||||
if (::stat(path.c_str(), &file_info) != 0)
|
||||
{
|
||||
g_tls_error = to_error(errno);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: correct file type check
|
||||
#ifdef _WIN32
|
||||
if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||
#else
|
||||
if (S_ISDIR(file_info.st_mode))
|
||||
#endif
|
||||
if (info.is_directory)
|
||||
{
|
||||
g_tls_error = error::exist;
|
||||
return false;
|
||||
@@ -466,44 +465,13 @@ bool fs::is_file(const std::string& path)
|
||||
|
||||
bool fs::is_dir(const std::string& path)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
fs::stat_t info{};
|
||||
if (!fs::stat(path, info))
|
||||
{
|
||||
stat_t info;
|
||||
if (!device->stat(path, info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.is_directory == false)
|
||||
{
|
||||
g_tls_error = error::exist;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const DWORD attrs = GetFileAttributesW(to_wchar(path).get());
|
||||
if (attrs == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
struct ::stat file_info;
|
||||
if (::stat(path.c_str(), &file_info) != 0)
|
||||
{
|
||||
g_tls_error = to_error(errno);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
||||
#else
|
||||
if (!S_ISDIR(file_info.st_mode))
|
||||
#endif
|
||||
if (!info.is_directory)
|
||||
{
|
||||
g_tls_error = error::exist;
|
||||
return false;
|
||||
@@ -781,7 +749,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
|
||||
// sendfile will work with non-socket output (i.e. regular file) on Linux 2.6.33+
|
||||
off_t bytes_copied = 0;
|
||||
struct ::stat fileinfo = { 0 };
|
||||
if (::fstat(input, &fileinfo) || ::sendfile(output, input, &bytes_copied, fileinfo.st_size))
|
||||
if (::fstat(input, &fileinfo) == -1 || ::sendfile(output, input, &bytes_copied, fileinfo.st_size) == -1)
|
||||
#else
|
||||
#error "Native file copy implementation is missing"
|
||||
#endif
|
||||
@@ -899,7 +867,7 @@ bool fs::utime(const std::string& path, s64 atime, s64 mtime)
|
||||
|
||||
#ifdef _WIN32
|
||||
// Open the file
|
||||
const auto handle = CreateFileW(to_wchar(path).get(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
const auto handle = CreateFileW(to_wchar(path).get(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
@@ -985,7 +953,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
disp = mode & fs::trunc ? TRUNCATE_EXISTING : OPEN_EXISTING;
|
||||
}
|
||||
|
||||
DWORD share = 0;
|
||||
DWORD share = FILE_SHARE_DELETE;
|
||||
if (!(mode & fs::unread) || !(mode & fs::write))
|
||||
{
|
||||
share |= FILE_SHARE_READ;
|
||||
@@ -993,7 +961,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
|
||||
if (!(mode & (fs::lock + fs::unread)) || !(mode & fs::write))
|
||||
{
|
||||
share |= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
share |= FILE_SHARE_WRITE;
|
||||
}
|
||||
|
||||
const HANDLE handle = CreateFileW(to_wchar(path).get(), access, share, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
@@ -1634,6 +1602,110 @@ bool fs::remove_all(const std::string& path, bool remove_root)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string fs::escape_path(std::string_view path)
|
||||
{
|
||||
std::string real; real.resize(path.size());
|
||||
|
||||
auto get_char = [&](std::size_t& from, std::size_t& to, std::size_t count)
|
||||
{
|
||||
std::memcpy(&real[to], &path[from], count);
|
||||
from += count, to += count;
|
||||
};
|
||||
|
||||
std::size_t i = 0, j = -1, pos_nondelim = 0, after_delim = 0;
|
||||
|
||||
if (i < path.size())
|
||||
{
|
||||
j = 0;
|
||||
}
|
||||
|
||||
for (; i < path.size();)
|
||||
{
|
||||
real[j] = path[i];
|
||||
#ifdef _Win32
|
||||
if (real[j] == '\\')
|
||||
{
|
||||
real[j] = '/';
|
||||
}
|
||||
#endif
|
||||
// If the current character was preceeded by a delimiter special treatment is required:
|
||||
// If another deleimiter is encountered, remove it (do not write it to output string)
|
||||
// Otherwise test if it is a "." or ".." sequence.
|
||||
if (std::exchange(after_delim, path[i] == delim[0] || path[i] == delim[1]))
|
||||
{
|
||||
if (!after_delim)
|
||||
{
|
||||
if (real[j] == '.')
|
||||
{
|
||||
if (i + 1 == path.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
get_char(i, j, 1);
|
||||
|
||||
switch (real[j])
|
||||
{
|
||||
case '.':
|
||||
{
|
||||
bool remove_element = true;
|
||||
std::size_t k = 1;
|
||||
|
||||
for (; k + i != path.size(); k++)
|
||||
{
|
||||
switch (path[i + k])
|
||||
{
|
||||
case '.': continue;
|
||||
case delim[0]: case delim[1]: break;
|
||||
default: remove_element = false; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (remove_element)
|
||||
{
|
||||
if (i == 1u)
|
||||
{
|
||||
j = pos_nondelim;
|
||||
real[j] = '\0';// Ensure termination at this posistion
|
||||
after_delim = true;
|
||||
i += k;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
get_char(i, j, k);
|
||||
continue;
|
||||
}
|
||||
case '/':
|
||||
{
|
||||
i++;
|
||||
after_delim = true;
|
||||
continue;
|
||||
}
|
||||
default: get_char(i, j, 1); continue;
|
||||
}
|
||||
}
|
||||
|
||||
pos_nondelim = j;
|
||||
get_char(i, j, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
get_char(i, j, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (j != umax && (real[j] == delim[0] || real[j] == delim[1])) j--; // Do not include a delmiter at the end
|
||||
|
||||
real.resize(j + 1);
|
||||
return real;
|
||||
}
|
||||
|
||||
u64 fs::get_dir_size(const std::string& path, u64 rounding_alignment)
|
||||
{
|
||||
u64 result = 0;
|
||||
|
||||
+9
-2
@@ -8,12 +8,15 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace fs
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static constexpr auto& delim = "/\\";
|
||||
static constexpr auto& wdelim = L"/\\";
|
||||
using native_handle = void*;
|
||||
#else
|
||||
static constexpr auto& delim = "/";
|
||||
static constexpr auto& wdelim = L"/";
|
||||
using native_handle = int;
|
||||
#endif
|
||||
|
||||
@@ -498,6 +501,9 @@ namespace fs
|
||||
// Get common cache directory
|
||||
const std::string& get_cache_dir();
|
||||
|
||||
// Get real path for comparisons (TODO: investigate std::filesystem::path::compare implementation)
|
||||
std::string escape_path(std::string_view path);
|
||||
|
||||
// Delete directory and all its contents recursively
|
||||
bool remove_all(const std::string& path, bool remove_root = true);
|
||||
|
||||
@@ -628,7 +634,8 @@ namespace fs
|
||||
template <typename... Args>
|
||||
bool write_file(const std::string& path, bs_t<fs::open_mode> mode, const Args&... args)
|
||||
{
|
||||
if (fs::file f{path, mode})
|
||||
// Always use write flag, remove read flag
|
||||
if (fs::file f{path, mode + fs::write - fs::read})
|
||||
{
|
||||
// Write args sequentially
|
||||
(f.write(args), ...);
|
||||
|
||||
+130
-599
@@ -82,7 +82,7 @@ static u8* add_jit_memory(std::size_t size, uint align)
|
||||
|
||||
if (pos == umax) [[unlikely]]
|
||||
{
|
||||
jit_log.warning("JIT: Out of memory (size=0x%x, align=0x%x, off=0x%x)", size, align, Off);
|
||||
jit_log.error("JIT: Out of memory (size=0x%x, align=0x%x, off=0x%x)", size, align, Off);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -194,56 +194,78 @@ void jit_runtime::finalize() noexcept
|
||||
std::memcpy(alloc(s_data_init.size(), 1, false), s_data_init.data(), s_data_init.size());
|
||||
}
|
||||
|
||||
asmjit::JitRuntime& asmjit::get_global_runtime()
|
||||
asmjit::Runtime& asmjit::get_global_runtime()
|
||||
{
|
||||
// 16 MiB for internal needs
|
||||
static constexpr u64 size = 1024 * 1024 * 16;
|
||||
|
||||
struct custom_runtime final : asmjit::HostRuntime
|
||||
{
|
||||
custom_runtime() noexcept
|
||||
{
|
||||
// Search starting in first 2 GiB of memory
|
||||
for (u64 addr = size;; addr += size)
|
||||
{
|
||||
if (auto ptr = utils::memory_reserve(size, reinterpret_cast<void*>(addr)))
|
||||
{
|
||||
m_pos.raw() = static_cast<std::byte*>(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize "end" pointer
|
||||
m_max = m_pos + size;
|
||||
|
||||
// Make memory writable + executable
|
||||
utils::memory_commit(m_pos, size, utils::protection::wx);
|
||||
}
|
||||
|
||||
asmjit::Error _add(void** dst, asmjit::CodeHolder* code) noexcept override
|
||||
{
|
||||
std::size_t codeSize = code->getCodeSize();
|
||||
if (!codeSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorNoCodeGenerated;
|
||||
}
|
||||
|
||||
void* p = m_pos.fetch_add(::align(codeSize, 4096));
|
||||
if (!p || m_pos > m_max) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorNoVirtualMemory;
|
||||
}
|
||||
|
||||
std::size_t relocSize = code->relocate(p);
|
||||
if (!relocSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorInvalidState;
|
||||
}
|
||||
|
||||
utils::memory_protect(p, ::align(codeSize, 4096), utils::protection::rx);
|
||||
flush(p, relocSize);
|
||||
*dst = p;
|
||||
|
||||
return asmjit::kErrorOk;
|
||||
}
|
||||
|
||||
asmjit::Error _release(void* ptr) noexcept override
|
||||
{
|
||||
return asmjit::kErrorOk;
|
||||
}
|
||||
|
||||
private:
|
||||
atomic_t<std::byte*> m_pos{};
|
||||
|
||||
std::byte* m_max{};
|
||||
};
|
||||
|
||||
// Magic static
|
||||
static asmjit::JitRuntime g_rt;
|
||||
static custom_runtime g_rt;
|
||||
return g_rt;
|
||||
}
|
||||
|
||||
void asmjit::build_transaction_enter(asmjit::X86Assembler& c, asmjit::Label fallback, const asmjit::X86Gp& ctr, uint less_than)
|
||||
{
|
||||
Label fall = c.newLabel();
|
||||
Label begin = c.newLabel();
|
||||
c.jmp(begin);
|
||||
c.bind(fall);
|
||||
|
||||
if (less_than < 65)
|
||||
{
|
||||
c.add(ctr, 1);
|
||||
c.test(x86::eax, _XABORT_RETRY);
|
||||
c.jz(fallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't repeat on explicit XABORT instruction (workaround)
|
||||
c.test(x86::eax, _XABORT_EXPLICIT);
|
||||
c.jnz(fallback);
|
||||
|
||||
// Count an attempt without RETRY flag as 65 normal attempts and continue
|
||||
c.push(x86::rax);
|
||||
c.not_(x86::eax);
|
||||
c.and_(x86::eax, _XABORT_RETRY);
|
||||
c.shl(x86::eax, 5);
|
||||
c.add(x86::eax, 1); // eax = RETRY ? 1 : 65
|
||||
c.add(ctr, x86::rax);
|
||||
c.pop(x86::rax);
|
||||
}
|
||||
|
||||
c.cmp(ctr, less_than);
|
||||
c.jae(fallback);
|
||||
c.align(kAlignCode, 16);
|
||||
c.bind(begin);
|
||||
c.xbegin(fall);
|
||||
}
|
||||
|
||||
void asmjit::build_transaction_abort(asmjit::X86Assembler& c, unsigned char code)
|
||||
{
|
||||
c.db(0xc6);
|
||||
c.db(0xf8);
|
||||
c.db(code);
|
||||
}
|
||||
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
#include <unordered_map>
|
||||
@@ -263,9 +285,9 @@ void asmjit::build_transaction_abort(asmjit::X86Assembler& c, unsigned char code
|
||||
#endif
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/ExecutionEngine/ObjectCache.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
@@ -279,290 +301,35 @@ void asmjit::build_transaction_abort(asmjit::X86Assembler& c, unsigned char code
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
class LLVMSegmentAllocator
|
||||
const bool jit_initialize = []() -> bool
|
||||
{
|
||||
public:
|
||||
// Size of virtual memory area reserved: default 512MB
|
||||
static constexpr u32 DEFAULT_SEGMENT_SIZE = 0x20000000;
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetAsmParser();
|
||||
LLVMLinkInMCJIT();
|
||||
return true;
|
||||
}();
|
||||
|
||||
LLVMSegmentAllocator()
|
||||
{
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetAsmParser();
|
||||
LLVMLinkInMCJIT();
|
||||
|
||||
// Try to reserve as much virtual memory in the first 2 GB address space beforehand, if possible.
|
||||
Segment found_segs[16];
|
||||
u32 num_segs = 0;
|
||||
#ifdef MAP_32BIT
|
||||
u64 max_size = 0x80000000u;
|
||||
while (num_segs < 16)
|
||||
{
|
||||
auto ptr = ::mmap(nullptr, max_size, PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_32BIT, -1, 0);
|
||||
if (ptr != reinterpret_cast<void*>(-1))
|
||||
found_segs[num_segs++] = Segment(ptr, static_cast<u32>(max_size));
|
||||
else if (max_size > 0x1000000)
|
||||
max_size -= 0x1000000;
|
||||
else
|
||||
break;
|
||||
}
|
||||
#else
|
||||
u64 start_addr = 0x10000000;
|
||||
while (num_segs < 16)
|
||||
{
|
||||
u64 max_addr = 0;
|
||||
u64 max_size = 0x1000000;
|
||||
for (u64 addr = start_addr; addr <= (0x80000000u - max_size); addr += 0x1000000)
|
||||
{
|
||||
for (auto curr_size = max_size; (0x80000000u - curr_size) >= addr; curr_size += 0x1000000)
|
||||
{
|
||||
if (auto ptr = utils::memory_reserve(curr_size, reinterpret_cast<void*>(addr)))
|
||||
{
|
||||
if (max_addr == 0 || max_size < curr_size)
|
||||
{
|
||||
max_addr = addr;
|
||||
max_size = curr_size;
|
||||
}
|
||||
utils::memory_release(ptr, curr_size);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_addr == 0)
|
||||
break;
|
||||
|
||||
if (auto ptr = utils::memory_reserve(max_size, reinterpret_cast<void*>(max_addr)))
|
||||
found_segs[num_segs++] = Segment(ptr, static_cast<u32>(max_size));
|
||||
|
||||
start_addr = max_addr + max_size;
|
||||
}
|
||||
#endif
|
||||
if (num_segs)
|
||||
{
|
||||
if (num_segs > 1)
|
||||
{
|
||||
m_segs.resize(num_segs);
|
||||
for (u32 i = 0; i < num_segs; i++)
|
||||
m_segs[i] = found_segs[i];
|
||||
}
|
||||
else
|
||||
m_curr = found_segs[0];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto ptr = utils::memory_reserve(DEFAULT_SEGMENT_SIZE))
|
||||
{
|
||||
m_curr.addr = static_cast<u8*>(ptr);
|
||||
m_curr.size = DEFAULT_SEGMENT_SIZE;
|
||||
m_curr.used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void* allocate(u32 size)
|
||||
{
|
||||
if (m_curr.remaining() >= size)
|
||||
return m_curr.advance(size);
|
||||
|
||||
if (reserve(size))
|
||||
return m_curr.advance(size);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool reserve(u32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
return true;
|
||||
|
||||
store_curr();
|
||||
|
||||
u32 best_idx = UINT_MAX;
|
||||
for (u32 i = 0, segs_size = ::size32(m_segs); i < segs_size; i++)
|
||||
{
|
||||
const auto seg_remaining = m_segs[i].remaining();
|
||||
if (seg_remaining < size)
|
||||
continue;
|
||||
|
||||
if (best_idx == UINT_MAX || m_segs[best_idx].remaining() > seg_remaining)
|
||||
best_idx = i;
|
||||
}
|
||||
|
||||
if (best_idx == UINT_MAX)
|
||||
{
|
||||
const auto size_to_reserve = (size > DEFAULT_SEGMENT_SIZE) ? ::align(size+4096, 4096) : DEFAULT_SEGMENT_SIZE;
|
||||
if (auto ptr = utils::memory_reserve(size_to_reserve))
|
||||
{
|
||||
best_idx = ::size32(m_segs);
|
||||
m_segs.emplace_back(ptr, size_to_reserve);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& best_seg = m_segs[best_idx];
|
||||
if (best_seg.addr != m_curr.addr)
|
||||
m_curr = best_seg;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<u64, u32> current_segment() const
|
||||
{
|
||||
return std::make_pair(reinterpret_cast<u64>(m_curr.addr), m_curr.size);
|
||||
}
|
||||
|
||||
std::pair<u64, u32> find_segment(u64 addr) const
|
||||
{
|
||||
for (const auto& seg: m_segs)
|
||||
{
|
||||
const u64 seg_addr = reinterpret_cast<u64>(seg.addr);
|
||||
if (addr < seg_addr)
|
||||
continue;
|
||||
|
||||
const auto end_addr = seg_addr + seg.size;
|
||||
if (addr < end_addr)
|
||||
return std::make_pair(seg_addr, seg.size);
|
||||
}
|
||||
|
||||
return std::make_pair(0, 0);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (m_segs.empty())
|
||||
{
|
||||
if (m_curr.addr != nullptr)
|
||||
{
|
||||
utils::memory_decommit(m_curr.addr, m_curr.size);
|
||||
m_curr.used = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (store_curr())
|
||||
m_curr = Segment();
|
||||
|
||||
auto allocated_it = std::remove_if(m_segs.begin(), m_segs.end(), [](const Segment& seg)
|
||||
{
|
||||
return reinterpret_cast<u64>(seg.addr + seg.size) > 0x80000000u;
|
||||
});
|
||||
if (allocated_it != m_segs.end())
|
||||
{
|
||||
for (auto it = allocated_it; it != m_segs.end(); ++it)
|
||||
utils::memory_release(it->addr, it->size);
|
||||
|
||||
m_segs.erase(allocated_it, m_segs.end());
|
||||
}
|
||||
|
||||
for (auto& seg : m_segs)
|
||||
{
|
||||
utils::memory_decommit(seg.addr, seg.size);
|
||||
seg.used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool store_curr()
|
||||
{
|
||||
if (m_curr.addr != nullptr)
|
||||
{
|
||||
const auto wanted_addr = m_curr.addr;
|
||||
auto existing_it = std::find_if(m_segs.begin(), m_segs.end(), [wanted_addr](const Segment& seg) { return seg.addr == wanted_addr; });
|
||||
if (existing_it != m_segs.end())
|
||||
existing_it->used = m_curr.used;
|
||||
else
|
||||
m_segs.push_back(m_curr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Segment
|
||||
{
|
||||
Segment() {}
|
||||
Segment(void* addr, u32 size)
|
||||
: addr(static_cast<u8*>(addr))
|
||||
, size(size)
|
||||
{}
|
||||
|
||||
u8* addr = nullptr;
|
||||
u32 size = 0;
|
||||
u32 used = 0;
|
||||
|
||||
u32 remaining() const
|
||||
{
|
||||
if (size > used)
|
||||
return size - used;
|
||||
|
||||
return 0;
|
||||
}
|
||||
void* advance(u32 offset)
|
||||
{
|
||||
const auto prev_used = used;
|
||||
used += offset;
|
||||
return &addr[prev_used];
|
||||
}
|
||||
};
|
||||
|
||||
Segment m_curr;
|
||||
std::vector<Segment> m_segs;
|
||||
};
|
||||
|
||||
// Memory manager mutex
|
||||
static shared_mutex s_mutex;
|
||||
// LLVM Memory allocator
|
||||
static LLVMSegmentAllocator s_alloc;
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::deque<std::pair<u64, std::vector<RUNTIME_FUNCTION>>> s_unwater;
|
||||
static std::vector<std::vector<RUNTIME_FUNCTION>> s_unwind; // .pdata
|
||||
#else
|
||||
static std::deque<std::pair<u8*, std::size_t>> s_unfire;
|
||||
#endif
|
||||
|
||||
// Reset memory manager
|
||||
extern void jit_finalize()
|
||||
// Simple memory manager
|
||||
struct MemoryManager1 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
#ifdef _WIN32
|
||||
for (auto&& unwind : s_unwind)
|
||||
{
|
||||
if (!RtlDeleteFunctionTable(unwind.data()))
|
||||
{
|
||||
jit_log.fatal("RtlDeleteFunctionTable() failed! Error %u", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
s_unwind.clear();
|
||||
#else
|
||||
for (auto&& t : s_unfire)
|
||||
{
|
||||
llvm::RTDyldMemoryManager::deregisterEHFramesInProcess(t.first, t.second);
|
||||
}
|
||||
|
||||
s_unfire.clear();
|
||||
#endif
|
||||
|
||||
s_alloc.reset();
|
||||
}
|
||||
|
||||
// Helper class
|
||||
struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
{
|
||||
std::unordered_map<std::string, u64>& m_link;
|
||||
|
||||
std::array<u8, 16>* m_tramps{};
|
||||
|
||||
u8* m_code_addr{}; // TODO
|
||||
|
||||
MemoryManager(std::unordered_map<std::string, u64>& table)
|
||||
: m_link(table)
|
||||
// 256 MiB for code or data
|
||||
static constexpr u64 c_max_size = 0x20000000 / 2;
|
||||
|
||||
// Allocation unit
|
||||
static constexpr u64 c_page_size = 4096;
|
||||
|
||||
// Reserve 512 MiB
|
||||
u8* const ptr = static_cast<u8*>(utils::memory_reserve(c_max_size * 2));
|
||||
|
||||
u64 code_ptr = 0;
|
||||
u64 data_ptr = c_max_size;
|
||||
|
||||
MemoryManager1() = default;
|
||||
|
||||
~MemoryManager1() override
|
||||
{
|
||||
utils::memory_release(ptr, c_max_size * 2);
|
||||
}
|
||||
|
||||
[[noreturn]] static void null()
|
||||
@@ -572,185 +339,64 @@ struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
|
||||
llvm::JITSymbol findSymbol(const std::string& name) override
|
||||
{
|
||||
auto& addr = m_link[name];
|
||||
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
|
||||
|
||||
// Find function address
|
||||
if (!addr)
|
||||
{
|
||||
addr = RTDyldMemoryManager::getSymbolAddress(name);
|
||||
|
||||
if (addr)
|
||||
{
|
||||
jit_log.warning("LLVM: Symbol requested: %s -> 0x%016llx", name, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_log.error("LLVM: Linkage failed: %s", name);
|
||||
addr = reinterpret_cast<u64>(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify address for small code model
|
||||
const u64 code_start = reinterpret_cast<u64>(m_code_addr);
|
||||
const s64 addr_diff = addr - code_start;
|
||||
if (addr_diff < INT_MIN || addr_diff > INT_MAX)
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// Allocate memory for trampolines
|
||||
if (m_tramps)
|
||||
{
|
||||
const s64 tramps_diff = reinterpret_cast<u64>(m_tramps) - code_start;
|
||||
if (tramps_diff < INT_MIN || tramps_diff > INT_MAX)
|
||||
m_tramps = nullptr; //previously allocated trampoline section too far away now
|
||||
}
|
||||
|
||||
if (!m_tramps)
|
||||
{
|
||||
m_tramps = reinterpret_cast<decltype(m_tramps)>(s_alloc.allocate(4096));
|
||||
utils::memory_commit(m_tramps, 4096, utils::protection::wx);
|
||||
}
|
||||
|
||||
// Create a trampoline
|
||||
auto& data = *m_tramps++;
|
||||
data[0x0] = 0xff; // JMP [rip+2]
|
||||
data[0x1] = 0x25;
|
||||
data[0x2] = 0x02;
|
||||
data[0x3] = 0x00;
|
||||
data[0x4] = 0x00;
|
||||
data[0x5] = 0x00;
|
||||
data[0x6] = 0x48; // MOV rax, imm64 (not executed)
|
||||
data[0x7] = 0xb8;
|
||||
std::memcpy(data.data() + 8, &addr, 8);
|
||||
addr = reinterpret_cast<u64>(&data);
|
||||
|
||||
// Reset pointer (memory page exhausted)
|
||||
if ((reinterpret_cast<u64>(m_tramps) % 4096) == 0)
|
||||
{
|
||||
m_tramps = nullptr;
|
||||
}
|
||||
addr = reinterpret_cast<uptr>(&null);
|
||||
}
|
||||
|
||||
return {addr, llvm::JITSymbolFlags::Exported};
|
||||
}
|
||||
|
||||
bool needsToReserveAllocationSpace() override { return true; }
|
||||
void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize, uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) override
|
||||
u8* allocate(u64& oldp, std::uintptr_t size, uint align, utils::protection prot)
|
||||
{
|
||||
const u32 wanted_code_size = ::align(static_cast<u32>(CodeSize), std::min(4096u, CodeAlign));
|
||||
const u32 wanted_rodata_size = ::align(static_cast<u32>(RODataSize), std::min(4096u, RODataAlign));
|
||||
const u32 wanted_rwdata_size = ::align(static_cast<u32>(RWDataSize), std::min(4096u, RWDataAlign));
|
||||
if (align > c_page_size)
|
||||
{
|
||||
jit_log.fatal("JIT: Unsupported alignment (size=0x%x, align=0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
const u64 olda = ::align(oldp, align);
|
||||
const u64 newp = ::align(olda + size, align);
|
||||
|
||||
// Setup segment for current module if needed
|
||||
s_alloc.reserve(wanted_code_size + wanted_rodata_size + wanted_rwdata_size);
|
||||
if ((newp - 1) / c_max_size != oldp / c_max_size)
|
||||
{
|
||||
jit_log.fatal("JIT: Out of memory (size=0x%x, align=0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((oldp - 1) / c_page_size != (newp - 1) / c_page_size)
|
||||
{
|
||||
// Allocate pages on demand
|
||||
const u64 pagea = ::align(oldp, c_page_size);
|
||||
const u64 psize = ::align(newp - pagea, c_page_size);
|
||||
utils::memory_commit(this->ptr + pagea, psize, prot);
|
||||
}
|
||||
|
||||
// Update allocation counter
|
||||
oldp = newp;
|
||||
|
||||
return this->ptr + olda;
|
||||
}
|
||||
|
||||
u8* allocateCodeSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name) override
|
||||
{
|
||||
void* ptr = nullptr;
|
||||
const u32 wanted_size = ::align(static_cast<u32>(size), 4096);
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// Simple allocation
|
||||
ptr = s_alloc.allocate(wanted_size);
|
||||
}
|
||||
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
jit_log.fatal("LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
utils::memory_commit(ptr, size, utils::protection::wx);
|
||||
m_code_addr = static_cast<u8*>(ptr);
|
||||
|
||||
jit_log.notice("LLVM: Code section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x)", sec_id, sec_name.data(), ptr, size, align);
|
||||
return static_cast<u8*>(ptr);
|
||||
return allocate(code_ptr, size, align, utils::protection::wx);
|
||||
}
|
||||
|
||||
u8* allocateDataSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
|
||||
{
|
||||
void* ptr = nullptr;
|
||||
const u32 wanted_size = ::align(static_cast<u32>(size), 4096);
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// Simple allocation
|
||||
ptr = s_alloc.allocate(wanted_size);
|
||||
}
|
||||
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
jit_log.fatal("LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!is_ro)
|
||||
{
|
||||
}
|
||||
|
||||
utils::memory_commit(ptr, size);
|
||||
|
||||
jit_log.notice("LLVM: Data section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x, %s)", sec_id, sec_name.data(), ptr, size, align, is_ro ? "ro" : "rw");
|
||||
return static_cast<u8*>(ptr);
|
||||
return allocate(data_ptr, size, align, utils::protection::rw);
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string* = nullptr) override
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// TODO: make only read-only sections read-only
|
||||
//#ifdef _WIN32
|
||||
// DWORD op;
|
||||
// VirtualProtect(s_memory, (u64)m_next - (u64)s_memory, PAGE_READONLY, &op);
|
||||
// VirtualProtect(s_code_addr, s_code_size, PAGE_EXECUTE_READ, &op);
|
||||
//#else
|
||||
// ::mprotect(s_memory, (u64)m_next - (u64)s_memory, PROT_READ);
|
||||
// ::mprotect(s_code_addr, s_code_size, PROT_READ | PROT_EXEC);
|
||||
//#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
#ifdef _WIN32
|
||||
// Fix RUNTIME_FUNCTION records (.pdata section)
|
||||
decltype(s_unwater)::value_type pdata_entry = std::move(s_unwater.front());
|
||||
s_unwater.pop_front();
|
||||
|
||||
// Use given memory segment as a BASE, compute the difference
|
||||
const u64 segment_start = pdata_entry.first;
|
||||
const u64 unwind_diff = (u64)addr - segment_start;
|
||||
|
||||
auto& pdata = pdata_entry.second;
|
||||
for (auto& rf : pdata)
|
||||
{
|
||||
rf.UnwindData += static_cast<DWORD>(unwind_diff);
|
||||
}
|
||||
|
||||
// Register .xdata UNWIND_INFO structs
|
||||
if (!RtlAddFunctionTable(pdata.data(), (DWORD)pdata.size(), segment_start))
|
||||
{
|
||||
jit_log.error("RtlAddFunctionTable() failed! Error %u", GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
s_unwind.emplace_back(std::move(pdata));
|
||||
}
|
||||
#else
|
||||
s_unfire.push_front(std::make_pair(addr, size));
|
||||
#endif
|
||||
|
||||
return RTDyldMemoryManager::registerEHFramesInProcess(addr, size);
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override
|
||||
@@ -784,14 +430,6 @@ struct MemoryManager2 : llvm::RTDyldMemoryManager
|
||||
|
||||
void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
{
|
||||
#ifndef _WIN32
|
||||
RTDyldMemoryManager::registerEHFramesInProcess(addr, size);
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
s_unfire.push_front(std::make_pair(addr, size));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override
|
||||
@@ -799,109 +437,6 @@ struct MemoryManager2 : llvm::RTDyldMemoryManager
|
||||
}
|
||||
};
|
||||
|
||||
// Simple memory manager. I promise there will be no MemoryManager4.
|
||||
struct MemoryManager3 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
std::vector<std::pair<u8*, std::size_t>> allocs;
|
||||
|
||||
MemoryManager3() = default;
|
||||
|
||||
~MemoryManager3() override
|
||||
{
|
||||
for (auto& a : allocs)
|
||||
{
|
||||
utils::memory_release(a.first, a.second);
|
||||
}
|
||||
}
|
||||
|
||||
u8* allocateCodeSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name) override
|
||||
{
|
||||
u8* r = static_cast<u8*>(utils::memory_reserve(size));
|
||||
utils::memory_commit(r, size, utils::protection::wx);
|
||||
allocs.emplace_back(r, size);
|
||||
return r;
|
||||
}
|
||||
|
||||
u8* allocateDataSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
|
||||
{
|
||||
u8* r = static_cast<u8*>(utils::memory_reserve(size));
|
||||
utils::memory_commit(r, size);
|
||||
allocs.emplace_back(r, size);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string* = nullptr) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
{
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Helper class
|
||||
struct EventListener : llvm::JITEventListener
|
||||
{
|
||||
MemoryManager& m_mem;
|
||||
|
||||
EventListener(MemoryManager& mem)
|
||||
: m_mem(mem)
|
||||
{
|
||||
}
|
||||
|
||||
void notifyObjectLoaded(ObjectKey K, const llvm::object::ObjectFile& obj, const llvm::RuntimeDyld::LoadedObjectInfo& inf) override
|
||||
{
|
||||
#ifdef _WIN32
|
||||
for (auto it = obj.section_begin(), end = obj.section_end(); it != end; ++it)
|
||||
{
|
||||
llvm::StringRef name;
|
||||
name = it->getName().get();
|
||||
|
||||
if (name == ".pdata")
|
||||
{
|
||||
llvm::StringRef data;
|
||||
data = it->getContents().get();
|
||||
|
||||
std::vector<RUNTIME_FUNCTION> rfs(data.size() / sizeof(RUNTIME_FUNCTION));
|
||||
|
||||
auto offsets = reinterpret_cast<DWORD*>(rfs.data());
|
||||
|
||||
// Initialize .pdata section using relocation info
|
||||
for (auto ri = it->relocation_begin(), end = it->relocation_end(); ri != end; ++ri)
|
||||
{
|
||||
if (ri->getType() == 3 /*R_X86_64_GOT32*/)
|
||||
{
|
||||
const u64 value = *reinterpret_cast<const DWORD*>(data.data() + ri->getOffset());
|
||||
offsets[ri->getOffset() / sizeof(DWORD)] = static_cast<DWORD>(value + ri->getSymbol()->getAddress().get());
|
||||
}
|
||||
}
|
||||
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// Use current memory segment as a BASE, compute the difference
|
||||
const u64 segment_start = s_alloc.current_segment().first;
|
||||
const u64 code_diff = reinterpret_cast<u64>(m_mem.m_code_addr) - segment_start;
|
||||
|
||||
// Fix RUNTIME_FUNCTION records (.pdata section)
|
||||
for (auto& rf : rfs)
|
||||
{
|
||||
rf.BeginAddress += static_cast<DWORD>(code_diff);
|
||||
rf.EndAddress += static_cast<DWORD>(code_diff);
|
||||
}
|
||||
|
||||
s_unwater.emplace_back(segment_start, std::move(rfs));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// Helper class
|
||||
class ObjectCache final : public llvm::ObjectCache
|
||||
{
|
||||
@@ -1104,20 +639,19 @@ std::string jit_compiler::cpu(const std::string& _cpu)
|
||||
}
|
||||
|
||||
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, const std::string& _cpu, u32 flags)
|
||||
: m_link(_link)
|
||||
, m_cpu(cpu(_cpu))
|
||||
: m_cpu(cpu(_cpu))
|
||||
{
|
||||
std::string result;
|
||||
|
||||
auto null_mod = std::make_unique<llvm::Module> ("null_", m_context);
|
||||
|
||||
if (m_link.empty())
|
||||
if (_link.empty())
|
||||
{
|
||||
std::unique_ptr<llvm::RTDyldMemoryManager> mem;
|
||||
|
||||
if (flags & 0x1)
|
||||
{
|
||||
mem = std::make_unique<MemoryManager3>();
|
||||
mem = std::make_unique<MemoryManager1>();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1138,21 +672,18 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
|
||||
else
|
||||
{
|
||||
// Primary JIT
|
||||
auto mem = std::make_unique<MemoryManager>(m_link);
|
||||
m_jit_el = std::make_unique<EventListener>(*mem);
|
||||
|
||||
m_engine.reset(llvm::EngineBuilder(std::move(null_mod))
|
||||
.setErrorStr(&result)
|
||||
.setEngineKind(llvm::EngineKind::JIT)
|
||||
.setMCJITMemoryManager(std::move(mem))
|
||||
.setMCJITMemoryManager(std::make_unique<MemoryManager1>())
|
||||
.setOptLevel(llvm::CodeGenOpt::Aggressive)
|
||||
.setCodeModel(flags & 0x2 ? llvm::CodeModel::Large : llvm::CodeModel::Small)
|
||||
.setMCPU(m_cpu)
|
||||
.create());
|
||||
|
||||
if (m_engine)
|
||||
for (auto&& [name, addr] : _link)
|
||||
{
|
||||
m_engine->RegisterJITEventListener(m_jit_el.get());
|
||||
m_engine->addGlobalMapping(name, addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+66
-18
@@ -53,18 +53,77 @@ struct jit_runtime final : asmjit::HostRuntime
|
||||
namespace asmjit
|
||||
{
|
||||
// Should only be used to build global functions
|
||||
asmjit::JitRuntime& get_global_runtime();
|
||||
asmjit::Runtime& get_global_runtime();
|
||||
|
||||
// Emit xbegin and adjacent loop, return label at xbegin
|
||||
void build_transaction_enter(X86Assembler& c, Label fallback, const X86Gp& ctr, uint less_than);
|
||||
// Emit xbegin and adjacent loop, return label at xbegin (don't use xabort please)
|
||||
template <typename F>
|
||||
[[nodiscard]] inline asmjit::Label build_transaction_enter(asmjit::X86Assembler& c, asmjit::Label fallback, F func)
|
||||
{
|
||||
Label fall = c.newLabel();
|
||||
Label begin = c.newLabel();
|
||||
c.jmp(begin);
|
||||
c.bind(fall);
|
||||
|
||||
// Emit xabort
|
||||
void build_transaction_abort(X86Assembler& c, unsigned char code);
|
||||
// Don't repeat on zero status (may indicate syscall or interrupt)
|
||||
c.test(x86::eax, x86::eax);
|
||||
c.jz(fallback);
|
||||
|
||||
// First invoked after failure (can fallback to proceed, or jump anywhere else)
|
||||
func();
|
||||
|
||||
// Other bad statuses are ignored regardless of repeat flag (TODO)
|
||||
c.align(kAlignCode, 16);
|
||||
c.bind(begin);
|
||||
return fall;
|
||||
|
||||
// xbegin should be issued manually, allows to add more check before entering transaction
|
||||
}
|
||||
|
||||
// Helper to spill RDX (EDX) register for RDTSC
|
||||
inline void build_swap_rdx_with(asmjit::X86Assembler& c, std::array<X86Gp, 4>& args, const asmjit::X86Gp& with)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
c.xchg(args[1], with);
|
||||
args[1] = with;
|
||||
#else
|
||||
c.xchg(args[2], with);
|
||||
args[2] = with;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get full RDTSC value into chosen register (clobbers rax/rdx or saves only rax with other target)
|
||||
inline void build_get_tsc(asmjit::X86Assembler& c, const asmjit::X86Gp& to = asmjit::x86::rax)
|
||||
{
|
||||
if (&to != &x86::rax && &to != &x86::rdx)
|
||||
{
|
||||
// Swap to save its contents
|
||||
c.xchg(x86::rax, to);
|
||||
}
|
||||
|
||||
c.rdtsc();
|
||||
c.shl(x86::rdx, 32);
|
||||
|
||||
if (&to == &x86::rax)
|
||||
{
|
||||
c.or_(x86::rax, x86::rdx);
|
||||
}
|
||||
else if (&to == &x86::rdx)
|
||||
{
|
||||
c.or_(x86::rdx, x86::rax);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Swap back, maybe there is more effective way to do it
|
||||
c.xchg(x86::rax, to);
|
||||
c.mov(to.r32(), to.r32());
|
||||
c.or_(to.r64(), x86::rdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build runtime function with asmjit::X86Assembler
|
||||
template <typename FT, typename F>
|
||||
FT build_function_asm(F&& builder)
|
||||
inline FT build_function_asm(F&& builder)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -89,6 +148,7 @@ FT build_function_asm(F&& builder)
|
||||
|
||||
X86Assembler compiler(&code);
|
||||
builder(std::ref(compiler), args);
|
||||
ASSERT(compiler.getLastError() == 0);
|
||||
|
||||
FT result;
|
||||
|
||||
@@ -135,15 +195,9 @@ class jit_compiler final
|
||||
// Local LLVM context
|
||||
llvm::LLVMContext m_context;
|
||||
|
||||
// JIT Event Listener
|
||||
std::unique_ptr<struct EventListener> m_jit_el;
|
||||
|
||||
// Execution instance
|
||||
std::unique_ptr<llvm::ExecutionEngine> m_engine;
|
||||
|
||||
// Link table
|
||||
std::unordered_map<std::string, u64> m_link;
|
||||
|
||||
// Arch
|
||||
std::string m_cpu;
|
||||
|
||||
@@ -182,12 +236,6 @@ public:
|
||||
|
||||
// Get CPU info
|
||||
static std::string cpu(const std::string& _cpu);
|
||||
|
||||
// Check JIT purpose
|
||||
bool is_primary() const
|
||||
{
|
||||
return !m_link.empty();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace fmt
|
||||
|
||||
+30
-12
@@ -1,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
@@ -1230,7 +1231,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
}
|
||||
};
|
||||
|
||||
if ((d_size | (d_size + addr)) >= 0x100000000ull)
|
||||
if (0x1'0000'0000ull - addr < d_size)
|
||||
{
|
||||
sig_log.error("Invalid d_size (0x%llx)", d_size);
|
||||
report_opcode();
|
||||
@@ -1240,7 +1241,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
// get length of data being accessed
|
||||
size_t a_size = get_x64_access_size(context, op, reg, d_size, i_size);
|
||||
|
||||
if ((a_size | (a_size + addr)) >= 0x100000000ull)
|
||||
if (0x1'0000'0000ull - addr < a_size)
|
||||
{
|
||||
sig_log.error("Invalid a_size (0x%llx)", a_size);
|
||||
report_opcode();
|
||||
@@ -1248,22 +1249,28 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
}
|
||||
|
||||
// check if address is RawSPU MMIO register
|
||||
if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET)
|
||||
do if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET));
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (a_size != 4 || !d_size || !i_size)
|
||||
if (!a_size || !d_size || !i_size)
|
||||
{
|
||||
sig_log.error("Invalid or unsupported instruction (op=%d, reg=%d, d_size=%lld, a_size=0x%llx, i_size=%lld)", +op, +reg, d_size, a_size, i_size);
|
||||
report_opcode();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a_size != 4)
|
||||
{
|
||||
// Might be unimplemented, such as writing MFC proxy EAL+EAH using 64-bit store
|
||||
break;
|
||||
}
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case X64OP_LOAD:
|
||||
@@ -1342,7 +1349,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
RIP(context) += i_size;
|
||||
g_tls_fault_spu++;
|
||||
return true;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (vm::check_addr(addr, std::max(1u, ::narrow<u32>(d_size)), is_writing ? vm::page_writable : vm::page_readable))
|
||||
{
|
||||
@@ -1413,11 +1420,11 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
{
|
||||
data2 = (SYS_MEMORY_PAGE_FAULT_TYPE_PPU_THREAD << 32) | cpu->id;
|
||||
}
|
||||
else
|
||||
else if (cpu->id_type() == 2)
|
||||
{
|
||||
const auto& spu = static_cast<spu_thread&>(*cpu);
|
||||
|
||||
const u64 type = spu.offset < RAW_SPU_BASE_ADDR ?
|
||||
const u64 type = spu.get_type() == spu_type::threaded ?
|
||||
SYS_MEMORY_PAGE_FAULT_TYPE_SPU_THREAD :
|
||||
SYS_MEMORY_PAGE_FAULT_TYPE_RAW_SPU;
|
||||
|
||||
@@ -1515,7 +1522,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
if (!access_violation_recovered)
|
||||
{
|
||||
vm_log.notice("\n%s", cpu->dump_all());
|
||||
vm_log.error("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
vm_log.error("Access violation %s location 0x%x (%s) [type=u%u]", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory", d_size * 8);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
@@ -1552,7 +1559,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
// Do not log any further access violations in this case.
|
||||
if (!access_violation_recovered)
|
||||
{
|
||||
vm_log.fatal("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
vm_log.fatal("Access violation %s location 0x%x (%s) [type=u%u]", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory", d_size * 8);
|
||||
}
|
||||
|
||||
while (Emu.IsPaused())
|
||||
@@ -1892,7 +1899,18 @@ void thread_base::initialize(void (*error_cb)(), bool(*wait_cb)(const void*))
|
||||
|
||||
void thread_base::notify_abort() noexcept
|
||||
{
|
||||
atomic_storage_futex::raw_notify(+m_state_notifier);
|
||||
m_signal.try_inc();
|
||||
|
||||
while (auto ptr = m_state_notifier.load())
|
||||
{
|
||||
// Since this function is not perfectly implemented, run it in a loop
|
||||
atomic_storage_futex::raw_notify(ptr);
|
||||
|
||||
if (m_state_notifier.load() == ptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool thread_base::finalize(thread_state result_state) noexcept
|
||||
@@ -1953,7 +1971,7 @@ bool thread_base::finalize(thread_state result_state) noexcept
|
||||
|
||||
void thread_base::finalize() noexcept
|
||||
{
|
||||
atomic_storage_futex::set_wait_callback([](const void*){ return true; });
|
||||
atomic_storage_futex::set_wait_callback(nullptr);
|
||||
g_tls_log_prefix = []() -> std::string { return {}; };
|
||||
thread_ctrl::g_tls_this_thread = nullptr;
|
||||
}
|
||||
|
||||
+17
-2
@@ -40,6 +40,8 @@ enum class thread_state : u32
|
||||
finished // Final state, always set at the end of thread execution
|
||||
};
|
||||
|
||||
class need_wakeup {};
|
||||
|
||||
template <class Context>
|
||||
class named_thread;
|
||||
|
||||
@@ -210,6 +212,12 @@ public:
|
||||
static_cast<thread_base&>(thread).notify();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void raw_notify(named_thread<T>& thread)
|
||||
{
|
||||
static_cast<thread_base&>(thread).notify_abort();
|
||||
}
|
||||
|
||||
// Read current state
|
||||
static inline thread_state state()
|
||||
{
|
||||
@@ -303,16 +311,18 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
|
||||
|
||||
if (_this->m_state >= thread_state::aborting)
|
||||
{
|
||||
_this->m_state_notifier.store(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
_this->m_state_notifier.release(data);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
_this->m_state_notifier.release(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
_this->m_state_notifier.store(data);
|
||||
|
||||
if (_this->m_state >= thread_state::aborting)
|
||||
{
|
||||
_this->m_state_notifier.release(nullptr);
|
||||
@@ -408,6 +418,11 @@ public:
|
||||
{
|
||||
thread::notify_abort();
|
||||
}
|
||||
|
||||
if constexpr (std::is_base_of_v<need_wakeup, Context>)
|
||||
{
|
||||
this->wake_up();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
||||
@@ -63,6 +63,17 @@ namespace utils
|
||||
#ifdef _WIN32
|
||||
return ::VirtualAlloc(use_addr, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
#else
|
||||
if (use_addr && reinterpret_cast<uptr>(use_addr) % 0x10000)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!use_addr)
|
||||
{
|
||||
// Hack: Ensure aligned 64k allocations
|
||||
size += 0x10000;
|
||||
}
|
||||
|
||||
auto ptr = ::mmap(use_addr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
|
||||
if (ptr == reinterpret_cast<void*>(-1))
|
||||
@@ -76,6 +87,20 @@ namespace utils
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!use_addr && ptr)
|
||||
{
|
||||
// Continuation of the hack above
|
||||
const auto misalign = reinterpret_cast<uptr>(ptr) % 0x10000;
|
||||
::munmap(ptr, 0x10000 - misalign);
|
||||
|
||||
if (misalign)
|
||||
{
|
||||
::munmap(static_cast<u8*>(ptr) + size - misalign, misalign);
|
||||
}
|
||||
|
||||
ptr = static_cast<u8*>(ptr) + (0x10000 - misalign);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -81,5 +81,8 @@ namespace utils
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
// Another userdata
|
||||
u64 info = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,8 +2,72 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
extern bool g_use_rtm;
|
||||
extern u64 g_rtm_tx_limit1;
|
||||
|
||||
namespace utils
|
||||
{
|
||||
// Transaction helper (result = pair of success and op result, or just bool)
|
||||
template <typename F, typename R = std::invoke_result_t<F>>
|
||||
inline auto tx_start(F op)
|
||||
{
|
||||
uint status = -1;
|
||||
|
||||
for (auto stamp0 = __rdtsc(), stamp1 = stamp0; g_use_rtm && stamp1 - stamp0 <= g_rtm_tx_limit1; stamp1 = __rdtsc())
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
__asm__ goto ("xbegin %l[retry];" ::: "memory" : retry);
|
||||
#else
|
||||
status = _xbegin();
|
||||
|
||||
if (status != _XBEGIN_STARTED) [[unlikely]]
|
||||
{
|
||||
goto retry;
|
||||
}
|
||||
#endif
|
||||
|
||||
if constexpr (std::is_void_v<R>)
|
||||
{
|
||||
std::invoke(op);
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("xend;" ::: "memory");
|
||||
#else
|
||||
_xend();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto result = std::invoke(op);
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("xend;" ::: "memory");
|
||||
#else
|
||||
_xend();
|
||||
#endif
|
||||
return std::make_pair(true, std::move(result));
|
||||
}
|
||||
|
||||
retry:
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("movl %%eax, %0;" : "=r" (status) :: "memory");
|
||||
#endif
|
||||
if (!status) [[unlikely]]
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (std::is_void_v<R>)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_pair(false, R());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Rotate helpers
|
||||
#if defined(__GNUG__)
|
||||
|
||||
|
||||
+24
-24
@@ -57,7 +57,7 @@ void fmt_class_string<patch_type>::format(std::string& out, u64 arg)
|
||||
|
||||
patch_engine::patch_engine()
|
||||
{
|
||||
const std::string patches_path = fs::get_config_dir() + "patches/";
|
||||
const std::string patches_path = get_patches_path();
|
||||
|
||||
if (!fs::create_path(patches_path))
|
||||
{
|
||||
@@ -73,7 +73,7 @@ std::string patch_engine::get_patch_config_path()
|
||||
|
||||
if (!fs::create_path(config_dir))
|
||||
{
|
||||
patch_log.error("Could not create path: %s", patch_path);
|
||||
patch_log.error("Could not create path: %s (%s)", patch_path, fs::g_tls_error);
|
||||
}
|
||||
|
||||
return patch_path;
|
||||
@@ -89,7 +89,7 @@ std::string patch_engine::get_patches_path()
|
||||
|
||||
std::string patch_engine::get_imported_patch_path()
|
||||
{
|
||||
return fs::get_config_dir() + "patches/imported_patch.yml";
|
||||
return get_patches_path() + "imported_patch.yml";
|
||||
}
|
||||
|
||||
static void append_log_message(std::stringstream* log_messages, const std::string& message)
|
||||
@@ -98,19 +98,24 @@ static void append_log_message(std::stringstream* log_messages, const std::strin
|
||||
*log_messages << message << std::endl;
|
||||
};
|
||||
|
||||
bool patch_engine::load(patch_map& patches_map, const std::string& path, bool importing, std::stringstream* log_messages)
|
||||
bool patch_engine::load(patch_map& patches_map, const std::string& path, std::string content, bool importing, std::stringstream* log_messages)
|
||||
{
|
||||
// Load patch file
|
||||
fs::file file{ path };
|
||||
|
||||
if (!file)
|
||||
if (content.empty())
|
||||
{
|
||||
// Do nothing
|
||||
return true;
|
||||
// Load patch file
|
||||
fs::file file{path};
|
||||
|
||||
if (!file)
|
||||
{
|
||||
// Do nothing
|
||||
return true;
|
||||
}
|
||||
|
||||
content = file.to_string();
|
||||
}
|
||||
|
||||
// Interpret yaml nodes
|
||||
auto [root, error] = yaml_load(file.to_string());
|
||||
auto [root, error] = yaml_load(content);
|
||||
|
||||
if (!error.empty() || !root)
|
||||
{
|
||||
@@ -543,18 +548,13 @@ bool patch_engine::read_patch_node(patch_info& info, YAML::Node node, const YAML
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
void patch_engine::append(const std::string& patch)
|
||||
{
|
||||
load(m_map, patch);
|
||||
}
|
||||
|
||||
void patch_engine::append_global_patches()
|
||||
{
|
||||
// Legacy patch.yml
|
||||
load(m_map, fs::get_config_dir() + "patch.yml");
|
||||
|
||||
// New patch.yml
|
||||
load(m_map, fs::get_config_dir() + "patches/patch.yml");
|
||||
load(m_map, get_patches_path() + "patch.yml");
|
||||
|
||||
// Imported patch.yml
|
||||
load(m_map, get_imported_patch_path());
|
||||
@@ -571,7 +571,7 @@ void patch_engine::append_title_patches(const std::string& title_id)
|
||||
load(m_map, fs::get_config_dir() + "data/" + title_id + "/patch.yml");
|
||||
|
||||
// New patch.yml
|
||||
load(m_map, fs::get_config_dir() + "patches/" + title_id + "_patch.yml");
|
||||
load(m_map, get_patches_path() + title_id + "_patch.yml");
|
||||
}
|
||||
|
||||
std::size_t patch_engine::apply(const std::string& name, u8* dst)
|
||||
@@ -801,11 +801,11 @@ std::size_t patch_engine::apply_patch(const std::string& name, u8* dst, u32 file
|
||||
|
||||
if (patch.is_legacy)
|
||||
{
|
||||
patch_log.notice("Applied legacy patch (hash='%s')(<- %d)", patch.hash, applied);
|
||||
patch_log.success("Applied legacy patch (hash='%s')(<- %d)", patch.hash, applied);
|
||||
}
|
||||
else
|
||||
{
|
||||
patch_log.notice("Applied patch (hash='%s', description='%s', author='%s', patch_version='%s', file_version='%s') (<- %d)", patch.hash, patch.description, patch.author, patch.patch_version, patch.version, applied);
|
||||
patch_log.success("Applied patch (hash='%s', description='%s', author='%s', patch_version='%s', file_version='%s') (<- %d)", patch.hash, patch.description, patch.author, patch.patch_version, patch.version, applied);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,7 +820,7 @@ void patch_engine::save_config(const patch_map& patches_map, bool enable_legacy_
|
||||
fs::file file(path, fs::rewrite);
|
||||
if (!file)
|
||||
{
|
||||
patch_log.fatal("Failed to open patch config file %s", path);
|
||||
patch_log.fatal("Failed to open patch config file %s (%s)", path, fs::g_tls_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -973,8 +973,8 @@ bool patch_engine::save_patches(const patch_map& patches, const std::string& pat
|
||||
fs::file file(path, fs::rewrite);
|
||||
if (!file)
|
||||
{
|
||||
patch_log.fatal("save_patches: Failed to open patch file %s", path);
|
||||
append_log_message(log_messages, fmt::format("Failed to open patch file %s", path));
|
||||
patch_log.fatal("save_patches: Failed to open patch file %s (%s)", path, fs::g_tls_error);
|
||||
append_log_message(log_messages, fmt::format("Failed to open patch file %s (%s)", path, fs::g_tls_error));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1059,7 +1059,7 @@ bool patch_engine::import_patches(const patch_engine::patch_map& patches, const
|
||||
{
|
||||
patch_engine::patch_map existing_patches;
|
||||
|
||||
if (load(existing_patches, path, true, log_messages))
|
||||
if (load(existing_patches, path, "", true, log_messages))
|
||||
{
|
||||
append_patches(existing_patches, patches, count, total, log_messages);
|
||||
return count == 0 || save_patches(existing_patches, path, log_messages);
|
||||
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
static std::string get_imported_patch_path();
|
||||
|
||||
// Load from file and append to specified patches map
|
||||
static bool load(patch_map& patches, const std::string& path, bool importing = false, std::stringstream* log_messages = nullptr);
|
||||
static bool load(patch_map& patches, const std::string& path, std::string content = "", bool importing = false, std::stringstream* log_messages = nullptr);
|
||||
|
||||
// Read and add a patch node to the patch info
|
||||
static bool read_patch_node(patch_info& info, YAML::Node node, const YAML::Node& root, std::stringstream* log_messages = nullptr);
|
||||
@@ -138,9 +138,6 @@ public:
|
||||
std::size_t apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr);
|
||||
|
||||
private:
|
||||
// Load from file and append to member patches map
|
||||
void append(const std::string& path);
|
||||
|
||||
// Internal: Apply patch (returns the number of entries applied)
|
||||
template <bool check_local_storage>
|
||||
std::size_t apply_patch(const std::string& name, u8* dst, u32 filesz, u32 ls_addr);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "stdafx.h"
|
||||
#include "cheat_info.h"
|
||||
#include "Config.h"
|
||||
#include "StrUtil.h"
|
||||
|
||||
LOG_CHANNEL(log_cheat, "Cheat");
|
||||
|
||||
bool cheat_info::from_str(const std::string& cheat_line)
|
||||
{
|
||||
auto cheat_vec = fmt::split(cheat_line, {"@@@"}, false);
|
||||
|
||||
s64 val64 = 0;
|
||||
if (cheat_vec.size() != 5 || !cfg::try_to_int64(&val64, cheat_vec[2], 0, cheat_type_max - 1))
|
||||
{
|
||||
log_cheat.fatal("Failed to parse cheat line");
|
||||
return false;
|
||||
}
|
||||
|
||||
game = cheat_vec[0];
|
||||
description = cheat_vec[1];
|
||||
type = cheat_type{::narrow<u8>(val64)};
|
||||
offset = std::stoul(cheat_vec[3]);
|
||||
red_script = cheat_vec[4];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string cheat_info::to_str() const
|
||||
{
|
||||
std::string cheat_str = game + "@@@" + description + "@@@" + std::to_string(static_cast<u8>(type)) + "@@@" + std::to_string(offset) + "@@@" + red_script + "@@@";
|
||||
return cheat_str;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
enum class cheat_type : u8
|
||||
{
|
||||
unsigned_8_cheat,
|
||||
unsigned_16_cheat,
|
||||
unsigned_32_cheat,
|
||||
unsigned_64_cheat,
|
||||
signed_8_cheat,
|
||||
signed_16_cheat,
|
||||
signed_32_cheat,
|
||||
signed_64_cheat,
|
||||
max
|
||||
};
|
||||
|
||||
constexpr u8 cheat_type_max = static_cast<u8>(cheat_type::max);
|
||||
|
||||
struct cheat_info
|
||||
{
|
||||
std::string game;
|
||||
std::string description;
|
||||
cheat_type type = cheat_type::max;
|
||||
u32 offset{};
|
||||
std::string red_script;
|
||||
|
||||
bool from_str(const std::string& cheat_line);
|
||||
std::string to_str() const;
|
||||
};
|
||||
+1
-1
@@ -12,7 +12,7 @@ void cond_variable::imp_wait(u32 _old, u64 _timeout) noexcept
|
||||
verify(HERE), _old;
|
||||
|
||||
// Wait with timeout
|
||||
m_value.wait<c_signal_mask>(_old, atomic_wait_timeout{_timeout > max_timeout ? UINT64_MAX : _timeout * 1000});
|
||||
m_value.wait(_old, c_signal_mask, atomic_wait_timeout{_timeout > max_timeout ? UINT64_MAX : _timeout * 1000});
|
||||
|
||||
// Cleanup
|
||||
m_value.atomic_op([](u32& value)
|
||||
|
||||
@@ -39,84 +39,6 @@ void shared_mutex::imp_unlock_shared(u32 old)
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::imp_lock_low(u32 val)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), val < c_err;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
busy_wait();
|
||||
|
||||
if (try_lock_low())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire writer lock and downgrade
|
||||
const u32 old = m_value.fetch_add(c_one);
|
||||
|
||||
if (old == 0)
|
||||
{
|
||||
lock_downgrade();
|
||||
return;
|
||||
}
|
||||
|
||||
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
|
||||
imp_wait();
|
||||
lock_downgrade();
|
||||
}
|
||||
|
||||
void shared_mutex::imp_unlock_low(u32 old)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), old - 1 < c_err;
|
||||
|
||||
// Check reader count, notify the writer if necessary
|
||||
if ((old - 1) % c_vip == 0)
|
||||
{
|
||||
imp_signal();
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::imp_lock_vip(u32 val)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), val < c_err;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
busy_wait();
|
||||
|
||||
if (try_lock_vip())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire writer lock and downgrade
|
||||
const u32 old = m_value.fetch_add(c_one);
|
||||
|
||||
if (old == 0)
|
||||
{
|
||||
lock_downgrade_to_vip();
|
||||
return;
|
||||
}
|
||||
|
||||
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
|
||||
imp_wait();
|
||||
lock_downgrade_to_vip();
|
||||
}
|
||||
|
||||
void shared_mutex::imp_unlock_vip(u32 old)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), old - 1 < c_err;
|
||||
|
||||
// Check reader count, notify the writer if necessary
|
||||
if ((old - 1) % c_one / c_vip == 0)
|
||||
{
|
||||
imp_signal();
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::imp_wait()
|
||||
{
|
||||
while (true)
|
||||
@@ -241,18 +163,3 @@ void shared_mutex::imp_lock_unlock()
|
||||
imp_wait();
|
||||
unlock();
|
||||
}
|
||||
|
||||
bool shared_mutex::downgrade_unique_vip_lock_to_low_or_unlock()
|
||||
{
|
||||
return m_value.atomic_op([](u32& value)
|
||||
{
|
||||
if (value % c_one / c_vip == 1)
|
||||
{
|
||||
value -= c_vip - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
value -= c_vip;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
+1
-117
@@ -12,17 +12,12 @@ class shared_mutex final
|
||||
c_one = 1u << 14, // Fixed-point 1.0 value (one writer, max_readers = c_one - 1)
|
||||
c_sig = 1u << 30,
|
||||
c_err = 1u << 31,
|
||||
c_vip = 1u << 7,
|
||||
};
|
||||
|
||||
atomic_t<u32> m_value{};
|
||||
|
||||
void imp_lock_shared(u32 val);
|
||||
void imp_unlock_shared(u32 old);
|
||||
void imp_lock_low(u32 val);
|
||||
void imp_unlock_low(u32 old);
|
||||
void imp_lock_vip(u32 val);
|
||||
void imp_unlock_vip(u32 old);
|
||||
void imp_wait();
|
||||
void imp_signal();
|
||||
void imp_lock(u32 val);
|
||||
@@ -88,64 +83,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_low()
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
// Conditional increment
|
||||
return value < c_vip - 1 && m_value.compare_and_swap_test(value, value + 1);
|
||||
}
|
||||
|
||||
void lock_low()
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
if (value >= c_vip - 1 || !m_value.compare_and_swap_test(value, value + 1)) [[unlikely]]
|
||||
{
|
||||
imp_lock_low(value);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_low()
|
||||
{
|
||||
// Unconditional decrement (can result in broken state)
|
||||
const u32 value = m_value.fetch_sub(1);
|
||||
|
||||
if (value >= c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock_low(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_vip()
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
// Conditional increment
|
||||
return (value < c_one - 1 || value & (c_one - c_vip)) && (value % c_vip) == 0 && m_value.compare_and_swap_test(value, value + c_vip);
|
||||
}
|
||||
|
||||
void lock_vip()
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
if ((value >= c_one - 1 && !(value & (c_one - c_vip))) || (value % c_vip) || !m_value.compare_and_swap_test(value, value + c_vip)) [[unlikely]]
|
||||
{
|
||||
imp_lock_vip(value);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_vip()
|
||||
{
|
||||
// Unconditional decrement (can result in broken state)
|
||||
const u32 value = m_value.fetch_sub(c_vip);
|
||||
|
||||
if (value >= c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock_vip(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return m_value.compare_and_swap_test(0, c_one);
|
||||
@@ -214,12 +151,6 @@ public:
|
||||
m_value -= c_one - 1;
|
||||
}
|
||||
|
||||
void lock_downgrade_to_vip()
|
||||
{
|
||||
// Convert to vip lock (can result in broken state)
|
||||
m_value -= c_one - c_vip;
|
||||
}
|
||||
|
||||
// Optimized wait for lockability without locking, relaxed
|
||||
void lock_unlock()
|
||||
{
|
||||
@@ -240,12 +171,9 @@ public:
|
||||
{
|
||||
return m_value.load() < c_one - 1;
|
||||
}
|
||||
|
||||
// Special purpose logic
|
||||
bool downgrade_unique_vip_lock_to_low_or_unlock();
|
||||
};
|
||||
|
||||
// Simplified shared (reader) lock implementation. Mutually incompatible with low_lock and vip_lock.
|
||||
// Simplified shared (reader) lock implementation.
|
||||
class reader_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
@@ -283,47 +211,3 @@ public:
|
||||
m_upgraded ? m_mutex.unlock() : m_mutex.unlock_shared();
|
||||
}
|
||||
};
|
||||
|
||||
// Special shared (reader) lock, mutually exclusive with vip locks. Mutually incompatible with normal shared (reader) lock.
|
||||
class low_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
|
||||
public:
|
||||
low_lock(const low_lock&) = delete;
|
||||
|
||||
low_lock& operator=(const low_lock&) = delete;
|
||||
|
||||
explicit low_lock(shared_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
m_mutex.lock_low();
|
||||
}
|
||||
|
||||
~low_lock()
|
||||
{
|
||||
m_mutex.unlock_low();
|
||||
}
|
||||
};
|
||||
|
||||
// Special shared (reader) lock, mutually exclusive with low locks. Mutually incompatible with normal shared (reader) lock.
|
||||
class vip_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
|
||||
public:
|
||||
vip_lock(const vip_lock&) = delete;
|
||||
|
||||
vip_lock& operator=(const vip_lock&) = delete;
|
||||
|
||||
explicit vip_lock(shared_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
m_mutex.lock_vip();
|
||||
}
|
||||
|
||||
~vip_lock()
|
||||
{
|
||||
m_mutex.unlock_vip();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -28,6 +28,12 @@ DYNAMIC_IMPORT("ntdll.dll", NtWaitForKeyedEvent, NTSTATUS(HANDLE, PVOID Key, BOO
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtReleaseKeyedEvent, NTSTATUS(HANDLE, PVOID Key, BOOLEAN Alertable, PLARGE_INTEGER Timeout));
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtWaitForSingleObject, NTSTATUS(HANDLE Handle, BOOLEAN Alertable, PLARGE_INTEGER Timeout));
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtDelayExecution, NTSTATUS(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval));
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtWaitForAlertByThreadId, NTSTATUS(PVOID Address, PLARGE_INTEGER Timeout));
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtAlertThreadByThreadId, NTSTATUS(DWORD_PTR ThreadId));
|
||||
|
||||
constexpr NTSTATUS NTSTATUS_SUCCESS = 0;
|
||||
constexpr NTSTATUS NTSTATUS_ALERTED = 0x101;
|
||||
constexpr NTSTATUS NTSTATUS_TIMEOUT = 0x102;
|
||||
#endif
|
||||
|
||||
#ifndef __linux__
|
||||
|
||||
+16
-5
@@ -64,6 +64,13 @@ bool utils::has_avx512()
|
||||
return g_value;
|
||||
}
|
||||
|
||||
bool utils::has_avx512_icl()
|
||||
{
|
||||
// Check AVX512IFMA, AVX512VBMI, AVX512VBMI2, AVX512VPOPCNTDQ, AVX512BITALG, AVX512VNNI, AVX512VPCLMULQDQ, AVX512GFNI, AVX512VAES (Icelake-client level support)
|
||||
static const bool g_value = has_avx512() && (get_cpuid(7, 0)[1] & 0x00200000) == 0x00200000 && (get_cpuid(7, 0)[2] & 0x00005f42) == 0x00005f42;
|
||||
return g_value;
|
||||
}
|
||||
|
||||
bool utils::has_xop()
|
||||
{
|
||||
static const bool g_value = has_avx() && get_cpuid(0x80000001, 0)[2] & 0x800;
|
||||
@@ -145,12 +152,16 @@ std::string utils::get_system_info()
|
||||
{
|
||||
result += " | AVX";
|
||||
|
||||
if (has_avx2())
|
||||
{
|
||||
result += '+';
|
||||
}
|
||||
|
||||
if (has_avx512())
|
||||
{
|
||||
result += "-512";
|
||||
|
||||
if (has_avx512_icl())
|
||||
{
|
||||
result += '+';
|
||||
}
|
||||
}
|
||||
else if (has_avx2())
|
||||
{
|
||||
result += '+';
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ namespace utils
|
||||
|
||||
bool has_avx512();
|
||||
|
||||
bool has_avx512_icl();
|
||||
|
||||
bool has_xop();
|
||||
|
||||
bool has_clwb();
|
||||
|
||||
+43
-5
@@ -18,7 +18,7 @@
|
||||
#include <array>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef __cpp_lib_bitops
|
||||
#if !defined(__cpp_lib_bitops) && _MSC_VER < 1928
|
||||
#define __cpp_lib_bitops
|
||||
#endif
|
||||
#endif
|
||||
@@ -94,6 +94,11 @@ namespace std
|
||||
{
|
||||
static_assert(sizeof(To) == sizeof(From), "std::bit_cast<>: incompatible type size");
|
||||
|
||||
if constexpr ((std::is_same_v<std::remove_const_t<To>, std::remove_const_t<From>> && std::is_constructible_v<To, From>) || (std::is_integral_v<From> && std::is_integral_v<To>))
|
||||
{
|
||||
return static_cast<To>(from);
|
||||
}
|
||||
|
||||
To result{};
|
||||
std::memcpy(&result, &from, sizeof(From));
|
||||
return result;
|
||||
@@ -237,7 +242,7 @@ namespace fmt
|
||||
const fmt_type_info* get_type_info();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename T, std::size_t Align>
|
||||
class atomic_t;
|
||||
|
||||
// Extract T::simple_type if available, remove cv qualifiers
|
||||
@@ -264,15 +269,21 @@ class b8
|
||||
public:
|
||||
b8() = default;
|
||||
|
||||
constexpr b8(bool value)
|
||||
constexpr b8(bool value) noexcept
|
||||
: m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr operator bool() const
|
||||
constexpr operator bool() const noexcept
|
||||
{
|
||||
return m_value != 0;
|
||||
}
|
||||
|
||||
constexpr bool set(bool value) noexcept
|
||||
{
|
||||
m_value = value;
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
@@ -293,6 +304,11 @@ struct alignas(16) u128
|
||||
{
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept
|
||||
{
|
||||
return !!(lo | hi);
|
||||
}
|
||||
|
||||
friend u128 operator+(const u128& l, const u128& r)
|
||||
{
|
||||
u128 value;
|
||||
@@ -373,6 +389,28 @@ struct alignas(16) u128
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator<<(u128 shift_value)
|
||||
{
|
||||
const u64 v0 = lo << (shift_value.lo & 63);
|
||||
const u64 v1 = __shiftleft128(lo, hi, shift_value.lo);
|
||||
|
||||
u128 value;
|
||||
value.lo = (shift_value.lo & 64) ? 0 : v0;
|
||||
value.hi = (shift_value.lo & 64) ? v0 : v1;
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator>>(u128 shift_value)
|
||||
{
|
||||
const u64 v0 = hi >> (shift_value.lo & 63);
|
||||
const u64 v1 = __shiftright128(lo, hi, shift_value.lo);
|
||||
|
||||
u128 value;
|
||||
value.lo = (shift_value.lo & 64) ? v0 : v1;
|
||||
value.hi = (shift_value.lo & 64) ? 0 : v0;
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator~() const
|
||||
{
|
||||
u128 value;
|
||||
@@ -1052,4 +1090,4 @@ inline constexpr uintmax_t ceil2(T value)
|
||||
return i + std::min<uintmax_t>(ispow2, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
Submodule Vulkan/glslang updated: bcf6a2430e...3ee5f2f1d3
@@ -38,7 +38,7 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DCMAKE_CXX_STANDARD=20 -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../glslang</CmakeCLI>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../glslang</CmakeCLI>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<NMakeBuildCommandLine>$(CmakeCLI)
|
||||
|
||||
+1
-1
Submodule Vulkan/spirv-headers updated: c0df742ec0...3fdabd0da2
+1
-1
Submodule Vulkan/spirv-tools updated: 49ca250b44...895927bd3f
@@ -38,7 +38,7 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DCMAKE_CXX_STANDARD=20 -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DSPIRV-Headers_SOURCE_DIR=$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)../spirv-headers')) ../spirv-tools</CmakeCLI>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DSPIRV-Headers_SOURCE_DIR=$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)../spirv-headers')) ../spirv-tools</CmakeCLI>
|
||||
<PropsAbsPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\common_default.props'))</PropsAbsPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
||||
@@ -96,6 +96,9 @@
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
@@ -125,6 +128,7 @@
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>ASMJIT_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">MaxSpeed</Optimization>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
||||
+9
-16
@@ -31,13 +31,13 @@ jobs:
|
||||
displayName: ccache
|
||||
|
||||
- bash: |
|
||||
docker pull --quiet rpcs3/rpcs3-travis-xenial:1.4
|
||||
docker pull --quiet rpcs3/rpcs3-travis-xenial:1.6
|
||||
docker run \
|
||||
-v $(pwd):/rpcs3 \
|
||||
--env-file .ci/travis.env \
|
||||
-v $CCACHE_DIR:/root/.ccache \
|
||||
-v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
|
||||
rpcs3/rpcs3-travis-xenial:1.4 \
|
||||
rpcs3/rpcs3-travis-xenial:1.6 \
|
||||
/rpcs3/.ci/build-linux.sh
|
||||
displayName: Docker setup and build
|
||||
|
||||
@@ -51,8 +51,8 @@ jobs:
|
||||
QT_VER: '5.14.2'
|
||||
QT_DATE: '202003291224'
|
||||
QTDIR: C:\Qt\$(QT_VER)\msvc2017_64
|
||||
VULKAN_VER: '1.2.135.0'
|
||||
VULKAN_SDK_SHA: '181b3353612c8b0fc5e1857b652d62140191ae42b98f2f0d532cf349cebfd8c6'
|
||||
VULKAN_VER: '1.2.154.1'
|
||||
VULKAN_SDK_SHA: 'b64471f3a720e649c1fae6535ea83b8c642655ebed1485bfdf15bf4d88f746d9'
|
||||
VULKAN_SDK: C:\VulkanSDK\$(VULKAN_VER)
|
||||
CACHE_DIR: ./cache
|
||||
|
||||
@@ -91,6 +91,7 @@ jobs:
|
||||
maximumCpuCount: true
|
||||
platform: x64
|
||||
configuration: 'Release - LLVM'
|
||||
msbuildArgs: '/p:VCToolsVersion=14.25.28610'
|
||||
displayName: Compile RPCS3
|
||||
|
||||
- bash: .ci/deploy-windows.sh
|
||||
@@ -100,16 +101,8 @@ jobs:
|
||||
condition: succeeded()
|
||||
artifact: RPCS3 for Windows
|
||||
|
||||
- task: GitHubRelease@1
|
||||
condition: eq(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
inputs:
|
||||
gitHubConnection: 'RPCS3-Token'
|
||||
repositoryName: 'RPCS3/rpcs3-binaries-win'
|
||||
releaseNotesFilePath: 'GitHubReleaseMessage.txt'
|
||||
action: 'create'
|
||||
target: '7d09e3be30805911226241afbb14f8cdc2eb054e'
|
||||
tagSource: 'userSpecifiedTag'
|
||||
tag: 'build-$(Build.SourceVersion)'
|
||||
title: $(AVVER)
|
||||
addChangeLog: false
|
||||
- bash: .ci/github-upload-windows.sh
|
||||
condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
displayName: Push build to GitHub
|
||||
env:
|
||||
RPCS3_TOKEN: $(RPCS3-Token)
|
||||
|
||||
Executable
+465
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
Nekotekina Theme for RPCS3 by GooseWing
|
||||
v1.0
|
||||
|
||||
Based on YoRHa Theme for RPCS3
|
||||
by Ani @ https://github.com/AniLeo
|
||||
r1 (2018.02.27)
|
||||
sorry for stealing
|
||||
*/
|
||||
|
||||
/*
|
||||
Color Scheme
|
||||
|
||||
- Kot Programs
|
||||
8c806a
|
||||
bd9d86
|
||||
c1b398
|
||||
eadfb1
|
||||
ebe4d2
|
||||
|
||||
- Light
|
||||
ffd785
|
||||
bfa163
|
||||
|
||||
- Dark
|
||||
705722
|
||||
5c471c
|
||||
4d4940
|
||||
*/
|
||||
|
||||
|
||||
/* Every widget */
|
||||
QWidget {
|
||||
font-family: SCE-PS3 Rodin LATIN;
|
||||
font-size: 9.00pt;
|
||||
|
||||
color: #ffd785;
|
||||
background: transparent;
|
||||
alternate-background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
/* Debugger: Sets font-family to default (any invalid value could be provided) */
|
||||
#debugger QListWidget, #debugger QTextEdit {
|
||||
font-family: none;
|
||||
}
|
||||
|
||||
|
||||
/* Log+TTY: Use flat dark color background with default font for better readability */
|
||||
#log_frame, #tty_frame {
|
||||
background: rgba(52, 49, 40, 0.9);
|
||||
font-size: 8.50pt;
|
||||
font-family: none;
|
||||
}
|
||||
|
||||
|
||||
/* Debugger: Restore original font size */
|
||||
#debugger QListWidget, #debugger QTextEdit {
|
||||
font-size: 9.50pt;
|
||||
}
|
||||
|
||||
|
||||
/* LLE: Style QListWidget checkboxes (QListWidget) */
|
||||
#lleList::indicator {
|
||||
border: 0.05em solid #4d4940;
|
||||
}
|
||||
#lleList::indicator::unchecked {
|
||||
background-color: #b3ac98;
|
||||
}
|
||||
#lleList::indicator::checked {
|
||||
background-color: #4d4940;
|
||||
}
|
||||
#lleList::indicator::disabled {
|
||||
background-color: #828790;
|
||||
}
|
||||
#lleList::item::selected {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Mouse Tooltips */
|
||||
QToolTip {
|
||||
background-color: #705722;
|
||||
color: #ffd785;
|
||||
border: 0.10em solid #705722;
|
||||
}
|
||||
|
||||
|
||||
/* CG Disasm and Trophy Manager: background-image doesn't work, use static color */
|
||||
QWidget#cg_disasm, QWidget#trophy_manager {
|
||||
background: #6e695c;
|
||||
}
|
||||
|
||||
|
||||
/* Main Window and Dialogs */
|
||||
QDialog, QMainWindow#main_window {
|
||||
border-image: url("GuiConfigs/kot-bg.jpg");
|
||||
}
|
||||
|
||||
|
||||
/* Table headers */
|
||||
QHeaderView::section {
|
||||
text-transform: uppercase;
|
||||
background: #bfa163;
|
||||
color: #4d4940;
|
||||
padding-left: 0.15em;
|
||||
padding-top: 0.15em;
|
||||
padding-bottom: 0.10em;
|
||||
text-transform: uppercase;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
/* All other Tabs */
|
||||
QTabBar {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
QTabBar::tab {
|
||||
background: transparent;
|
||||
padding-left: 0.50em;
|
||||
padding-right: 0.50em;
|
||||
padding-top: 0.25em;
|
||||
padding-bottom: 0.25em;
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
QTabBar::tab::selected {
|
||||
background: #705722;
|
||||
color: #ffd785;
|
||||
border-bottom-style: solid;
|
||||
}
|
||||
|
||||
|
||||
/* Settings Dialog: Tabs */
|
||||
QTabBar#tab_bar_settings {
|
||||
border-bottom: 0.05em solid #705722;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
QTabBar::tab#tab_bar_settings {
|
||||
background: transparent;
|
||||
width: 5.20em;
|
||||
padding-left: 0.50em;
|
||||
padding-right: 0.50em;
|
||||
padding-top: 0.65em;
|
||||
padding-bottom: 0.65em;
|
||||
margin-right: 0.25em;
|
||||
font-size: 10.5pt;
|
||||
font-weight: 550;
|
||||
}
|
||||
QTabBar::tab:last#tab_bar_settings {
|
||||
margin-right: 0em;
|
||||
}
|
||||
QTabBar::tab:!selected:hover#tab_bar_settings {
|
||||
background: transparent;
|
||||
color: #705722;
|
||||
}
|
||||
QTabBar::tab::selected#tab_bar_settings {
|
||||
background: #bfa163;
|
||||
color: #705722;
|
||||
border-bottom-style: solid;
|
||||
margin-top: 0.15em;
|
||||
}
|
||||
|
||||
|
||||
/* Checkboxes */
|
||||
QCheckBox::indicator {
|
||||
border-radius: 0.1em;
|
||||
border: 0.05em solid #5c471c;
|
||||
margin-top: 0.05em;
|
||||
width: 0.8em;
|
||||
height: 0.8em;
|
||||
}
|
||||
QCheckBox::indicator:checked {
|
||||
background-color: #ffd785; /* Light */
|
||||
}
|
||||
QCheckBox::indicator:unchecked {
|
||||
background-color: #705722; /* Dark */
|
||||
}
|
||||
QCheckBox::indicator::disabled {
|
||||
background-color: #828790; /* Gray */
|
||||
}
|
||||
|
||||
|
||||
/* Radio Buttons */
|
||||
QRadioButton::indicator {
|
||||
border-radius: 0.4em;
|
||||
border: 0.05em solid #5c471c;
|
||||
width: 0.8em;
|
||||
height: 0.8em;
|
||||
}
|
||||
QRadioButton::indicator:checked {
|
||||
background-color: #ffd785; /* Light */
|
||||
}
|
||||
QRadioButton::indicator:unchecked {
|
||||
background-color: #705722; /* Dark */
|
||||
}
|
||||
QRadioButton::indicator::disabled {
|
||||
background-color: #828790; /* Gray */
|
||||
}
|
||||
|
||||
|
||||
/* Combo Boxes */
|
||||
QComboBox {
|
||||
background: transparent;
|
||||
color: #ffd785;
|
||||
border: 0.05em solid #ffd785;
|
||||
border-radius: 0.15em;
|
||||
padding-bottom: 0.2em;
|
||||
padding-left: 0.4em;
|
||||
}
|
||||
QComboBox QAbstractItemView {
|
||||
background: #bfa163;
|
||||
color: #4d4940;
|
||||
}
|
||||
QComboBox::disabled {
|
||||
background: #828790;
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Group Boxes (Settings Dialog) */
|
||||
QGroupBox {
|
||||
margin-top: 1em;
|
||||
border: 0.05em solid #ffd785;
|
||||
text-transform: uppercase;
|
||||
font-size: 9.25pt;
|
||||
background-color: rgba(41,41,41,120);
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
subcontrol-position: top;
|
||||
padding: 0.3em 0.5em 0.3em 0.5em;
|
||||
color: #ffd785;
|
||||
}
|
||||
|
||||
|
||||
/* Buttons */
|
||||
QPushButton {
|
||||
background: #b89754;
|
||||
color: #292929;
|
||||
}
|
||||
QPushButton::disabled {
|
||||
background: #828790;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
|
||||
/* QSpinBox (Settings -> Emulator -> width/height) */
|
||||
/* QDoubleSpinBox (Pads -> Mouse Acceleration -> x/y) */
|
||||
QSpinBox, QDoubleSpinBox {
|
||||
background: transparent;
|
||||
/*background-color: #bfa163;*/
|
||||
border: 0.05em solid #4d4940;
|
||||
border-radius: 0.10em;
|
||||
color: #ffd785;
|
||||
}
|
||||
|
||||
|
||||
/* Styles Sliders */
|
||||
QSlider::groove:horizontal {
|
||||
border: 0.10em solid #ffd785;
|
||||
border-radius: 0.10em;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
background: #ffd785;
|
||||
width: 0.50em;
|
||||
}
|
||||
|
||||
QSlider#sizeSlider::groove:horizontal {
|
||||
border: 0.10em solid #ffd785;
|
||||
border-radius: 0.10em;
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
/* Log and Debugger borders */
|
||||
QTextEdit {
|
||||
border: 0.05em solid #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* For dock buttons to be visible */
|
||||
QDockWidget {
|
||||
background: transparent;
|
||||
text-transform: uppercase;
|
||||
color: #4d4940;
|
||||
font-weight: 500;
|
||||
}
|
||||
[floating="true"] {
|
||||
border-image: url("GuiConfigs/kot-bg.jpg");
|
||||
}
|
||||
QDockWidget::title {
|
||||
background: #bfa163;
|
||||
padding-top: 0.2em;
|
||||
}
|
||||
QDockWidget::close-button, QDockWidget::float-button {
|
||||
background-color: #bfa163;
|
||||
}
|
||||
|
||||
|
||||
/* Disable ugly borders */
|
||||
QTabWidget::pane {
|
||||
border: 0em solid #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Top menu bar */
|
||||
QMenuBar {
|
||||
height:1.50em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
QMenuBar::item {
|
||||
margin-right: 0.20em;
|
||||
margin-left: 0.20em;
|
||||
padding-left: 1.20em;
|
||||
padding-right: 1.20em;
|
||||
}
|
||||
QMenuBar::item:selected {
|
||||
background: #4d4940;
|
||||
color: #aea993;
|
||||
}
|
||||
|
||||
|
||||
QMenu {
|
||||
background: #bfa163;
|
||||
color: #4d4940;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
QMenu::item {
|
||||
padding-left: 1.5em;
|
||||
padding-right: 0.75em;
|
||||
padding-top: 0.25em;
|
||||
padding-bottom: 0.25em;
|
||||
|
||||
}
|
||||
QMenu::item:selected {
|
||||
background: #4d4940;
|
||||
color: #aea993;
|
||||
border: 0.05em solid #4d4940;
|
||||
}
|
||||
QMenu::item:disabled {
|
||||
background-color: #828790;
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Pad Settings: Controller Image */
|
||||
QLabel#l_controller {
|
||||
color: #ffd785;
|
||||
}
|
||||
|
||||
|
||||
/* Game Grid Font */
|
||||
QTableWidget#game_grid {
|
||||
font-weight: 600;
|
||||
color: #4d4940;
|
||||
text-transform: uppercase;
|
||||
selection-color: #aea993;
|
||||
}
|
||||
QTableWidget#game_grid::item:selected:active {
|
||||
selection-background-color: #4d4940;
|
||||
}
|
||||
QTableWidget#game_grid::item:selected:!active {
|
||||
selection-background-color: #615c51;
|
||||
}
|
||||
|
||||
|
||||
/* Debug UI Settings buttons */
|
||||
QLabel#color_button {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
/* Search bar on main Toolbar */
|
||||
QLineEdit#mw_searchbar {
|
||||
margin-left: 0.7em;
|
||||
color: #4d4940;
|
||||
font-size: 10.25pt;
|
||||
}
|
||||
|
||||
|
||||
/* Uniform colors in Toolbar */
|
||||
QToolButton {
|
||||
background: transparent;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
QToolButton::hover {
|
||||
background-color: #b3ac98;
|
||||
}
|
||||
|
||||
|
||||
/* Set Theme UI colors */
|
||||
QLabel#gamelist_icon_background_color {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
|
||||
/* Set Windows Taskbar Thumbnail colors */
|
||||
QLabel#thumbnail_icon_color {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
|
||||
QLabel#log_level_always {
|
||||
color: #00ffff; /* Cyan */
|
||||
}
|
||||
QLabel#log_level_fatal {
|
||||
color: #ff00ff; /* Fuchsia */
|
||||
}
|
||||
QLabel#log_level_error {
|
||||
color: #ff0000; /* Red */
|
||||
}
|
||||
QLabel#log_level_todo {
|
||||
color: #ff6000; /* Orange */
|
||||
}
|
||||
QLabel#log_level_success {
|
||||
color: #00ff00; /* Green */
|
||||
}
|
||||
QLabel#log_level_warning {
|
||||
color: #ffff00; /* Yellow */
|
||||
}
|
||||
QLabel#log_level_notice {
|
||||
color: #ffffff; /* White */
|
||||
}
|
||||
QLabel#log_level_trace {
|
||||
color: #808080; /* Gray */
|
||||
}
|
||||
QLabel#log_stack {
|
||||
color: #b3ac98; /* Light */
|
||||
}
|
||||
|
||||
/* Set TTY colors */
|
||||
#tty_frame {
|
||||
color: #b3ac98; /* Light */
|
||||
}
|
||||
|
||||
|
||||
/* Memory Viewer */
|
||||
QLabel#memory_viewer_address_panel {
|
||||
color: #0000ff; /* Font Color: Blue */
|
||||
}
|
||||
QLabel#memory_viewer_hex_panel {
|
||||
color: #4d4940; /* Font Color: Grey */
|
||||
}
|
||||
QLabel#memory_viewer_ascii_panel {
|
||||
color: #4d4940; /* Font Color: Grey */
|
||||
}
|
||||
|
||||
|
||||
/* Debugger colors */
|
||||
QLabel#debugger_frame_breakpoint {
|
||||
color: #000000; /* Font Color: Black */
|
||||
background-color: #ffff00; /* Yellow */
|
||||
}
|
||||
QLabel#debugger_frame_pc {
|
||||
color: #000000; /* Font Color: Black */
|
||||
background-color: #00ff00; /* Green */
|
||||
}
|
||||
|
||||
|
||||
/* Trophy Notification Popup */
|
||||
QWidget#trophy_notification_frame {
|
||||
background-color: #b3ac98;
|
||||
color: #4d4940;
|
||||
}
|
||||
@@ -460,10 +460,6 @@ QSpinBox:hover, QDoubleSpinBox:hover {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
QSpinBox::up-button, QSpinBox::down-button, QDoubleSpinBox::up-button, QDoubleSpinBox::down-button {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QSpinBox:disabled, QDoubleSpinBox:disabled {
|
||||
color: #455971;
|
||||
background: #26293b;
|
||||
|
||||
@@ -482,10 +482,6 @@ QSpinBox:hover, QDoubleSpinBox:hover {
|
||||
color: #455971;
|
||||
}
|
||||
|
||||
QSpinBox::up-button, QSpinBox::down-button, QDoubleSpinBox::up-button, QDoubleSpinBox::down-button {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QSpinBox:disabled, QDoubleSpinBox:disabled {
|
||||
background-color: #b3b3b3;
|
||||
color: #455971;
|
||||
|
||||
@@ -71,6 +71,22 @@ QWidget {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
/* Style QTreeWidget checkboxes */
|
||||
QTreeWidget::indicator {
|
||||
border: 0.05em solid #4d4940;
|
||||
}
|
||||
QTreeWidget::indicator::unchecked {
|
||||
background-color: #b3ac98;
|
||||
}
|
||||
QTreeWidget::indicator::checked {
|
||||
background-color: #4d4940;
|
||||
}
|
||||
QTreeWidget::indicator::disabled {
|
||||
background-color: #828790;
|
||||
}
|
||||
QTreeWidget::item::selected {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
/* Mouse Tooltips */
|
||||
QToolTip {
|
||||
@@ -80,14 +96,8 @@ QToolTip {
|
||||
}
|
||||
|
||||
|
||||
/* CG Disasm and Trophy Manager: background-image doesn't work, use static color */
|
||||
QWidget#cg_disasm, QWidget#trophy_manager {
|
||||
background: #b3ac98;
|
||||
}
|
||||
|
||||
|
||||
/* Main Window and Dialogs */
|
||||
QDialog, QMainWindow#main_window {
|
||||
/* Main Window, Dialogs and some Dialogs that are actually widgets */
|
||||
QDialog, QWidget#trophy_manager, QWidget#cg_disasm, QMainWindow#main_window {
|
||||
border-image: url("GuiConfigs/YoRHa-background.jpg");
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
+1
-1
Submodule llvm updated: f5679565d3...8c02f52a12
@@ -1,7 +1,7 @@
|
||||
REM You need cmake and python to update the project files
|
||||
REM this script relies on CWD being the path that this script is in
|
||||
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
cmake -G "Visual Studio 16 2019 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DLLVM_USE_INTEL_JITEVENTS=ON -DLLVM_ENABLE_Z3_SOLVER=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=10.0 -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm
|
||||
|
||||
RD /S /Q cmake
|
||||
RD /S /Q CMakeFiles
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
@@ -36,7 +39,7 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -Thost=x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DCMAKE_CXX_STANDARD=20 -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm</CmakeCLI>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -Thost=x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm</CmakeCLI>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<NMakePreprocessorDefinitions>
|
||||
|
||||
@@ -83,7 +83,7 @@ set_target_properties(rpcs3
|
||||
AUTOUIC ON)
|
||||
|
||||
target_link_libraries(rpcs3 rpcs3_emu rpcs3_ui)
|
||||
target_link_libraries(rpcs3 3rdparty::discord-rpc 3rdparty::qt5 3rdparty::hidapi 3rdparty::libusb)
|
||||
target_link_libraries(rpcs3 3rdparty::discord-rpc 3rdparty::qt5 3rdparty::hidapi 3rdparty::libusb 3rdparty::wolfssl)
|
||||
target_link_libraries(rpcs3 ${ADDITIONAL_LIBS})
|
||||
|
||||
# Win resource file
|
||||
@@ -107,7 +107,7 @@ if(UNIX)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(rpcs3 ws2_32.lib Winmm.lib Psapi.lib gdi32.lib setupapi.lib)
|
||||
target_link_libraries(rpcs3 ws2_32.lib Iphlpapi.lib Winmm.lib Psapi.lib gdi32.lib setupapi.lib)
|
||||
else()
|
||||
target_link_libraries(rpcs3 ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
+40
-12
@@ -576,14 +576,32 @@ int validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *
|
||||
int dev_hash_result = 0;
|
||||
|
||||
const s32 file_name_length = ::narrow<s32>(std::strlen(file_name), HERE);
|
||||
std::unique_ptr<u8[]> buf(new u8[0x30 + file_name_length]);
|
||||
const std::size_t buf_len = 0x30 + file_name_length;
|
||||
|
||||
std::unique_ptr<u8[]> buf(new u8[buf_len]);
|
||||
std::unique_ptr<u8[]> buf_lower(new u8[buf_len]);
|
||||
std::unique_ptr<u8[]> buf_upper(new u8[buf_len]);
|
||||
|
||||
// Build the title buffer (content_id + file_name).
|
||||
memcpy(buf.get(), npd->content_id, 0x30);
|
||||
memcpy(buf.get() + 0x30, file_name, file_name_length);
|
||||
std::memcpy(buf.get(), npd->content_id, 0x30);
|
||||
std::memcpy(buf.get() + 0x30, file_name, file_name_length);
|
||||
|
||||
std::memcpy(buf_lower.get(), buf.get(), buf_len);
|
||||
std::memcpy(buf_upper.get(), buf.get(), buf_len);
|
||||
|
||||
for (std::size_t i = std::basic_string_view<u8>(buf.get() + 0x30, file_name_length).find_last_of('.'); i < buf_len; i++)
|
||||
{
|
||||
const u8 c = static_cast<u8>(buf[i]);
|
||||
buf_upper[i] = std::toupper(c);
|
||||
buf_lower[i] = std::tolower(c);
|
||||
}
|
||||
|
||||
// Hash with NPDRM_OMAC_KEY_3 and compare with title_hash.
|
||||
title_hash_result = cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf.get(), 0x30 + file_name_length, npd->title_hash, 0x10);
|
||||
// Try to ignore case sensivity with file extension
|
||||
title_hash_result =
|
||||
cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf.get(), buf_len, npd->title_hash, 0x10) ||
|
||||
cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf_lower.get(), buf_len, npd->title_hash, 0x10) ||
|
||||
cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf_upper.get(), buf_len, npd->title_hash, 0x10);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
@@ -674,7 +692,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
}
|
||||
|
||||
// Perform header validation (EDAT only).
|
||||
char real_file_name[MAX_PATH];
|
||||
char real_file_name[CRYPTO_MAX_PATH];
|
||||
extract_file_name(input_file_name, real_file_name);
|
||||
if (!validate_npd_hashes(real_file_name, devklic, &NPD, verbose))
|
||||
{
|
||||
@@ -696,14 +714,20 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
// Make sure we don't have an empty RIF key.
|
||||
if (key == v128{})
|
||||
{
|
||||
edat_log.error("EDAT: A valid RAP file is needed for this EDAT file!");
|
||||
edat_log.error("EDAT: A valid RAP file is needed for this EDAT file! (local activation)");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ((NPD.license & 0x1) == 0x1) // Type 1: Use network activation.
|
||||
{
|
||||
edat_log.error("EDAT: Network license not supported!");
|
||||
return 1;
|
||||
memcpy(&key, rifkey, 0x10);
|
||||
|
||||
// Make sure we don't have an empty RIF key.
|
||||
if (key == v128{})
|
||||
{
|
||||
edat_log.error("EDAT: A valid RAP file is needed for this EDAT file! (network activation)");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
@@ -774,7 +798,7 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
|
||||
}
|
||||
|
||||
// Perform header validation (EDAT only).
|
||||
char real_file_name[MAX_PATH];
|
||||
char real_file_name[CRYPTO_MAX_PATH];
|
||||
extract_file_name(input_file_name.c_str(), real_file_name);
|
||||
if (!validate_npd_hashes(real_file_name, custom_klic, &NPD, false))
|
||||
{
|
||||
@@ -898,13 +922,17 @@ bool EDATADecrypter::ReadHeader()
|
||||
|
||||
if (dec_key == v128{})
|
||||
{
|
||||
edat_log.warning("EDAT: Empty Dec key!");
|
||||
edat_log.warning("EDAT: Empty Dec key for local actívation!");
|
||||
}
|
||||
}
|
||||
else if ((npdHeader.license & 0x1) == 0x1) // Type 1: Use network activation.
|
||||
{
|
||||
edat_log.error("EDAT: Network license not supported!");
|
||||
return false;
|
||||
dec_key = std::move(rif_key);
|
||||
|
||||
if (dec_key == v128{})
|
||||
{
|
||||
edat_log.warning("EDAT: Empty Dec key for network activation!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -535,7 +535,7 @@ package_error package_reader::check_target_app_version()
|
||||
const auto category = psf::get_string(psf, "CATEGORY", "");
|
||||
const auto title_id = psf::get_string(psf, "TITLE_ID", "");
|
||||
const auto app_ver = psf::get_string(psf, "APP_VER", "");
|
||||
auto target_app_ver = psf::get_string(psf, "TARGET_APP_VER", "");
|
||||
const auto target_app_ver = psf::get_string(psf, "TARGET_APP_VER", "");
|
||||
|
||||
if (category != "GD")
|
||||
{
|
||||
@@ -561,7 +561,7 @@ package_error package_reader::check_target_app_version()
|
||||
return package_error::no_error;
|
||||
}
|
||||
|
||||
const fs::file installed_sfo_file(Emu.GetHddDir() + "game/" + title_id + "/PARAM.SFO");
|
||||
const fs::file installed_sfo_file(Emu.GetHddDir() + "game/" + std::string(title_id) + "/PARAM.SFO");
|
||||
if (!installed_sfo_file)
|
||||
{
|
||||
if (!target_app_ver.empty())
|
||||
@@ -587,9 +587,9 @@ package_error package_reader::check_target_app_version()
|
||||
}
|
||||
|
||||
std::add_pointer_t<char> ev0, ev1;
|
||||
const double old_version = std::strtod(installed_app_ver.c_str(), &ev0);
|
||||
const double old_version = std::strtod(installed_app_ver.data(), &ev0);
|
||||
|
||||
if (installed_app_ver.c_str() + installed_app_ver.size() != ev0)
|
||||
if (installed_app_ver.data() + installed_app_ver.size() != ev0)
|
||||
{
|
||||
pkg_log.error("Failed to convert the installed app version to double (%s)", installed_app_ver);
|
||||
return package_error::other;
|
||||
@@ -599,9 +599,9 @@ package_error package_reader::check_target_app_version()
|
||||
{
|
||||
// This is most likely the first patch. Let's make sure its version is high enough for the installed game.
|
||||
|
||||
const double new_version = std::strtod(app_ver.c_str(), &ev1);
|
||||
const double new_version = std::strtod(app_ver.data(), &ev1);
|
||||
|
||||
if (app_ver.c_str() + app_ver.size() != ev1)
|
||||
if (app_ver.data() + app_ver.size() != ev1)
|
||||
{
|
||||
pkg_log.error("Failed to convert the package's app version to double (%s)", app_ver);
|
||||
return package_error::other;
|
||||
@@ -619,9 +619,9 @@ package_error package_reader::check_target_app_version()
|
||||
|
||||
// Check if the installed app version matches the target app version
|
||||
|
||||
const double target_version = std::strtod(target_app_ver.c_str(), &ev1);
|
||||
const double target_version = std::strtod(target_app_ver.data(), &ev1);
|
||||
|
||||
if (target_app_ver.c_str() + target_app_ver.size() != ev1)
|
||||
if (target_app_ver.data() + target_app_ver.size() != ev1)
|
||||
{
|
||||
pkg_log.error("Failed to convert the package's target app version to double (%s)", target_app_ver);
|
||||
return package_error::other;
|
||||
|
||||
@@ -1112,8 +1112,12 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
|
||||
if (ctrl->npdrm.license == 1) // Network license.
|
||||
{
|
||||
self_log.error("SELF: Can't decrypt network NPDRM!");
|
||||
return false;
|
||||
// Try to find a RAP file to get the key.
|
||||
if (!GetKeyFromRap(ctrl->npdrm.content_id, npdrm_key))
|
||||
{
|
||||
self_log.error("SELF: Can't decrypt network NPDRM!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ctrl->npdrm.license == 2) // Local license.
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <time.h>
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include "Utilities/span.h"
|
||||
#include "Utilities/File.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -120,16 +121,16 @@ void cmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_
|
||||
aes_cmac(&ctx, in_len, in, hash);
|
||||
}
|
||||
|
||||
char* extract_file_name(const char* file_path, char real_file_name[MAX_PATH])
|
||||
char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PATH])
|
||||
{
|
||||
std::string_view v(file_path);
|
||||
|
||||
if (auto pos = v.find_last_of("/\\"); pos != umax)
|
||||
if (auto pos = v.find_last_of(fs::delim); pos != umax)
|
||||
{
|
||||
v.remove_prefix(pos + 1);
|
||||
}
|
||||
|
||||
gsl::span r(real_file_name, MAX_PATH);
|
||||
gsl::span r(real_file_name, CRYPTO_MAX_PATH);
|
||||
strcpy_trunc(r, v);
|
||||
return real_file_name;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
// Copyright (C) 2014 Hykem <hykem@hotmail.com>
|
||||
// Licensed under the terms of the GNU GPL, version 3
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
#include "../../Utilities/types.h"
|
||||
|
||||
#define MAX_PATH 4096
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
#include "lz.h"
|
||||
#include "ec.h"
|
||||
|
||||
enum { CRYPTO_MAX_PATH = 4096 };
|
||||
|
||||
// Auxiliary functions (endian swap, xor, and file name).
|
||||
inline u16 swap16(u16 i)
|
||||
{
|
||||
@@ -42,7 +42,7 @@ inline u64 swap64(u64 i)
|
||||
#endif
|
||||
}
|
||||
|
||||
char* extract_file_name(const char* file_path, char real_file_name[MAX_PATH]);
|
||||
char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PATH]);
|
||||
|
||||
// Hex string conversion auxiliary functions.
|
||||
u64 hex_to_u64(const char* hex_str);
|
||||
|
||||
@@ -12,8 +12,7 @@ LOG_CHANNEL(OpenAL);
|
||||
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) { OpenAL.error("%s: OpenALC error 0x%04x", sit, g_last_alc_error); return; }} while(0)
|
||||
|
||||
OpenALBackend::OpenALBackend()
|
||||
: m_sampling_rate(get_sampling_rate())
|
||||
, m_sample_size(get_sample_size())
|
||||
: AudioBackend()
|
||||
{
|
||||
ALCdevice* m_device = alcOpenDevice(nullptr);
|
||||
checkForAlcError("alcOpenDevice");
|
||||
@@ -24,13 +23,17 @@ OpenALBackend::OpenALBackend()
|
||||
alcMakeContextCurrent(m_context);
|
||||
checkForAlcError("alcMakeContextCurrent");
|
||||
|
||||
if (get_channels() == 2)
|
||||
switch (m_channels)
|
||||
{
|
||||
case 2:
|
||||
m_format = (m_sample_size == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
case 6:
|
||||
m_format = (m_sample_size == 2) ? AL_FORMAT_51CHN16 : AL_FORMAT_51CHN32;
|
||||
break;
|
||||
default:
|
||||
m_format = (m_sample_size == 2) ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,9 +15,6 @@ private:
|
||||
u32 m_next_buffer = 0;
|
||||
u32 m_num_unqueued = 0;
|
||||
|
||||
const u32 m_sampling_rate;
|
||||
const u32 m_sample_size;
|
||||
|
||||
void unqueue_processed();
|
||||
|
||||
public:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifndef HAVE_ALSA
|
||||
#ifndef HAVE_ALSA
|
||||
#error "ALSA support disabled but still being built."
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@ static bool check(int err, const char* reason)
|
||||
}
|
||||
|
||||
ALSABackend::ALSABackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -51,14 +52,14 @@ void ALSABackend::Open(u32 num_buffers)
|
||||
if (!check(snd_pcm_hw_params_set_access(tls_handle, tls_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_set_format(tls_handle, tls_hw_params, g_cfg.audio.convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
|
||||
if (!check(snd_pcm_hw_params_set_format(tls_handle, tls_hw_params, m_convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
|
||||
return;
|
||||
|
||||
uint rate = get_sampling_rate();
|
||||
uint rate = m_sampling_rate;
|
||||
if (!check(snd_pcm_hw_params_set_rate_near(tls_handle, tls_hw_params, &rate, nullptr), "snd_pcm_hw_params_set_rate_near"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_set_channels(tls_handle, tls_hw_params, get_channels()), "snd_pcm_hw_params_set_channels"))
|
||||
if (!check(snd_pcm_hw_params_set_channels(tls_handle, tls_hw_params, m_channels), "snd_pcm_hw_params_set_channels"))
|
||||
return;
|
||||
|
||||
//uint period = 5333;
|
||||
@@ -92,7 +93,7 @@ void ALSABackend::Open(u32 num_buffers)
|
||||
if (!check(snd_pcm_sw_params_current(tls_handle, tls_sw_params), "snd_pcm_sw_params_current"))
|
||||
return;
|
||||
|
||||
period_frames *= g_cfg.audio.startt;
|
||||
period_frames *= m_start_threshold;
|
||||
|
||||
if (!check(snd_pcm_sw_params_set_start_threshold(tls_handle, tls_sw_params, period_frames + 1), "snd_pcm_sw_params_set_start_threshold"))
|
||||
return;
|
||||
@@ -132,7 +133,7 @@ void ALSABackend::Close()
|
||||
|
||||
bool ALSABackend::AddData(const void* src, u32 num_samples)
|
||||
{
|
||||
u32 num_frames = num_samples / get_channels();
|
||||
u32 num_frames = num_samples / m_channels;
|
||||
|
||||
int res = snd_pcm_writei(tls_handle, src, num_frames);
|
||||
|
||||
|
||||
@@ -2,29 +2,67 @@
|
||||
#include "AudioBackend.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
u32 AudioBackend::get_sampling_rate()
|
||||
AudioBackend::AudioBackend()
|
||||
{
|
||||
m_convert_to_u16 = static_cast<bool>(g_cfg.audio.convert_to_u16);
|
||||
m_sample_size = m_convert_to_u16 ? sizeof(u16) : sizeof(float);
|
||||
m_start_threshold = g_cfg.audio.start_threshold;
|
||||
|
||||
const u32 sampling_period_multiplier_u32 = g_cfg.audio.sampling_period_multiplier;
|
||||
|
||||
if (sampling_period_multiplier_u32 == 100)
|
||||
return DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
{
|
||||
m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
|
||||
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
|
||||
m_sampling_rate = static_cast<u32>(f32{ DEFAULT_AUDIO_SAMPLING_RATE } *sampling_rate_multiplier);
|
||||
}
|
||||
|
||||
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
|
||||
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
|
||||
return static_cast<u32>(f32{DEFAULT_AUDIO_SAMPLING_RATE} * sampling_rate_multiplier);
|
||||
const audio_downmix downmix = g_cfg.audio.audio_channel_downmix.get();
|
||||
|
||||
switch (downmix)
|
||||
{
|
||||
case audio_downmix::no_downmix:
|
||||
m_channels = 8;
|
||||
break;
|
||||
case audio_downmix::downmix_to_stereo:
|
||||
m_channels = 2;
|
||||
break;
|
||||
case audio_downmix::downmix_to_5_1:
|
||||
m_channels = 6;
|
||||
break;
|
||||
case audio_downmix::use_application_settings:
|
||||
m_channels = 2; // TODO
|
||||
break;
|
||||
default:
|
||||
fmt::throw_exception("Unknown audio channel mode %s (%d)", downmix, static_cast<int>(downmix));
|
||||
}
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_sample_size()
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
u32 AudioBackend::get_sampling_rate() const
|
||||
{
|
||||
return g_cfg.audio.convert_to_u16 ? sizeof(u16) : sizeof(float);
|
||||
return m_sampling_rate;
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_channels()
|
||||
u32 AudioBackend::get_sample_size() const
|
||||
{
|
||||
return g_cfg.audio.downmix_to_2ch ? 2 : 8;
|
||||
return m_sample_size;
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_channels() const
|
||||
{
|
||||
return m_channels;
|
||||
}
|
||||
|
||||
bool AudioBackend::get_convert_to_u16() const
|
||||
{
|
||||
return m_convert_to_u16;
|
||||
}
|
||||
|
||||
bool AudioBackend::has_capability(u32 cap) const
|
||||
|
||||
@@ -20,6 +20,8 @@ public:
|
||||
SET_FREQUENCY_RATIO = 0x8, // Implements SetFrequencyRatio
|
||||
};
|
||||
|
||||
AudioBackend();
|
||||
|
||||
virtual ~AudioBackend() = default;
|
||||
|
||||
/*
|
||||
@@ -94,13 +96,22 @@ public:
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
static u32 get_sampling_rate();
|
||||
u32 get_sampling_rate() const;
|
||||
|
||||
static u32 get_sample_size();
|
||||
u32 get_sample_size() const;
|
||||
|
||||
static u32 get_channels();
|
||||
u32 get_channels() const;
|
||||
|
||||
bool get_convert_to_u16() const;
|
||||
|
||||
bool has_capability(u32 cap) const;
|
||||
|
||||
void dump_capabilities(std::string& out) const;
|
||||
|
||||
protected:
|
||||
bool m_convert_to_u16 = false;
|
||||
u32 m_sample_size = sizeof(float);
|
||||
u32 m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
u32 m_channels = 0;
|
||||
u32 m_start_threshold = 1;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifndef HAVE_FAUDIO
|
||||
#ifndef HAVE_FAUDIO
|
||||
#error "FAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
LOG_CHANNEL(FAudio_, "FAudio");
|
||||
|
||||
FAudioBackend::FAudioBackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
u32 res;
|
||||
|
||||
@@ -20,7 +21,7 @@ FAudioBackend::FAudioBackend()
|
||||
return;
|
||||
}
|
||||
|
||||
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000, 0, 0, nullptr);
|
||||
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, m_channels, 48000, 0, 0, nullptr);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
|
||||
@@ -102,17 +103,13 @@ void FAudioBackend::Close()
|
||||
|
||||
void FAudioBackend::Open(u32 /* num_buffers */)
|
||||
{
|
||||
const u32 sample_size = AudioBackend::get_sample_size();
|
||||
const u32 channels = AudioBackend::get_channels();
|
||||
const u32 sampling_rate = AudioBackend::get_sampling_rate();
|
||||
|
||||
FAudioWaveFormatEx waveformatex;
|
||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = channels;
|
||||
waveformatex.nSamplesPerSec = sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<u32>(sampling_rate * channels * sample_size);
|
||||
waveformatex.nBlockAlign = channels * sample_size;
|
||||
waveformatex.wBitsPerSample = sample_size * 8;
|
||||
waveformatex.wFormatTag = m_convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = m_channels;
|
||||
waveformatex.nSamplesPerSec = m_sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<u32>(m_sampling_rate * m_channels * m_sample_size);
|
||||
waveformatex.nBlockAlign = m_channels * m_sample_size;
|
||||
waveformatex.wBitsPerSample = m_sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, nullptr, nullptr, nullptr);
|
||||
@@ -140,7 +137,7 @@ bool FAudioBackend::AddData(const void* src, u32 num_samples)
|
||||
}
|
||||
|
||||
FAudioBuffer buffer;
|
||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
||||
buffer.AudioBytes = num_samples * m_sample_size;
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = FAUDIO_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifndef HAVE_PULSE
|
||||
#ifndef HAVE_PULSE
|
||||
#error "PulseAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <pulse/error.h>
|
||||
|
||||
PulseBackend::PulseBackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -19,7 +20,8 @@ PulseBackend::~PulseBackend()
|
||||
|
||||
void PulseBackend::Close()
|
||||
{
|
||||
if(this->connection) {
|
||||
if (this->connection)
|
||||
{
|
||||
pa_simple_free(this->connection);
|
||||
this->connection = nullptr;
|
||||
}
|
||||
@@ -28,20 +30,30 @@ void PulseBackend::Close()
|
||||
void PulseBackend::Open(u32 /* num_buffers */)
|
||||
{
|
||||
pa_sample_spec ss;
|
||||
ss.format = (get_sample_size() == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
|
||||
ss.rate = get_sampling_rate();
|
||||
ss.format = (m_sample_size == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
|
||||
ss.rate = m_sampling_rate;
|
||||
|
||||
pa_channel_map channel_map;
|
||||
|
||||
if (get_channels() == 2)
|
||||
if (m_channels == 2)
|
||||
{
|
||||
channel_map.channels = 2;
|
||||
channel_map.channels = 2;
|
||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||
}
|
||||
else if (m_channels == 6)
|
||||
{
|
||||
channel_map.channels = 6;
|
||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
|
||||
channel_map.map[3] = PA_CHANNEL_POSITION_LFE;
|
||||
channel_map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
|
||||
channel_map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel_map.channels = 8;
|
||||
channel_map.channels = 8;
|
||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
|
||||
@@ -55,7 +67,8 @@ void PulseBackend::Open(u32 /* num_buffers */)
|
||||
|
||||
int err;
|
||||
this->connection = pa_simple_new(NULL, "RPCS3", PA_STREAM_PLAYBACK, NULL, "Game", &ss, &channel_map, NULL, &err);
|
||||
if(!this->connection) {
|
||||
if (!this->connection)
|
||||
{
|
||||
fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err));
|
||||
}
|
||||
}
|
||||
@@ -65,10 +78,11 @@ bool PulseBackend::AddData(const void* src, u32 num_samples)
|
||||
AUDIT(this->connection);
|
||||
|
||||
int err;
|
||||
if(pa_simple_write(this->connection, src, num_samples * get_sample_size(), &err) < 0) {
|
||||
if (pa_simple_write(this->connection, src, num_samples * m_sample_size, &err) < 0)
|
||||
{
|
||||
fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,26 +9,32 @@
|
||||
|
||||
#include "XAudio2Backend.h"
|
||||
#include <Windows.h>
|
||||
#include <system_error>
|
||||
|
||||
#pragma comment(lib, "xaudio2_9redist.lib")
|
||||
|
||||
LOG_CHANNEL(XAudio);
|
||||
|
||||
XAudio2Backend::XAudio2Backend()
|
||||
: AudioBackend()
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IXAudio2> instance;
|
||||
|
||||
// In order to prevent errors on CreateMasteringVoice, apparently we need CoInitializeEx according to:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/xaudio2fx/nf-xaudio2fx-xaudio2createvolumemeter
|
||||
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
|
||||
HRESULT hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("XAudio2Create() failed(0x%08x)", (u32)hr);
|
||||
XAudio.error("XAudio2Create() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return;
|
||||
}
|
||||
|
||||
hr = instance->CreateMasteringVoice(&m_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
|
||||
hr = instance->CreateMasteringVoice(&m_master_voice, m_channels, 48000);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("CreateMasteringVoice() failed(0x%08x)", (u32)hr);
|
||||
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,7 +68,7 @@ void XAudio2Backend::Play()
|
||||
HRESULT hr = m_source_voice->Start();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("Start() failed(0x%08x)", (u32)hr);
|
||||
XAudio.error("Start() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
@@ -80,7 +86,7 @@ void XAudio2Backend::Pause()
|
||||
HRESULT hr = m_source_voice->Stop();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("Stop() failed(0x%08x)", (u32)hr);
|
||||
XAudio.error("Stop() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
@@ -89,23 +95,19 @@ void XAudio2Backend::Open(u32 /* num_buffers */)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
const u32 sample_size = AudioBackend::get_sample_size();
|
||||
const u32 channels = AudioBackend::get_channels();
|
||||
const u32 sampling_rate = AudioBackend::get_sampling_rate();
|
||||
|
||||
WAVEFORMATEX waveformatex;
|
||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = channels;
|
||||
waveformatex.nSamplesPerSec = sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(sampling_rate * channels * sample_size);
|
||||
waveformatex.nBlockAlign = channels * sample_size;
|
||||
waveformatex.wBitsPerSample = sample_size * 8;
|
||||
waveformatex.wFormatTag = m_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = m_channels;
|
||||
waveformatex.nSamplesPerSec = m_sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(m_sampling_rate * m_channels * m_sample_size);
|
||||
waveformatex.nBlockAlign = m_channels * m_sample_size;
|
||||
waveformatex.wBitsPerSample = m_sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("CreateSourceVoice() failed(0x%08x)", (u32)hr);
|
||||
XAudio.error("CreateSourceVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
@@ -139,7 +141,7 @@ bool XAudio2Backend::AddData(const void* src, u32 num_samples)
|
||||
|
||||
XAUDIO2_BUFFER buffer;
|
||||
|
||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
||||
buffer.AudioBytes = num_samples * m_sample_size;
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
@@ -152,7 +154,7 @@ bool XAudio2Backend::AddData(const void* src, u32 num_samples)
|
||||
HRESULT hr = m_source_voice->SubmitSourceBuffer(&buffer);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("AddData() failed(0x%08x)", (u32)hr);
|
||||
XAudio.error("AddData() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
@@ -167,7 +169,7 @@ void XAudio2Backend::Flush()
|
||||
HRESULT hr = m_source_voice->FlushSourceBuffers();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("FlushSourceBuffers() failed(0x%08x)", (u32)hr);
|
||||
XAudio.error("FlushSourceBuffers() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
@@ -190,7 +192,7 @@ f32 XAudio2Backend::SetFrequencyRatio(f32 new_ratio)
|
||||
HRESULT hr = m_source_voice->SetFrequencyRatio(new_ratio);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("SetFrequencyRatio() failed(0x%08x)", (u32)hr);
|
||||
XAudio.error("SetFrequencyRatio() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
Emu.Pause();
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
add_library(rpcs3_emu
|
||||
IdManager.cpp
|
||||
localized_string.cpp
|
||||
System.cpp
|
||||
system_config.cpp
|
||||
system_config_types.cpp
|
||||
VFS.cpp
|
||||
GDB.cpp
|
||||
title.cpp
|
||||
perf_meter.cpp
|
||||
)
|
||||
|
||||
# prevent WolfSSL from warning about not having harden options
|
||||
add_compile_definitions(WC_NO_HARDEN)
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
PRIVATE
|
||||
3rdparty::zlib 3rdparty::yaml-cpp
|
||||
PUBLIC
|
||||
3rdparty::libevdev)
|
||||
3rdparty::libevdev 3rdparty::flatbuffers)
|
||||
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
@@ -35,6 +40,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
../util/yaml.cpp
|
||||
../util/cereal.cpp
|
||||
../../Utilities/bin_patch.cpp
|
||||
../../Utilities/cheat_info.cpp
|
||||
../../Utilities/cond.cpp
|
||||
../../Utilities/Config.cpp
|
||||
../../Utilities/dynamic_library.cpp
|
||||
@@ -333,10 +339,6 @@ target_link_libraries(rpcs3_emu
|
||||
PRIVATE
|
||||
3rdparty::stblib 3rdparty::libpng)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
target_link_libraries(rpcs3_emu PUBLIC -latomic)
|
||||
endif()
|
||||
|
||||
|
||||
# CPU
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
@@ -350,6 +352,7 @@ target_link_libraries(rpcs3_emu
|
||||
|
||||
# Io
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
Io/interception.cpp
|
||||
Io/KeyboardHandler.cpp
|
||||
Io/pad_config.cpp
|
||||
Io/pad_config_types.cpp
|
||||
@@ -361,7 +364,12 @@ target_sources(rpcs3_emu PRIVATE
|
||||
|
||||
# Np
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
NP/fb_helpers.cpp
|
||||
NP/np_handler.cpp
|
||||
NP/signaling_handler.cpp
|
||||
NP/np_structs_extra.cpp
|
||||
NP/rpcn_client.cpp
|
||||
NP/rpcn_config.cpp
|
||||
)
|
||||
|
||||
# Memory
|
||||
@@ -436,6 +444,7 @@ if(TARGET 3rdparty_vulkan)
|
||||
RSX/VK/VKMemAlloc.cpp
|
||||
RSX/VK/VKPresent.cpp
|
||||
RSX/VK/VKProgramPipeline.cpp
|
||||
RSX/VK/VKQueryPool.cpp
|
||||
RSX/VK/VKRenderPass.cpp
|
||||
RSX/VK/VKResolveHelper.cpp
|
||||
RSX/VK/VKResourceManager.cpp
|
||||
@@ -451,7 +460,7 @@ target_link_libraries(rpcs3_emu
|
||||
3rdparty::ffmpeg 3rdparty::cereal
|
||||
3rdparty::opengl 3rdparty::stblib
|
||||
3rdparty::vulkan 3rdparty::glew
|
||||
3rdparty::libusb
|
||||
3rdparty::libusb 3rdparty::wolfssl
|
||||
PRIVATE
|
||||
3rdparty::span 3rdparty::xxhash
|
||||
)
|
||||
|
||||
@@ -56,7 +56,30 @@ protected:
|
||||
|
||||
virtual u32 DisAsmBranchTarget(const s32 imm) = 0;
|
||||
|
||||
std::string FixOp(std::string op)
|
||||
// TODO: Add builtin fmt helpper for best performance
|
||||
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
||||
static std::string SignedHex(T value)
|
||||
{
|
||||
const auto v = static_cast<std::make_signed_t<T>>(value);
|
||||
|
||||
if (v == std::numeric_limits<std::make_signed_t<T>>::min())
|
||||
{
|
||||
// for INTx_MIN
|
||||
return fmt::format("-0x%x", v);
|
||||
}
|
||||
|
||||
const auto av = std::abs(v);
|
||||
|
||||
if (av < 10)
|
||||
{
|
||||
// Does not need hex
|
||||
return fmt::format("%d", v);
|
||||
}
|
||||
|
||||
return fmt::format("%s%s", v < 0 ? "-" : "", av);
|
||||
}
|
||||
|
||||
static std::string FixOp(std::string op)
|
||||
{
|
||||
op.resize(std::max<std::size_t>(op.length(), 10), ' ');
|
||||
return op;
|
||||
|
||||
+391
-99
@@ -8,17 +8,24 @@
|
||||
#include "Emu/GDB.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/perf_meter.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <numeric>
|
||||
#include <map>
|
||||
|
||||
DECLARE(cpu_thread::g_threads_created){0};
|
||||
DECLARE(cpu_thread::g_threads_deleted){0};
|
||||
DECLARE(cpu_thread::g_suspend_counter){0};
|
||||
|
||||
LOG_CHANNEL(profiler);
|
||||
LOG_CHANNEL(sys_log, "SYS");
|
||||
|
||||
static thread_local u64 s_tls_thread_slot = -1;
|
||||
|
||||
extern thread_local void(*g_tls_log_control)(const char* fmt, u64 progress);
|
||||
|
||||
template <>
|
||||
void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
|
||||
{
|
||||
@@ -29,6 +36,7 @@ void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
|
||||
case cpu_flag::stop: return "STOP";
|
||||
case cpu_flag::exit: return "EXIT";
|
||||
case cpu_flag::wait: return "w";
|
||||
case cpu_flag::temp: return "t";
|
||||
case cpu_flag::pause: return "p";
|
||||
case cpu_flag::suspend: return "s";
|
||||
case cpu_flag::ret: return "ret";
|
||||
@@ -245,24 +253,31 @@ struct cpu_counter
|
||||
// For synchronizing suspend_all operation
|
||||
alignas(64) shared_mutex cpu_suspend_lock;
|
||||
|
||||
// Workload linked list
|
||||
alignas(64) atomic_t<cpu_thread::suspend_work*> cpu_suspend_work{};
|
||||
|
||||
// Semaphore for global thread array (global counter)
|
||||
alignas(64) atomic_t<u32> cpu_array_sema{0};
|
||||
|
||||
// Semaphore subdivision for each array slot (64 x N in total)
|
||||
atomic_t<u64> cpu_array_bits[6]{};
|
||||
alignas(64) atomic_t<u64> cpu_array_bits[3]{};
|
||||
|
||||
// Copy of array bits for internal use
|
||||
alignas(64) u64 cpu_copy_bits[3]{};
|
||||
|
||||
// All registered threads
|
||||
atomic_t<cpu_thread*> cpu_array[sizeof(cpu_array_bits) * 8]{};
|
||||
|
||||
u64 add(cpu_thread* _this)
|
||||
u64 add(cpu_thread* _this, bool restore = false) noexcept
|
||||
{
|
||||
if (!cpu_array_sema.try_inc(sizeof(cpu_counter::cpu_array_bits) * 8))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
u64 array_slot = -1;
|
||||
|
||||
if (!restore && !cpu_array_sema.try_inc(sizeof(cpu_counter::cpu_array_bits) * 8))
|
||||
{
|
||||
sys_log.fatal("Too many threads.");
|
||||
return array_slot;
|
||||
}
|
||||
|
||||
for (u32 i = 0;; i = (i + 1) % ::size32(cpu_array_bits))
|
||||
{
|
||||
const auto [bits, ok] = cpu_array_bits[i].fetch_op([](u64& bits) -> u64
|
||||
@@ -281,44 +296,92 @@ struct cpu_counter
|
||||
{
|
||||
// Get actual slot number
|
||||
array_slot = i * 64 + std::countr_one(bits);
|
||||
break;
|
||||
|
||||
// Register thread
|
||||
if (cpu_array[array_slot].compare_and_swap_test(nullptr, _this)) [[likely]]
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
sys_log.fatal("Unexpected slot registration failure (%u).", array_slot);
|
||||
cpu_array_bits[array_slot / 64] &= ~(1ull << (array_slot % 64));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Register and wait if necessary
|
||||
verify("cpu_counter::add()" HERE), cpu_array[array_slot].exchange(_this) == nullptr;
|
||||
if (!restore)
|
||||
{
|
||||
// First time (thread created)
|
||||
_this->state += cpu_flag::wait;
|
||||
cpu_suspend_lock.lock_unlock();
|
||||
}
|
||||
|
||||
_this->state += cpu_flag::wait;
|
||||
cpu_suspend_lock.lock_unlock();
|
||||
return array_slot;
|
||||
}
|
||||
|
||||
void remove(cpu_thread* _this, u64 slot)
|
||||
void remove(cpu_thread* _this, u64 slot) noexcept
|
||||
{
|
||||
// Unregister and wait if necessary
|
||||
_this->state += cpu_flag::wait;
|
||||
if (cpu_array[slot].exchange(nullptr) != _this)
|
||||
|
||||
std::lock_guard lock(cpu_suspend_lock);
|
||||
|
||||
if (!cpu_array[slot].compare_and_swap_test(_this, nullptr))
|
||||
{
|
||||
sys_log.fatal("Inconsistency for array slot %u", slot);
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_array_bits[slot / 64] &= ~(1ull << (slot % 64));
|
||||
cpu_array_sema--;
|
||||
cpu_suspend_lock.lock_unlock();
|
||||
}
|
||||
|
||||
// Remove temporarily
|
||||
void remove(cpu_thread* _this) noexcept
|
||||
{
|
||||
// Unregister temporarily (called from check_state)
|
||||
const u64 index = s_tls_thread_slot;
|
||||
|
||||
if (index >= std::size(cpu_array))
|
||||
{
|
||||
sys_log.fatal("Index out of bounds (%u).", index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu_array[index].load() == _this && cpu_array[index].compare_and_swap_test(_this, nullptr))
|
||||
{
|
||||
cpu_array_bits[index / 64] &= ~(1ull << (index % 64));
|
||||
return;
|
||||
}
|
||||
|
||||
sys_log.fatal("Thread not found in cpu_array (%s).", _this->get_name());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
void for_all_cpu(F&& func) noexcept
|
||||
template <bool UseCopy = false, typename F>
|
||||
void for_all_cpu(F func) noexcept
|
||||
{
|
||||
auto ctr = g_fxo->get<cpu_counter>();
|
||||
const auto ctr = g_fxo->get<cpu_counter>();
|
||||
|
||||
for (u32 i = 0; i < ::size32(ctr->cpu_array_bits); i++)
|
||||
{
|
||||
for (u64 bits = ctr->cpu_array_bits[i]; bits; bits &= bits - 1)
|
||||
for (u64 bits = (UseCopy ? ctr->cpu_copy_bits[i] : ctr->cpu_array_bits[i].load()); bits; bits &= bits - 1)
|
||||
{
|
||||
const u64 index = i * 64 + std::countr_zero(bits);
|
||||
|
||||
if (cpu_thread* cpu = ctr->cpu_array[index].load())
|
||||
{
|
||||
func(cpu);
|
||||
if constexpr (std::is_invocable_v<F, cpu_thread*, u64>)
|
||||
{
|
||||
func(cpu, index);
|
||||
continue;
|
||||
}
|
||||
|
||||
if constexpr (std::is_invocable_v<F, cpu_thread*>)
|
||||
{
|
||||
func(cpu);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,7 +401,7 @@ void cpu_thread::operator()()
|
||||
{
|
||||
thread_ctrl::set_native_priority(-1);
|
||||
}
|
||||
|
||||
|
||||
// force input/output denormals to zero for SPU threads (FTZ/DAZ)
|
||||
_mm_setcsr( _mm_getcsr() | 0x8040 );
|
||||
|
||||
@@ -378,23 +441,63 @@ void cpu_thread::operator()()
|
||||
}
|
||||
|
||||
// Register thread in g_cpu_array
|
||||
const u64 array_slot = g_fxo->get<cpu_counter>()->add(this);
|
||||
s_tls_thread_slot = g_fxo->get<cpu_counter>()->add(this);
|
||||
|
||||
if (array_slot == umax)
|
||||
if (s_tls_thread_slot == umax)
|
||||
{
|
||||
sys_log.fatal("Too many threads.");
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_storage_futex::set_notify_callback([](const void*, u64 progress)
|
||||
{
|
||||
static thread_local bool wait_set = false;
|
||||
|
||||
cpu_thread* _cpu = get_current_cpu_thread();
|
||||
|
||||
// Wait flag isn't set asynchronously so this should be thread-safe
|
||||
if (progress == 0 && !(_cpu->state & cpu_flag::wait))
|
||||
{
|
||||
// Operation just started and syscall is imminent
|
||||
_cpu->state += cpu_flag::wait + cpu_flag::temp;
|
||||
wait_set = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (progress == umax && std::exchange(wait_set, false))
|
||||
{
|
||||
// Operation finished: need to clean wait flag
|
||||
verify(HERE), !_cpu->check_state();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
g_tls_log_control = [](const char* fmt, u64 progress)
|
||||
{
|
||||
static thread_local bool wait_set = false;
|
||||
|
||||
cpu_thread* _cpu = get_current_cpu_thread();
|
||||
|
||||
if (progress == 0 && !(_cpu->state & cpu_flag::wait))
|
||||
{
|
||||
_cpu->state += cpu_flag::wait + cpu_flag::temp;
|
||||
wait_set = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (progress == umax && std::exchange(wait_set, false))
|
||||
{
|
||||
verify(HERE), !_cpu->check_state();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
static thread_local struct thread_cleanup_t
|
||||
{
|
||||
cpu_thread* _this;
|
||||
u64 slot;
|
||||
std::string name;
|
||||
|
||||
thread_cleanup_t(cpu_thread* _this, u64 slot)
|
||||
thread_cleanup_t(cpu_thread* _this)
|
||||
: _this(_this)
|
||||
, slot(slot)
|
||||
, name(thread_ctrl::get_name())
|
||||
{
|
||||
}
|
||||
@@ -411,7 +514,11 @@ void cpu_thread::operator()()
|
||||
ptr->compare_and_swap(_this, nullptr);
|
||||
}
|
||||
|
||||
g_fxo->get<cpu_counter>()->remove(_this, slot);
|
||||
atomic_storage_futex::set_notify_callback(nullptr);
|
||||
|
||||
g_tls_log_control = [](const char*, u64){};
|
||||
|
||||
g_fxo->get<cpu_counter>()->remove(_this, s_tls_thread_slot);
|
||||
|
||||
_this = nullptr;
|
||||
}
|
||||
@@ -424,7 +531,7 @@ void cpu_thread::operator()()
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
} cleanup{this, array_slot};
|
||||
} cleanup{this};
|
||||
|
||||
// Check thread status
|
||||
while (!(state & (cpu_flag::exit + cpu_flag::dbg_global_stop)) && thread_ctrl::state() != thread_state::aborting)
|
||||
@@ -433,11 +540,21 @@ void cpu_thread::operator()()
|
||||
if (!(state & cpu_flag::stop))
|
||||
{
|
||||
cpu_task();
|
||||
state -= cpu_flag::ret;
|
||||
|
||||
if (state & cpu_flag::ret && state.test_and_reset(cpu_flag::ret))
|
||||
{
|
||||
cpu_return();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
thread_ctrl::wait();
|
||||
|
||||
if (state & cpu_flag::ret && state.test_and_reset(cpu_flag::ret))
|
||||
{
|
||||
cpu_return();
|
||||
}
|
||||
}
|
||||
|
||||
// Complete cleanup gracefully
|
||||
@@ -464,13 +581,9 @@ bool cpu_thread::check_state() noexcept
|
||||
}
|
||||
|
||||
bool cpu_sleep_called = false;
|
||||
bool cpu_flag_memory = false;
|
||||
bool cpu_can_stop = true;
|
||||
bool escape, retval;
|
||||
|
||||
if (!(state & cpu_flag::wait))
|
||||
{
|
||||
state += cpu_flag::wait;
|
||||
}
|
||||
u64 susp_ctr = -1;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -479,6 +592,21 @@ bool cpu_thread::check_state() noexcept
|
||||
{
|
||||
bool store = false;
|
||||
|
||||
if (flags & cpu_flag::pause && !(flags & cpu_flag::wait))
|
||||
{
|
||||
// Save value before state is saved and cpu_flag::wait is observed
|
||||
susp_ctr = g_suspend_counter;
|
||||
}
|
||||
|
||||
if (flags & cpu_flag::temp) [[unlikely]]
|
||||
{
|
||||
// Sticky flag, indicates check_state() is not allowed to return true
|
||||
flags -= cpu_flag::temp;
|
||||
flags -= cpu_flag::wait;
|
||||
cpu_can_stop = false;
|
||||
store = true;
|
||||
}
|
||||
|
||||
if (flags & cpu_flag::signal)
|
||||
{
|
||||
flags -= cpu_flag::signal;
|
||||
@@ -490,20 +618,20 @@ bool cpu_thread::check_state() noexcept
|
||||
if (!(flags & (cpu_flag::exit + cpu_flag::dbg_global_stop + cpu_flag::ret + cpu_flag::stop)))
|
||||
{
|
||||
// Check pause flags which hold thread inside check_state
|
||||
if (flags & (cpu_flag::pause + cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause))
|
||||
if (flags & (cpu_flag::pause + cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::memory))
|
||||
{
|
||||
if (!(flags & cpu_flag::wait))
|
||||
{
|
||||
flags += cpu_flag::wait;
|
||||
store = true;
|
||||
}
|
||||
|
||||
escape = false;
|
||||
return store;
|
||||
}
|
||||
|
||||
if (flags & cpu_flag::memory)
|
||||
if (flags & cpu_flag::wait)
|
||||
{
|
||||
// wait flag will be cleared later (optimization)
|
||||
cpu_flag_memory = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AUDIT(!cpu_flag_memory);
|
||||
flags -= cpu_flag::wait;
|
||||
store = true;
|
||||
}
|
||||
@@ -512,12 +640,18 @@ bool cpu_thread::check_state() noexcept
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_flag_memory = false;
|
||||
retval = true;
|
||||
if (cpu_can_stop && !(flags & cpu_flag::wait))
|
||||
{
|
||||
flags += cpu_flag::wait;
|
||||
store = true;
|
||||
}
|
||||
|
||||
retval = cpu_can_stop;
|
||||
}
|
||||
|
||||
if (flags & cpu_flag::dbg_step)
|
||||
if (cpu_can_stop && flags & cpu_flag::dbg_step)
|
||||
{
|
||||
// Can't process dbg_step if we only paused temporarily
|
||||
flags += cpu_flag::dbg_pause;
|
||||
flags -= cpu_flag::dbg_step;
|
||||
store = true;
|
||||
@@ -529,23 +663,30 @@ bool cpu_thread::check_state() noexcept
|
||||
|
||||
if (escape)
|
||||
{
|
||||
if (cpu_flag_memory)
|
||||
if (s_tls_thread_slot == umax)
|
||||
{
|
||||
cpu_mem();
|
||||
|
||||
if (state & (cpu_flag::pause + cpu_flag::memory)) [[unlikely]]
|
||||
{
|
||||
state += cpu_flag::wait;
|
||||
continue;
|
||||
}
|
||||
// Restore thread in the suspend list
|
||||
std::lock_guard lock(g_fxo->get<cpu_counter>()->cpu_suspend_lock);
|
||||
s_tls_thread_slot = g_fxo->get<cpu_counter>()->add(this, true);
|
||||
}
|
||||
|
||||
verify(HERE), cpu_can_stop || !retval;
|
||||
return retval;
|
||||
}
|
||||
else if (!cpu_sleep_called && state0 & cpu_flag::suspend)
|
||||
|
||||
if (!cpu_sleep_called && state0 & cpu_flag::suspend)
|
||||
{
|
||||
cpu_sleep();
|
||||
cpu_sleep_called = true;
|
||||
|
||||
if (cpu_can_stop && s_tls_thread_slot != umax)
|
||||
{
|
||||
// Exclude inactive threads from the suspend list (optimization)
|
||||
std::lock_guard lock(g_fxo->get<cpu_counter>()->cpu_suspend_lock);
|
||||
g_fxo->get<cpu_counter>()->remove(this);
|
||||
s_tls_thread_slot = -1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -555,8 +696,48 @@ bool cpu_thread::check_state() noexcept
|
||||
}
|
||||
else
|
||||
{
|
||||
// If only cpu_flag::pause was set, notification won't arrive
|
||||
g_fxo->get<cpu_counter>()->cpu_suspend_lock.lock_unlock();
|
||||
if (state0 & cpu_flag::memory)
|
||||
{
|
||||
vm::passive_lock(*this);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If only cpu_flag::pause was set, wait on suspend counter instead
|
||||
if (state0 & cpu_flag::pause)
|
||||
{
|
||||
if (state0 & cpu_flag::wait)
|
||||
{
|
||||
// Otherwise, value must be reliable because cpu_flag::wait hasn't been observed yet
|
||||
susp_ctr = -1;
|
||||
}
|
||||
|
||||
// Hard way
|
||||
if (susp_ctr == umax) [[unlikely]]
|
||||
{
|
||||
g_fxo->get<cpu_counter>()->cpu_suspend_lock.lock_unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wait for current suspend_all operation
|
||||
for (u64 i = 0;; i++)
|
||||
{
|
||||
if (i < 20)
|
||||
{
|
||||
busy_wait(300);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_suspend_counter.wait(susp_ctr);
|
||||
}
|
||||
|
||||
if (!(state & cpu_flag::pause))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
susp_ctr = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -627,7 +808,7 @@ std::string cpu_thread::dump_callstack() const
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<u32> cpu_thread::dump_callstack_list() const
|
||||
std::vector<std::pair<u32, u32>> cpu_thread::dump_callstack_list() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -637,68 +818,171 @@ std::string cpu_thread::dump_misc() const
|
||||
return fmt::format("Type: %s\n" "State: %s\n", typeid(*this).name(), state.load());
|
||||
}
|
||||
|
||||
cpu_thread::suspend_all::suspend_all(cpu_thread* _this) noexcept
|
||||
: m_this(_this)
|
||||
bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspended) noexcept
|
||||
{
|
||||
if (m_this)
|
||||
{
|
||||
m_this->state += cpu_flag::wait;
|
||||
}
|
||||
// Can't allow pre-set wait bit (it'd be a problem)
|
||||
verify(HERE), !_this || !(_this->state & cpu_flag::wait);
|
||||
|
||||
g_fxo->get<cpu_counter>()->cpu_suspend_lock.lock_vip();
|
||||
// cpu_counter object
|
||||
const auto ctr = g_fxo->get<cpu_counter>();
|
||||
|
||||
for_all_cpu([](cpu_thread* cpu)
|
||||
// Try to push workload
|
||||
auto& queue = ctr->cpu_suspend_work;
|
||||
|
||||
do
|
||||
{
|
||||
if (!(cpu->state & cpu_flag::pause))
|
||||
// Load current head
|
||||
next = queue.load();
|
||||
|
||||
if (!next && cancel_if_not_suspended) [[unlikely]]
|
||||
{
|
||||
cpu->state += cpu_flag::pause;
|
||||
// Give up if not suspended
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
busy_wait(500);
|
||||
if (!_this && next)
|
||||
{
|
||||
// If _this == nullptr, it only works if this is the first workload pushed
|
||||
ctr->cpu_suspend_lock.lock_unlock();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (!queue.compare_and_swap_test(next, this));
|
||||
|
||||
while (true)
|
||||
if (!next)
|
||||
{
|
||||
bool ok = true;
|
||||
// Monitor the performance only of the actual suspend processing owner
|
||||
perf_meter<"SUSPEND"_u64> perf0;
|
||||
|
||||
// First thread to push the work to the workload list pauses all threads and processes it
|
||||
std::lock_guard lock(ctr->cpu_suspend_lock);
|
||||
|
||||
// Try to prefetch cpu->state earlier
|
||||
for_all_cpu([&](cpu_thread* cpu)
|
||||
{
|
||||
if (!(cpu->state & cpu_flag::wait))
|
||||
if (cpu != _this)
|
||||
{
|
||||
ok = false;
|
||||
_m_prefetchw(&cpu->state);
|
||||
}
|
||||
});
|
||||
|
||||
if (ok) [[likely]]
|
||||
// Copy of thread bits
|
||||
decltype(ctr->cpu_copy_bits) copy2{};
|
||||
|
||||
for (u32 i = 0; i < ::size32(ctr->cpu_copy_bits); i++)
|
||||
{
|
||||
break;
|
||||
copy2[i] = ctr->cpu_copy_bits[i] = ctr->cpu_array_bits[i].load();
|
||||
}
|
||||
|
||||
busy_wait(500);
|
||||
}
|
||||
}
|
||||
for_all_cpu([&](cpu_thread* cpu, u64 index)
|
||||
{
|
||||
if (cpu == _this || cpu->state.fetch_add(cpu_flag::pause) & cpu_flag::wait)
|
||||
{
|
||||
// Clear bits as long as wait flag is set
|
||||
ctr->cpu_copy_bits[index / 64] &= ~(1ull << (index % 64));
|
||||
}
|
||||
|
||||
cpu_thread::suspend_all::~suspend_all()
|
||||
{
|
||||
// Make sure the latest thread does the cleanup and notifies others
|
||||
if (g_fxo->get<cpu_counter>()->cpu_suspend_lock.downgrade_unique_vip_lock_to_low_or_unlock())
|
||||
{
|
||||
for_all_cpu([&](cpu_thread* cpu)
|
||||
if (cpu == _this)
|
||||
{
|
||||
copy2[index / 64] &= ~(1ull << (index % 64));
|
||||
}
|
||||
});
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Check only CPUs which haven't acknowledged their waiting state yet
|
||||
for_all_cpu<true>([&](cpu_thread* cpu, u64 index)
|
||||
{
|
||||
if (cpu->state & cpu_flag::wait)
|
||||
{
|
||||
ctr->cpu_copy_bits[index / 64] &= ~(1ull << (index % 64));
|
||||
}
|
||||
});
|
||||
|
||||
if (!std::accumulate(std::begin(ctr->cpu_copy_bits), std::end(ctr->cpu_copy_bits), u64{0}, std::bit_or()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
_mm_pause();
|
||||
}
|
||||
|
||||
// Extract queue and reverse element order (FILO to FIFO) (TODO: maybe leave order as is?)
|
||||
auto* head = queue.exchange(nullptr);
|
||||
|
||||
s8 min_prio = head->prio;
|
||||
s8 max_prio = head->prio;
|
||||
|
||||
if (auto* prev = head->next)
|
||||
{
|
||||
head->next = nullptr;
|
||||
|
||||
do
|
||||
{
|
||||
auto* pre2 = prev->next;
|
||||
prev->next = head;
|
||||
|
||||
head = std::exchange(prev, pre2);
|
||||
|
||||
// Fill priority range
|
||||
min_prio = std::min<s8>(min_prio, head->prio);
|
||||
max_prio = std::max<s8>(max_prio, head->prio);
|
||||
}
|
||||
while (prev);
|
||||
}
|
||||
|
||||
// Execute prefetch hint(s)
|
||||
for (auto work = head; work; work = work->next)
|
||||
{
|
||||
for (u32 i = 0; i < work->prf_size; i++)
|
||||
{
|
||||
_m_prefetchw(work->prf_list[0]);
|
||||
}
|
||||
}
|
||||
|
||||
for_all_cpu<true>([&](cpu_thread* cpu)
|
||||
{
|
||||
_m_prefetchw(&cpu->state);
|
||||
});
|
||||
|
||||
// Execute all stored workload
|
||||
for (s32 prio = max_prio; prio >= min_prio; prio--)
|
||||
{
|
||||
// ... according to priorities
|
||||
for (auto work = head; work; work = work->next)
|
||||
{
|
||||
// Properly sorting single-linked list may require to optimize the loop
|
||||
if (work->prio == prio)
|
||||
{
|
||||
work->exec(work->func_ptr, work->res_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not sure if needed, may be overkill. Some workloads may execute instructions with non-temporal hint.
|
||||
_mm_sfence();
|
||||
|
||||
// Finalization
|
||||
g_suspend_counter++;
|
||||
|
||||
// Exact bitset for flag pause removal
|
||||
std::memcpy(ctr->cpu_copy_bits, copy2, sizeof(copy2));
|
||||
|
||||
for_all_cpu<true>([&](cpu_thread* cpu)
|
||||
{
|
||||
cpu->state -= cpu_flag::pause;
|
||||
});
|
||||
|
||||
g_fxo->get<cpu_counter>()->cpu_suspend_lock.unlock_low();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_fxo->get<cpu_counter>()->cpu_suspend_lock.lock_unlock();
|
||||
// Seems safe to set pause on self because wait flag hasn't been observed yet
|
||||
_this->state += cpu_flag::pause + cpu_flag::temp;
|
||||
_this->check_state();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_this)
|
||||
{
|
||||
m_this->check_state();
|
||||
}
|
||||
g_suspend_counter.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
void cpu_thread::stop_all() noexcept
|
||||
@@ -711,13 +995,16 @@ void cpu_thread::stop_all() noexcept
|
||||
}
|
||||
else
|
||||
{
|
||||
::vip_lock lock(g_fxo->get<cpu_counter>()->cpu_suspend_lock);
|
||||
std::lock_guard lock(g_fxo->get<cpu_counter>()->cpu_suspend_lock);
|
||||
|
||||
for_all_cpu([](cpu_thread* cpu)
|
||||
auto on_stop = [](u32, cpu_thread& cpu)
|
||||
{
|
||||
cpu->state += cpu_flag::dbg_global_stop;
|
||||
cpu->abort();
|
||||
});
|
||||
cpu.state += cpu_flag::dbg_global_stop;
|
||||
cpu.abort();
|
||||
};
|
||||
|
||||
idm::select<named_thread<ppu_thread>>(on_stop);
|
||||
idm::select<named_thread<spu_thread>>(on_stop);
|
||||
}
|
||||
|
||||
sys_log.notice("All CPU threads have been signaled.");
|
||||
@@ -727,7 +1014,12 @@ void cpu_thread::stop_all() noexcept
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
sys_log.notice("All CPU threads have been stopped.");
|
||||
sys_log.notice("All CPU threads have been stopped. [+: %u]", +g_threads_created);
|
||||
|
||||
std::lock_guard lock(g_fxo->get<cpu_counter>()->cpu_suspend_lock);
|
||||
|
||||
g_threads_deleted -= g_threads_created.load();
|
||||
g_threads_created = 0;
|
||||
}
|
||||
|
||||
void cpu_thread::flush_profilers() noexcept
|
||||
|
||||
+73
-19
@@ -11,6 +11,7 @@ enum class cpu_flag : u32
|
||||
stop, // Thread not running (HLE, initial state)
|
||||
exit, // Irreversible exit
|
||||
wait, // Indicates waiting state, set by the thread itself
|
||||
temp, // Indicates that the thread cannot properly return after next check_state()
|
||||
pause, // Thread suspended by suspend_all technique
|
||||
suspend, // Thread suspended
|
||||
ret, // Callback return requested
|
||||
@@ -27,9 +28,6 @@ enum class cpu_flag : u32
|
||||
|
||||
class cpu_thread
|
||||
{
|
||||
// PPU cache backward compatibility hack
|
||||
char dummy[sizeof(std::shared_ptr<void>) - 8];
|
||||
|
||||
public:
|
||||
u64 block_hash = 0;
|
||||
|
||||
@@ -75,6 +73,11 @@ public:
|
||||
return !!(state & (cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause));
|
||||
}
|
||||
|
||||
bool has_pause_flag() const
|
||||
{
|
||||
return !!(state & cpu_flag::pause);
|
||||
}
|
||||
|
||||
// Check thread type
|
||||
u32 id_type() const
|
||||
{
|
||||
@@ -88,13 +91,13 @@ private:
|
||||
|
||||
public:
|
||||
// Thread stats for external observation
|
||||
static atomic_t<u64> g_threads_created, g_threads_deleted;
|
||||
static atomic_t<u64> g_threads_created, g_threads_deleted, g_suspend_counter;
|
||||
|
||||
// Get thread name (as assigned to named_thread)
|
||||
std::string get_name() const;
|
||||
|
||||
// Get CPU state dump (everything)
|
||||
virtual std::string dump_all() const = 0;
|
||||
virtual std::string dump_all() const;
|
||||
|
||||
// Get CPU register dump
|
||||
virtual std::string dump_regs() const;
|
||||
@@ -103,7 +106,7 @@ public:
|
||||
virtual std::string dump_callstack() const;
|
||||
|
||||
// Get CPU call stack list
|
||||
virtual std::vector<u32> dump_callstack_list() const;
|
||||
virtual std::vector<std::pair<u32, u32>> dump_callstack_list() const;
|
||||
|
||||
// Get CPU dump of misc information
|
||||
virtual std::string dump_misc() const;
|
||||
@@ -114,24 +117,75 @@ public:
|
||||
// Callback for cpu_flag::suspend
|
||||
virtual void cpu_sleep() {}
|
||||
|
||||
// Callback for cpu_flag::memory
|
||||
virtual void cpu_mem() {}
|
||||
// Callback for cpu_flag::ret
|
||||
virtual void cpu_return() {}
|
||||
|
||||
// Callback for vm::temporary_unlock
|
||||
virtual void cpu_unmem() {}
|
||||
|
||||
// Thread locker
|
||||
class suspend_all
|
||||
// For internal use
|
||||
struct suspend_work
|
||||
{
|
||||
cpu_thread* m_this;
|
||||
// Task priority
|
||||
s8 prio;
|
||||
|
||||
public:
|
||||
suspend_all(cpu_thread* _this) noexcept;
|
||||
suspend_all(const suspend_all&) = delete;
|
||||
suspend_all& operator=(const suspend_all&) = delete;
|
||||
~suspend_all();
|
||||
// Size of prefetch list workload
|
||||
u32 prf_size;
|
||||
void* const* prf_list;
|
||||
|
||||
void* func_ptr;
|
||||
void* res_buf;
|
||||
|
||||
// Type-erased op executor
|
||||
void (*exec)(void* func, void* res);
|
||||
|
||||
// Next object in the linked list
|
||||
suspend_work* next;
|
||||
|
||||
// Internal method
|
||||
bool push(cpu_thread* _this, bool cancel_if_not_suspended = false) noexcept;
|
||||
};
|
||||
|
||||
// Suspend all threads and execute op (may be executed by other thread than caller!)
|
||||
template <s8 Prio = 0, typename F>
|
||||
static auto suspend_all(cpu_thread* _this, std::initializer_list<void*> hints, F op)
|
||||
{
|
||||
if constexpr (std::is_void_v<std::invoke_result_t<F>>)
|
||||
{
|
||||
suspend_work work{Prio, ::size32(hints), hints.begin(), &op, nullptr, [](void* func, void*)
|
||||
{
|
||||
std::invoke(*static_cast<F*>(func));
|
||||
}};
|
||||
|
||||
work.push(_this);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::invoke_result_t<F> result;
|
||||
|
||||
suspend_work work{Prio, ::size32(hints), hints.begin(), &op, &result, [](void* func, void* res_buf)
|
||||
{
|
||||
*static_cast<std::invoke_result_t<F>*>(res_buf) = std::invoke(*static_cast<F*>(func));
|
||||
}};
|
||||
|
||||
work.push(_this);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Push the workload only if threads are being suspended by suspend_all()
|
||||
template <s8 Prio = 0, typename F>
|
||||
static bool if_suspended(cpu_thread* _this, std::initializer_list<void*> hints, F op)
|
||||
{
|
||||
static_assert(std::is_void_v<std::invoke_result_t<F>>, "Unimplemented (must return void)");
|
||||
{
|
||||
suspend_work work{Prio, ::size32(hints), hints.begin(), &op, nullptr, [](void* func, void*)
|
||||
{
|
||||
std::invoke(*static_cast<F*>(func));
|
||||
}};
|
||||
|
||||
return work.push(_this, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop all threads with cpu_flag::dbg_global_stop
|
||||
static void stop_all() noexcept;
|
||||
|
||||
|
||||
@@ -57,6 +57,15 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
|
||||
{
|
||||
m_use_fma = true;
|
||||
}
|
||||
|
||||
// Test AVX-512_icelake features (TODO)
|
||||
if (cpu == "icelake" ||
|
||||
cpu == "icelake-client" ||
|
||||
cpu == "icelake-server" ||
|
||||
cpu == "tigerlake")
|
||||
{
|
||||
m_use_avx512_icl = true;
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type)
|
||||
@@ -65,9 +74,9 @@ llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type)
|
||||
uint s2 = val->getType()->getScalarSizeInBits();
|
||||
|
||||
if (type->isVectorTy())
|
||||
s1 *= type->getVectorNumElements();
|
||||
s1 *= llvm::cast<llvm::VectorType>(type)->getNumElements();
|
||||
if (val->getType()->isVectorTy())
|
||||
s2 *= val->getType()->getVectorNumElements();
|
||||
s2 *= llvm::cast<llvm::VectorType>(val->getType())->getNumElements();
|
||||
|
||||
if (s1 != s2)
|
||||
{
|
||||
@@ -83,18 +92,37 @@ llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type)
|
||||
}
|
||||
|
||||
template <>
|
||||
v128 cpu_translator::get_const_vector<v128>(llvm::Constant* c, u32 a, u32 b)
|
||||
std::pair<bool, v128> cpu_translator::get_const_vector<v128>(llvm::Value* c, u32 a, u32 b)
|
||||
{
|
||||
v128 result{};
|
||||
|
||||
if (!llvm::isa<llvm::Constant>(c))
|
||||
{
|
||||
return {false, result};
|
||||
}
|
||||
|
||||
const auto t = c->getType();
|
||||
|
||||
if (!t->isVectorTy())
|
||||
{
|
||||
if (const auto ci = llvm::dyn_cast<llvm::ConstantInt>(c); ci && ci->getBitWidth() == 128)
|
||||
{
|
||||
auto cv = ci->getValue();
|
||||
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
result._bit[i] = cv[i];
|
||||
}
|
||||
|
||||
return {true, result};
|
||||
}
|
||||
|
||||
fmt::throw_exception("[0x%x, %u] Not a vector" HERE, a, b);
|
||||
}
|
||||
|
||||
if (uint sz = llvm::cast<llvm::VectorType>(t)->getBitWidth() - 128)
|
||||
if (auto v = llvm::cast<llvm::VectorType>(t); v->getScalarSizeInBits() * v->getNumElements() != 128)
|
||||
{
|
||||
fmt::throw_exception("[0x%x, %u] Bad vector size: %u" HERE, a, b, sz + 128);
|
||||
fmt::throw_exception("[0x%x, %u] Bad vector size: i%ux%u" HERE, a, b, v->getScalarSizeInBits(), v->getNumElements());
|
||||
}
|
||||
|
||||
const auto cv = llvm::dyn_cast<llvm::ConstantDataVector>(c);
|
||||
@@ -106,13 +134,17 @@ v128 cpu_translator::get_const_vector<v128>(llvm::Constant* c, u32 a, u32 b)
|
||||
return {};
|
||||
}
|
||||
|
||||
if (llvm::isa<llvm::ConstantExpr>(c))
|
||||
{
|
||||
// Sorry, if we cannot evaluate it we cannot use it
|
||||
fmt::throw_exception("[0x%x, %u] Constant Expression!" HERE, a, b);
|
||||
}
|
||||
|
||||
fmt::throw_exception("[0x%x, %u] Unexpected constant type" HERE, a, b);
|
||||
}
|
||||
|
||||
const auto sct = t->getScalarType();
|
||||
|
||||
v128 result;
|
||||
|
||||
if (sct->isIntegerTy(8))
|
||||
{
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
@@ -160,13 +192,19 @@ v128 cpu_translator::get_const_vector<v128>(llvm::Constant* c, u32 a, u32 b)
|
||||
fmt::throw_exception("[0x%x, %u] Unexpected vector element type" HERE, a, b);
|
||||
}
|
||||
|
||||
return result;
|
||||
return {true, result};
|
||||
}
|
||||
|
||||
template <>
|
||||
llvm::Constant* cpu_translator::make_const_vector<v128>(v128 v, llvm::Type* t)
|
||||
{
|
||||
verify(HERE), t->isVectorTy() && llvm::cast<llvm::VectorType>(t)->getBitWidth() == 128;
|
||||
if (const auto ct = llvm::dyn_cast<llvm::IntegerType>(t); ct && ct->getBitWidth() == 128)
|
||||
{
|
||||
return llvm::ConstantInt::get(t, llvm::APInt(128, llvm::makeArrayRef(reinterpret_cast<const u64*>(v._bytes), 2)));
|
||||
}
|
||||
|
||||
verify(HERE), t->isVectorTy();
|
||||
verify(HERE), 128 == t->getScalarSizeInBits() * llvm::cast<llvm::VectorType>(t)->getNumElements();
|
||||
|
||||
const auto sct = t->getScalarType();
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ struct llvm_value_t<T[N]> : llvm_value_t<std::conditional_t<(std::extent_v<T> >
|
||||
}
|
||||
else if constexpr (N > 1)
|
||||
{
|
||||
return llvm::VectorType::get(base::get_type(context), N);
|
||||
return llvm::VectorType::get(base::get_type(context), N, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2283,9 +2283,11 @@ struct llvm_splat
|
||||
|
||||
if (auto i = llvm::dyn_cast_or_null<llvm::ShuffleVectorInst>(value))
|
||||
{
|
||||
if (llvm::isa<llvm::ConstantAggregateZero>(i->getOperand(2)))
|
||||
if (llvm::isa<llvm::ConstantAggregateZero>(i->getOperand(1)) || llvm::isa<llvm::UndefValue>(i->getOperand(1)))
|
||||
{
|
||||
if (auto j = llvm::dyn_cast<llvm::InsertElementInst>(i->getOperand(0)))
|
||||
static constexpr int zero_array[llvm_value_t<U>::is_vector]{};
|
||||
|
||||
if (auto j = llvm::dyn_cast<llvm::InsertElementInst>(i->getOperand(0)); j && i->getShuffleMask().equals(zero_array))
|
||||
{
|
||||
if (llvm::cast<llvm::ConstantInt>(j->getOperand(2))->isZero())
|
||||
{
|
||||
@@ -2311,7 +2313,7 @@ struct llvm_zshuffle
|
||||
using type = std::remove_extent_t<T>[N];
|
||||
|
||||
llvm_expr_t<A1> a1;
|
||||
u32 index_array[N];
|
||||
int index_array[N];
|
||||
|
||||
static_assert(llvm_value_t<T>::is_vector, "llvm_zshuffle<>: invalid type");
|
||||
|
||||
@@ -2334,7 +2336,7 @@ struct llvm_zshuffle
|
||||
|
||||
if (auto z = llvm::dyn_cast<llvm::ConstantAggregateZero>(i->getOperand(1)); z && z->getType() == v1->getType())
|
||||
{
|
||||
if (llvm::ConstantDataVector::get(value->getContext(), index_array) == i->getOperand(2))
|
||||
if (i->getShuffleMask().equals(index_array))
|
||||
{
|
||||
if (auto r1 = a1.match(v1); v1)
|
||||
{
|
||||
@@ -2356,7 +2358,7 @@ struct llvm_shuffle2
|
||||
|
||||
llvm_expr_t<A1> a1;
|
||||
llvm_expr_t<A2> a2;
|
||||
u32 index_array[N];
|
||||
int index_array[N];
|
||||
|
||||
static_assert(llvm_value_t<T>::is_vector, "llvm_shuffle2<>: invalid type");
|
||||
|
||||
@@ -2382,7 +2384,7 @@ struct llvm_shuffle2
|
||||
|
||||
if (v1->getType() == v2->getType() && v1->getType() == llvm_value_t<T>::get_type(v1->getContext()))
|
||||
{
|
||||
if (llvm::ConstantDataVector::get(value->getContext(), index_array) == i->getOperand(2))
|
||||
if (i->getShuffleMask().equals(index_array))
|
||||
{
|
||||
if (auto r1 = a1.match(v1); v1)
|
||||
{
|
||||
@@ -2423,6 +2425,9 @@ protected:
|
||||
// Allow FMA
|
||||
bool m_use_fma = false;
|
||||
|
||||
// Allow Icelake tier AVX-512
|
||||
bool m_use_avx512_icl = false;
|
||||
|
||||
// IR builder
|
||||
llvm::IRBuilder<>* m_ir;
|
||||
|
||||
@@ -2662,13 +2667,13 @@ public:
|
||||
template <typename T, typename... Args, typename = std::enable_if_t<llvm_zshuffle<sizeof...(Args), T>::is_ok>>
|
||||
static auto zshuffle(T&& v, Args... indices)
|
||||
{
|
||||
return llvm_zshuffle<sizeof...(Args), T>{std::forward<T>(v), {static_cast<u32>(indices)...}};
|
||||
return llvm_zshuffle<sizeof...(Args), T>{std::forward<T>(v), {static_cast<int>(indices)...}};
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename... Args, typename = std::enable_if_t<llvm_shuffle2<sizeof...(Args), T, U>::is_ok>>
|
||||
static auto shuffle2(T&& v1, U&& v2, Args... indices)
|
||||
{
|
||||
return llvm_shuffle2<sizeof...(Args), T, U>{std::forward<T>(v1), std::forward<U>(v2), {static_cast<u32>(indices)...}};
|
||||
return llvm_shuffle2<sizeof...(Args), T, U>{std::forward<T>(v1), std::forward<U>(v2), {static_cast<int>(indices)...}};
|
||||
}
|
||||
|
||||
// Average: (a + b + 1) >> 1
|
||||
@@ -2682,7 +2687,7 @@ public:
|
||||
const auto cast_op = result.is_sint ? llvm::Instruction::SExt : llvm::Instruction::ZExt;
|
||||
llvm::Type* cast_to = m_ir->getIntNTy(result.esize * 2);
|
||||
if constexpr (result.is_vector != 0)
|
||||
cast_to = llvm::VectorType::get(cast_to, result.is_vector);
|
||||
cast_to = llvm::VectorType::get(cast_to, result.is_vector, false);
|
||||
|
||||
const auto axt = m_ir->CreateCast(cast_op, a.eval(m_ir), cast_to);
|
||||
const auto bxt = m_ir->CreateCast(cast_op, b.eval(m_ir), cast_to);
|
||||
@@ -2744,19 +2749,83 @@ public:
|
||||
}
|
||||
|
||||
// TODO: Support doubles
|
||||
auto fre(value_t<f32[4]> a)
|
||||
template <typename T, typename = std::enable_if_t<llvm_value_t<typename T::type>::esize == 32u && llvm_value_t<typename T::type>::is_float>>
|
||||
auto fre(T a)
|
||||
{
|
||||
decltype(a) result;
|
||||
value_t<typename T::type> result;
|
||||
const auto av = a.eval(m_ir);
|
||||
result.value = m_ir->CreateCall(m_module->getOrInsertFunction("llvm.x86.sse.rcp.ps", av->getType(), av->getType()).getCallee(), {av});
|
||||
result.value = m_ir->CreateCall(m_module->getOrInsertFunction("llvm.x86.sse.rcp.ps", av->getType(), av->getType()), {av});
|
||||
return result;
|
||||
}
|
||||
|
||||
auto frsqe(value_t<f32[4]> a)
|
||||
template <typename T, typename = std::enable_if_t<llvm_value_t<typename T::type>::esize == 32u && llvm_value_t<typename T::type>::is_float>>
|
||||
auto frsqe(T a)
|
||||
{
|
||||
decltype(a) result;
|
||||
value_t<typename T::type> result;
|
||||
const auto av = a.eval(m_ir);
|
||||
result.value = m_ir->CreateCall(m_module->getOrInsertFunction("llvm.x86.sse.rsqrt.ps", av->getType(), av->getType()).getCallee(), {av});
|
||||
result.value = m_ir->CreateCall(m_module->getOrInsertFunction("llvm.x86.sse.rsqrt.ps", av->getType(), av->getType()), {av});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename = std::enable_if_t<std::is_same_v<typename T::type, typename U::type> && llvm_value_t<typename T::type>::esize == 32u && llvm_value_t<typename T::type>::is_float>>
|
||||
auto fmax(T a, U b)
|
||||
{
|
||||
value_t<typename T::type> result;
|
||||
const auto av = a.eval(m_ir);
|
||||
const auto bv = b.eval(m_ir);
|
||||
result.value = m_ir->CreateCall(m_module->getOrInsertFunction("llvm.x86.sse.max.ps", av->getType(), av->getType(), av->getType()), {av, bv});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename = std::enable_if_t<std::is_same_v<typename T::type, typename U::type> && llvm_value_t<typename T::type>::esize == 32u && llvm_value_t<typename T::type>::is_float>>
|
||||
auto fmin(T a, U b)
|
||||
{
|
||||
value_t<typename T::type> result;
|
||||
const auto av = a.eval(m_ir);
|
||||
const auto bv = b.eval(m_ir);
|
||||
result.value = m_ir->CreateCall(m_module->getOrInsertFunction("llvm.x86.sse.min.ps", av->getType(), av->getType(), av->getType()), {av, bv});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
value_t<u8[16]> gf2p8affineqb(T1 a, T2 b, u8 c)
|
||||
{
|
||||
value_t<u8[16]> result;
|
||||
|
||||
const auto data0 = a.eval(m_ir);
|
||||
const auto data1 = b.eval(m_ir);
|
||||
|
||||
const auto immediate = (llvm_const_int<u8>{c});
|
||||
const auto imm8 = immediate.eval(m_ir);
|
||||
|
||||
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_vgf2p8affineqb_128), {data0, data1, imm8});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
value_t<u8[16]> vperm2b(T1 a, T2 b, T3 c)
|
||||
{
|
||||
value_t<u8[16]> result;
|
||||
|
||||
const auto data0 = a.eval(m_ir);
|
||||
const auto data1 = b.eval(m_ir);
|
||||
const auto index = c.eval(m_ir);
|
||||
const auto zeros = llvm::ConstantAggregateZero::get(get_type<u8[16]>());
|
||||
|
||||
if (auto c = llvm::dyn_cast<llvm::Constant>(index))
|
||||
{
|
||||
// Convert VPERM2B index back to LLVM vector shuffle mask
|
||||
const auto cv = llvm::dyn_cast<llvm::ConstantDataVector>(c);
|
||||
|
||||
if (cv || llvm::isa<llvm::ConstantAggregateZero>(c))
|
||||
{
|
||||
result.value = m_ir->CreateZExt(cv, get_type<u32[16]>());
|
||||
result.value = m_ir->CreateShuffleVector(data0, data1, result.value);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpermi2var_qi_128), {data0, index, data1});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2837,7 +2906,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename R = v128>
|
||||
R get_const_vector(llvm::Constant*, u32 a, u32 b);
|
||||
std::pair<bool, R> get_const_vector(llvm::Value*, u32 a, u32 b);
|
||||
|
||||
template <typename T = v128>
|
||||
llvm::Constant* make_const_vector(T, llvm::Type*);
|
||||
@@ -2863,7 +2932,7 @@ struct fmt_unveil<llvm::TypeSize, void>
|
||||
template <>
|
||||
inline llvm::Type* cpu_translator::get_type<__m128i>()
|
||||
{
|
||||
return llvm::VectorType::get(llvm::Type::getInt8Ty(m_context), 16);
|
||||
return llvm::VectorType::get(llvm::Type::getInt8Ty(m_context), 16, false);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "StaticHLE.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/PPUOpcodes.h"
|
||||
|
||||
LOG_CHANNEL(static_hle);
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Utilities/types.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/PPUOpcodes.h"
|
||||
#include "Emu/Memory/vm_ptr.h"
|
||||
#include <vector>
|
||||
|
||||
struct shle_pattern
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "Emu/Cell/lv2/sys_process.h"
|
||||
@@ -44,8 +45,43 @@ void fmt_class_string<CellAudioError>::format(std::string& out, u64 arg)
|
||||
|
||||
cell_audio_config::cell_audio_config()
|
||||
{
|
||||
raw = audio::get_raw_config();
|
||||
reset();
|
||||
}
|
||||
|
||||
void cell_audio_config::reset()
|
||||
{
|
||||
backend.reset();
|
||||
backend = Emu.GetCallbacks().get_audio();
|
||||
|
||||
audio_channels = backend->get_channels();
|
||||
audio_sampling_rate = backend->get_sampling_rate();
|
||||
audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate;
|
||||
|
||||
audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels;
|
||||
audio_buffer_size = audio_buffer_length * backend->get_sample_size();
|
||||
|
||||
desired_buffer_duration = raw.desired_buffer_duration * 1000llu;
|
||||
|
||||
buffering_enabled = raw.buffering_enabled && backend->has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING);;
|
||||
|
||||
minimum_block_period = audio_block_period / 2;
|
||||
maximum_block_period = (6 * audio_block_period) / 5;
|
||||
|
||||
desired_full_buffers = buffering_enabled ? static_cast<u32>(desired_buffer_duration / audio_block_period) + 3 : 2;
|
||||
num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS;
|
||||
|
||||
fully_untouched_timeout = static_cast<u64>(audio_block_period) * 2;
|
||||
partially_untouched_timeout = static_cast<u64>(audio_block_period) * 4;
|
||||
|
||||
const bool raw_time_stretching_enabled = buffering_enabled && raw.enable_time_stretching && (raw.time_stretching_threshold > 0);
|
||||
|
||||
time_stretching_enabled = raw_time_stretching_enabled && backend->has_capability(AudioBackend::SET_FREQUENCY_RATIO);
|
||||
|
||||
time_stretching_threshold = raw.time_stretching_threshold / 100.0f;
|
||||
|
||||
// Warn if audio backend does not support all requested features
|
||||
if (raw_buffering_enabled && !buffering_enabled)
|
||||
if (raw.buffering_enabled && !buffering_enabled)
|
||||
{
|
||||
cellAudio.error("Audio backend %s does not support buffering, this option will be ignored.", backend->GetName());
|
||||
}
|
||||
@@ -122,6 +158,11 @@ f32 audio_ringbuffer::set_frequency_ratio(f32 new_ratio)
|
||||
return frequency_ratio;
|
||||
}
|
||||
|
||||
u64 audio_ringbuffer::get_timestamp() const
|
||||
{
|
||||
return get_system_time() - Emu.GetPauseTime();
|
||||
}
|
||||
|
||||
void audio_ringbuffer::enqueue(const float* in_buffer)
|
||||
{
|
||||
AUDIT(cur_pos < cfg.num_allocated_buffers);
|
||||
@@ -142,7 +183,7 @@ void audio_ringbuffer::enqueue(const float* in_buffer)
|
||||
}
|
||||
|
||||
// Enqueue audio
|
||||
bool success = backend->AddData(buf, AUDIO_BUFFER_SAMPLES * cfg.audio_channels);
|
||||
const bool success = backend->AddData(buf, AUDIO_BUFFER_SAMPLES * cfg.audio_channels);
|
||||
if (!success)
|
||||
{
|
||||
cellAudio.error("Could not enqueue buffer onto audio backend. Attempting to recover...");
|
||||
@@ -311,8 +352,8 @@ void audio_port::tag(s32 offset)
|
||||
// We use -0.0f in case games check if the buffer is empty. -0.0f == 0.0f evaluates to true, but std::signbit can be used to distinguish them
|
||||
const f32 tag = -0.0f;
|
||||
|
||||
const u32 tag_first_pos = num_channels == 2 ? PORT_BUFFER_TAG_FIRST_2CH : PORT_BUFFER_TAG_FIRST_8CH;
|
||||
const u32 tag_delta = num_channels == 2 ? PORT_BUFFER_TAG_DELTA_2CH : PORT_BUFFER_TAG_DELTA_8CH;
|
||||
const u32 tag_first_pos = num_channels == 2 ? PORT_BUFFER_TAG_FIRST_2CH : num_channels == 6 ? PORT_BUFFER_TAG_FIRST_6CH : PORT_BUFFER_TAG_FIRST_8CH;
|
||||
const u32 tag_delta = num_channels == 2 ? PORT_BUFFER_TAG_DELTA_2CH : num_channels == 6 ? PORT_BUFFER_TAG_DELTA_6CH : PORT_BUFFER_TAG_DELTA_8CH;
|
||||
|
||||
for (u32 tag_pos = tag_first_pos, tag_nr = 0; tag_nr < PORT_BUFFER_TAG_COUNT; tag_pos += tag_delta, tag_nr++)
|
||||
{
|
||||
@@ -341,8 +382,8 @@ std::tuple<u32, u32, u32, u32> cell_audio_thread::count_port_buffer_tags()
|
||||
u32 port_pos = port.position();
|
||||
|
||||
// Find the last tag that has been touched
|
||||
const u32 tag_first_pos = port.num_channels == 2 ? PORT_BUFFER_TAG_FIRST_2CH : PORT_BUFFER_TAG_FIRST_8CH;
|
||||
const u32 tag_delta = port.num_channels == 2 ? PORT_BUFFER_TAG_DELTA_2CH : PORT_BUFFER_TAG_DELTA_8CH;
|
||||
const u32 tag_first_pos = port.num_channels == 2 ? PORT_BUFFER_TAG_FIRST_2CH : port.num_channels == 6 ? PORT_BUFFER_TAG_FIRST_6CH : PORT_BUFFER_TAG_FIRST_8CH;
|
||||
const u32 tag_delta = port.num_channels == 2 ? PORT_BUFFER_TAG_DELTA_2CH : port.num_channels == 6 ? PORT_BUFFER_TAG_DELTA_6CH : PORT_BUFFER_TAG_DELTA_8CH;
|
||||
|
||||
u32 last_touched_tag_nr = port.prev_touched_tag_nr;
|
||||
bool retouched = false;
|
||||
@@ -500,6 +541,63 @@ void cell_audio_thread::advance(u64 timestamp, bool reset)
|
||||
}
|
||||
}
|
||||
|
||||
namespace audio
|
||||
{
|
||||
cell_audio_config::raw_config get_raw_config()
|
||||
{
|
||||
return
|
||||
{
|
||||
.buffering_enabled = static_cast<bool>(g_cfg.audio.enable_buffering),
|
||||
.desired_buffer_duration = g_cfg.audio.desired_buffer_duration,
|
||||
.enable_time_stretching = static_cast<bool>(g_cfg.audio.enable_time_stretching),
|
||||
.time_stretching_threshold = g_cfg.audio.time_stretching_threshold,
|
||||
.convert_to_u16 = static_cast<bool>(g_cfg.audio.convert_to_u16),
|
||||
.start_threshold = static_cast<u32>(g_cfg.audio.start_threshold),
|
||||
.sampling_period_multiplier = static_cast<u32>(g_cfg.audio.sampling_period_multiplier),
|
||||
.downmix = g_cfg.audio.audio_channel_downmix,
|
||||
.renderer = g_cfg.audio.renderer
|
||||
};
|
||||
}
|
||||
|
||||
void configure_audio()
|
||||
{
|
||||
if (const auto g_audio = g_fxo->get<cell_audio>())
|
||||
{
|
||||
// Only reboot the audio renderer if a relevant setting changed
|
||||
const auto new_raw = get_raw_config();
|
||||
|
||||
if (const auto raw = g_audio->cfg.raw;
|
||||
raw.desired_buffer_duration != new_raw.desired_buffer_duration ||
|
||||
raw.buffering_enabled != new_raw.buffering_enabled ||
|
||||
raw.time_stretching_threshold != new_raw.time_stretching_threshold ||
|
||||
raw.enable_time_stretching != new_raw.enable_time_stretching ||
|
||||
raw.convert_to_u16 != new_raw.convert_to_u16 ||
|
||||
raw.start_threshold != new_raw.start_threshold ||
|
||||
raw.sampling_period_multiplier != new_raw.sampling_period_multiplier ||
|
||||
raw.downmix != new_raw.downmix ||
|
||||
raw.renderer != new_raw.renderer)
|
||||
{
|
||||
g_audio->cfg.raw = new_raw;
|
||||
g_audio->m_update_configuration = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cell_audio_thread::update_config()
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
// Clear ringbuffer
|
||||
ringbuffer.reset();
|
||||
|
||||
// Reload config
|
||||
cfg.reset();
|
||||
|
||||
// Allocate ringbuffer
|
||||
ringbuffer.reset(new audio_ringbuffer(cfg));
|
||||
}
|
||||
|
||||
void cell_audio_thread::operator()()
|
||||
{
|
||||
thread_ctrl::set_native_priority(1);
|
||||
@@ -519,6 +617,12 @@ void cell_audio_thread::operator()()
|
||||
// Main cellAudio loop
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
if (m_update_configuration)
|
||||
{
|
||||
update_config();
|
||||
m_update_configuration = false;
|
||||
}
|
||||
|
||||
const u64 timestamp = ringbuffer->update();
|
||||
|
||||
if (Emu.IsPaused())
|
||||
@@ -742,16 +846,19 @@ void cell_audio_thread::operator()()
|
||||
|
||||
// Mix
|
||||
float *buf = ringbuffer->get_current_buffer();
|
||||
if (cfg.audio_channels == 2)
|
||||
{
|
||||
mix<true>(buf);
|
||||
}
|
||||
else if (cfg.audio_channels == 8)
|
||||
{
|
||||
mix<false>(buf);
|
||||
}
|
||||
else
|
||||
|
||||
switch (cfg.audio_channels)
|
||||
{
|
||||
case 2:
|
||||
mix<audio_downmix::downmix_to_stereo>(buf);
|
||||
break;
|
||||
case 6:
|
||||
mix<audio_downmix::downmix_to_5_1>(buf);
|
||||
break;
|
||||
case 8:
|
||||
mix<audio_downmix::no_downmix>(buf);
|
||||
break;
|
||||
default:
|
||||
fmt::throw_exception("Unsupported number of audio channels: %u", cfg.audio_channels);
|
||||
}
|
||||
|
||||
@@ -766,12 +873,12 @@ void cell_audio_thread::operator()()
|
||||
ringbuffer.reset();
|
||||
}
|
||||
|
||||
template <bool DownmixToStereo>
|
||||
template <audio_downmix downmix>
|
||||
void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
||||
{
|
||||
AUDIT(out_buffer != nullptr);
|
||||
|
||||
constexpr u32 channels = DownmixToStereo ? 2 : 8;
|
||||
constexpr u32 channels = downmix == audio_downmix::no_downmix ? 8 : downmix == audio_downmix::downmix_to_5_1 ? 6 : 2;
|
||||
constexpr u32 out_buffer_sz = channels * AUDIO_BUFFER_SAMPLES;
|
||||
|
||||
bool first_mix = true;
|
||||
@@ -823,14 +930,18 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
||||
out_buffer[out + 0] = left;
|
||||
out_buffer[out + 1] = right;
|
||||
|
||||
if constexpr (!DownmixToStereo)
|
||||
if constexpr (downmix != audio_downmix::downmix_to_stereo)
|
||||
{
|
||||
out_buffer[out + 2] = 0.0f;
|
||||
out_buffer[out + 3] = 0.0f;
|
||||
out_buffer[out + 4] = 0.0f;
|
||||
out_buffer[out + 5] = 0.0f;
|
||||
out_buffer[out + 6] = 0.0f;
|
||||
out_buffer[out + 7] = 0.0f;
|
||||
|
||||
if constexpr (downmix != audio_downmix::downmix_to_5_1)
|
||||
{
|
||||
out_buffer[out + 6] = 0.0f;
|
||||
out_buffer[out + 7] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
first_mix = false;
|
||||
@@ -866,12 +977,21 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
||||
const float side_left = buf[in + 6] * m;
|
||||
const float side_right = buf[in + 7] * m;
|
||||
|
||||
if constexpr (DownmixToStereo)
|
||||
if constexpr (downmix == audio_downmix::downmix_to_stereo)
|
||||
{
|
||||
// Don't mix in the lfe as per dolby specification and based on documentation
|
||||
const float mid = center * 0.5;
|
||||
out_buffer[out + 0] = left * minus_3db + mid + side_left * 0.5 + rear_left * 0.5;
|
||||
out_buffer[out + 1] = right * minus_3db + mid + side_right * 0.5 + rear_right * 0.5;
|
||||
const float mid = center * 0.5f;
|
||||
out_buffer[out + 0] = left * minus_3db + mid + side_left * 0.5f + rear_left * 0.5f;
|
||||
out_buffer[out + 1] = right * minus_3db + mid + side_right * 0.5f + rear_right * 0.5f;
|
||||
}
|
||||
else if constexpr (downmix == audio_downmix::downmix_to_5_1)
|
||||
{
|
||||
out_buffer[out + 0] = left;
|
||||
out_buffer[out + 1] = right;
|
||||
out_buffer[out + 2] = center;
|
||||
out_buffer[out + 3] = low_freq;
|
||||
out_buffer[out + 4] = side_left + rear_left;
|
||||
out_buffer[out + 5] = side_right + rear_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -902,12 +1022,21 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
||||
const float side_left = buf[in + 6] * m;
|
||||
const float side_right = buf[in + 7] * m;
|
||||
|
||||
if constexpr (DownmixToStereo)
|
||||
if constexpr (downmix == audio_downmix::downmix_to_stereo)
|
||||
{
|
||||
// Don't mix in the lfe as per dolby specification and based on documentation
|
||||
const float mid = center * 0.5;
|
||||
out_buffer[out + 0] += left * minus_3db + mid + side_left * 0.5 + rear_left * 0.5;
|
||||
out_buffer[out + 1] += right * minus_3db + mid + side_right * 0.5 + rear_right * 0.5;
|
||||
const float mid = center * 0.5f;
|
||||
out_buffer[out + 0] += left * minus_3db + mid + side_left * 0.5f + rear_left * 0.5f;
|
||||
out_buffer[out + 1] += right * minus_3db + mid + side_right * 0.5f + rear_right * 0.5f;
|
||||
}
|
||||
else if constexpr (downmix == audio_downmix::downmix_to_5_1)
|
||||
{
|
||||
out_buffer[out + 0] += left;
|
||||
out_buffer[out + 1] += right;
|
||||
out_buffer[out + 2] += center;
|
||||
out_buffer[out + 3] += low_freq;
|
||||
out_buffer[out + 4] += side_left + rear_left;
|
||||
out_buffer[out + 5] += side_right + rear_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -934,7 +1063,7 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
||||
{
|
||||
std::memset(out_buffer, 0, out_buffer_sz * sizeof(float));
|
||||
}
|
||||
else if (g_cfg.audio.convert_to_u16)
|
||||
else if (cfg.backend->get_convert_to_u16())
|
||||
{
|
||||
// convert the data from float to u16 with clipping:
|
||||
// 2x MULPS
|
||||
@@ -1097,7 +1226,7 @@ error_code cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PORT_FULL;
|
||||
}
|
||||
|
||||
|
||||
// TODO: is this necessary in any way? (Based on libaudio.prx)
|
||||
//const u64 num_channels_non_0 = std::max<u64>(1, num_channels);
|
||||
|
||||
@@ -1368,7 +1497,7 @@ error_code cellAudioSetPortLevel(u32 portNum, float level)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
static error_code AudioCreateNotifyEventQueue(vm::ptr<u32> id, vm::ptr<u64> key, u32 queue_type)
|
||||
static error_code AudioCreateNotifyEventQueue(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<u64> key, u32 queue_type)
|
||||
{
|
||||
vm::var<sys_event_queue_attribute_t> attr;
|
||||
attr->protocol = SYS_SYNC_FIFO;
|
||||
@@ -1384,7 +1513,7 @@ static error_code AudioCreateNotifyEventQueue(vm::ptr<u32> id, vm::ptr<u64> key,
|
||||
// So check initialization as well
|
||||
const u32 queue_depth = g_fxo->get<cell_audio>()->init && g_ps3_process_info.sdk_ver <= 0x35FFFF ? 2 : 8;
|
||||
|
||||
if (CellError res{sys_event_queue_create(id, attr, key_value, queue_depth) + 0u})
|
||||
if (CellError res{sys_event_queue_create(ppu, id, attr, key_value, queue_depth) + 0u})
|
||||
{
|
||||
if (res != CELL_EEXIST)
|
||||
{
|
||||
@@ -1401,14 +1530,14 @@ static error_code AudioCreateNotifyEventQueue(vm::ptr<u32> id, vm::ptr<u64> key,
|
||||
return CELL_AUDIO_ERROR_EVENT_QUEUE;
|
||||
}
|
||||
|
||||
error_code cellAudioCreateNotifyEventQueue(vm::ptr<u32> id, vm::ptr<u64> key)
|
||||
error_code cellAudioCreateNotifyEventQueue(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<u64> key)
|
||||
{
|
||||
cellAudio.warning("cellAudioCreateNotifyEventQueue(id=*0x%x, key=*0x%x)", id, key);
|
||||
|
||||
return AudioCreateNotifyEventQueue(id, key, SYS_PPU_QUEUE);
|
||||
return AudioCreateNotifyEventQueue(ppu, id, key, SYS_PPU_QUEUE);
|
||||
}
|
||||
|
||||
error_code cellAudioCreateNotifyEventQueueEx(vm::ptr<u32> id, vm::ptr<u64> key, u32 iFlags)
|
||||
error_code cellAudioCreateNotifyEventQueueEx(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<u64> key, u32 iFlags)
|
||||
{
|
||||
cellAudio.warning("cellAudioCreateNotifyEventQueueEx(id=*0x%x, key=*0x%x, iFlags=0x%x)", id, key, iFlags);
|
||||
|
||||
@@ -1418,7 +1547,7 @@ error_code cellAudioCreateNotifyEventQueueEx(vm::ptr<u32> id, vm::ptr<u64> key,
|
||||
}
|
||||
|
||||
const u32 queue_type = (iFlags & CELL_AUDIO_CREATEEVENTFLAG_SPU) ? SYS_SPU_QUEUE : SYS_PPU_QUEUE;
|
||||
return AudioCreateNotifyEventQueue(id, key, queue_type);
|
||||
return AudioCreateNotifyEventQueue(ppu, id, key, queue_type);
|
||||
}
|
||||
|
||||
error_code AudioSetNotifyEventQueue(u64 key, u32 iFlags)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
#include "Emu/Audio/AudioDumper.h"
|
||||
#include "Emu/system_config_types.h"
|
||||
|
||||
struct lv2_event_queue;
|
||||
|
||||
@@ -64,6 +65,7 @@ enum
|
||||
CELL_AUDIO_PORTATTR_OUT_PERSONAL_2 = 0x0000000004000000ULL,
|
||||
CELL_AUDIO_PORTATTR_OUT_PERSONAL_3 = 0x0000000008000000ULL,
|
||||
CELL_AUDIO_PORTATTR_OUT_SECONDARY = 0x0000000000000001ULL,
|
||||
CELL_AUDIO_PORTATTR_OUT_STREAM1 = 0x0000000000000001ULL,
|
||||
|
||||
CELL_AUDIO_STATUS_CLOSE = 0x1010,
|
||||
CELL_AUDIO_STATUS_READY = 1,
|
||||
@@ -100,6 +102,7 @@ enum : u32
|
||||
MAX_AUDIO_EVENT_QUEUES = 64,
|
||||
|
||||
AUDIO_BLOCK_SIZE_2CH = 2 * AUDIO_BUFFER_SAMPLES,
|
||||
AUDIO_BLOCK_SIZE_6CH = 6 * AUDIO_BUFFER_SAMPLES,
|
||||
AUDIO_BLOCK_SIZE_8CH = 8 * AUDIO_BUFFER_SAMPLES,
|
||||
|
||||
PORT_BUFFER_TAG_COUNT = 6,
|
||||
@@ -108,6 +111,10 @@ enum : u32
|
||||
PORT_BUFFER_TAG_DELTA_2CH = PORT_BUFFER_TAG_LAST_2CH / (PORT_BUFFER_TAG_COUNT - 1),
|
||||
PORT_BUFFER_TAG_FIRST_2CH = PORT_BUFFER_TAG_LAST_2CH % (PORT_BUFFER_TAG_COUNT - 1),
|
||||
|
||||
PORT_BUFFER_TAG_LAST_6CH = AUDIO_BLOCK_SIZE_6CH - 1,
|
||||
PORT_BUFFER_TAG_DELTA_6CH = PORT_BUFFER_TAG_LAST_6CH / (PORT_BUFFER_TAG_COUNT - 1),
|
||||
PORT_BUFFER_TAG_FIRST_6CH = PORT_BUFFER_TAG_LAST_6CH % (PORT_BUFFER_TAG_COUNT - 1),
|
||||
|
||||
PORT_BUFFER_TAG_LAST_8CH = AUDIO_BLOCK_SIZE_8CH - 1,
|
||||
PORT_BUFFER_TAG_DELTA_8CH = PORT_BUFFER_TAG_LAST_8CH / (PORT_BUFFER_TAG_COUNT - 1),
|
||||
PORT_BUFFER_TAG_FIRST_8CH = PORT_BUFFER_TAG_LAST_8CH % (PORT_BUFFER_TAG_COUNT - 1),
|
||||
@@ -182,49 +189,59 @@ struct audio_port
|
||||
|
||||
struct cell_audio_config
|
||||
{
|
||||
const std::shared_ptr<AudioBackend> backend = Emu.GetCallbacks().get_audio();
|
||||
struct raw_config
|
||||
{
|
||||
bool buffering_enabled = false;
|
||||
s64 desired_buffer_duration = 0;
|
||||
bool enable_time_stretching = false;
|
||||
s64 time_stretching_threshold = 0;
|
||||
bool convert_to_u16 = false;
|
||||
u32 start_threshold = 0;
|
||||
u32 sampling_period_multiplier = 0;
|
||||
audio_downmix downmix = audio_downmix::downmix_to_stereo;
|
||||
audio_renderer renderer = audio_renderer::null;
|
||||
} raw;
|
||||
|
||||
const u32 audio_channels = AudioBackend::get_channels();
|
||||
const u32 audio_sampling_rate = AudioBackend::get_sampling_rate();
|
||||
const u32 audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate;
|
||||
std::shared_ptr<AudioBackend> backend = nullptr;
|
||||
|
||||
const u32 audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels;
|
||||
const u32 audio_buffer_size = audio_buffer_length * AudioBackend::get_sample_size();
|
||||
u32 audio_channels = 0;
|
||||
u32 audio_sampling_rate = 0;
|
||||
u32 audio_block_period = 0;
|
||||
|
||||
u32 audio_buffer_length = 0;
|
||||
u32 audio_buffer_size = 0;
|
||||
|
||||
/*
|
||||
* Buffering
|
||||
*/
|
||||
const u64 desired_buffer_duration = g_cfg.audio.desired_buffer_duration * 1000llu;
|
||||
private:
|
||||
const bool raw_buffering_enabled = static_cast<bool>(g_cfg.audio.enable_buffering);
|
||||
public:
|
||||
|
||||
u64 desired_buffer_duration = 0;
|
||||
|
||||
// We need a non-blocking backend (implementing play/pause/flush) to be able to do buffering correctly
|
||||
// We also need to be able to query the current playing state
|
||||
const bool buffering_enabled = raw_buffering_enabled && backend->has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING);
|
||||
bool buffering_enabled = false;
|
||||
|
||||
const u64 minimum_block_period = audio_block_period / 2; // the block period will not be dynamically lowered below this value (usecs)
|
||||
const u64 maximum_block_period = (6 * audio_block_period) / 5; // the block period will not be dynamically increased above this value (usecs)
|
||||
u64 minimum_block_period = 0; // the block period will not be dynamically lowered below this value (usecs)
|
||||
u64 maximum_block_period = 0; // the block period will not be dynamically increased above this value (usecs)
|
||||
|
||||
const u32 desired_full_buffers = buffering_enabled ? static_cast<u32>(desired_buffer_duration / audio_block_period) + 3 : 2;
|
||||
const u32 num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS; // number of ringbuffer buffers
|
||||
u32 desired_full_buffers = 0;
|
||||
u32 num_allocated_buffers = 0; // number of ringbuffer buffers
|
||||
|
||||
const f32 period_average_alpha = 0.02f; // alpha factor for the m_average_period rolling average
|
||||
|
||||
const s64 period_comparison_margin = 250; // when comparing the current period time with the desired period, if it is below this number of usecs we do not wait any longer
|
||||
|
||||
const u64 fully_untouched_timeout = 2 * audio_block_period; // timeout if the game has not touched any audio buffer yet
|
||||
const u64 partially_untouched_timeout = 4 * audio_block_period; // timeout if the game has not touched all audio buffers yet
|
||||
u64 fully_untouched_timeout = 0; // timeout if the game has not touched any audio buffer yet
|
||||
u64 partially_untouched_timeout = 0; // timeout if the game has not touched all audio buffers yet
|
||||
|
||||
/*
|
||||
* Time Stretching
|
||||
*/
|
||||
private:
|
||||
const bool raw_time_stretching_enabled = buffering_enabled && g_cfg.audio.enable_time_stretching && (g_cfg.audio.time_stretching_threshold > 0);
|
||||
public:
|
||||
// We need to be able to set a dynamic frequency ratio to be able to do time stretching
|
||||
const bool time_stretching_enabled = raw_time_stretching_enabled && backend->has_capability(AudioBackend::SET_FREQUENCY_RATIO);
|
||||
|
||||
const f32 time_stretching_threshold = g_cfg.audio.time_stretching_threshold / 100.0f; // we only apply time stretching below this buffer fill rate (adjusted for average period)
|
||||
// We need to be able to set a dynamic frequency ratio to be able to do time stretching
|
||||
bool time_stretching_enabled = false;
|
||||
|
||||
f32 time_stretching_threshold = 0.0f; // we only apply time stretching below this buffer fill rate (adjusted for average period)
|
||||
const f32 time_stretching_step = 0.1f; // will only reduce/increase the frequency ratio in steps of at least this value
|
||||
const f32 time_stretching_scale = 0.9f;
|
||||
|
||||
@@ -232,6 +249,11 @@ public:
|
||||
* Constructor
|
||||
*/
|
||||
cell_audio_config();
|
||||
|
||||
/*
|
||||
* Config changes
|
||||
*/
|
||||
void reset();
|
||||
};
|
||||
|
||||
class audio_ringbuffer
|
||||
@@ -285,10 +307,7 @@ public:
|
||||
return buffer[num].get();
|
||||
}
|
||||
|
||||
u64 get_timestamp() const
|
||||
{
|
||||
return get_system_time() - Emu.GetPauseTime();
|
||||
}
|
||||
u64 get_timestamp() const;
|
||||
|
||||
float* get_current_buffer() const
|
||||
{
|
||||
@@ -332,12 +351,13 @@ public:
|
||||
|
||||
class cell_audio_thread
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<audio_ringbuffer> ringbuffer;
|
||||
|
||||
void reset_ports(s32 offset = 0);
|
||||
void advance(u64 timestamp, bool reset = true);
|
||||
std::tuple<u32, u32, u32, u32> count_port_buffer_tags();
|
||||
template <bool DownmixToStereo>
|
||||
template <audio_downmix downmix>
|
||||
void mix(float *out_buffer, s32 offset = 0);
|
||||
void finish_port_volume_stepping();
|
||||
|
||||
@@ -346,8 +366,11 @@ class cell_audio_thread
|
||||
return (time_left > 350) ? time_left - 250 : 100;
|
||||
}
|
||||
|
||||
void update_config();
|
||||
|
||||
public:
|
||||
cell_audio_config cfg;
|
||||
atomic_t<bool> m_update_configuration = false;
|
||||
|
||||
shared_mutex mutex;
|
||||
atomic_t<u32> init = 0;
|
||||
@@ -370,7 +393,7 @@ public:
|
||||
u64 m_counter = 0;
|
||||
u64 m_start_time = 0;
|
||||
u64 m_dynamic_period = 0;
|
||||
f32 m_average_playtime;
|
||||
f32 m_average_playtime = 0.0f;
|
||||
|
||||
void operator()();
|
||||
|
||||
@@ -400,3 +423,9 @@ public:
|
||||
};
|
||||
|
||||
using cell_audio = named_thread<cell_audio_thread>;
|
||||
|
||||
namespace audio
|
||||
{
|
||||
cell_audio_config::raw_config get_raw_config();
|
||||
void configure_audio();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "cellCamera.h"
|
||||
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/lv2/sys_event.h"
|
||||
#include "Emu/IdManager.h"
|
||||
@@ -26,7 +27,9 @@ void fmt_class_string<CellCameraError>::format(std::string& out, u64 arg)
|
||||
STR_CASE(CELL_CAMERA_ERROR_RESOLUTION_UNKNOWN);
|
||||
STR_CASE(CELL_CAMERA_ERROR_BAD_FRAMERATE);
|
||||
STR_CASE(CELL_CAMERA_ERROR_TIMEOUT);
|
||||
STR_CASE(CELL_CAMERA_ERROR_BUSY);
|
||||
STR_CASE(CELL_CAMERA_ERROR_FATAL);
|
||||
STR_CASE(CELL_CAMERA_ERROR_MUTEX);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/Timer.h"
|
||||
#include "Emu/Cell/lv2/sys_memory.h"
|
||||
@@ -22,7 +22,9 @@ enum CellCameraError : u32
|
||||
CELL_CAMERA_ERROR_RESOLUTION_UNKNOWN = 0x8014080b,
|
||||
CELL_CAMERA_ERROR_BAD_FRAMERATE = 0x8014080c,
|
||||
CELL_CAMERA_ERROR_TIMEOUT = 0x8014080d,
|
||||
CELL_CAMERA_ERROR_BUSY = 0x8014080e,
|
||||
CELL_CAMERA_ERROR_FATAL = 0x8014080f,
|
||||
CELL_CAMERA_ERROR_MUTEX = 0x80140810,
|
||||
};
|
||||
|
||||
// Event masks
|
||||
@@ -322,6 +324,39 @@ enum
|
||||
GET_DEF = 0x87,
|
||||
};
|
||||
|
||||
enum // version
|
||||
{
|
||||
CELL_CAMERA_INFO_VER_100 = 0x0100,
|
||||
CELL_CAMERA_INFO_VER_101 = 0x0101,
|
||||
CELL_CAMERA_INFO_VER_200 = 0x0200,
|
||||
CELL_CAMERA_INFO_VER = CELL_CAMERA_INFO_VER_200,
|
||||
|
||||
CELL_CAMERA_READ_VER_100 = 0x0100,
|
||||
CELL_CAMERA_READ_VER = CELL_CAMERA_READ_VER_100,
|
||||
};
|
||||
|
||||
// Other
|
||||
enum
|
||||
{
|
||||
CELL_CAMERA_MAX_CAMERAS = 1
|
||||
};
|
||||
|
||||
struct CellCameraInfo
|
||||
{
|
||||
// filled in by application as inputs for open
|
||||
be_t<s32> format;
|
||||
be_t<s32> resolution;
|
||||
be_t<s32> framerate;
|
||||
|
||||
// filled in by open
|
||||
vm::bptr<u8> buffer;
|
||||
be_t<s32> bytesize;
|
||||
be_t<s32> width;
|
||||
be_t<s32> height;
|
||||
be_t<s32> dev_num;
|
||||
be_t<s32> guid;
|
||||
};
|
||||
|
||||
struct CellCameraInfoEx
|
||||
{
|
||||
be_t<s32> format; // CellCameraFormat
|
||||
|
||||
@@ -1,22 +1,43 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "cellDaisy.h"
|
||||
|
||||
LOG_CHANNEL(cellDaisy);
|
||||
|
||||
template <>
|
||||
void fmt_class_string<CellDaisyError>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_enum(out, arg, [](CellDaisyError value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
STR_CASE(CELL_DAISY_ERROR_NO_BEGIN);
|
||||
STR_CASE(CELL_DAISY_ERROR_INVALID_PORT_ATTACH);
|
||||
STR_CASE(CELL_DAISY_ERROR_NOT_IMPLEMENTED);
|
||||
STR_CASE(CELL_DAISY_ERROR_AGAIN);
|
||||
STR_CASE(CELL_DAISY_ERROR_INVAL);
|
||||
STR_CASE(CELL_DAISY_ERROR_PERM);
|
||||
STR_CASE(CELL_DAISY_ERROR_BUSY);
|
||||
STR_CASE(CELL_DAISY_ERROR_STAT);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
using LFQueue2 = struct CellDaisyLFQueue2;
|
||||
using Lock = struct CellDaisyLock;
|
||||
using ScatterGatherInterlock = struct CellDaisyScatterGatherInterlock;
|
||||
using AtomicInterlock = volatile struct CellDaisyAtomicInterlock;
|
||||
|
||||
s32 cellDaisyLFQueue2GetPopPointer(vm::ptr<LFQueue2> queue, vm::ptr<s32> pPointer, u32 isBlocking)
|
||||
error_code cellDaisyLFQueue2GetPopPointer(vm::ptr<LFQueue2> queue, vm::ptr<s32> pPointer, u32 isBlocking)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLFQueue2GetPopPointer()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLFQueue2CompletePopPointer(vm::ptr<LFQueue2> queue, s32 pointer, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal, u32 isQueueFull)
|
||||
error_code cellDaisyLFQueue2CompletePopPointer(vm::ptr<LFQueue2> queue, s32 pointer, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal, u32 isQueueFull)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLFQueue2CompletePopPointer()");
|
||||
return CELL_OK;
|
||||
@@ -27,7 +48,7 @@ void cellDaisyLFQueue2PushOpen(vm::ptr<LFQueue2> queue)
|
||||
cellDaisy.todo("cellDaisyLFQueue2PushOpen()");
|
||||
}
|
||||
|
||||
s32 cellDaisyLFQueue2PushClose(vm::ptr<LFQueue2> queue, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal)
|
||||
error_code cellDaisyLFQueue2PushClose(vm::ptr<LFQueue2> queue, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLFQueue2PushClose()");
|
||||
return CELL_OK;
|
||||
@@ -38,73 +59,73 @@ void cellDaisyLFQueue2PopOpen(vm::ptr<LFQueue2> queue)
|
||||
cellDaisy.todo("cellDaisyLFQueue2PopOpen()");
|
||||
}
|
||||
|
||||
s32 cellDaisyLFQueue2PopClose(vm::ptr<LFQueue2> queue, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal)
|
||||
error_code cellDaisyLFQueue2PopClose(vm::ptr<LFQueue2> queue, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLFQueue2PopClose()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLFQueue2HasUnfinishedConsumer(vm::ptr<LFQueue2> queue, u32 isCancelled)
|
||||
error_code cellDaisyLFQueue2HasUnfinishedConsumer(vm::ptr<LFQueue2> queue, u32 isCancelled)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLFQueue2HasUnfinishedConsumer()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisy_snprintf(vm::ptr<char> buffer, u32 count, vm::cptr<char> fmt, ppu_va_args_t fmt_args)
|
||||
error_code cellDaisy_snprintf(vm::ptr<char> buffer, u32 count, vm::cptr<char> fmt, ppu_va_args_t fmt_args)
|
||||
{
|
||||
cellDaisy.todo("cellDaisy_snprintf()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLock_initialize(vm::ptr<Lock> _this, u32 depth)
|
||||
error_code cellDaisyLock_initialize(vm::ptr<Lock> _this, u32 depth)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLock_initialize()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLock_getNextHeadPointer(vm::ptr<Lock> _this)
|
||||
error_code cellDaisyLock_getNextHeadPointer(vm::ptr<Lock> _this)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLock_getNextHeadPointer()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLock_getNextTailPointer(vm::ptr<Lock> _this)
|
||||
error_code cellDaisyLock_getNextTailPointer(vm::ptr<Lock> _this)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLock_getNextTailPointer()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLock_completeConsume(vm::ptr<Lock> _this, u32 pointer)
|
||||
error_code cellDaisyLock_completeConsume(vm::ptr<Lock> _this, u32 pointer)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLock_completeConsume()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLock_completeProduce(vm::ptr<Lock> _this, u32 pointer)
|
||||
error_code cellDaisyLock_completeProduce(vm::ptr<Lock> _this, u32 pointer)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLock_completeProduce()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLock_pushOpen(vm::ptr<Lock> _this)
|
||||
error_code cellDaisyLock_pushOpen(vm::ptr<Lock> _this)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLock_pushOpen()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLock_pushClose(vm::ptr<Lock> _this)
|
||||
error_code cellDaisyLock_pushClose(vm::ptr<Lock> _this)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLock_pushClose()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLock_popOpen(vm::ptr<Lock> _this)
|
||||
error_code cellDaisyLock_popOpen(vm::ptr<Lock> _this)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLock_popOpen()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyLock_popClose(vm::ptr<Lock> _this)
|
||||
error_code cellDaisyLock_popClose(vm::ptr<Lock> _this)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyLock_popClose()");
|
||||
return CELL_OK;
|
||||
@@ -125,13 +146,13 @@ void cellDaisyScatterGatherInterlock_9tor(vm::ptr<ScatterGatherInterlock> _this)
|
||||
cellDaisy.todo("cellDaisyScatterGatherInterlock_9tor()");
|
||||
}
|
||||
|
||||
s32 cellDaisyScatterGatherInterlock_probe(vm::ptr<ScatterGatherInterlock> _this, u32 isBlocking)
|
||||
error_code cellDaisyScatterGatherInterlock_probe(vm::ptr<ScatterGatherInterlock> _this, u32 isBlocking)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyScatterGatherInterlock_probe()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDaisyScatterGatherInterlock_release(vm::ptr<ScatterGatherInterlock> _this)
|
||||
error_code cellDaisyScatterGatherInterlock_release(vm::ptr<ScatterGatherInterlock> _this)
|
||||
{
|
||||
cellDaisy.todo("cellDaisyScatterGatherInterlock_release()");
|
||||
return CELL_OK;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
// libDaisy = 0x80410501 - 0x804105ff
|
||||
|
||||
// Error codes
|
||||
enum
|
||||
enum CellDaisyError : u32
|
||||
{
|
||||
CELL_DAISY_ERROR_NO_BEGIN = 0x80410501,
|
||||
CELL_DAISY_ERROR_INVALID_PORT_ATTACH = 0x80410502,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
@@ -10,6 +11,24 @@
|
||||
|
||||
LOG_CHANNEL(cellDmux);
|
||||
|
||||
template <>
|
||||
void fmt_class_string<CellDmuxError>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_enum(out, arg, [](CellDmuxError value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
STR_CASE(CELL_DMUX_ERROR_ARG);
|
||||
STR_CASE(CELL_DMUX_ERROR_SEQ);
|
||||
STR_CASE(CELL_DMUX_ERROR_BUSY);
|
||||
STR_CASE(CELL_DMUX_ERROR_EMPTY);
|
||||
STR_CASE(CELL_DMUX_ERROR_FATAL);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
/* Demuxer Thread Classes */
|
||||
|
||||
enum
|
||||
@@ -940,7 +959,7 @@ void dmuxQueryEsAttr(u32 info /* may be 0 */, vm::cptr<CellCodecEsFilterId> esFi
|
||||
cellDmux.warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2);
|
||||
}
|
||||
|
||||
s32 cellDmuxQueryAttr(vm::cptr<CellDmuxType> type, vm::ptr<CellDmuxAttr> attr)
|
||||
error_code cellDmuxQueryAttr(vm::cptr<CellDmuxType> type, vm::ptr<CellDmuxAttr> attr)
|
||||
{
|
||||
cellDmux.warning("cellDmuxQueryAttr(type=*0x%x, attr=*0x%x)", type, attr);
|
||||
|
||||
@@ -953,7 +972,7 @@ s32 cellDmuxQueryAttr(vm::cptr<CellDmuxType> type, vm::ptr<CellDmuxAttr> attr)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxQueryAttr2(vm::cptr<CellDmuxType2> type2, vm::ptr<CellDmuxAttr> attr)
|
||||
error_code cellDmuxQueryAttr2(vm::cptr<CellDmuxType2> type2, vm::ptr<CellDmuxAttr> attr)
|
||||
{
|
||||
cellDmux.warning("cellDmuxQueryAttr2(demuxerType2=*0x%x, demuxerAttr=*0x%x)", type2, attr);
|
||||
|
||||
@@ -966,7 +985,7 @@ s32 cellDmuxQueryAttr2(vm::cptr<CellDmuxType2> type2, vm::ptr<CellDmuxAttr> attr
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxOpen(vm::cptr<CellDmuxType> type, vm::cptr<CellDmuxResource> res, vm::cptr<CellDmuxCb> cb, vm::ptr<u32> handle)
|
||||
error_code cellDmuxOpen(vm::cptr<CellDmuxType> type, vm::cptr<CellDmuxResource> res, vm::cptr<CellDmuxCb> cb, vm::ptr<u32> handle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxOpen(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle);
|
||||
|
||||
@@ -979,7 +998,7 @@ s32 cellDmuxOpen(vm::cptr<CellDmuxType> type, vm::cptr<CellDmuxResource> res, vm
|
||||
fmt::throw_exception("cellDmux disabled, use LLE.");
|
||||
}
|
||||
|
||||
s32 cellDmuxOpenEx(vm::cptr<CellDmuxType> type, vm::cptr<CellDmuxResourceEx> resEx, vm::cptr<CellDmuxCb> cb, vm::ptr<u32> handle)
|
||||
error_code cellDmuxOpenEx(vm::cptr<CellDmuxType> type, vm::cptr<CellDmuxResourceEx> resEx, vm::cptr<CellDmuxCb> cb, vm::ptr<u32> handle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxOpenEx(type=*0x%x, resEx=*0x%x, cb=*0x%x, handle=*0x%x)", type, resEx, cb, handle);
|
||||
|
||||
@@ -992,14 +1011,14 @@ s32 cellDmuxOpenEx(vm::cptr<CellDmuxType> type, vm::cptr<CellDmuxResourceEx> res
|
||||
fmt::throw_exception("cellDmux disabled, use LLE.");
|
||||
}
|
||||
|
||||
s32 cellDmuxOpenExt(vm::cptr<CellDmuxType> type, vm::cptr<CellDmuxResourceEx> resEx, vm::cptr<CellDmuxCb> cb, vm::ptr<u32> handle)
|
||||
error_code cellDmuxOpenExt(vm::cptr<CellDmuxType> type, vm::cptr<CellDmuxResourceEx> resEx, vm::cptr<CellDmuxCb> cb, vm::ptr<u32> handle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxOpenExt(type=*0x%x, resEx=*0x%x, cb=*0x%x, handle=*0x%x)", type, resEx, cb, handle);
|
||||
|
||||
return cellDmuxOpenEx(type, resEx, cb, handle);
|
||||
}
|
||||
|
||||
s32 cellDmuxOpen2(vm::cptr<CellDmuxType2> type2, vm::cptr<CellDmuxResource2> res2, vm::cptr<CellDmuxCb> cb, vm::ptr<u32> handle)
|
||||
error_code cellDmuxOpen2(vm::cptr<CellDmuxType2> type2, vm::cptr<CellDmuxResource2> res2, vm::cptr<CellDmuxCb> cb, vm::ptr<u32> handle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxOpen2(type2=*0x%x, res2=*0x%x, cb=*0x%x, handle=*0x%x)", type2, res2, cb, handle);
|
||||
|
||||
@@ -1012,7 +1031,7 @@ s32 cellDmuxOpen2(vm::cptr<CellDmuxType2> type2, vm::cptr<CellDmuxResource2> res
|
||||
fmt::throw_exception("cellDmux disabled, use LLE.");
|
||||
}
|
||||
|
||||
s32 cellDmuxClose(u32 handle)
|
||||
error_code cellDmuxClose(u32 handle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxClose(handle=0x%x)", handle);
|
||||
|
||||
@@ -1041,7 +1060,7 @@ s32 cellDmuxClose(u32 handle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxSetStream(u32 handle, u32 streamAddress, u32 streamSize, b8 discontinuity, u64 userData)
|
||||
error_code cellDmuxSetStream(u32 handle, u32 streamAddress, u32 streamSize, b8 discontinuity, u64 userData)
|
||||
{
|
||||
cellDmux.trace("cellDmuxSetStream(handle=0x%x, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx)", handle, streamAddress, streamSize, discontinuity, userData);
|
||||
|
||||
@@ -1069,7 +1088,7 @@ s32 cellDmuxSetStream(u32 handle, u32 streamAddress, u32 streamSize, b8 disconti
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxResetStream(u32 handle)
|
||||
error_code cellDmuxResetStream(u32 handle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxResetStream(handle=0x%x)", handle);
|
||||
|
||||
@@ -1084,7 +1103,7 @@ s32 cellDmuxResetStream(u32 handle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxResetStreamAndWaitDone(u32 handle)
|
||||
error_code cellDmuxResetStreamAndWaitDone(u32 handle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxResetStreamAndWaitDone(handle=0x%x)", handle);
|
||||
|
||||
@@ -1117,7 +1136,7 @@ s32 cellDmuxResetStreamAndWaitDone(u32 handle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxQueryEsAttr(vm::cptr<CellDmuxType> type, vm::cptr<CellCodecEsFilterId> esFilterId, u32 esSpecificInfo, vm::ptr<CellDmuxEsAttr> esAttr)
|
||||
error_code cellDmuxQueryEsAttr(vm::cptr<CellDmuxType> type, vm::cptr<CellCodecEsFilterId> esFilterId, u32 esSpecificInfo, vm::ptr<CellDmuxEsAttr> esAttr)
|
||||
{
|
||||
cellDmux.warning("cellDmuxQueryEsAttr(demuxerType=*0x%x, esFilterId=*0x%x, esSpecificInfo=*0x%x, esAttr=*0x%x)", type, esFilterId, esSpecificInfo, esAttr);
|
||||
|
||||
@@ -1131,7 +1150,7 @@ s32 cellDmuxQueryEsAttr(vm::cptr<CellDmuxType> type, vm::cptr<CellCodecEsFilterI
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxQueryEsAttr2(vm::cptr<CellDmuxType2> type2, vm::cptr<CellCodecEsFilterId> esFilterId, u32 esSpecificInfo, vm::ptr<CellDmuxEsAttr> esAttr)
|
||||
error_code cellDmuxQueryEsAttr2(vm::cptr<CellDmuxType2> type2, vm::cptr<CellCodecEsFilterId> esFilterId, u32 esSpecificInfo, vm::ptr<CellDmuxEsAttr> esAttr)
|
||||
{
|
||||
cellDmux.warning("cellDmuxQueryEsAttr2(type2=*0x%x, esFilterId=*0x%x, esSpecificInfo=*0x%x, esAttr=*0x%x)", type2, esFilterId, esSpecificInfo, esAttr);
|
||||
|
||||
@@ -1145,7 +1164,7 @@ s32 cellDmuxQueryEsAttr2(vm::cptr<CellDmuxType2> type2, vm::cptr<CellCodecEsFilt
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxEnableEs(u32 handle, vm::cptr<CellCodecEsFilterId> esFilterId, vm::cptr<CellDmuxEsResource> esResourceInfo, vm::cptr<CellDmuxEsCb> esCb, u32 esSpecificInfo, vm::ptr<u32> esHandle)
|
||||
error_code cellDmuxEnableEs(u32 handle, vm::cptr<CellCodecEsFilterId> esFilterId, vm::cptr<CellDmuxEsResource> esResourceInfo, vm::cptr<CellDmuxEsCb> esCb, u32 esSpecificInfo, vm::ptr<u32> esHandle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxEnableEs(handle=0x%x, esFilterId=*0x%x, esResourceInfo=*0x%x, esCb=*0x%x, esSpecificInfo=*0x%x, esHandle=*0x%x)", handle, esFilterId, esResourceInfo, esCb, esSpecificInfo, esHandle);
|
||||
|
||||
@@ -1175,7 +1194,7 @@ s32 cellDmuxEnableEs(u32 handle, vm::cptr<CellCodecEsFilterId> esFilterId, vm::c
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxDisableEs(u32 esHandle)
|
||||
error_code cellDmuxDisableEs(u32 esHandle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxDisableEs(esHandle=0x%x)", esHandle);
|
||||
|
||||
@@ -1194,7 +1213,7 @@ s32 cellDmuxDisableEs(u32 esHandle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxResetEs(u32 esHandle)
|
||||
error_code cellDmuxResetEs(u32 esHandle)
|
||||
{
|
||||
cellDmux.trace("cellDmuxResetEs(esHandle=0x%x)", esHandle);
|
||||
|
||||
@@ -1213,7 +1232,7 @@ s32 cellDmuxResetEs(u32 esHandle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxGetAu(u32 esHandle, vm::ptr<u32> auInfo, vm::ptr<u32> auSpecificInfo)
|
||||
error_code cellDmuxGetAu(u32 esHandle, vm::ptr<u32> auInfo, vm::ptr<u32> auSpecificInfo)
|
||||
{
|
||||
cellDmux.trace("cellDmuxGetAu(esHandle=0x%x, auInfo=**0x%x, auSpecificInfo=**0x%x)", esHandle, auInfo, auSpecificInfo);
|
||||
|
||||
@@ -1236,7 +1255,7 @@ s32 cellDmuxGetAu(u32 esHandle, vm::ptr<u32> auInfo, vm::ptr<u32> auSpecificInfo
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxPeekAu(u32 esHandle, vm::ptr<u32> auInfo, vm::ptr<u32> auSpecificInfo)
|
||||
error_code cellDmuxPeekAu(u32 esHandle, vm::ptr<u32> auInfo, vm::ptr<u32> auSpecificInfo)
|
||||
{
|
||||
cellDmux.trace("cellDmuxPeekAu(esHandle=0x%x, auInfo=**0x%x, auSpecificInfo=**0x%x)", esHandle, auInfo, auSpecificInfo);
|
||||
|
||||
@@ -1259,7 +1278,7 @@ s32 cellDmuxPeekAu(u32 esHandle, vm::ptr<u32> auInfo, vm::ptr<u32> auSpecificInf
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxGetAuEx(u32 esHandle, vm::ptr<u32> auInfoEx, vm::ptr<u32> auSpecificInfo)
|
||||
error_code cellDmuxGetAuEx(u32 esHandle, vm::ptr<u32> auInfoEx, vm::ptr<u32> auSpecificInfo)
|
||||
{
|
||||
cellDmux.trace("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx=**0x%x, auSpecificInfo=**0x%x)", esHandle, auInfoEx, auSpecificInfo);
|
||||
|
||||
@@ -1282,7 +1301,7 @@ s32 cellDmuxGetAuEx(u32 esHandle, vm::ptr<u32> auInfoEx, vm::ptr<u32> auSpecific
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxPeekAuEx(u32 esHandle, vm::ptr<u32> auInfoEx, vm::ptr<u32> auSpecificInfo)
|
||||
error_code cellDmuxPeekAuEx(u32 esHandle, vm::ptr<u32> auInfoEx, vm::ptr<u32> auSpecificInfo)
|
||||
{
|
||||
cellDmux.trace("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx=**0x%x, auSpecificInfo=**0x%x)", esHandle, auInfoEx, auSpecificInfo);
|
||||
|
||||
@@ -1305,7 +1324,7 @@ s32 cellDmuxPeekAuEx(u32 esHandle, vm::ptr<u32> auInfoEx, vm::ptr<u32> auSpecifi
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxReleaseAu(u32 esHandle)
|
||||
error_code cellDmuxReleaseAu(u32 esHandle)
|
||||
{
|
||||
cellDmux.trace("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
|
||||
|
||||
@@ -1323,7 +1342,7 @@ s32 cellDmuxReleaseAu(u32 esHandle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDmuxFlushEs(u32 esHandle)
|
||||
error_code cellDmuxFlushEs(u32 esHandle)
|
||||
{
|
||||
cellDmux.warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Memory/vm_ptr.h"
|
||||
|
||||
// Error Codes
|
||||
enum
|
||||
enum CellDmuxError :u32
|
||||
{
|
||||
CELL_DMUX_ERROR_ARG = 0x80610201,
|
||||
CELL_DMUX_ERROR_SEQ = 0x80610202,
|
||||
|
||||
@@ -1,81 +1,81 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
LOG_CHANNEL(cellDtcpIpUtility);
|
||||
|
||||
s32 cellDtcpIpRead()
|
||||
error_code cellDtcpIpRead()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpFinalize()
|
||||
error_code cellDtcpIpFinalize()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpActivate()
|
||||
error_code cellDtcpIpActivate()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpOpen()
|
||||
error_code cellDtcpIpOpen()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpCheckActivation()
|
||||
error_code cellDtcpIpCheckActivation()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpInitialize()
|
||||
error_code cellDtcpIpInitialize()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpGetDecryptedData()
|
||||
error_code cellDtcpIpGetDecryptedData()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpStopSequence()
|
||||
error_code cellDtcpIpStopSequence()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpSeek()
|
||||
error_code cellDtcpIpSeek()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpStartSequence()
|
||||
error_code cellDtcpIpStartSequence()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpSetEncryptedData()
|
||||
error_code cellDtcpIpSetEncryptedData()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpClose()
|
||||
error_code cellDtcpIpClose()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellDtcpIpSuspendActivationForDebug()
|
||||
error_code cellDtcpIpSuspendActivationForDebug()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellDtcpIpUtility);
|
||||
return CELL_OK;
|
||||
|
||||
@@ -8,8 +8,46 @@
|
||||
|
||||
LOG_CHANNEL(cellFont);
|
||||
|
||||
template <>
|
||||
void fmt_class_string<CellFontError>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_enum(out, arg, [](auto error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
STR_CASE(CELL_FONT_ERROR_FATAL);
|
||||
STR_CASE(CELL_FONT_ERROR_INVALID_PARAMETER);
|
||||
STR_CASE(CELL_FONT_ERROR_UNINITIALIZED);
|
||||
STR_CASE(CELL_FONT_ERROR_INITIALIZE_FAILED);
|
||||
STR_CASE(CELL_FONT_ERROR_INVALID_CACHE_BUFFER);
|
||||
STR_CASE(CELL_FONT_ERROR_ALREADY_INITIALIZED);
|
||||
STR_CASE(CELL_FONT_ERROR_ALLOCATION_FAILED);
|
||||
STR_CASE(CELL_FONT_ERROR_NO_SUPPORT_FONTSET);
|
||||
STR_CASE(CELL_FONT_ERROR_OPEN_FAILED);
|
||||
STR_CASE(CELL_FONT_ERROR_READ_FAILED);
|
||||
STR_CASE(CELL_FONT_ERROR_FONT_OPEN_FAILED);
|
||||
STR_CASE(CELL_FONT_ERROR_FONT_NOT_FOUND);
|
||||
STR_CASE(CELL_FONT_ERROR_FONT_OPEN_MAX);
|
||||
STR_CASE(CELL_FONT_ERROR_FONT_CLOSE_FAILED);
|
||||
STR_CASE(CELL_FONT_ERROR_ALREADY_OPENED);
|
||||
STR_CASE(CELL_FONT_ERROR_NO_SUPPORT_FUNCTION);
|
||||
STR_CASE(CELL_FONT_ERROR_NO_SUPPORT_CODE);
|
||||
STR_CASE(CELL_FONT_ERROR_NO_SUPPORT_GLYPH);
|
||||
STR_CASE(CELL_FONT_ERROR_BUFFER_SIZE_NOT_ENOUGH);
|
||||
STR_CASE(CELL_FONT_ERROR_RENDERER_ALREADY_BIND);
|
||||
STR_CASE(CELL_FONT_ERROR_RENDERER_UNBIND);
|
||||
STR_CASE(CELL_FONT_ERROR_RENDERER_INVALID);
|
||||
STR_CASE(CELL_FONT_ERROR_RENDERER_ALLOCATION_FAILED);
|
||||
STR_CASE(CELL_FONT_ERROR_ENOUGH_RENDERING_BUFFER);
|
||||
STR_CASE(CELL_FONT_ERROR_NO_SUPPORT_SURFACE);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
// Functions
|
||||
s32 cellFontInitializeWithRevision(u64 revisionFlags, vm::ptr<CellFontConfig> config)
|
||||
error_code cellFontInitializeWithRevision(u64 revisionFlags, vm::ptr<CellFontConfig> config)
|
||||
{
|
||||
cellFont.warning("cellFontInitializeWithRevision(revisionFlags=0x%llx, config=*0x%x)", revisionFlags, config);
|
||||
|
||||
@@ -26,26 +64,26 @@ s32 cellFontInitializeWithRevision(u64 revisionFlags, vm::ptr<CellFontConfig> co
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetRevisionFlags(vm::ptr<u64> revisionFlags)
|
||||
error_code cellFontGetRevisionFlags(vm::ptr<u64> revisionFlags)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontEnd()
|
||||
error_code cellFontEnd()
|
||||
{
|
||||
cellFont.warning("cellFontEnd()");
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetFontsetOpenMode(u32 openMode)
|
||||
error_code cellFontSetFontsetOpenMode(u32 openMode)
|
||||
{
|
||||
cellFont.todo("cellFontSetFontsetOpenMode(openMode=0x%x)", openMode);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontOpenFontMemory(vm::ptr<CellFontLibrary> library, u32 fontAddr, u32 fontSize, u32 subNum, u32 uniqueId, vm::ptr<CellFont> font)
|
||||
error_code cellFontOpenFontMemory(vm::ptr<CellFontLibrary> library, u32 fontAddr, u32 fontSize, u32 subNum, u32 uniqueId, vm::ptr<CellFont> font)
|
||||
{
|
||||
cellFont.warning("cellFontOpenFontMemory(library=*0x%x, fontAddr=0x%x, fontSize=%d, subNum=%d, uniqueId=%d, font=*0x%x)", library, fontAddr, fontSize, subNum, uniqueId, font);
|
||||
|
||||
@@ -61,7 +99,7 @@ s32 cellFontOpenFontMemory(vm::ptr<CellFontLibrary> library, u32 fontAddr, u32 f
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontOpenFontFile(vm::ptr<CellFontLibrary> library, vm::cptr<char> fontPath, u32 subNum, s32 uniqueId, vm::ptr<CellFont> font)
|
||||
error_code cellFontOpenFontFile(vm::ptr<CellFontLibrary> library, vm::cptr<char> fontPath, u32 subNum, s32 uniqueId, vm::ptr<CellFont> font)
|
||||
{
|
||||
cellFont.warning("cellFontOpenFontFile(library=*0x%x, fontPath=%s, subNum=%d, uniqueId=%d, font=*0x%x)", library, fontPath, subNum, uniqueId, font);
|
||||
|
||||
@@ -80,7 +118,7 @@ s32 cellFontOpenFontFile(vm::ptr<CellFontLibrary> library, vm::cptr<char> fontPa
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 cellFontOpenFontset(ppu_thread& ppu, vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> font)
|
||||
error_code cellFontOpenFontset(ppu_thread& ppu, vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> font)
|
||||
{
|
||||
cellFont.warning("cellFontOpenFontset(library=*0x%x, fontType=*0x%x, font=*0x%x)", library, fontType, font);
|
||||
|
||||
@@ -151,17 +189,16 @@ s32 cellFontOpenFontset(ppu_thread& ppu, vm::ptr<CellFontLibrary> library, vm::p
|
||||
break;
|
||||
|
||||
default:
|
||||
cellFont.warning("cellFontOpenFontset: fontType->type = %d not supported.", fontType->type);
|
||||
return CELL_FONT_ERROR_NO_SUPPORT_FONTSET;
|
||||
return { CELL_FONT_ERROR_NO_SUPPORT_FONTSET, fontType->type };
|
||||
}
|
||||
|
||||
s32 ret = cellFontOpenFontFile(library, vm::make_str(file), 0, 0, font); //TODO: Find the correct values of subNum, uniqueId
|
||||
error_code ret = cellFontOpenFontFile(library, vm::make_str(file), 0, 0, font); //TODO: Find the correct values of subNum, uniqueId
|
||||
font->origin = CELL_FONT_OPEN_FONTSET;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 cellFontOpenFontInstance(vm::ptr<CellFont> openedFont, vm::ptr<CellFont> font)
|
||||
error_code cellFontOpenFontInstance(vm::ptr<CellFont> openedFont, vm::ptr<CellFont> font)
|
||||
{
|
||||
cellFont.warning("cellFontOpenFontInstance(openedFont=*0x%x, font=*0x%x)", openedFont, font);
|
||||
|
||||
@@ -175,17 +212,17 @@ s32 cellFontOpenFontInstance(vm::ptr<CellFont> openedFont, vm::ptr<CellFont> fon
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetFontOpenMode(u32 openMode)
|
||||
error_code cellFontSetFontOpenMode(u32 openMode)
|
||||
{
|
||||
cellFont.todo("cellFontSetFontOpenMode(openMode=0x%x)", openMode);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontCreateRenderer(vm::ptr<CellFontLibrary> library, vm::ptr<CellFontRendererConfig> config, vm::ptr<CellFontRenderer> Renderer)
|
||||
error_code cellFontCreateRenderer(vm::ptr<CellFontLibrary> library, vm::ptr<CellFontRendererConfig> config, vm::ptr<CellFontRenderer> Renderer)
|
||||
{
|
||||
cellFont.todo("cellFontCreateRenderer(library=*0x%x, config=*0x%x, Renderer=*0x%x)", library, config, Renderer);
|
||||
|
||||
//Write data in Renderer
|
||||
// Write data in Renderer
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -211,7 +248,7 @@ void cellFontRenderSurfaceSetScissor(vm::ptr<CellFontRenderSurface> surface, s32
|
||||
surface->sc_y1 = h;
|
||||
}
|
||||
|
||||
s32 cellFontSetScalePixel(vm::ptr<CellFont> font, float w, float h)
|
||||
error_code cellFontSetScalePixel(vm::ptr<CellFont> font, float w, float h)
|
||||
{
|
||||
cellFont.trace("cellFontSetScalePixel(font=*0x%x, w=%f, h=%f)", font, w, h);
|
||||
|
||||
@@ -221,7 +258,7 @@ s32 cellFontSetScalePixel(vm::ptr<CellFont> font, float w, float h)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetHorizontalLayout(vm::ptr<CellFont> font, vm::ptr<CellFontHorizontalLayout> layout)
|
||||
error_code cellFontGetHorizontalLayout(vm::ptr<CellFont> font, vm::ptr<CellFontHorizontalLayout> layout)
|
||||
{
|
||||
cellFont.trace("cellFontGetHorizontalLayout(font=*0x%x, layout=*0x%x)", font, layout);
|
||||
|
||||
@@ -236,7 +273,7 @@ s32 cellFontGetHorizontalLayout(vm::ptr<CellFont> font, vm::ptr<CellFontHorizont
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontBindRenderer(vm::ptr<CellFont> font, vm::ptr<CellFontRenderer> renderer)
|
||||
error_code cellFontBindRenderer(vm::ptr<CellFont> font, vm::ptr<CellFontRenderer> renderer)
|
||||
{
|
||||
cellFont.warning("cellFontBindRenderer(font=*0x%x, renderer=*0x%x)", font, renderer);
|
||||
|
||||
@@ -250,7 +287,7 @@ s32 cellFontBindRenderer(vm::ptr<CellFont> font, vm::ptr<CellFontRenderer> rende
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontUnbindRenderer(vm::ptr<CellFont> font)
|
||||
error_code cellFontUnbindRenderer(vm::ptr<CellFont> font)
|
||||
{
|
||||
cellFont.warning("cellFontBindRenderer(font=*0x%x)", font);
|
||||
|
||||
@@ -264,13 +301,13 @@ s32 cellFontUnbindRenderer(vm::ptr<CellFont> font)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontDestroyRenderer()
|
||||
error_code cellFontDestroyRenderer()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetupRenderScalePixel(vm::ptr<CellFont> font, float w, float h)
|
||||
error_code cellFontSetupRenderScalePixel(vm::ptr<CellFont> font, float w, float h)
|
||||
{
|
||||
cellFont.todo("cellFontSetupRenderScalePixel(font=*0x%x, w=%f, h=%f)", font, w, h);
|
||||
|
||||
@@ -283,7 +320,7 @@ s32 cellFontSetupRenderScalePixel(vm::ptr<CellFont> font, float w, float h)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetRenderCharGlyphMetrics(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFontGlyphMetrics> metrics)
|
||||
error_code cellFontGetRenderCharGlyphMetrics(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFontGlyphMetrics> metrics)
|
||||
{
|
||||
cellFont.todo("cellFontGetRenderCharGlyphMetrics(font=*0x%x, code=0x%x, metrics=*0x%x)", font, code, metrics);
|
||||
|
||||
@@ -296,7 +333,7 @@ s32 cellFontGetRenderCharGlyphMetrics(vm::ptr<CellFont> font, u32 code, vm::ptr<
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontRenderCharGlyphImage(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFontRenderSurface> surface, float x, float y, vm::ptr<CellFontGlyphMetrics> metrics, vm::ptr<CellFontImageTransInfo> transInfo)
|
||||
error_code cellFontRenderCharGlyphImage(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFontRenderSurface> surface, float x, float y, vm::ptr<CellFontGlyphMetrics> metrics, vm::ptr<CellFontImageTransInfo> transInfo)
|
||||
{
|
||||
cellFont.notice("cellFontRenderCharGlyphImage(font=*0x%x, code=0x%x, surface=*0x%x, x=%f, y=%f, metrics=*0x%x, trans=*0x%x)", font, code, surface, x, y, metrics, transInfo);
|
||||
|
||||
@@ -341,13 +378,13 @@ s32 cellFontRenderCharGlyphImage(vm::ptr<CellFont> font, u32 code, vm::ptr<CellF
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontEndLibrary()
|
||||
error_code cellFontEndLibrary()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetEffectSlant(vm::ptr<CellFont> font, float slantParam)
|
||||
error_code cellFontSetEffectSlant(vm::ptr<CellFont> font, float slantParam)
|
||||
{
|
||||
cellFont.trace("cellFontSetEffectSlant(font=*0x%x, slantParam=%f)", font, slantParam);
|
||||
|
||||
@@ -361,7 +398,7 @@ s32 cellFontSetEffectSlant(vm::ptr<CellFont> font, float slantParam)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetEffectSlant(vm::ptr<CellFont> font, vm::ptr<float> slantParam)
|
||||
error_code cellFontGetEffectSlant(vm::ptr<CellFont> font, vm::ptr<float> slantParam)
|
||||
{
|
||||
cellFont.warning("cellFontSetEffectSlant(font=*0x%x, slantParam=*0x%x)", font, slantParam);
|
||||
|
||||
@@ -370,7 +407,7 @@ s32 cellFontGetEffectSlant(vm::ptr<CellFont> font, vm::ptr<float> slantParam)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetFontIdCode(vm::ptr<CellFont> font, u32 code, vm::ptr<u32> fontId, vm::ptr<u32> fontCode)
|
||||
error_code cellFontGetFontIdCode(vm::ptr<CellFont> font, u32 code, vm::ptr<u32> fontId, vm::ptr<u32> fontCode)
|
||||
{
|
||||
cellFont.todo("cellFontGetFontIdCode(font=*0x%x, code=%d, fontId=*0x%x, fontCode=*0x%x)", font, code, fontId, fontCode);
|
||||
|
||||
@@ -378,7 +415,7 @@ s32 cellFontGetFontIdCode(vm::ptr<CellFont> font, u32 code, vm::ptr<u32> fontId,
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontCloseFont(vm::ptr<CellFont> font)
|
||||
error_code cellFontCloseFont(vm::ptr<CellFont> font)
|
||||
{
|
||||
cellFont.warning("cellFontCloseFont(font=*0x%x)", font);
|
||||
|
||||
@@ -392,7 +429,7 @@ s32 cellFontCloseFont(vm::ptr<CellFont> font)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetCharGlyphMetrics(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFontGlyphMetrics> metrics)
|
||||
error_code cellFontGetCharGlyphMetrics(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFontGlyphMetrics> metrics)
|
||||
{
|
||||
cellFont.warning("cellFontGetCharGlyphMetrics(font=*0x%x, code=0x%x, metrics=*0x%x)", font, code, metrics);
|
||||
|
||||
@@ -415,13 +452,13 @@ s32 cellFontGetCharGlyphMetrics(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFo
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGraphicsSetFontRGBA()
|
||||
error_code cellFontGraphicsSetFontRGBA()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontOpenFontsetOnMemory(ppu_thread& ppu, vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> font)
|
||||
error_code cellFontOpenFontsetOnMemory(ppu_thread& ppu, vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> font)
|
||||
{
|
||||
cellFont.todo("cellFontOpenFontsetOnMemory(library=*0x%x, fontType=*0x%x, font=*0x%x)", library, fontType, font);
|
||||
|
||||
@@ -433,109 +470,109 @@ s32 cellFontOpenFontsetOnMemory(ppu_thread& ppu, vm::ptr<CellFontLibrary> librar
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGraphicsSetScalePixel()
|
||||
error_code cellFontGraphicsSetScalePixel()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGraphicsGetScalePixel()
|
||||
error_code cellFontGraphicsGetScalePixel()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetEffectWeight()
|
||||
error_code cellFontSetEffectWeight()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphSetupVertexesGlyph()
|
||||
error_code cellFontGlyphSetupVertexesGlyph()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetVerticalLayout()
|
||||
error_code cellFontGetVerticalLayout()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetRenderCharGlyphMetricsVertical()
|
||||
error_code cellFontGetRenderCharGlyphMetricsVertical()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetScalePoint()
|
||||
error_code cellFontSetScalePoint()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetupRenderEffectSlant()
|
||||
error_code cellFontSetupRenderEffectSlant()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGraphicsSetLineRGBA()
|
||||
error_code cellFontGraphicsSetLineRGBA()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGraphicsSetDrawType()
|
||||
error_code cellFontGraphicsSetDrawType()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontEndGraphics()
|
||||
error_code cellFontEndGraphics()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGraphicsSetupDrawContext()
|
||||
error_code cellFontGraphicsSetupDrawContext()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetupRenderEffectWeight()
|
||||
error_code cellFontSetupRenderEffectWeight()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphGetOutlineControlDistance()
|
||||
error_code cellFontGlyphGetOutlineControlDistance()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphGetVertexesGlyphSize()
|
||||
error_code cellFontGlyphGetVertexesGlyphSize()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGenerateCharGlyph()
|
||||
error_code cellFontGenerateCharGlyph()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontDeleteGlyph()
|
||||
error_code cellFontDeleteGlyph()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontExtend(u32 a1, u32 a2, u32 a3)
|
||||
error_code cellFontExtend(u32 a1, u32 a2, u32 a3)
|
||||
{
|
||||
cellFont.todo("cellFontExtend(a1=0x%x, a2=0x%x, a3=0x%x)", a1, a2, a3);
|
||||
//In a test I did: a1=0xcfe00000, a2=0x0, a3=(pointer to something)
|
||||
@@ -555,229 +592,229 @@ s32 cellFontExtend(u32 a1, u32 a2, u32 a3)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontRenderCharGlyphImageVertical()
|
||||
error_code cellFontRenderCharGlyphImageVertical()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetResolutionDpi()
|
||||
error_code cellFontSetResolutionDpi()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetCharGlyphMetricsVertical()
|
||||
error_code cellFontGetCharGlyphMetricsVertical()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFont);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetRenderEffectWeight()
|
||||
error_code cellFontGetRenderEffectWeight()
|
||||
{
|
||||
cellFont.todo("cellFontGetRenderEffectWeight()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGraphicsGetDrawType()
|
||||
error_code cellFontGraphicsGetDrawType()
|
||||
{
|
||||
cellFont.todo("cellFontGraphicsGetDrawType()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetKerning()
|
||||
error_code cellFontGetKerning()
|
||||
{
|
||||
cellFont.todo("cellFontGetKerning()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetRenderScaledKerning()
|
||||
error_code cellFontGetRenderScaledKerning()
|
||||
{
|
||||
cellFont.todo("cellFontGetRenderScaledKerning()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetRenderScalePixel()
|
||||
error_code cellFontGetRenderScalePixel()
|
||||
{
|
||||
cellFont.todo("cellFontGetRenderScalePixel()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphGetScalePixel()
|
||||
error_code cellFontGlyphGetScalePixel()
|
||||
{
|
||||
cellFont.todo("cellFontGlyphGetScalePixel()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphGetHorizontalShift()
|
||||
error_code cellFontGlyphGetHorizontalShift()
|
||||
{
|
||||
cellFont.todo("cellFontGlyphGetHorizontalShift()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontRenderCharGlyphImageHorizontal()
|
||||
error_code cellFontRenderCharGlyphImageHorizontal()
|
||||
{
|
||||
cellFont.todo("cellFontRenderCharGlyphImageHorizontal()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetEffectWeight()
|
||||
error_code cellFontGetEffectWeight()
|
||||
{
|
||||
cellFont.todo("cellFontGetEffectWeight()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetScalePixel()
|
||||
error_code cellFontGetScalePixel()
|
||||
{
|
||||
cellFont.todo("cellFontGetScalePixel()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontClearFileCache()
|
||||
error_code cellFontClearFileCache()
|
||||
{
|
||||
cellFont.todo("cellFontClearFileCache()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontAdjustFontScaling()
|
||||
error_code cellFontAdjustFontScaling()
|
||||
{
|
||||
cellFont.todo("cellFontAdjustFontScaling()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontSetupRenderScalePoint()
|
||||
error_code cellFontSetupRenderScalePoint()
|
||||
{
|
||||
cellFont.todo("cellFontSetupRenderScalePoint()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphGetVerticalShift()
|
||||
error_code cellFontGlyphGetVerticalShift()
|
||||
{
|
||||
cellFont.todo("cellFontGlyphGetVerticalShift()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetGlyphExpandBufferInfo()
|
||||
error_code cellFontGetGlyphExpandBufferInfo()
|
||||
{
|
||||
cellFont.todo("cellFontGetGlyphExpandBufferInfo()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetLibrary()
|
||||
error_code cellFontGetLibrary()
|
||||
{
|
||||
cellFont.todo("cellFontGetLibrary()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontVertexesGlyphRelocate()
|
||||
error_code cellFontVertexesGlyphRelocate()
|
||||
{
|
||||
cellFont.todo("cellFontVertexesGlyphRelocate()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetInitializedRevisionFlags()
|
||||
error_code cellFontGetInitializedRevisionFlags()
|
||||
{
|
||||
cellFont.todo("cellFontGetInitializedRevisionFlags()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetResolutionDpi()
|
||||
error_code cellFontGetResolutionDpi()
|
||||
{
|
||||
cellFont.todo("cellFontGetResolutionDpi()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphRenderImageVertical()
|
||||
error_code cellFontGlyphRenderImageVertical()
|
||||
{
|
||||
cellFont.todo("cellFontGlyphRenderImageVertical()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphRenderImageHorizontal()
|
||||
error_code cellFontGlyphRenderImageHorizontal()
|
||||
{
|
||||
cellFont.todo("cellFontGlyphRenderImageHorizontal()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontAdjustGlyphExpandBuffer()
|
||||
error_code cellFontAdjustGlyphExpandBuffer()
|
||||
{
|
||||
cellFont.todo("cellFontAdjustGlyphExpandBuffer()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetRenderScalePoint()
|
||||
error_code cellFontGetRenderScalePoint()
|
||||
{
|
||||
cellFont.todo("cellFontGetRenderScalePoint()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGraphicsGetFontRGBA()
|
||||
error_code cellFontGraphicsGetFontRGBA()
|
||||
{
|
||||
cellFont.todo("cellFontGraphicsGetFontRGBA()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphGetOutlineVertexes()
|
||||
error_code cellFontGlyphGetOutlineVertexes()
|
||||
{
|
||||
cellFont.todo("cellFontGlyphGetOutlineVertexes()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontDelete()
|
||||
error_code cellFontDelete()
|
||||
{
|
||||
cellFont.todo("cellFontDelete()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontPatchWorks()
|
||||
error_code cellFontPatchWorks()
|
||||
{
|
||||
cellFont.todo("cellFontPatchWorks()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGlyphRenderImage()
|
||||
error_code cellFontGlyphRenderImage()
|
||||
{
|
||||
cellFont.todo("cellFontGlyphRenderImage()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetBindingRenderer()
|
||||
error_code cellFontGetBindingRenderer()
|
||||
{
|
||||
cellFont.todo("cellFontGetBindingRenderer()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGenerateCharGlyphVertical()
|
||||
error_code cellFontGenerateCharGlyphVertical()
|
||||
{
|
||||
cellFont.todo("cellFontGenerateCharGlyphVertical()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetRenderEffectSlant()
|
||||
error_code cellFontGetRenderEffectSlant()
|
||||
{
|
||||
cellFont.todo("cellFontGetRenderEffectSlant()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGetScalePoint()
|
||||
error_code cellFontGetScalePoint()
|
||||
{
|
||||
cellFont.todo("cellFontGetScalePoint()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontGraphicsGetLineRGBA()
|
||||
error_code cellFontGraphicsGetLineRGBA()
|
||||
{
|
||||
cellFont.todo("cellFontGraphicsGetLineRGBA()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontControl()
|
||||
error_code cellFontControl()
|
||||
{
|
||||
cellFont.todo("cellFontControl()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontStatic()
|
||||
error_code cellFontStatic()
|
||||
{
|
||||
cellFont.todo("cellFontStatic()");
|
||||
return CELL_OK;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Memory/vm_ptr.h"
|
||||
|
||||
// Error codes
|
||||
enum
|
||||
enum CellFontError : u32
|
||||
{
|
||||
CELL_FONT_ERROR_FATAL = 0x80540001,
|
||||
CELL_FONT_ERROR_INVALID_PARAMETER = 0x80540002,
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
LOG_CHANNEL(cellFontFT);
|
||||
|
||||
s32 cellFontInitLibraryFreeType()
|
||||
error_code cellFontInitLibraryFreeType()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontInitLibraryFreeTypeWithRevision(u64 revisionFlags, vm::ptr<CellFontLibraryConfigFT> config, vm::pptr<CellFontLibrary> lib)
|
||||
error_code cellFontInitLibraryFreeTypeWithRevision(u64 revisionFlags, vm::ptr<CellFontLibraryConfigFT> config, vm::pptr<CellFontLibrary> lib)
|
||||
{
|
||||
cellFontFT.warning("cellFontInitLibraryFreeTypeWithRevision(revisionFlags=0x%llx, config=*0x%x, lib=**0x%x)", revisionFlags, config, lib);
|
||||
|
||||
@@ -20,247 +20,247 @@ s32 cellFontInitLibraryFreeTypeWithRevision(u64 revisionFlags, vm::ptr<CellFontL
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontFTGetRevisionFlags()
|
||||
error_code cellFontFTGetRevisionFlags()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontFTGetInitializedRevisionFlags()
|
||||
error_code cellFontFTGetInitializedRevisionFlags()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTCacheStream_CacheEnd()
|
||||
error_code FTCacheStream_CacheEnd()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTCacheStream_CacheInit()
|
||||
error_code FTCacheStream_CacheInit()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTCacheStream_CalcCacheIndexSize()
|
||||
error_code FTCacheStream_CalcCacheIndexSize()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTCacheStream_End()
|
||||
error_code FTCacheStream_End()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTCacheStream_Init()
|
||||
error_code FTCacheStream_Init()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_Close()
|
||||
error_code FTFaceH_Close()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_FontFamilyName()
|
||||
error_code FTFaceH_FontFamilyName()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_FontStyleName()
|
||||
error_code FTFaceH_FontStyleName()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetAscender()
|
||||
error_code FTFaceH_GetAscender()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetBoundingBoxHeight()
|
||||
error_code FTFaceH_GetBoundingBoxHeight()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetBoundingBoxMaxX()
|
||||
error_code FTFaceH_GetBoundingBoxMaxX()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetBoundingBoxMaxY()
|
||||
error_code FTFaceH_GetBoundingBoxMaxY()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetBoundingBoxMinX()
|
||||
error_code FTFaceH_GetBoundingBoxMinX()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetBoundingBoxMinY()
|
||||
error_code FTFaceH_GetBoundingBoxMinY()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetBoundingBoxWidth()
|
||||
error_code FTFaceH_GetBoundingBoxWidth()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetCompositeCodes()
|
||||
error_code FTFaceH_GetCompositeCodes()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetGlyphImage()
|
||||
error_code FTFaceH_GetGlyphImage()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetGlyphMetrics()
|
||||
error_code FTFaceH_GetGlyphMetrics()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetKerning()
|
||||
error_code FTFaceH_GetKerning()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetMaxHorizontalAdvance()
|
||||
error_code FTFaceH_GetMaxHorizontalAdvance()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetMaxVerticalAdvance()
|
||||
error_code FTFaceH_GetMaxVerticalAdvance()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetRenderBufferSize()
|
||||
error_code FTFaceH_GetRenderBufferSize()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetRenderEffectSlant()
|
||||
error_code FTFaceH_GetRenderEffectSlant()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetRenderEffectWeight()
|
||||
error_code FTFaceH_GetRenderEffectWeight()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetRenderScale()
|
||||
error_code FTFaceH_GetRenderScale()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetRenderScalePixel()
|
||||
error_code FTFaceH_GetRenderScalePixel()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_GetRenderScalePoint()
|
||||
error_code FTFaceH_GetRenderScalePoint()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_SetCompositeCodes()
|
||||
error_code FTFaceH_SetCompositeCodes()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_SetRenderEffectSlant()
|
||||
error_code FTFaceH_SetRenderEffectSlant()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_SetRenderEffectWeight()
|
||||
error_code FTFaceH_SetRenderEffectWeight()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_SetRenderScalePixel()
|
||||
error_code FTFaceH_SetRenderScalePixel()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTFaceH_SetRenderScalePoint()
|
||||
error_code FTFaceH_SetRenderScalePoint()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTManager_CloseFace()
|
||||
error_code FTManager_CloseFace()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTManager_Done_FreeType()
|
||||
error_code FTManager_Done_FreeType()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTManager_Init_FreeType()
|
||||
error_code FTManager_Init_FreeType()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTManager_OpenFileFace()
|
||||
error_code FTManager_OpenFileFace()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTManager_OpenMemFace()
|
||||
error_code FTManager_OpenMemFace()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTManager_OpenStreamFace()
|
||||
error_code FTManager_OpenStreamFace()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 FTManager_SetFontOpenMode()
|
||||
error_code FTManager_SetFontOpenMode()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
|
||||
@@ -342,25 +342,54 @@ error_code cellFsGetFreeSize(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32>
|
||||
{
|
||||
cellFs.todo("cellFsGetFreeSize(path=%s, block_size=*0x%x, block_count=*0x%x)", path, block_size, block_count);
|
||||
|
||||
if (block_size)
|
||||
{
|
||||
*block_size = 0;
|
||||
}
|
||||
|
||||
if (block_count)
|
||||
{
|
||||
*block_count = 0;
|
||||
}
|
||||
|
||||
if (!path || !block_size || !block_count)
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
fs::device_stat info;
|
||||
fs::statfs(vfs::get(path.get_ptr()), info);
|
||||
*block_size = 4096;
|
||||
*block_count = info.avail_free / 4096;
|
||||
*block_size = 0;
|
||||
*block_count = 0;
|
||||
|
||||
vm::var<lv2_file_c0000002> op;
|
||||
op->_vtable = vm::cast(0xfae12000);
|
||||
op->op = 0xC0000002;
|
||||
op->out_code = 0x80010003;
|
||||
op->path = path;
|
||||
|
||||
if (!std::strncmp(path.get_ptr(), "/dev_hdd0", 9))
|
||||
{
|
||||
sys_fs_fcntl(ppu, -1, 0xC0000002, op, sizeof(*op));
|
||||
*block_count = op->out_block_count;
|
||||
*block_size = op->out_block_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::var<u64> _block_size, avail;
|
||||
|
||||
if (auto err = sys_fs_disk_free(ppu, path, vm::var<u64>{}, avail))
|
||||
{
|
||||
if (err + 0u == CELL_EPERM)
|
||||
{
|
||||
return not_an_error(CELL_EINVAL);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!*avail)
|
||||
{
|
||||
return CELL_ENOTDIR;
|
||||
}
|
||||
|
||||
if (auto err = cellFsGetBlockSize(ppu, path, vm::var<u64>{}, _block_size))
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
*block_count = *avail / *_block_size;
|
||||
*block_size = *_block_size;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user