Compare commits
486 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c16e176fbe | |||
| 55fccf03fa | |||
| d3f9ae4868 | |||
| debeafa36b | |||
| 39e946630d | |||
| 8d815e8ee0 | |||
| 430b57833d | |||
| e32c48d0dd | |||
| e2402b1c8f | |||
| 36abdd7114 | |||
| 79f54771b5 | |||
| 2556f84752 | |||
| c8e624850b | |||
| 56692e23f5 | |||
| b38ce9452d | |||
| fcba193a3c | |||
| 6fc7fa3b13 | |||
| ad4216a3fc | |||
| 08c3a38b67 | |||
| b8165af054 | |||
| 90b6912daa | |||
| 862727e9bf | |||
| 9e9a3262eb | |||
| c268189e38 | |||
| 94431a7a33 | |||
| b4d5b44e00 | |||
| 16f006362e | |||
| dfec577417 | |||
| 33e2f8766a | |||
| 31a080a9cb | |||
| 14e9c8954c | |||
| dff7352e2e | |||
| 30bb6c9fb9 | |||
| 7485ec2223 | |||
| 60082864a6 | |||
| dcb8f21b2b | |||
| b18a97e777 | |||
| c7d93bd470 | |||
| 7bf8917c08 | |||
| 093198e3d5 | |||
| e48bd29584 | |||
| 1444981bdc | |||
| e3f6bbfcc9 | |||
| 89922b254c | |||
| ea8918291b | |||
| 21445fa01a | |||
| 8d340eecc1 | |||
| 463826bf13 | |||
| 40eda1b972 | |||
| a5c3e303c7 | |||
| 270a21ebae | |||
| 6aa96e5f81 | |||
| 1792714901 | |||
| 54ab16ab35 | |||
| c58959eba2 | |||
| 2f53d58cd9 | |||
| e0d6f8a311 | |||
| e48ec75896 | |||
| 58d8c65990 | |||
| dd66380132 | |||
| 92dd801ecd | |||
| fba1db29b3 | |||
| 1111c1952b | |||
| 7833862342 | |||
| 78c1a6f326 | |||
| 060ddca1ab | |||
| a9fd2f76d2 | |||
| d1837b54b4 | |||
| 26746ac9ee | |||
| c019b10aa8 | |||
| 0cd316116b | |||
| c92a556093 | |||
| d6f6752af0 | |||
| d7e04e9b0a | |||
| c1aaa1bcf6 | |||
| 10fe14e783 | |||
| 0231902a69 | |||
| dbeb8cfbec | |||
| 96bd150518 | |||
| cb1fb19dea | |||
| 3b37f5b156 | |||
| a989634ba5 | |||
| d865186f23 | |||
| e63245a6dc | |||
| 682fd15441 | |||
| bbd81b9395 | |||
| cb6186ea60 | |||
| 12bfc7d56a | |||
| 7dc4ccc87d | |||
| 622894a7e3 | |||
| 965ec8ec81 | |||
| 103b2fe5fd | |||
| b6bfde6d64 | |||
| 1ec2752ed2 | |||
| a5b6b2e9b5 | |||
| f51b100a8c | |||
| 412db758e8 | |||
| f617f69be8 | |||
| b81d278aee | |||
| aee4bfa369 | |||
| 517f0e1bac | |||
| 08837d2cd0 | |||
| 9a4c823366 | |||
| 7f3ad4fc2c | |||
| 9e7b759236 | |||
| 67853b464c | |||
| 51ffd4a377 | |||
| dada2e85a2 | |||
| 2a53824b02 | |||
| 3dc1dfa4a2 | |||
| 95e0d1a560 | |||
| 8effbf7e4d | |||
| 72ad1abd39 | |||
| 2a89d87fab | |||
| 33eeee0ff2 | |||
| 3c46388be5 | |||
| d37b9497a2 | |||
| 17512f2a28 | |||
| 597a9f6dd6 | |||
| e90b399329 | |||
| 7c8be662c6 | |||
| e38b005a8b | |||
| f0abb4473e | |||
| d62e90f5b4 | |||
| 4ecf8ecd06 | |||
| 9a3b72f762 | |||
| 7285af4771 | |||
| ec37e8f0dc | |||
| 41f05f6864 | |||
| cc2fa94fa1 | |||
| 2f579311b8 | |||
| ac034040ce | |||
| 59410b9d62 | |||
| 6f665da016 | |||
| c567c92d4b | |||
| 75b2dfa66d | |||
| c40826c140 | |||
| 175aa510c8 | |||
| 236ac7d062 | |||
| 00f1b2bfa7 | |||
| a9fad83971 | |||
| 1550dc7f1f | |||
| bbb4c109d7 | |||
| a6fa091ab3 | |||
| 6a1fa88e15 | |||
| 787e79c687 | |||
| 7468d96c51 | |||
| 9c9ece3d95 | |||
| 316b3a8851 | |||
| 2023057fbb | |||
| 94c048d018 | |||
| e126af63ed | |||
| 750359d780 | |||
| 8588b2b11a | |||
| 4594c912a6 | |||
| afcfd81496 | |||
| aa06aaab8e | |||
| fdca881e34 | |||
| 81de7a5863 | |||
| efbf044ea0 | |||
| 46a1c09abe | |||
| 6a3e795d73 | |||
| e0f08cd5c1 | |||
| a539308545 | |||
| 3364a46139 | |||
| fb4e64d15e | |||
| 68349e48cd | |||
| 4dff8b16f1 | |||
| 9245565085 | |||
| 86ca381a3c | |||
| a7952e15c7 | |||
| 643f81b5db | |||
| cf5a66a204 | |||
| e05239f3d9 | |||
| 0e73b58abf | |||
| 59dc5dcd54 | |||
| adedc7c667 | |||
| 29ad568791 | |||
| 453a3c4852 | |||
| 2e824827b7 | |||
| 3393d13b67 | |||
| 1da7689526 | |||
| 806758d06f | |||
| 580f9bf03a | |||
| 707a648a4c | |||
| 213a19c9f3 | |||
| e32ed90d21 | |||
| 2f822abb47 | |||
| 1ca83bc629 | |||
| 77485747f1 | |||
| 40adf4b944 | |||
| 2aad5a7f3a | |||
| 0f29a5be9f | |||
| 397c2698ae | |||
| 0f00bb77fe | |||
| a73303a047 | |||
| 0334243a69 | |||
| bb809c865f | |||
| 20750c260e | |||
| 37dd1b3ed0 | |||
| f3ac3476cb | |||
| 67ae1c9f69 | |||
| fd583dbbc3 | |||
| d8d0af2bb3 | |||
| b176085e14 | |||
| 4cfdb71d3a | |||
| 38590e321e | |||
| a09900a64f | |||
| 4a7d982a2b | |||
| ee69468104 | |||
| 4739ab58cc | |||
| be5b982e45 | |||
| 86ad4ed6c1 | |||
| 3056a4db83 | |||
| adc8a360ad | |||
| 719dafa679 | |||
| ecf7d4e59d | |||
| 45863bc7c5 | |||
| ea0545779a | |||
| e625bab7eb | |||
| 2930d609ea | |||
| 069ca214ff | |||
| d699db2d19 | |||
| 8e15de5c83 | |||
| 69a90ef9e7 | |||
| d39361705a | |||
| 4512c10ce5 | |||
| 5e24167d6c | |||
| 64d28ba435 | |||
| 7febbdf52b | |||
| b64b98490e | |||
| f40602cc59 | |||
| ef8afa7873 | |||
| df4fc947ec | |||
| eecfbf3fa6 | |||
| cfbe7669b4 | |||
| ccaeb87b01 | |||
| fc98f35ea7 | |||
| 998f867c29 | |||
| eb8325afcb | |||
| 7674c29c78 | |||
| 573734fab8 | |||
| 2cbd983b4c | |||
| 18983f5476 | |||
| 75ef154c12 | |||
| 414a354511 | |||
| 2168511e5b | |||
| f64d6bc687 | |||
| 3e83729cb2 | |||
| 83256cdacb | |||
| f748fe688c | |||
| 188f5c7c3c | |||
| 838346e4f7 | |||
| 12dc03a903 | |||
| e17c2f2397 | |||
| 071baf63b0 | |||
| 1795d5bcc9 | |||
| 27125c6f72 | |||
| 12694dcf69 | |||
| e7d8ef924f | |||
| 0f682b7da1 | |||
| 2b385f28f0 | |||
| ac8e914a25 | |||
| 3067c86d65 | |||
| 96afc15fa2 | |||
| 66f694bb39 | |||
| 06025cd19d | |||
| fc698a4df2 | |||
| 2cd47c0415 | |||
| b032f2dd87 | |||
| 3acd442c2e | |||
| 6b43e5c80e | |||
| 183380fe57 | |||
| 7abc5f3ead | |||
| 1867f9aa1f | |||
| f47c7e0ef1 | |||
| 36ab866c2c | |||
| f943deb2c3 | |||
| 27ea25a999 | |||
| 989b353fbd | |||
| c1607d14dc | |||
| 85884d14cd | |||
| 08cf275bc8 | |||
| 88ba3c47c2 | |||
| 4aee44b1c0 | |||
| e3d4c067df | |||
| dfc626c99c | |||
| 8786516c58 | |||
| 34e945128f | |||
| 7db6165b46 | |||
| 883f2e92ae | |||
| 3e8b003515 | |||
| ed66e9e9b9 | |||
| f87e11d16a | |||
| 5a64556fbf | |||
| d71f4b33d7 | |||
| c91bc03532 | |||
| 348fab33a8 | |||
| 68f3df4975 | |||
| f6f8996aa9 | |||
| 8533f962c6 | |||
| af33c0c69f | |||
| 50b1402d66 | |||
| cfd5c62386 | |||
| 569f72c360 | |||
| df74d49f72 | |||
| eac31dfd03 | |||
| 0b1a7ee346 | |||
| 77ba2b40e7 | |||
| 94239f5526 | |||
| 148edc005a | |||
| ec59f4d37e | |||
| 2c03878c3b | |||
| c8c845a659 | |||
| a54f1970f1 | |||
| 7f602937a3 | |||
| c2631c914d | |||
| c17014a055 | |||
| c572226b0d | |||
| 6718b0683e | |||
| 3735df4f53 | |||
| 4746ef09cd | |||
| ed93bbd16d | |||
| 041daab068 | |||
| e5c831a800 | |||
| b8ed3eb824 | |||
| 95f9f04612 | |||
| 823c72bf27 | |||
| 9b387485b5 | |||
| 56e27bdd49 | |||
| 30e8c3e951 | |||
| 96b7e4c67f | |||
| 65d93c97ea | |||
| a92b8acba7 | |||
| 85f4c38b4e | |||
| 40c51a1f05 | |||
| a6c2e995af | |||
| 596e671973 | |||
| d38b2eb8ef | |||
| bb9444e19a | |||
| 26d406fec3 | |||
| dda0b8af45 | |||
| d5ce4e0f6b | |||
| e5cfe710fa | |||
| 2a0e2ce0a2 | |||
| ef56433684 | |||
| 8bc3a39586 | |||
| e13a671f86 | |||
| 48f82c75c1 | |||
| a5955657c5 | |||
| 319657e815 | |||
| c589001dff | |||
| c04cd2228e | |||
| cba51b4a5e | |||
| 8962ddca01 | |||
| 1808a4373b | |||
| bb22afb7f1 | |||
| ce571cb6ca | |||
| ac9afbfede | |||
| 4e8130bd99 | |||
| 00c9321b1d | |||
| 8e8b582747 | |||
| 6f2e843193 | |||
| 7d9460a560 | |||
| 32f2b14429 | |||
| 651f8512eb | |||
| 3dac7d16e7 | |||
| 240f80b467 | |||
| 17b5a36b59 | |||
| ea326a5f29 | |||
| c271415328 | |||
| f28c7d029c | |||
| d7f317fa58 | |||
| 3f2c34edd2 | |||
| 566a8ac5ac | |||
| 71b5bc4fe6 | |||
| a427783bac | |||
| 23dc6a44f6 | |||
| 9ef5a01de4 | |||
| cdfe3ee7c8 | |||
| c3c73c7e24 | |||
| af8d308a69 | |||
| a7da245656 | |||
| e9713f9635 | |||
| 3dbde04d18 | |||
| 1611588682 | |||
| 93c72822a3 | |||
| 6f5bcf12c6 | |||
| 07dba02897 | |||
| db685879af | |||
| 94e8d6fe13 | |||
| 0d1fbfb755 | |||
| 10c52cf569 | |||
| 7661df0847 | |||
| e8ad6ec673 | |||
| 3ef48cbdd5 | |||
| 5fe36872c5 | |||
| d33955c290 | |||
| 606a60e901 | |||
| 93f5154429 | |||
| a6e046c6c3 | |||
| 8eae8cb86c | |||
| abe5013f1d | |||
| ca7de4bcb1 | |||
| 9a9b5860df | |||
| 0971636c07 | |||
| 50fcec63e0 | |||
| 8a87dc63b1 | |||
| efea3aa385 | |||
| 86bab5b7c3 | |||
| 675ed82c0b | |||
| 58dd0198dd | |||
| 16f833a516 | |||
| 0392830950 | |||
| 04efc6b4a4 | |||
| 8edd7d54cf | |||
| f19744ae88 | |||
| 01ee119c59 | |||
| 4cd60aca22 | |||
| 81ba791ee7 | |||
| c7a94a80df | |||
| c509226bab | |||
| 312b35051d | |||
| e401d85af7 | |||
| e4c9af176b | |||
| 9c354ee269 | |||
| 96d880839a | |||
| e23db7efbd | |||
| fd540f1820 | |||
| 7d55a85fa6 | |||
| fa7ef870dd | |||
| ecacb874e4 | |||
| 0b2e0a1b28 | |||
| a08d60fbbe | |||
| ef6041c14f | |||
| 25954758d7 | |||
| 0ae1578dce | |||
| 2039b85be3 | |||
| 8eae73dd02 | |||
| fe9a24a1b8 | |||
| 3d974eed03 | |||
| 329b58c8cd | |||
| 2d82e3ef9a | |||
| faaf644331 | |||
| d7aedb439e | |||
| 9c11840e40 | |||
| 4c36b80300 | |||
| f7fa5aab70 | |||
| 17aeefe1b0 | |||
| 825ae5b8aa | |||
| 3513f6d83c | |||
| 4ad4badcfe | |||
| b67837c0ef | |||
| b5f3f910f6 | |||
| b0a7448394 | |||
| bed7763a3b | |||
| 572c075a4b | |||
| bad7756af2 | |||
| 45c89030ac | |||
| 7aad4f4253 | |||
| 9e9385a877 | |||
| 431d69ac87 | |||
| 3be24f1e6f | |||
| c45deb3f87 | |||
| 213674511e | |||
| 6548e3f7d0 | |||
| a269ae7e30 | |||
| 862295d9f3 | |||
| 61e130e68c | |||
| 236e32fb3d | |||
| 067ea68979 | |||
| 7504503d5f | |||
| 108d0d49ec | |||
| 2c424a0911 | |||
| ffe1b287a8 | |||
| 485fca34b0 | |||
| 0b984e9a23 | |||
| 74e084c893 | |||
| 47ae192cf8 | |||
| 80b7fd5f3f | |||
| 0227b16d06 | |||
| 2a1af17f67 | |||
| b6e9746198 | |||
| bc141831f7 | |||
| acd3fd0c3e | |||
| 2369266b8a |
@@ -43,6 +43,7 @@ cmake .. \
|
||||
-DUSE_SYSTEM_CURL=ON \
|
||||
-DUSE_SDL=ON \
|
||||
-DUSE_SYSTEM_FFMPEG=OFF \
|
||||
-DUSE_DISCORD_RPC=ON \
|
||||
-DOpenGL_GL_PREFERENCE=LEGACY \
|
||||
-DLLVM_DIR=/opt/llvm/lib/cmake/llvm \
|
||||
-DSTATIC_LINK_LLVM=ON \
|
||||
|
||||
+5
-3
@@ -1,7 +1,9 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
export HOMEBREW_NO_AUTO_UPDATE=1
|
||||
brew install -f --overwrite nasm ninja git p7zip ccache pipenv #create-dmg
|
||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||
brew unlink certifi
|
||||
brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
|
||||
|
||||
#/usr/sbin/softwareupdate --install-rosetta --agree-to-license
|
||||
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
@@ -13,8 +15,8 @@ arch -x86_64 /usr/local/bin/brew reinstall -f --build-from-source gnutls freetyp
|
||||
arch -x86_64 /usr/local/bin/brew install llvm@16 glew cmake sdl2 vulkan-headers coreutils
|
||||
arch -x86_64 /usr/local/bin/brew link -f llvm@16 ffmpeg@5
|
||||
|
||||
# moltenvk based on commit for 1.2.6 release
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/4ac0cfaca4c2505abe2fcbcc0ce5816572103a6c/Formula/m/molten-vk.rb
|
||||
# moltenvk based on commit for 1.2.7 release
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/05a8770c483cfddf5b077667a392d846bc2ad719/Formula/m/molten-vk.rb
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb
|
||||
#export MACOSX_DEPLOYMENT_TARGET=12.0
|
||||
export CXX=clang++
|
||||
|
||||
+6
-1
@@ -12,11 +12,16 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
||||
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh
|
||||
chmod +x ./linuxdeploy-plugin-checkrt.sh
|
||||
|
||||
EXTRA_QT_PLUGINS="svg;" APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt
|
||||
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
|
||||
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration"
|
||||
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt
|
||||
|
||||
# Remove libwayland-client because it has platform-dependent exports and breaks other OSes
|
||||
rm -f ./AppDir/usr/lib/libwayland-client.so*
|
||||
|
||||
# Remove libvulkan because it causes issues with gamescope
|
||||
rm -f ./AppDir/usr/lib/libvulkan.so*
|
||||
|
||||
# Remove git directory containing local commit history file
|
||||
rm -rf ./AppDir/usr/share/rpcs3/git
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ QT_DECL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtdeclarative${QT_SUFFIX}"
|
||||
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qttools${QT_SUFFIX}"
|
||||
QT_MM_URL="${QT_HOST}${QT_PREFIX}addons.qtmultimedia.${QT_PREFIX_2}qtmultimedia${QT_SUFFIX}"
|
||||
QT_SVG_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtsvg${QT_SUFFIX}"
|
||||
QT_5CMP_URL="${QT_HOST}${QT_PREFIX}qt5compat.${QT_PREFIX_2}qt5compat${QT_SUFFIX}"
|
||||
LLVMLIBS_URL='https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z'
|
||||
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z'
|
||||
VULKAN_SDK_URL="https://www.dropbox.com/scl/fi/sjjh0fc4ld281pjbl2xzu/VulkanSDK-1.3.268.0-Installer.exe?rlkey=f6wzc0lvms5vwkt2z3qabfv9d&dl=1"
|
||||
@@ -30,7 +29,6 @@ DEP_URLS=" \
|
||||
$QT_TOOL_URL \
|
||||
$QT_MM_URL \
|
||||
$QT_SVG_URL \
|
||||
$QT_5CMP_URL \
|
||||
$LLVMLIBS_URL \
|
||||
$GLSLANG_URL \
|
||||
$VULKAN_SDK_URL"
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@ env:
|
||||
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
|
||||
RPCS3_TOKEN: ENCRYPTED[!a4c3850e29ab150692286a74bec29819d25971a7ec431b86de2a35f7ed90c5b2ab3c93469f9298e30924d843599110e9!]
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.6.1'
|
||||
QT_VER: '6.6.3'
|
||||
|
||||
# windows_task:
|
||||
# matrix:
|
||||
@@ -21,7 +21,7 @@ env:
|
||||
# COMPILER: msvc
|
||||
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
|
||||
# QT_VER_MSVC: 'msvc2019'
|
||||
# QT_DATE: '202311210527'
|
||||
# QT_DATE: '202403191840'
|
||||
# QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
|
||||
# VULKAN_VER: '1.3.268.0'
|
||||
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
||||
@@ -56,7 +56,7 @@ env:
|
||||
|
||||
# linux_task:
|
||||
# container:
|
||||
# image: rpcs3/rpcs3-ci-focal:1.5
|
||||
# image: rpcs3/rpcs3-ci-focal:1.7
|
||||
# cpu: 4
|
||||
# memory: 16G
|
||||
# env:
|
||||
|
||||
@@ -130,6 +130,9 @@ yaml-cpp.pc
|
||||
# miniupnp
|
||||
/3rdparty/miniupnp/x64/*
|
||||
|
||||
# opencv
|
||||
/3rdparty/opencv/*
|
||||
|
||||
# llvm
|
||||
/3rdparty/llvm/llvm_build
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
# 7z sdk
|
||||
if(WIN32)
|
||||
if(WIN32 OR APPLE)
|
||||
add_library(3rdparty_7z STATIC EXCLUDE_FROM_ALL
|
||||
src/7zAlloc.c
|
||||
src/7zArcIn.c
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/FAudio updated: 758c90af12...70fec4889f
Vendored
+1
-1
@@ -4,7 +4,7 @@ include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(moltenvk
|
||||
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
|
||||
GIT_TAG 9e4ee9e
|
||||
GIT_TAG 66f6ff1
|
||||
BUILD_IN_SOURCE 1
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
|
||||
CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/SoundTouch/soundtouch updated: ced3ce8d5e...394e1f58b2
-1276
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
Vendored
+1
-1
Submodule 3rdparty/curl/curl updated: 7161cb17c0...de7b3e8921
Vendored
+7
-3
@@ -44,7 +44,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<AdditionalIncludeDirectories>curl\include;curl\lib;extra;$(SolutionDir)3rdparty\wolfssl\wolfssl\wolfssl;$(SolutionDir)3rdparty\wolfssl\wolfssl;$(SolutionDir)3rdparty\wolfssl\extra\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>HAVE_SNI;NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;NO_MD4;WOLFSSL_USER_SETTINGS;USE_IPV6;SIZEOF_LONG=4;SIZEOF_LONG_LONG=8;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WOLFSSL_ALT_CERT_CHAINS;HAVE_SNI;NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;NO_MD4;WOLFSSL_USER_SETTINGS;USE_IPV6;SIZEOF_LONG=4;SIZEOF_LONG_LONG=8;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
@@ -92,9 +92,11 @@
|
||||
<ClCompile Include="curl\lib\curl_range.c" />
|
||||
<ClCompile Include="curl\lib\curl_rtmp.c" />
|
||||
<ClCompile Include="curl\lib\curl_sasl.c" />
|
||||
<ClCompile Include="curl\lib\curl_sha512_256.c" />
|
||||
<ClCompile Include="curl\lib\curl_sspi.c" />
|
||||
<ClCompile Include="curl\lib\curl_threads.c" />
|
||||
<ClCompile Include="curl\lib\curl_trc.c" />
|
||||
<ClCompile Include="curl\lib\cw-out.c" />
|
||||
<ClCompile Include="curl\lib\dict.c" />
|
||||
<ClCompile Include="curl\lib\doh.c" />
|
||||
<ClCompile Include="curl\lib\dynbuf.c" />
|
||||
@@ -156,6 +158,7 @@
|
||||
<ClCompile Include="curl\lib\psl.c" />
|
||||
<ClCompile Include="curl\lib\rand.c" />
|
||||
<ClCompile Include="curl\lib\rename.c" />
|
||||
<ClCompile Include="curl\lib\request.c" />
|
||||
<ClCompile Include="curl\lib\rtsp.c" />
|
||||
<ClCompile Include="curl\lib\select.c" />
|
||||
<ClCompile Include="curl\lib\sendf.c" />
|
||||
@@ -286,12 +289,13 @@
|
||||
<ClInclude Include="curl\lib\curl_setup.h" />
|
||||
<ClInclude Include="curl\lib\curl_setup_once.h" />
|
||||
<ClInclude Include="curl\lib\curl_sha256.h" />
|
||||
<ClInclude Include="curl\lib\curl_sha512_256.h" />
|
||||
<ClInclude Include="curl\lib\curl_sspi.h" />
|
||||
<ClInclude Include="curl\lib\curl_threads.h" />
|
||||
<ClInclude Include="curl\lib\curl_trc.h" />
|
||||
<ClInclude Include="curl\lib\cw-out.h" />
|
||||
<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\dynhds.h" />
|
||||
<ClInclude Include="curl\lib\easyif.h" />
|
||||
@@ -341,6 +345,7 @@
|
||||
<ClInclude Include="curl\lib\psl.h" />
|
||||
<ClInclude Include="curl\lib\rand.h" />
|
||||
<ClInclude Include="curl\lib\rename.h" />
|
||||
<ClInclude Include="curl\lib\request.h" />
|
||||
<ClInclude Include="curl\lib\rtsp.h" />
|
||||
<ClInclude Include="curl\lib\select.h" />
|
||||
<ClInclude Include="curl\lib\sendf.h" />
|
||||
@@ -386,7 +391,6 @@
|
||||
<ClInclude Include="curl\lib\vauth\vauth.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\gtls.h" />
|
||||
<ClInclude Include="curl\lib\vtls\keylog.h" />
|
||||
|
||||
+18
-6
@@ -504,6 +504,15 @@
|
||||
<ClCompile Include="curl\lib\curl_trc.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\request.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\cw-out.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curl_sha512_256.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="curl\include\curl\curl.h">
|
||||
@@ -677,9 +686,6 @@
|
||||
<ClInclude Include="curl\lib\doh.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\dotdot.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\easyif.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -890,9 +896,6 @@
|
||||
<ClInclude Include="curl\lib\vssh\ssh.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\vssh\wolfssh.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\vtls\bearssl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -1028,6 +1031,15 @@
|
||||
<ClInclude Include="curl\lib\curl_trc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\request.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\cw-out.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_sha512_256.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="curl\lib\libcurl.rc">
|
||||
|
||||
Vendored
+2
@@ -1,6 +1,8 @@
|
||||
# DiscordRPC
|
||||
add_library(3rdparty_discordRPC INTERFACE)
|
||||
|
||||
check_cxx_compiler_flag("-msse -msse2 -mcx16" COMPILER_X86)
|
||||
|
||||
# We don't want Discord Rich Presence on the BSDs and other OSes
|
||||
if (USE_DISCORD_RPC AND (WIN32 OR CMAKE_SYSTEM MATCHES "Linux" OR APPLE) AND COMPILER_X86)
|
||||
if (WIN32 AND NOT MSVC)
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/flatbuffers updated: 06c5c7ed0b...0100f6a577
Vendored
+2
-2
@@ -39,9 +39,9 @@
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
|
||||
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B build</CmakeReleaseCLI>
|
||||
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B build</CmakeReleaseCLI>
|
||||
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B build</CmakeDebugCLI>
|
||||
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DENABLE_OPT=OFF -S glslang -B build</CmakeDebugCLI>
|
||||
<PropsAbsPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\buildfiles\msvc\common_default.props'))</PropsAbsPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
||||
Vendored
+2
-2
@@ -44,12 +44,12 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)lib/</OutDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)lib/</OutDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
||||
Vendored
+5
-2
@@ -4,11 +4,14 @@ if (NOT USE_SYSTEM_LIBPNG)
|
||||
# We use libpng's static library and don't need to build the shared library and run the tests
|
||||
set(PNG_SHARED OFF CACHE BOOL "Build shared lib")
|
||||
set(PNG_TESTS OFF CACHE BOOL "Build libpng tests")
|
||||
set(PNG_BUILD_ZLIB ON CACHE BOOL "ZLIB is already build or package is found")
|
||||
if (NOT USE_SYSTEM_ZLIB)
|
||||
set(PNG_BUILD_ZLIB ON CACHE BOOL "Custom zlib location, else find_package is used")
|
||||
add_library(ZLIB::ZLIB INTERFACE IMPORTED)
|
||||
target_link_libraries(ZLIB::ZLIB INTERFACE 3rdparty_zlib)
|
||||
endif()
|
||||
set(SKIP_INSTALL_ALL ON)
|
||||
add_subdirectory(libpng EXCLUDE_FROM_ALL)
|
||||
target_include_directories(png_static INTERFACE "${libpng_BINARY_DIR}" "${libpng_SOURCE_DIR}")
|
||||
target_link_libraries(png_static 3rdparty::zlib)
|
||||
|
||||
set(LIBPNG_TARGET png_static PARENT_SCOPE)
|
||||
else()
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/libpng/libpng updated: f135775ad4...ed217e3e60
Vendored
+18
-20
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug Library|x64">
|
||||
<Configuration>Debug Library</Configuration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release Library|x64">
|
||||
<Configuration>Release Library</Configuration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
@@ -19,11 +19,11 @@
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default_macros.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'" Label="Configuration">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'" Label="Configuration">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@@ -33,28 +33,28 @@
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'" Label="PropertySheets">
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'" Label="PropertySheets">
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<CustomBuildBeforeTargets />
|
||||
<TargetName>$(ProjectName)16</TargetName>
|
||||
<OutDir>$(SolutionDir)lib/</OutDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<CustomBuildBeforeTargets />
|
||||
<TargetName>$(ProjectName)16</TargetName>
|
||||
<OutDir>$(SolutionDir)lib/</OutDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>$(WarningLevel)</WarningLevel>
|
||||
@@ -74,19 +74,17 @@
|
||||
<DisableSpecificWarnings>$(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<AdditionalIncludeDirectories>$(ZLibSrcDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>$(TreatWarningAsError)</TreatWarningAsError>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>$(WarningLevel)</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
@@ -115,8 +113,8 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="libpng\png.c">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="libpng\pngerror.c" />
|
||||
<ClCompile Include="libpng\pngget.c" />
|
||||
@@ -135,8 +133,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="libpng\scripts\pngwin.rc">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/libsdl-org/SDL updated: 15ead9a40d...f461d91cd2
Vendored
+21
-1
@@ -11,6 +11,12 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_steamdeck.c" />
|
||||
<ClCompile Include="SDL\src\joystick\SDL_steam_virtual_gamepad.c" />
|
||||
<ClCompile Include="SDL\src\joystick\steam\SDL_steamcontroller.c" />
|
||||
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx.c" />
|
||||
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_sse.c" />
|
||||
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_std.c" />
|
||||
<ClInclude Include="SDL\include\begin_code.h" />
|
||||
<ClInclude Include="SDL\include\close_code.h" />
|
||||
<ClInclude Include="SDL\include\SDL.h" />
|
||||
@@ -133,7 +139,9 @@
|
||||
<ClInclude Include="SDL\src\joystick\hidapi\SDL_hidapi_rumble.h" />
|
||||
<ClInclude Include="SDL\src\joystick\SDL_gamecontrollerdb.h" />
|
||||
<ClInclude Include="SDL\src\joystick\SDL_joystick_c.h" />
|
||||
<ClInclude Include="SDL\src\joystick\SDL_steam_virtual_gamepad.h" />
|
||||
<ClInclude Include="SDL\src\joystick\SDL_sysjoystick.h" />
|
||||
<ClInclude Include="SDL\src\joystick\steam\SDL_steamcontroller.h" />
|
||||
<ClInclude Include="SDL\src\joystick\usb_ids.h" />
|
||||
<ClInclude Include="SDL\src\joystick\virtual\SDL_virtualjoystick_c.h" />
|
||||
<ClInclude Include="SDL\src\joystick\windows\SDL_dinputjoystick_c.h" />
|
||||
@@ -188,6 +196,13 @@
|
||||
<ClInclude Include="SDL\src\video\dummy\SDL_nullevents_c.h" />
|
||||
<ClInclude Include="SDL\src\video\dummy\SDL_nullframebuffer_c.h" />
|
||||
<ClInclude Include="SDL\src\video\dummy\SDL_nullvideo.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codecs_common.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std_decode.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std_encode.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std_decode.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std_encode.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vulkan\vk_icd.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vulkan\vk_layer.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vulkan\vk_platform.h" />
|
||||
@@ -238,7 +253,13 @@
|
||||
<ClInclude Include="SDL\src\video\windows\SDL_windowswindow.h" />
|
||||
<ClInclude Include="SDL\src\video\windows\wmmsg.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_common.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_internal.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx_func.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_sse.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_sse_func.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_std.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_std_func.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -418,7 +439,6 @@
|
||||
<ClCompile Include="SDL\src\video\windows\SDL_windowsvideo.c" />
|
||||
<ClCompile Include="SDL\src\video\windows\SDL_windowsvulkan.c" />
|
||||
<ClCompile Include="SDL\src\video\windows\SDL_windowswindow.c" />
|
||||
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb.c" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}</ProjectGuid>
|
||||
|
||||
+21
-1
@@ -178,10 +178,15 @@
|
||||
<ClCompile Include="SDL\src\video\windows\SDL_windowsvideo.c" />
|
||||
<ClCompile Include="SDL\src\video\windows\SDL_windowsvulkan.c" />
|
||||
<ClCompile Include="SDL\src\video\windows\SDL_windowswindow.c" />
|
||||
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb.c" />
|
||||
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_ps3.c" />
|
||||
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_steam.c" />
|
||||
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_wii.c" />
|
||||
<ClCompile Include="SDL\src\joystick\steam\SDL_steamcontroller.c" />
|
||||
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx.c" />
|
||||
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_sse.c" />
|
||||
<ClCompile Include="SDL\src\video\yuv2rgb\yuv_rgb_std.c" />
|
||||
<ClCompile Include="SDL\src\joystick\hidapi\SDL_hidapi_steamdeck.c" />
|
||||
<ClCompile Include="SDL\src\joystick\SDL_steam_virtual_gamepad.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="SDL\include\begin_code.h" />
|
||||
@@ -409,5 +414,20 @@
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_sse_func.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_std_func.h" />
|
||||
<ClInclude Include="SDL\src\joystick\hidapi\SDL_hidapi_nintendo.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_common.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_internal.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_lsx_func.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_sse.h" />
|
||||
<ClInclude Include="SDL\src\video\yuv2rgb\yuv_rgb_std.h" />
|
||||
<ClInclude Include="SDL\src\joystick\steam\SDL_steamcontroller.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std_decode.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h264std_encode.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std_decode.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codec_h265std_encode.h" />
|
||||
<ClInclude Include="SDL\src\video\khronos\vk_video\vulkan_video_codecs_common.h" />
|
||||
<ClInclude Include="SDL\src\joystick\SDL_steam_virtual_gamepad.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Vendored
+1
-1
Submodule 3rdparty/libusb/libusb updated: 4239bc3a50...d52e355daa
+1
-3
@@ -35,7 +35,7 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
<OutDir>$(SolutionDir)lib/</OutDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)/</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
|
||||
<TargetName>libusb-1.0</TargetName>
|
||||
</PropertyGroup>
|
||||
@@ -50,11 +50,9 @@
|
||||
<ClCompile Condition="'$(Configuration)'=='Debug'">
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<ClCompile Condition="'$(Configuration)'=='Release'">
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)libusb-1.0.lib</OutputFile>
|
||||
|
||||
Vendored
+6
-14
@@ -36,12 +36,7 @@ if(WITH_LLVM)
|
||||
|
||||
set(STATIC_LINK_LLVM ON CACHE BOOL "Link against LLVM statically. This will get set to ON if you build LLVM from the submodule." FORCE)
|
||||
|
||||
# now tries to find LLVM again
|
||||
find_package(LLVM 16.0 CONFIG)
|
||||
if(NOT LLVM_FOUND)
|
||||
set(LLVM_DIR "${CMAKE_CURRENT_BINARY_DIR}/llvm_build/lib/cmake/llvm/")
|
||||
find_package(LLVM 17.0 CONFIG)
|
||||
endif()
|
||||
if(NOT LLVM_FOUND)
|
||||
message(FATAL_ERROR "Couldn't build LLVM from the submodule. You might need to run `git submodule update --init`")
|
||||
endif()
|
||||
@@ -53,20 +48,16 @@ if(WITH_LLVM)
|
||||
set(LLVM_DIR ${CMAKE_SOURCE_DIR}/${LLVM_DIR})
|
||||
endif()
|
||||
|
||||
find_package(LLVM 16.0 CONFIG)
|
||||
if(NOT LLVM_FOUND)
|
||||
find_package(LLVM 17.0 CONFIG)
|
||||
endif()
|
||||
find_package(LLVM CONFIG)
|
||||
|
||||
if (NOT LLVM_FOUND)
|
||||
if (LLVM_VERSION AND LLVM_VERSION_MAJOR LESS 16)
|
||||
message(FATAL_ERROR "Found LLVM version ${LLVM_VERSION}. Required versions 16...17. \
|
||||
Enable BUILD_LLVM option to build LLVM from included as a git submodule.")
|
||||
endif()
|
||||
|
||||
message(FATAL_ERROR "Can't find LLVM libraries from the CMAKE_PREFIX_PATH path or LLVM_DIR. \
|
||||
Enable BUILD_LLVM option to build LLVM from included as a git submodule.")
|
||||
endif()
|
||||
if (LLVM_VERSION VERSION_LESS 16)
|
||||
message(FATAL_ERROR "Found LLVM version ${LLVM_VERSION}. Required version 16 or above. \
|
||||
Enable BUILD_LLVM option to build LLVM from included as a git submodule.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (STATIC_LINK_LLVM)
|
||||
@@ -89,6 +80,7 @@ if(WITH_LLVM)
|
||||
Core
|
||||
ExecutionEngine
|
||||
MCJIT
|
||||
Passes
|
||||
)
|
||||
else()
|
||||
set(LLVM_LIBS LLVM)
|
||||
|
||||
+2
-2
@@ -39,9 +39,9 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./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_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeReleaseCLI>
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./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_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeReleaseCLI>
|
||||
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -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_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeDebugCLI>
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -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_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeDebugCLI>
|
||||
<CmakeCleanCLI>echo Cleaning..
|
||||
for /F "delims= eol=|" %%f in ('
|
||||
dir /b ^| findstr /V "[^.]*\build[^.]*\.vcxproj"') do (
|
||||
|
||||
+2
-2
@@ -39,9 +39,9 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="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 -DCMAKE_INSTALL_PREFIX="./Release" -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeReleaseCLI>
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="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 -DCMAKE_INSTALL_PREFIX="./Release" -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeReleaseCLI>
|
||||
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DCMAKE_INSTALL_PREFIX="./Debug" -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeDebugCLI>
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DCMAKE_INSTALL_PREFIX="./Debug" -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm/llvm</CmakeDebugCLI>
|
||||
<CmakeCleanCLI>echo Cleaning..
|
||||
for /F "delims= eol=|" %%f in ('
|
||||
dir /b ^| findstr /V "[^.]*\build[^.]*\.vcxproj"') do (
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/miniupnp/miniupnp updated: e439318cf7...7f189988a0
-2
@@ -58,7 +58,6 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>generated;miniupnp\miniupnpc;miniupnp\miniupnpc\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -80,7 +79,6 @@ cscript genminiupnpcstrings.vbs</Command>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>generated;miniupnp\miniupnpc;miniupnp\miniupnpc\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
|
||||
Vendored
-2
@@ -27,10 +27,8 @@
|
||||
#include <sys/un.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
constexpr SOCKET invalid_socket = INVALID_SOCKET;
|
||||
|
||||
Vendored
+1
@@ -18,6 +18,7 @@ else()
|
||||
set(WOLFSSL_SNI ON CACHE STRING "Enable SNI (default: disabled)")
|
||||
set(WOLFSSL_OPENSSLEXTRA ON CACHE STRING "Enable extra OpenSSL API, size+ (default: disabled)")
|
||||
set(WOLFSSL_HARDEN OFF CACHE STRING "Enable Hardened build, Enables Timing Resistance and Blinding (default: enabled)")
|
||||
set(WOLFSSL_ALT_CERT_CHAINS ON CACHE STRING "Enable support for Alternate certification chains (default: disabled)")
|
||||
|
||||
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@
|
||||
#define ECC_TIMING_RESISTANT
|
||||
#define USE_FAST_MATH
|
||||
#define FP_MAX_BITS 8192
|
||||
#ifndef WOLFSSL_ALT_CERT_CHAINS
|
||||
#define WOLFSSL_ALT_CERT_CHAINS
|
||||
#endif
|
||||
|
||||
/* UTF-8 aware filesystem functions for Windows */
|
||||
#define WOLFSSL_USER_FILESYSTEM
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/wolfssl/wolfssl updated: 66596ad9e1...8970ff4c34
Vendored
+6
-3
@@ -1,10 +1,9 @@
|
||||
if (USE_SYSTEM_ZLIB)
|
||||
message(STATUS "RPCS3: Using system ZLIB")
|
||||
find_package(ZLIB QUIET)
|
||||
find_package(ZLIB QUIET REQUIRED)
|
||||
|
||||
add_library(3rdparty_zlib INTERFACE)
|
||||
target_link_libraries(3rdparty_zlib INTERFACE ${ZLIB_LIBRARIES})
|
||||
target_include_directories(3rdparty_zlib INTERFACE ${ZLIB_INCLUDE_DIRS})
|
||||
target_link_libraries(3rdparty_zlib INTERFACE ZLIB::ZLIB)
|
||||
target_compile_definitions(3rdparty_zlib INTERFACE -DZLIB_CONST=1)
|
||||
else()
|
||||
message(STATUS "RPCS3: Using builtin ZLIB")
|
||||
@@ -15,4 +14,8 @@ else()
|
||||
target_link_libraries(3rdparty_zlib INTERFACE zlibstatic)
|
||||
target_include_directories(3rdparty_zlib INTERFACE zlib ${CMAKE_CURRENT_BINARY_DIR}/zlib)
|
||||
target_compile_definitions(3rdparty_zlib INTERFACE -DZLIB_CONST=1)
|
||||
|
||||
if(NOT MSVC)
|
||||
set(ZLIB_ROOT ${CMAKE_CURRENT_BINARY_DIR}/zlib PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/zlib/zlib updated: 09155eaa2f...51b7f2abda
Vendored
-1
@@ -88,7 +88,6 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<DisableSpecificWarnings>$(DisableSpecificWarnings);4127;4131;4242;4244</DisableSpecificWarnings>
|
||||
<TreatWarningAsError>$(TreatWarningAsError)</TreatWarningAsError>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
||||
+11
-9
@@ -5,23 +5,25 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
|
||||
|
||||
## Setup your environment
|
||||
|
||||
### Windows 7 or later
|
||||
### Windows 10 or later
|
||||
|
||||
* [CMake 3.16.9+](https://www.cmake.org/download/) (add to PATH)
|
||||
* [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
|
||||
* [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
|
||||
* [Qt 6.6.1](https://www.qt.io/download-qt-installer)
|
||||
* [Qt 6.6.3](https://www.qt.io/download-qt-installer)
|
||||
* [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (or at least Visual Studio 2019 16.11.xx+ as C++20 is not included in previous versions)
|
||||
* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\6.6.1\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\6.6.3\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
|
||||
|
||||
**NOTE: If you have issues with the Qt plugin, you may want to uninstall the Qt Plugin and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2019) instead.**
|
||||
|
||||
### Linux
|
||||
|
||||
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager.
|
||||
|
||||
* Clang 12+ or GCC 11+
|
||||
* [CMake 3.16.9+](https://www.cmake.org/download/)
|
||||
* [Qt 6.6.1](https://www.qt.io/download-qt-installer)
|
||||
* [CMake 3.28.0+](https://www.cmake.org/download/)
|
||||
* [Qt 6.6.3](https://www.qt.io/download-qt-installer)
|
||||
* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
* [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
|
||||
|
||||
@@ -96,9 +98,9 @@ git submodule update --init
|
||||
#### Configuring the Qt plugin (if used)
|
||||
|
||||
1) Go to `Extensions->Qt VS Tools->Qt Versions`.
|
||||
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.6.1\msvc2019_64`, version will fill in automatically.
|
||||
3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`.
|
||||
4) Set `Build: Run pre-build setup` to `true`.
|
||||
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.6.3\msvc2019_64`, version will fill in automatically.
|
||||
3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the legacy Qt plugin)
|
||||
4) Set `Build: Run pre-build setup` to `true`. (Only available in the legacy Qt plugin)
|
||||
|
||||
#### Building the projects
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ struct bf_base
|
||||
{
|
||||
using type = T;
|
||||
using vtype = std::common_type_t<type>;
|
||||
using utype = typename std::make_unsigned<vtype>::type;
|
||||
using utype = std::make_unsigned_t<vtype>;
|
||||
|
||||
static constexpr bool can_be_packed = N < (sizeof(int) * 8 + (std::is_unsigned_v<vtype> ? 1 : 0)) && sizeof(vtype) > sizeof(int);
|
||||
using compact_type = std::conditional_t<can_be_packed, std::conditional_t<std::is_unsigned_v<vtype>, uint, int>, vtype>;
|
||||
|
||||
+186
-36
@@ -1,12 +1,14 @@
|
||||
#include "File.h"
|
||||
#include "mutex.h"
|
||||
#include "StrFmt.h"
|
||||
#include "StrUtil.h"
|
||||
#include "Crypto/sha1.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#include "util/asm.hpp"
|
||||
#include "util/coro.hpp"
|
||||
@@ -49,23 +51,6 @@ static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void to_utf8(std::string& out, const wchar_t* source)
|
||||
{
|
||||
// String size
|
||||
const usz length = std::wcslen(source);
|
||||
|
||||
// Safe buffer size for max possible output length (including null terminator)
|
||||
const int buf_size = narrow<int>(length * 3 + 1);
|
||||
|
||||
// Resize buffer
|
||||
out.resize(buf_size - 1);
|
||||
|
||||
const int result = WideCharToMultiByte(CP_UTF8, 0, source, static_cast<int>(length) + 1, &out.front(), buf_size, nullptr, nullptr);
|
||||
|
||||
// Fix the size
|
||||
out.resize(ensure(result) - 1);
|
||||
}
|
||||
|
||||
static time_t to_time(const ULARGE_INTEGER& ft)
|
||||
{
|
||||
return ft.QuadPart / 10000000ULL - 11644473600ULL;
|
||||
@@ -153,6 +138,7 @@ static fs::error to_error(DWORD e)
|
||||
#if defined(__APPLE__)
|
||||
#include <copyfile.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <limits.h>
|
||||
#elif defined(__linux__) || defined(__sun)
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/syscall.h>
|
||||
@@ -371,6 +357,12 @@ namespace fs
|
||||
return false;
|
||||
}
|
||||
|
||||
bool device_base::create_symlink(const std::string&)
|
||||
{
|
||||
g_tls_error = error::readonly;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool device_base::rename(const std::string&, const std::string&)
|
||||
{
|
||||
g_tls_error = error::readonly;
|
||||
@@ -531,7 +523,7 @@ bool fs::get_stat(const std::string& path, stat_t& info)
|
||||
// Handle drives specially
|
||||
if (epath.find_first_of(delim) == umax && epath.ends_with(':'))
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrs{};
|
||||
|
||||
// Must end with a delimiter
|
||||
if (!GetFileAttributesExW(to_wchar(std::string(epath) + '/').get(), GetFileExInfoStandard, &attrs))
|
||||
@@ -553,8 +545,6 @@ bool fs::get_stat(const std::string& path, stat_t& info)
|
||||
return true;
|
||||
}
|
||||
|
||||
WIN32_FIND_DATA attrs;
|
||||
|
||||
// Allowed by FindFirstFileExW but we should not allow it
|
||||
if (epath.ends_with("*"))
|
||||
{
|
||||
@@ -562,6 +552,8 @@ bool fs::get_stat(const std::string& path, stat_t& info)
|
||||
return false;
|
||||
}
|
||||
|
||||
WIN32_FIND_DATA attrs{};
|
||||
|
||||
const auto wchar_ptr = to_wchar(std::string(epath));
|
||||
const std::wstring_view wpath_view = wchar_ptr.get();
|
||||
|
||||
@@ -595,6 +587,7 @@ bool fs::get_stat(const std::string& path, stat_t& info)
|
||||
}
|
||||
|
||||
info.is_directory = (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
info.is_symlink = (attrs.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
|
||||
info.is_writable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
info.size = attrs.nFileSizeLow | (u64{attrs.nFileSizeHigh} << 32);
|
||||
info.atime = to_time(attrs.ftLastAccessTime);
|
||||
@@ -609,6 +602,7 @@ bool fs::get_stat(const std::string& path, stat_t& info)
|
||||
}
|
||||
|
||||
info.is_directory = S_ISDIR(file_info.st_mode);
|
||||
info.is_symlink = S_ISLNK(file_info.st_mode);
|
||||
info.is_writable = file_info.st_mode & 0200; // HACK: approximation
|
||||
info.size = file_info.st_size;
|
||||
info.atime = file_info.st_atime;
|
||||
@@ -662,6 +656,23 @@ bool fs::is_dir(const std::string& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fs::is_symlink(const std::string& path)
|
||||
{
|
||||
fs::stat_t info{};
|
||||
if (!fs::get_stat(path, info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!info.is_symlink)
|
||||
{
|
||||
g_tls_error = error::exist;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fs::statfs(const std::string& path, fs::device_stat& info)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
@@ -761,7 +772,7 @@ bool fs::create_path(const std::string& path)
|
||||
|
||||
#ifdef _WIN32
|
||||
// Workaround: don't call is_dir with naked drive letter
|
||||
if (parent.size() < path.size() && parent.back() != ':' && !is_dir(parent) && !create_path(parent))
|
||||
if (parent.size() < path.size() && (parent.empty() || (parent.back() != ':' && !is_dir(parent) && !create_path(parent))))
|
||||
#else
|
||||
if (parent.size() < path.size() && !is_dir(parent) && !create_path(parent))
|
||||
#endif
|
||||
@@ -797,10 +808,35 @@ bool fs::remove_dir(const std::string& path)
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (::rmdir(path.c_str()) != 0)
|
||||
{
|
||||
g_tls_error = to_error(errno);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fs::create_symlink(const std::string& path, const std::string& target)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
{
|
||||
return device->create_symlink(path);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const DWORD flags = is_dir(target) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
|
||||
if (!CreateSymbolicLinkW(to_wchar(path).get(), to_wchar(target).get(), flags))
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
if (::rmdir(path.c_str()) != 0)
|
||||
if (::symlink(target.c_str(), path.c_str()) != 0)
|
||||
{
|
||||
g_tls_error = to_error(errno);
|
||||
return false;
|
||||
@@ -1789,7 +1825,7 @@ bool fs::dir::open(const std::string& path)
|
||||
{
|
||||
dir_entry info;
|
||||
|
||||
to_utf8(info.name, found.cFileName);
|
||||
info.name = wchar_to_utf8(found.cFileName);
|
||||
info.is_directory = (found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
info.is_writable = (found.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
info.size = (static_cast<u64>(found.nFileSizeHigh) << 32) | static_cast<u64>(found.nFileSizeLow);
|
||||
@@ -1905,9 +1941,9 @@ bool fs::dir::open(const std::string& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fs::file::strict_read_check(u64 _size, u64 type_size) const
|
||||
bool fs::file::strict_read_check(u64 offset, u64 _size, u64 type_size) const
|
||||
{
|
||||
if (usz pos0 = pos(), size0 = size(); (pos0 >= size0 ? 0 : (size0 - pos0)) / type_size < _size)
|
||||
if (usz pos0 = offset, size0 = size(); (pos0 >= size0 ? 0 : (size0 - pos0)) / type_size < _size)
|
||||
{
|
||||
fs::g_tls_error = fs::error::inval;
|
||||
return false;
|
||||
@@ -1916,6 +1952,72 @@ bool fs::file::strict_read_check(u64 _size, u64 type_size) const
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string fs::get_executable_path()
|
||||
{
|
||||
// Use magic static
|
||||
static const std::string s_exe_path = []
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
constexpr DWORD size = 32767;
|
||||
std::vector<wchar_t> buffer(size);
|
||||
GetModuleFileNameW(nullptr, buffer.data(), size);
|
||||
return wchar_to_utf8(buffer.data());
|
||||
#elif defined(__APPLE__)
|
||||
char bin_path[PATH_MAX];
|
||||
uint32_t bin_path_size = sizeof(bin_path);
|
||||
if (_NSGetExecutablePath(bin_path, &bin_path_size) != 0)
|
||||
{
|
||||
std::cerr << "Failed to find app binary path" << std::endl;
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
// App bundle directory is three levels up from the binary.
|
||||
return get_parent_dir(bin_path, 3);
|
||||
#else
|
||||
if (const char* appimage_path = ::getenv("APPIMAGE"))
|
||||
{
|
||||
std::cout << "Found AppImage path: " << appimage_path << std::endl;
|
||||
return std::string(appimage_path);
|
||||
}
|
||||
|
||||
std::cout << "No AppImage path found, checking for executable" << std::endl;
|
||||
|
||||
char exe_path[PATH_MAX];
|
||||
const ssize_t len = ::readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
|
||||
|
||||
if (len == -1)
|
||||
{
|
||||
std::cerr << "Failed to find executable path" << std::endl;
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
exe_path[len] = '\0';
|
||||
std::cout << "Found exec path: " << exe_path << std::endl;
|
||||
|
||||
return std::string(exe_path);
|
||||
#endif
|
||||
}();
|
||||
|
||||
return s_exe_path;
|
||||
}
|
||||
|
||||
std::string fs::get_executable_dir()
|
||||
{
|
||||
// Use magic static
|
||||
static const std::string s_exe_dir = []
|
||||
{
|
||||
std::string exe_path = get_executable_path();
|
||||
if (exe_path.empty())
|
||||
{
|
||||
return exe_path;
|
||||
}
|
||||
|
||||
return get_parent_dir(exe_path) + "/";
|
||||
}();
|
||||
|
||||
return s_exe_dir;
|
||||
}
|
||||
|
||||
const std::string& fs::get_config_dir()
|
||||
{
|
||||
// Use magic static
|
||||
@@ -1923,17 +2025,52 @@ const std::string& fs::get_config_dir()
|
||||
{
|
||||
std::string dir;
|
||||
|
||||
#ifdef _WIN32
|
||||
wchar_t buf[32768];
|
||||
constexpr DWORD size = static_cast<DWORD>(std::size(buf));
|
||||
if (GetEnvironmentVariable(L"RPCS3_CONFIG_DIR", buf, size) - 1 >= size - 1 &&
|
||||
GetModuleFileName(nullptr, buf, size) - 1 >= size - 1)
|
||||
// Check if a portable directory exists.
|
||||
std::string portable_dir = get_executable_dir() + "/portable/";
|
||||
if (is_dir(portable_dir))
|
||||
{
|
||||
MessageBoxA(nullptr, fmt::format("GetModuleFileName() failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
|
||||
return dir; // empty
|
||||
return portable_dir;
|
||||
}
|
||||
|
||||
to_utf8(dir, buf); // Convert to UTF-8
|
||||
#ifdef _WIN32
|
||||
std::vector<wchar_t> buf;
|
||||
|
||||
// Check if RPCS3_CONFIG_DIR is set and get the required buffer size
|
||||
DWORD size = GetEnvironmentVariable(L"RPCS3_CONFIG_DIR", nullptr, 0);
|
||||
if (size > 0)
|
||||
{
|
||||
// Resize buffer and fetch RPCS3_CONFIG_DIR
|
||||
buf.resize(size);
|
||||
|
||||
if (GetEnvironmentVariable(L"RPCS3_CONFIG_DIR", buf.data(), size) != (size - 1))
|
||||
{
|
||||
// Clear buffer on failure and notify user
|
||||
MessageBoxA(nullptr, fmt::format("GetEnvironmentVariable(RPCS3_CONFIG_DIR) failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
|
||||
buf.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to executable path if needed
|
||||
for (DWORD buf_size = MAX_PATH; size == 0; buf_size += MAX_PATH)
|
||||
{
|
||||
buf.resize(buf_size);
|
||||
size = GetModuleFileName(nullptr, buf.data(), buf_size);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
MessageBoxA(nullptr, fmt::format("GetModuleFileName() failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
|
||||
return dir; // empty
|
||||
}
|
||||
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
// Try again with increased buffer size
|
||||
size = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
dir = wchar_to_utf8(buf.data());
|
||||
|
||||
std::replace(dir.begin(), dir.end(), '\\', '/');
|
||||
|
||||
@@ -2018,10 +2155,23 @@ const std::string& fs::get_temp_dir()
|
||||
return dir; // empty
|
||||
}
|
||||
|
||||
to_utf8(dir, buf);
|
||||
dir = wchar_to_utf8(buf);
|
||||
#else
|
||||
// TODO
|
||||
dir = get_cache_dir();
|
||||
const char* tmp_dir = getenv("TMPDIR");
|
||||
if (tmp_dir == nullptr || tmp_dir[0] == '\0')
|
||||
{
|
||||
// Fall back to cache directory
|
||||
dir = get_cache_dir();
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = tmp_dir;
|
||||
if (!dir.ends_with("/"))
|
||||
{
|
||||
// Ensure path ends with a separator
|
||||
dir += "/";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return dir;
|
||||
|
||||
+24
-6
@@ -66,6 +66,7 @@ namespace fs
|
||||
struct stat_t
|
||||
{
|
||||
bool is_directory;
|
||||
bool is_symlink;
|
||||
bool is_writable;
|
||||
u64 size;
|
||||
s64 atime;
|
||||
@@ -155,6 +156,7 @@ namespace fs
|
||||
virtual bool statfs(const std::string& path, device_stat& info) = 0;
|
||||
virtual bool remove_dir(const std::string& path);
|
||||
virtual bool create_dir(const std::string& path);
|
||||
virtual bool create_symlink(const std::string& path);
|
||||
virtual bool rename(const std::string& from, const std::string& to);
|
||||
virtual bool remove(const std::string& path);
|
||||
virtual bool trunc(const std::string& path, u64 length);
|
||||
@@ -197,6 +199,9 @@ namespace fs
|
||||
// Check whether the directory exists and is NOT a file
|
||||
bool is_dir(const std::string& path);
|
||||
|
||||
// Check whether the path points to an existing symlink
|
||||
bool is_symlink(const std::string& path);
|
||||
|
||||
// Get filesystem information
|
||||
bool statfs(const std::string& path, device_stat& info);
|
||||
|
||||
@@ -209,6 +214,9 @@ namespace fs
|
||||
// Create directories
|
||||
bool create_path(const std::string& path);
|
||||
|
||||
// Create symbolic link
|
||||
bool create_symlink(const std::string& path, const std::string& target);
|
||||
|
||||
// Rename (move) file or directory
|
||||
bool rename(const std::string& from, const std::string& to, bool overwrite);
|
||||
|
||||
@@ -306,7 +314,7 @@ namespace fs
|
||||
}
|
||||
|
||||
// Check if the handle is capable of reading (size * type_size) of bytes at the time of calling
|
||||
bool strict_read_check(u64 size, u64 type_size = 1) const;
|
||||
bool strict_read_check(u64 offset, u64 size, u64 type_size) const;
|
||||
|
||||
// Read the data from the file and return the amount of data written in buffer
|
||||
u64 read(void* buffer, u64 count,
|
||||
@@ -424,7 +432,7 @@ namespace fs
|
||||
if (_size != umax)
|
||||
{
|
||||
// If _size arg is too high std::bad_alloc may happen during resize and then we cannot error check
|
||||
if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(_size, sizeof(T)))
|
||||
if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(pos(), _size, sizeof(T)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -449,7 +457,7 @@ namespace fs
|
||||
|
||||
// Read POD std::vector
|
||||
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
|
||||
bool read(std::vector<T>& vec, usz _size = umax,
|
||||
bool read(std::vector<T>& vec, usz _size = umax, bool use_offs = false, usz offset = umax,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
@@ -460,7 +468,7 @@ namespace fs
|
||||
if (_size != umax)
|
||||
{
|
||||
// If _size arg is too high std::bad_alloc may happen during resize and then we cannot error check
|
||||
if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(_size, sizeof(T)))
|
||||
if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(use_offs ? offset : pos(), _size, sizeof(T)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -468,6 +476,11 @@ namespace fs
|
||||
vec.resize(_size);
|
||||
}
|
||||
|
||||
if (use_offs)
|
||||
{
|
||||
return read_at(offset, vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
|
||||
}
|
||||
|
||||
return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
|
||||
}
|
||||
|
||||
@@ -510,8 +523,7 @@ namespace fs
|
||||
{
|
||||
std::vector<T> result;
|
||||
result.resize(size() / sizeof(T));
|
||||
seek(0);
|
||||
if (!read(result, result.size(), file, func, line, col)) xfail({line, col, file, func});
|
||||
if (!read(result, result.size(), true, 0, file, func, line, col)) xfail({line, col, file, func});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -660,6 +672,12 @@ namespace fs
|
||||
}
|
||||
};
|
||||
|
||||
// Get executable path
|
||||
std::string get_executable_path();
|
||||
|
||||
// Get executable containing directory
|
||||
std::string get_executable_dir();
|
||||
|
||||
// Get configuration directory
|
||||
const std::string& get_config_dir();
|
||||
|
||||
|
||||
+1
-1
@@ -554,4 +554,4 @@ public:
|
||||
static std::string triple2();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // LLVM_AVAILABLE
|
||||
|
||||
@@ -4,16 +4,13 @@
|
||||
#include "StrFmt.h"
|
||||
#include "File.h"
|
||||
#include "util/logs.hpp"
|
||||
#include "mutex.h"
|
||||
#include "util/vm.hpp"
|
||||
#include "util/asm.hpp"
|
||||
#include "util/v128.hpp"
|
||||
#include "util/simd.hpp"
|
||||
#include "Crypto/unzip.h"
|
||||
|
||||
#include <charconv>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#define CAN_OVERCOMMIT
|
||||
#endif
|
||||
|
||||
@@ -22,6 +19,7 @@ LOG_CHANNEL(jit_log, "JIT");
|
||||
void jit_announce(uptr func, usz size, std::string_view name)
|
||||
{
|
||||
#ifdef __linux__
|
||||
#if 0
|
||||
static const struct tmp_perf_map
|
||||
{
|
||||
std::string name{fmt::format("/tmp/perf-%d.map", getpid())};
|
||||
@@ -47,6 +45,7 @@ void jit_announce(uptr func, usz size, std::string_view name)
|
||||
fs::remove_file(s_map.name);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!size)
|
||||
@@ -845,648 +844,3 @@ void asmjit::simd_builder::vec_extract_gpr(u32 esize, const x86::Gp& dst, const
|
||||
}
|
||||
|
||||
#endif /* X86 */
|
||||
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <deque>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma GCC diagnostic ignored "-Wextra"
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#pragma GCC diagnostic ignored "-Wredundant-decls"
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
|
||||
#endif
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/TargetParser/Host.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/ObjectCache.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Object/SymbolSize.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
const bool jit_initialize = []() -> bool
|
||||
{
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetAsmParser();
|
||||
LLVMLinkInMCJIT();
|
||||
return true;
|
||||
}();
|
||||
|
||||
[[noreturn]] static void null(const char* name)
|
||||
{
|
||||
fmt::throw_exception("Null function: %s", name);
|
||||
}
|
||||
|
||||
namespace vm
|
||||
{
|
||||
extern u8* const g_sudo_addr;
|
||||
}
|
||||
|
||||
static shared_mutex null_mtx;
|
||||
|
||||
static std::unordered_map<std::string, u64> null_funcs;
|
||||
|
||||
static u64 make_null_function(const std::string& name)
|
||||
{
|
||||
if (name.starts_with("__0x"))
|
||||
{
|
||||
u32 addr = -1;
|
||||
auto res = std::from_chars(name.c_str() + 4, name.c_str() + name.size(), addr, 16);
|
||||
|
||||
if (res.ec == std::errc() && res.ptr == name.c_str() + name.size() && addr < 0x8000'0000)
|
||||
{
|
||||
// Point the garbage to reserved, non-executable memory
|
||||
return reinterpret_cast<u64>(vm::g_sudo_addr + addr);
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard lock(null_mtx);
|
||||
|
||||
if (u64& func_ptr = null_funcs[name]) [[likely]]
|
||||
{
|
||||
// Already exists
|
||||
return func_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
// Build a "null" function that contains its name
|
||||
const auto func = build_function_asm<void (*)()>("NULL", [&](native_asm& c, auto& args)
|
||||
{
|
||||
#if defined(ARCH_X64)
|
||||
Label data = c.newLabel();
|
||||
c.lea(args[0], x86::qword_ptr(data, 0));
|
||||
c.jmp(Imm(&null));
|
||||
c.align(AlignMode::kCode, 16);
|
||||
c.bind(data);
|
||||
|
||||
// Copy function name bytes
|
||||
for (char ch : name)
|
||||
c.db(ch);
|
||||
c.db(0);
|
||||
c.align(AlignMode::kData, 16);
|
||||
#else
|
||||
// AArch64 implementation
|
||||
Label jmp_address = c.newLabel();
|
||||
Label data = c.newLabel();
|
||||
// Force absolute jump to prevent out of bounds PC-rel jmp
|
||||
c.ldr(args[0], arm::ptr(jmp_address));
|
||||
c.br(args[0]);
|
||||
c.align(AlignMode::kCode, 16);
|
||||
|
||||
c.bind(data);
|
||||
c.embed(name.c_str(), name.size());
|
||||
c.embedUInt8(0U);
|
||||
c.bind(jmp_address);
|
||||
c.embedUInt64(reinterpret_cast<u64>(&null));
|
||||
c.align(AlignMode::kData, 16);
|
||||
#endif
|
||||
});
|
||||
|
||||
func_ptr = reinterpret_cast<u64>(func);
|
||||
return func_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
struct JITAnnouncer : llvm::JITEventListener
|
||||
{
|
||||
void notifyObjectLoaded(u64, const llvm::object::ObjectFile& obj, const llvm::RuntimeDyld::LoadedObjectInfo& info) override
|
||||
{
|
||||
using namespace llvm;
|
||||
|
||||
object::OwningBinary<object::ObjectFile> debug_obj_ = info.getObjectForDebug(obj);
|
||||
if (!debug_obj_.getBinary())
|
||||
{
|
||||
#ifdef __linux__
|
||||
jit_log.error("LLVM: Failed to announce JIT events (no debug object)");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
const object::ObjectFile& debug_obj = *debug_obj_.getBinary();
|
||||
|
||||
for (const auto& [sym, size] : computeSymbolSizes(debug_obj))
|
||||
{
|
||||
Expected<object::SymbolRef::Type> type_ = sym.getType();
|
||||
if (!type_ || *type_ != object::SymbolRef::ST_Function)
|
||||
continue;
|
||||
|
||||
Expected<StringRef> name = sym.getName();
|
||||
if (!name)
|
||||
continue;
|
||||
|
||||
Expected<u64> addr = sym.getAddress();
|
||||
if (!addr)
|
||||
continue;
|
||||
|
||||
jit_announce(*addr, size, {name->data(), name->size()});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Simple memory manager
|
||||
struct MemoryManager1 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
// 256 MiB for code or data
|
||||
static constexpr u64 c_max_size = 0x20000000 / 2;
|
||||
|
||||
// Allocation unit (2M)
|
||||
static constexpr u64 c_page_size = 2 * 1024 * 1024;
|
||||
|
||||
// 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(const MemoryManager1&) = delete;
|
||||
|
||||
MemoryManager1& operator=(const MemoryManager1&) = delete;
|
||||
|
||||
~MemoryManager1() override
|
||||
{
|
||||
// Hack: don't release to prevent reuse of address space, see jit_announce
|
||||
utils::memory_decommit(ptr, c_max_size * 2);
|
||||
}
|
||||
|
||||
llvm::JITSymbol findSymbol(const std::string& name) override
|
||||
{
|
||||
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
addr = make_null_function(name);
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
fmt::throw_exception("Failed to link '%s'", name);
|
||||
}
|
||||
}
|
||||
|
||||
return {addr, llvm::JITSymbolFlags::Exported};
|
||||
}
|
||||
|
||||
u8* allocate(u64& oldp, uptr size, uint align, utils::protection prot)
|
||||
{
|
||||
if (align > c_page_size)
|
||||
{
|
||||
jit_log.fatal("Unsupported alignment (size=0x%x, align=0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const u64 olda = utils::align(oldp, align);
|
||||
const u64 newp = utils::align(olda + size, align);
|
||||
|
||||
if ((newp - 1) / c_max_size != oldp / c_max_size)
|
||||
{
|
||||
jit_log.fatal("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 = utils::align(oldp, c_page_size);
|
||||
const u64 psize = utils::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(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/) override
|
||||
{
|
||||
return allocate(code_ptr, size, align, utils::protection::wx);
|
||||
}
|
||||
|
||||
u8* allocateDataSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/, bool /*is_ro*/) override
|
||||
{
|
||||
return allocate(data_ptr, size, align, utils::protection::rw);
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string* = nullptr) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void registerEHFrames(u8*, u64, usz) override
|
||||
{
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Simple memory manager
|
||||
struct MemoryManager2 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
MemoryManager2() = default;
|
||||
|
||||
~MemoryManager2() override
|
||||
{
|
||||
}
|
||||
|
||||
llvm::JITSymbol findSymbol(const std::string& name) override
|
||||
{
|
||||
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
addr = make_null_function(name);
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
fmt::throw_exception("Failed to link '%s' (MM2)", name);
|
||||
}
|
||||
}
|
||||
|
||||
return {addr, llvm::JITSymbolFlags::Exported};
|
||||
}
|
||||
|
||||
u8* allocateCodeSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/) override
|
||||
{
|
||||
return jit_runtime::alloc(size, align, true);
|
||||
}
|
||||
|
||||
u8* allocateDataSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/, bool /*is_ro*/) override
|
||||
{
|
||||
return jit_runtime::alloc(size, align, false);
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string* = nullptr) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void registerEHFrames(u8*, u64, usz) override
|
||||
{
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Helper class
|
||||
class ObjectCache final : public llvm::ObjectCache
|
||||
{
|
||||
const std::string& m_path;
|
||||
|
||||
public:
|
||||
ObjectCache(const std::string& path)
|
||||
: m_path(path)
|
||||
{
|
||||
}
|
||||
|
||||
~ObjectCache() override = default;
|
||||
|
||||
void notifyObjectCompiled(const llvm::Module* _module, llvm::MemoryBufferRef obj) override
|
||||
{
|
||||
std::string name = m_path;
|
||||
name.append(_module->getName().data());
|
||||
//fs::file(name, fs::rewrite).write(obj.getBufferStart(), obj.getBufferSize());
|
||||
name.append(".gz");
|
||||
|
||||
fs::file module_file(name, fs::rewrite);
|
||||
|
||||
if (!module_file)
|
||||
{
|
||||
jit_log.error("LLVM: Failed to create module file: %s (%s)", name, fs::g_tls_error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!zip(obj.getBufferStart(), obj.getBufferSize(), module_file))
|
||||
{
|
||||
jit_log.error("LLVM: Failed to compress module: %s", _module->getName().data());
|
||||
module_file.close();
|
||||
fs::remove_file(name);
|
||||
return;
|
||||
}
|
||||
|
||||
jit_log.notice("LLVM: Created module: %s", _module->getName().data());
|
||||
}
|
||||
|
||||
static std::unique_ptr<llvm::MemoryBuffer> load(const std::string& path)
|
||||
{
|
||||
if (fs::file cached{path + ".gz", fs::read})
|
||||
{
|
||||
const std::vector<u8> cached_data = cached.to_vector<u8>();
|
||||
|
||||
if (cached_data.empty()) [[unlikely]]
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::vector<u8> out = unzip(cached_data);
|
||||
|
||||
if (out.empty())
|
||||
{
|
||||
jit_log.error("LLVM: Failed to unzip module: '%s'", path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(out.size());
|
||||
std::memcpy(buf->getBufferStart(), out.data(), out.size());
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (fs::file cached{path, fs::read})
|
||||
{
|
||||
if (cached.size() == 0) [[unlikely]]
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(cached.size());
|
||||
cached.read(buf->getBufferStart(), buf->getBufferSize());
|
||||
return buf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* _module) override
|
||||
{
|
||||
std::string path = m_path;
|
||||
path.append(_module->getName().data());
|
||||
|
||||
if (auto buf = load(path))
|
||||
{
|
||||
jit_log.notice("LLVM: Loaded module: %s", _module->getName().data());
|
||||
return buf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
std::string jit_compiler::cpu(const std::string& _cpu)
|
||||
{
|
||||
std::string m_cpu = _cpu;
|
||||
|
||||
if (m_cpu.empty())
|
||||
{
|
||||
m_cpu = llvm::sys::getHostCPUName().str();
|
||||
|
||||
if (m_cpu == "sandybridge" ||
|
||||
m_cpu == "ivybridge" ||
|
||||
m_cpu == "haswell" ||
|
||||
m_cpu == "broadwell" ||
|
||||
m_cpu == "skylake" ||
|
||||
m_cpu == "skylake-avx512" ||
|
||||
m_cpu == "cascadelake" ||
|
||||
m_cpu == "cooperlake" ||
|
||||
m_cpu == "cannonlake" ||
|
||||
m_cpu == "icelake" ||
|
||||
m_cpu == "icelake-client" ||
|
||||
m_cpu == "icelake-server" ||
|
||||
m_cpu == "tigerlake" ||
|
||||
m_cpu == "rocketlake" ||
|
||||
m_cpu == "alderlake" ||
|
||||
m_cpu == "raptorlake" ||
|
||||
m_cpu == "meteorlake")
|
||||
{
|
||||
// Downgrade if AVX is not supported by some chips
|
||||
if (!utils::has_avx())
|
||||
{
|
||||
m_cpu = "nehalem";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cpu == "skylake-avx512" ||
|
||||
m_cpu == "cascadelake" ||
|
||||
m_cpu == "cooperlake" ||
|
||||
m_cpu == "cannonlake" ||
|
||||
m_cpu == "icelake" ||
|
||||
m_cpu == "icelake-client" ||
|
||||
m_cpu == "icelake-server" ||
|
||||
m_cpu == "tigerlake" ||
|
||||
m_cpu == "rocketlake")
|
||||
{
|
||||
// Downgrade if AVX-512 is disabled or not supported
|
||||
if (!utils::has_avx512())
|
||||
{
|
||||
m_cpu = "skylake";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cpu == "znver1" && utils::has_clwb())
|
||||
{
|
||||
// Upgrade
|
||||
m_cpu = "znver2";
|
||||
}
|
||||
|
||||
if ((m_cpu == "znver3" || m_cpu == "goldmont" || m_cpu == "alderlake" || m_cpu == "raptorlake" || m_cpu == "meteorlake") && utils::has_avx512_icl())
|
||||
{
|
||||
// Upgrade
|
||||
m_cpu = "icelake-client";
|
||||
}
|
||||
|
||||
if (m_cpu == "goldmont" && utils::has_avx2())
|
||||
{
|
||||
// Upgrade
|
||||
m_cpu = "alderlake";
|
||||
}
|
||||
}
|
||||
|
||||
return m_cpu;
|
||||
}
|
||||
|
||||
std::string jit_compiler::triple1()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
|
||||
#elif defined(__APPLE__) && defined(ARCH_X64)
|
||||
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
|
||||
#elif defined(__APPLE__) && defined(ARCH_ARM64)
|
||||
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
|
||||
#else
|
||||
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string jit_compiler::triple2()
|
||||
{
|
||||
#if defined(_WIN32) && defined(ARCH_X64)
|
||||
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
|
||||
#elif defined(_WIN32) && defined(ARCH_ARM64)
|
||||
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
|
||||
#elif defined(__APPLE__) && defined(ARCH_X64)
|
||||
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
|
||||
#elif defined(__APPLE__) && defined(ARCH_ARM64)
|
||||
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
|
||||
#else
|
||||
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
|
||||
#endif
|
||||
}
|
||||
|
||||
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, const std::string& _cpu, u32 flags)
|
||||
: m_context(new llvm::LLVMContext)
|
||||
, m_cpu(cpu(_cpu))
|
||||
{
|
||||
std::string result;
|
||||
|
||||
auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context);
|
||||
null_mod->setTargetTriple(jit_compiler::triple1());
|
||||
|
||||
std::unique_ptr<llvm::RTDyldMemoryManager> mem;
|
||||
|
||||
if (_link.empty())
|
||||
{
|
||||
// Auxiliary JIT (does not use custom memory manager, only writes the objects)
|
||||
if (flags & 0x1)
|
||||
{
|
||||
mem = std::make_unique<MemoryManager1>();
|
||||
}
|
||||
else
|
||||
{
|
||||
mem = std::make_unique<MemoryManager2>();
|
||||
null_mod->setTargetTriple(jit_compiler::triple2());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mem = std::make_unique<MemoryManager1>();
|
||||
}
|
||||
|
||||
{
|
||||
m_engine.reset(llvm::EngineBuilder(std::move(null_mod))
|
||||
.setErrorStr(&result)
|
||||
.setEngineKind(llvm::EngineKind::JIT)
|
||||
.setMCJITMemoryManager(std::move(mem))
|
||||
.setOptLevel(llvm::CodeGenOpt::Aggressive)
|
||||
.setCodeModel(flags & 0x2 ? llvm::CodeModel::Large : llvm::CodeModel::Small)
|
||||
#ifdef __APPLE__
|
||||
//.setCodeModel(llvm::CodeModel::Large)
|
||||
#endif
|
||||
.setRelocationModel(llvm::Reloc::Model::PIC_)
|
||||
.setMCPU(m_cpu)
|
||||
.create());
|
||||
}
|
||||
|
||||
if (!_link.empty())
|
||||
{
|
||||
for (auto&& [name, addr] : _link)
|
||||
{
|
||||
m_engine->updateGlobalMapping(name, addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_link.empty() || !(flags & 0x1))
|
||||
{
|
||||
m_engine->RegisterJITEventListener(llvm::JITEventListener::createIntelJITEventListener());
|
||||
m_engine->RegisterJITEventListener(new JITAnnouncer);
|
||||
}
|
||||
|
||||
if (!m_engine)
|
||||
{
|
||||
fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
|
||||
}
|
||||
}
|
||||
|
||||
jit_compiler::~jit_compiler()
|
||||
{
|
||||
}
|
||||
|
||||
void jit_compiler::add(std::unique_ptr<llvm::Module> _module, const std::string& path)
|
||||
{
|
||||
ObjectCache cache{path};
|
||||
m_engine->setObjectCache(&cache);
|
||||
|
||||
const auto ptr = _module.get();
|
||||
m_engine->addModule(std::move(_module));
|
||||
m_engine->generateCodeForModule(ptr);
|
||||
m_engine->setObjectCache(nullptr);
|
||||
|
||||
for (auto& func : ptr->functions())
|
||||
{
|
||||
// Delete IR to lower memory consumption
|
||||
func.deleteBody();
|
||||
}
|
||||
}
|
||||
|
||||
void jit_compiler::add(std::unique_ptr<llvm::Module> _module)
|
||||
{
|
||||
const auto ptr = _module.get();
|
||||
m_engine->addModule(std::move(_module));
|
||||
m_engine->generateCodeForModule(ptr);
|
||||
|
||||
for (auto& func : ptr->functions())
|
||||
{
|
||||
// Delete IR to lower memory consumption
|
||||
func.deleteBody();
|
||||
}
|
||||
}
|
||||
|
||||
void jit_compiler::add(const std::string& path)
|
||||
{
|
||||
auto cache = ObjectCache::load(path);
|
||||
|
||||
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
|
||||
{
|
||||
m_engine->addObjectFile(llvm::object::OwningBinary<llvm::object::ObjectFile>(std::move(*object_file), std::move(cache)));
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_log.error("ObjectCache: Adding failed: %s", path);
|
||||
}
|
||||
}
|
||||
|
||||
bool jit_compiler::check(const std::string& path)
|
||||
{
|
||||
if (auto cache = ObjectCache::load(path))
|
||||
{
|
||||
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fs::remove_file(path))
|
||||
{
|
||||
jit_log.error("ObjectCache: Removed damaged file: %s", path);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void jit_compiler::update_global_mapping(const std::string& name, u64 addr)
|
||||
{
|
||||
m_engine->updateGlobalMapping(name, addr);
|
||||
}
|
||||
|
||||
void jit_compiler::fin()
|
||||
{
|
||||
m_engine->finalizeObject();
|
||||
}
|
||||
|
||||
u64 jit_compiler::get(const std::string& name)
|
||||
{
|
||||
return m_engine->getGlobalValueAddress(name);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,661 @@
|
||||
#include "util/types.hpp"
|
||||
#include "util/sysinfo.hpp"
|
||||
#include "JIT.h"
|
||||
#include "StrFmt.h"
|
||||
#include "File.h"
|
||||
#include "util/logs.hpp"
|
||||
#include "mutex.h"
|
||||
#include "util/vm.hpp"
|
||||
#include "util/asm.hpp"
|
||||
#include "Crypto/unzip.h"
|
||||
|
||||
#include <charconv>
|
||||
|
||||
LOG_CHANNEL(jit_log, "JIT");
|
||||
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma GCC diagnostic ignored "-Wextra"
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#pragma GCC diagnostic ignored "-Wredundant-decls"
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
|
||||
#endif
|
||||
#include <llvm/Support/CodeGen.h>
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/TargetParser/Host.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/ObjectCache.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Object/SymbolSize.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
const bool jit_initialize = []() -> bool
|
||||
{
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetAsmParser();
|
||||
LLVMLinkInMCJIT();
|
||||
return true;
|
||||
}();
|
||||
|
||||
[[noreturn]] static void null(const char* name)
|
||||
{
|
||||
fmt::throw_exception("Null function: %s", name);
|
||||
}
|
||||
|
||||
namespace vm
|
||||
{
|
||||
extern u8* const g_sudo_addr;
|
||||
}
|
||||
|
||||
static shared_mutex null_mtx;
|
||||
|
||||
static std::unordered_map<std::string, u64> null_funcs;
|
||||
|
||||
static u64 make_null_function(const std::string& name)
|
||||
{
|
||||
if (name.starts_with("__0x"))
|
||||
{
|
||||
u32 addr = -1;
|
||||
auto res = std::from_chars(name.c_str() + 4, name.c_str() + name.size(), addr, 16);
|
||||
|
||||
if (res.ec == std::errc() && res.ptr == name.c_str() + name.size() && addr < 0x8000'0000)
|
||||
{
|
||||
// Point the garbage to reserved, non-executable memory
|
||||
return reinterpret_cast<u64>(vm::g_sudo_addr + addr);
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard lock(null_mtx);
|
||||
|
||||
if (u64& func_ptr = null_funcs[name]) [[likely]]
|
||||
{
|
||||
// Already exists
|
||||
return func_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
// Build a "null" function that contains its name
|
||||
const auto func = build_function_asm<void (*)()>("NULL", [&](native_asm& c, auto& args)
|
||||
{
|
||||
#if defined(ARCH_X64)
|
||||
Label data = c.newLabel();
|
||||
c.lea(args[0], x86::qword_ptr(data, 0));
|
||||
c.jmp(Imm(&null));
|
||||
c.align(AlignMode::kCode, 16);
|
||||
c.bind(data);
|
||||
|
||||
// Copy function name bytes
|
||||
for (char ch : name)
|
||||
c.db(ch);
|
||||
c.db(0);
|
||||
c.align(AlignMode::kData, 16);
|
||||
#else
|
||||
// AArch64 implementation
|
||||
Label jmp_address = c.newLabel();
|
||||
Label data = c.newLabel();
|
||||
// Force absolute jump to prevent out of bounds PC-rel jmp
|
||||
c.ldr(args[0], arm::ptr(jmp_address));
|
||||
c.br(args[0]);
|
||||
c.align(AlignMode::kCode, 16);
|
||||
|
||||
c.bind(data);
|
||||
c.embed(name.c_str(), name.size());
|
||||
c.embedUInt8(0U);
|
||||
c.bind(jmp_address);
|
||||
c.embedUInt64(reinterpret_cast<u64>(&null));
|
||||
c.align(AlignMode::kData, 16);
|
||||
#endif
|
||||
});
|
||||
|
||||
func_ptr = reinterpret_cast<u64>(func);
|
||||
return func_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
struct JITAnnouncer : llvm::JITEventListener
|
||||
{
|
||||
void notifyObjectLoaded(u64, const llvm::object::ObjectFile& obj, const llvm::RuntimeDyld::LoadedObjectInfo& info) override
|
||||
{
|
||||
using namespace llvm;
|
||||
|
||||
object::OwningBinary<object::ObjectFile> debug_obj_ = info.getObjectForDebug(obj);
|
||||
if (!debug_obj_.getBinary())
|
||||
{
|
||||
#ifdef __linux__
|
||||
jit_log.error("LLVM: Failed to announce JIT events (no debug object)");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
const object::ObjectFile& debug_obj = *debug_obj_.getBinary();
|
||||
|
||||
for (const auto& [sym, size] : computeSymbolSizes(debug_obj))
|
||||
{
|
||||
Expected<object::SymbolRef::Type> type_ = sym.getType();
|
||||
if (!type_ || *type_ != object::SymbolRef::ST_Function)
|
||||
continue;
|
||||
|
||||
Expected<StringRef> name = sym.getName();
|
||||
if (!name)
|
||||
continue;
|
||||
|
||||
Expected<u64> addr = sym.getAddress();
|
||||
if (!addr)
|
||||
continue;
|
||||
|
||||
jit_announce(*addr, size, {name->data(), name->size()});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Simple memory manager
|
||||
struct MemoryManager1 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
// 256 MiB for code or data
|
||||
static constexpr u64 c_max_size = 0x20000000 / 2;
|
||||
|
||||
// Allocation unit (2M)
|
||||
static constexpr u64 c_page_size = 2 * 1024 * 1024;
|
||||
|
||||
// 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(const MemoryManager1&) = delete;
|
||||
|
||||
MemoryManager1& operator=(const MemoryManager1&) = delete;
|
||||
|
||||
~MemoryManager1() override
|
||||
{
|
||||
// Hack: don't release to prevent reuse of address space, see jit_announce
|
||||
utils::memory_decommit(ptr, c_max_size * 2);
|
||||
}
|
||||
|
||||
llvm::JITSymbol findSymbol(const std::string& name) override
|
||||
{
|
||||
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
addr = make_null_function(name);
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
fmt::throw_exception("Failed to link '%s'", name);
|
||||
}
|
||||
}
|
||||
|
||||
return {addr, llvm::JITSymbolFlags::Exported};
|
||||
}
|
||||
|
||||
u8* allocate(u64& oldp, uptr size, uint align, utils::protection prot)
|
||||
{
|
||||
if (align > c_page_size)
|
||||
{
|
||||
jit_log.fatal("Unsupported alignment (size=0x%x, align=0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const u64 olda = utils::align(oldp, align);
|
||||
const u64 newp = utils::align(olda + size, align);
|
||||
|
||||
if ((newp - 1) / c_max_size != oldp / c_max_size)
|
||||
{
|
||||
jit_log.fatal("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 = utils::align(oldp, c_page_size);
|
||||
const u64 psize = utils::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(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/) override
|
||||
{
|
||||
return allocate(code_ptr, size, align, utils::protection::wx);
|
||||
}
|
||||
|
||||
u8* allocateDataSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/, bool /*is_ro*/) override
|
||||
{
|
||||
return allocate(data_ptr, size, align, utils::protection::rw);
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string* = nullptr) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void registerEHFrames(u8*, u64, usz) override
|
||||
{
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Simple memory manager
|
||||
struct MemoryManager2 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
MemoryManager2() = default;
|
||||
|
||||
~MemoryManager2() override
|
||||
{
|
||||
}
|
||||
|
||||
llvm::JITSymbol findSymbol(const std::string& name) override
|
||||
{
|
||||
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
addr = make_null_function(name);
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
fmt::throw_exception("Failed to link '%s' (MM2)", name);
|
||||
}
|
||||
}
|
||||
|
||||
return {addr, llvm::JITSymbolFlags::Exported};
|
||||
}
|
||||
|
||||
u8* allocateCodeSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/) override
|
||||
{
|
||||
return jit_runtime::alloc(size, align, true);
|
||||
}
|
||||
|
||||
u8* allocateDataSection(uptr size, uint align, uint /*sec_id*/, llvm::StringRef /*sec_name*/, bool /*is_ro*/) override
|
||||
{
|
||||
return jit_runtime::alloc(size, align, false);
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string* = nullptr) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void registerEHFrames(u8*, u64, usz) override
|
||||
{
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Helper class
|
||||
class ObjectCache final : public llvm::ObjectCache
|
||||
{
|
||||
const std::string& m_path;
|
||||
|
||||
public:
|
||||
ObjectCache(const std::string& path)
|
||||
: m_path(path)
|
||||
{
|
||||
}
|
||||
|
||||
~ObjectCache() override = default;
|
||||
|
||||
void notifyObjectCompiled(const llvm::Module* _module, llvm::MemoryBufferRef obj) override
|
||||
{
|
||||
std::string name = m_path;
|
||||
name.append(_module->getName().data());
|
||||
//fs::file(name, fs::rewrite).write(obj.getBufferStart(), obj.getBufferSize());
|
||||
name.append(".gz");
|
||||
|
||||
fs::file module_file(name, fs::rewrite);
|
||||
|
||||
if (!module_file)
|
||||
{
|
||||
jit_log.error("LLVM: Failed to create module file: %s (%s)", name, fs::g_tls_error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!zip(obj.getBufferStart(), obj.getBufferSize(), module_file))
|
||||
{
|
||||
jit_log.error("LLVM: Failed to compress module: %s", _module->getName().data());
|
||||
module_file.close();
|
||||
fs::remove_file(name);
|
||||
return;
|
||||
}
|
||||
|
||||
jit_log.notice("LLVM: Created module: %s", _module->getName().data());
|
||||
}
|
||||
|
||||
static std::unique_ptr<llvm::MemoryBuffer> load(const std::string& path)
|
||||
{
|
||||
if (fs::file cached{path + ".gz", fs::read})
|
||||
{
|
||||
const std::vector<u8> cached_data = cached.to_vector<u8>();
|
||||
|
||||
if (cached_data.empty()) [[unlikely]]
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::vector<u8> out = unzip(cached_data);
|
||||
|
||||
if (out.empty())
|
||||
{
|
||||
jit_log.error("LLVM: Failed to unzip module: '%s'", path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(out.size());
|
||||
std::memcpy(buf->getBufferStart(), out.data(), out.size());
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (fs::file cached{path, fs::read})
|
||||
{
|
||||
if (cached.size() == 0) [[unlikely]]
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(cached.size());
|
||||
cached.read(buf->getBufferStart(), buf->getBufferSize());
|
||||
return buf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* _module) override
|
||||
{
|
||||
std::string path = m_path;
|
||||
path.append(_module->getName().data());
|
||||
|
||||
if (auto buf = load(path))
|
||||
{
|
||||
jit_log.notice("LLVM: Loaded module: %s", _module->getName().data());
|
||||
return buf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
std::string jit_compiler::cpu(const std::string& _cpu)
|
||||
{
|
||||
std::string m_cpu = _cpu;
|
||||
|
||||
if (m_cpu.empty())
|
||||
{
|
||||
m_cpu = llvm::sys::getHostCPUName().str();
|
||||
|
||||
if (m_cpu == "sandybridge" ||
|
||||
m_cpu == "ivybridge" ||
|
||||
m_cpu == "haswell" ||
|
||||
m_cpu == "broadwell" ||
|
||||
m_cpu == "skylake" ||
|
||||
m_cpu == "skylake-avx512" ||
|
||||
m_cpu == "cascadelake" ||
|
||||
m_cpu == "cooperlake" ||
|
||||
m_cpu == "cannonlake" ||
|
||||
m_cpu == "icelake" ||
|
||||
m_cpu == "icelake-client" ||
|
||||
m_cpu == "icelake-server" ||
|
||||
m_cpu == "tigerlake" ||
|
||||
m_cpu == "rocketlake" ||
|
||||
m_cpu == "alderlake" ||
|
||||
m_cpu == "raptorlake" ||
|
||||
m_cpu == "meteorlake")
|
||||
{
|
||||
// Downgrade if AVX is not supported by some chips
|
||||
if (!utils::has_avx())
|
||||
{
|
||||
m_cpu = "nehalem";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cpu == "skylake-avx512" ||
|
||||
m_cpu == "cascadelake" ||
|
||||
m_cpu == "cooperlake" ||
|
||||
m_cpu == "cannonlake" ||
|
||||
m_cpu == "icelake" ||
|
||||
m_cpu == "icelake-client" ||
|
||||
m_cpu == "icelake-server" ||
|
||||
m_cpu == "tigerlake" ||
|
||||
m_cpu == "rocketlake")
|
||||
{
|
||||
// Downgrade if AVX-512 is disabled or not supported
|
||||
if (!utils::has_avx512())
|
||||
{
|
||||
m_cpu = "skylake";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cpu == "znver1" && utils::has_clwb())
|
||||
{
|
||||
// Upgrade
|
||||
m_cpu = "znver2";
|
||||
}
|
||||
|
||||
if ((m_cpu == "znver3" || m_cpu == "goldmont" || m_cpu == "alderlake" || m_cpu == "raptorlake" || m_cpu == "meteorlake") && utils::has_avx512_icl())
|
||||
{
|
||||
// Upgrade
|
||||
m_cpu = "icelake-client";
|
||||
}
|
||||
|
||||
if (m_cpu == "goldmont" && utils::has_avx2())
|
||||
{
|
||||
// Upgrade
|
||||
m_cpu = "alderlake";
|
||||
}
|
||||
}
|
||||
|
||||
return m_cpu;
|
||||
}
|
||||
|
||||
std::string jit_compiler::triple1()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
|
||||
#elif defined(__APPLE__) && defined(ARCH_X64)
|
||||
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
|
||||
#elif defined(__APPLE__) && defined(ARCH_ARM64)
|
||||
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
|
||||
#else
|
||||
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string jit_compiler::triple2()
|
||||
{
|
||||
#if defined(_WIN32) && defined(ARCH_X64)
|
||||
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
|
||||
#elif defined(_WIN32) && defined(ARCH_ARM64)
|
||||
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
|
||||
#elif defined(__APPLE__) && defined(ARCH_X64)
|
||||
return llvm::Triple::normalize("x86_64-unknown-linux-gnu");
|
||||
#elif defined(__APPLE__) && defined(ARCH_ARM64)
|
||||
return llvm::Triple::normalize("aarch64-unknown-linux-gnu");
|
||||
#else
|
||||
return llvm::Triple::normalize(llvm::sys::getProcessTriple());
|
||||
#endif
|
||||
}
|
||||
|
||||
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, const std::string& _cpu, u32 flags)
|
||||
: m_context(new llvm::LLVMContext)
|
||||
, m_cpu(cpu(_cpu))
|
||||
{
|
||||
std::string result;
|
||||
|
||||
auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context);
|
||||
null_mod->setTargetTriple(jit_compiler::triple1());
|
||||
|
||||
std::unique_ptr<llvm::RTDyldMemoryManager> mem;
|
||||
|
||||
if (_link.empty())
|
||||
{
|
||||
// Auxiliary JIT (does not use custom memory manager, only writes the objects)
|
||||
if (flags & 0x1)
|
||||
{
|
||||
mem = std::make_unique<MemoryManager1>();
|
||||
}
|
||||
else
|
||||
{
|
||||
mem = std::make_unique<MemoryManager2>();
|
||||
null_mod->setTargetTriple(jit_compiler::triple2());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mem = std::make_unique<MemoryManager1>();
|
||||
}
|
||||
|
||||
{
|
||||
m_engine.reset(llvm::EngineBuilder(std::move(null_mod))
|
||||
.setErrorStr(&result)
|
||||
.setEngineKind(llvm::EngineKind::JIT)
|
||||
.setMCJITMemoryManager(std::move(mem))
|
||||
#if LLVM_VERSION_MAJOR < 18
|
||||
.setOptLevel(llvm::CodeGenOpt::Aggressive)
|
||||
#else
|
||||
.setOptLevel(llvm::CodeGenOptLevel::Aggressive)
|
||||
#endif
|
||||
.setCodeModel(flags & 0x2 ? llvm::CodeModel::Large : llvm::CodeModel::Small)
|
||||
#ifdef __APPLE__
|
||||
//.setCodeModel(llvm::CodeModel::Large)
|
||||
#endif
|
||||
.setRelocationModel(llvm::Reloc::Model::PIC_)
|
||||
.setMCPU(m_cpu)
|
||||
.create());
|
||||
}
|
||||
|
||||
if (!_link.empty())
|
||||
{
|
||||
for (auto&& [name, addr] : _link)
|
||||
{
|
||||
m_engine->updateGlobalMapping(name, addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_link.empty() || !(flags & 0x1))
|
||||
{
|
||||
m_engine->RegisterJITEventListener(llvm::JITEventListener::createIntelJITEventListener());
|
||||
m_engine->RegisterJITEventListener(new JITAnnouncer);
|
||||
}
|
||||
|
||||
if (!m_engine)
|
||||
{
|
||||
fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
|
||||
}
|
||||
}
|
||||
|
||||
jit_compiler::~jit_compiler()
|
||||
{
|
||||
}
|
||||
|
||||
void jit_compiler::add(std::unique_ptr<llvm::Module> _module, const std::string& path)
|
||||
{
|
||||
ObjectCache cache{path};
|
||||
m_engine->setObjectCache(&cache);
|
||||
|
||||
const auto ptr = _module.get();
|
||||
m_engine->addModule(std::move(_module));
|
||||
m_engine->generateCodeForModule(ptr);
|
||||
m_engine->setObjectCache(nullptr);
|
||||
|
||||
for (auto& func : ptr->functions())
|
||||
{
|
||||
// Delete IR to lower memory consumption
|
||||
func.deleteBody();
|
||||
}
|
||||
}
|
||||
|
||||
void jit_compiler::add(std::unique_ptr<llvm::Module> _module)
|
||||
{
|
||||
const auto ptr = _module.get();
|
||||
m_engine->addModule(std::move(_module));
|
||||
m_engine->generateCodeForModule(ptr);
|
||||
|
||||
for (auto& func : ptr->functions())
|
||||
{
|
||||
// Delete IR to lower memory consumption
|
||||
func.deleteBody();
|
||||
}
|
||||
}
|
||||
|
||||
void jit_compiler::add(const std::string& path)
|
||||
{
|
||||
auto cache = ObjectCache::load(path);
|
||||
|
||||
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
|
||||
{
|
||||
m_engine->addObjectFile(llvm::object::OwningBinary<llvm::object::ObjectFile>(std::move(*object_file), std::move(cache)));
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_log.error("ObjectCache: Adding failed: %s", path);
|
||||
}
|
||||
}
|
||||
|
||||
bool jit_compiler::check(const std::string& path)
|
||||
{
|
||||
if (auto cache = ObjectCache::load(path))
|
||||
{
|
||||
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fs::remove_file(path))
|
||||
{
|
||||
jit_log.error("ObjectCache: Removed damaged file: %s", path);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void jit_compiler::update_global_mapping(const std::string& name, u64 addr)
|
||||
{
|
||||
m_engine->updateGlobalMapping(name, addr);
|
||||
}
|
||||
|
||||
void jit_compiler::fin()
|
||||
{
|
||||
m_engine->finalizeObject();
|
||||
}
|
||||
|
||||
u64 jit_compiler::get(const std::string& name)
|
||||
{
|
||||
return m_engine->getGlobalValueAddress(name);
|
||||
}
|
||||
|
||||
#endif // LLVM_AVAILABLE
|
||||
+11
-1
@@ -35,6 +35,9 @@ std::string wchar_to_utf8(std::wstring_view src)
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#elif defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
@@ -52,6 +55,8 @@ std::u16string utf8_to_utf16(std::string_view src)
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#elif defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
@@ -513,7 +518,7 @@ struct fmt::cfmt_src
|
||||
TYPE(llong);
|
||||
TYPE(schar);
|
||||
TYPE(short);
|
||||
if (std::is_signed<char>::value) TYPE(char);
|
||||
if (std::is_signed_v<char>) TYPE(char);
|
||||
TYPE(long);
|
||||
TYPE(s128);
|
||||
|
||||
@@ -652,6 +657,11 @@ std::string fmt::to_lower(std::string_view string)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string fmt::truncate(std::string_view src, usz length)
|
||||
{
|
||||
return std::string(src.begin(), src.begin() + std::min(src.size(), length));
|
||||
}
|
||||
|
||||
bool fmt::match(const std::string& source, const std::string& mask)
|
||||
{
|
||||
usz source_position = 0, mask_position = 0;
|
||||
|
||||
+3
-3
@@ -54,7 +54,7 @@ struct fmt_unveil
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) <= 8 && alignof(T) <= 8>>
|
||||
{
|
||||
using type = T;
|
||||
|
||||
@@ -65,7 +65,7 @@ struct fmt_unveil<T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <=
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_floating_point_v<T> && sizeof(T) <= 8 && alignof(T) <= 8>>
|
||||
{
|
||||
using type = T;
|
||||
|
||||
@@ -77,7 +77,7 @@ struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_enum<T>::value>>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_enum_v<T>>>
|
||||
{
|
||||
using type = T;
|
||||
|
||||
|
||||
@@ -178,6 +178,8 @@ namespace fmt
|
||||
std::string to_upper(std::string_view string);
|
||||
std::string to_lower(std::string_view string);
|
||||
|
||||
std::string truncate(std::string_view src, usz length);
|
||||
|
||||
bool match(const std::string& source, const std::string& mask);
|
||||
|
||||
struct buf_to_hexstring
|
||||
|
||||
+21
-2
@@ -46,6 +46,7 @@ DYNAMIC_IMPORT_RENAME("Kernel32.dll", SetThreadDescriptionImport, "SetThreadDesc
|
||||
#include <time.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -2192,7 +2193,10 @@ u64 thread_base::finalize(thread_state result_state) noexcept
|
||||
return thread_ctrl::get_name_cached();
|
||||
};
|
||||
|
||||
sig_log.notice("Thread time: %fs (%fGc); Faults: %u [rsx:%u, spu:%u]; [soft:%u hard:%u]; Switches:[vol:%u unvol:%u]; Wait:[%.3fs, spur:%u]",
|
||||
const bool is_cpu_thread = !!cpu_thread::get_current();
|
||||
auto& thread_log = (is_cpu_thread || g_tls_fault_all ? sig_log.notice : sig_log.trace);
|
||||
|
||||
thread_log("Thread time: %fs (%fGc); Faults: %u [rsx:%u, spu:%u]; [soft:%u hard:%u]; Switches:[vol:%u unvol:%u]; Wait:[%.3fs, spur:%u]",
|
||||
time / 1000000000.,
|
||||
cycles / 1000000000.,
|
||||
g_tls_fault_all,
|
||||
@@ -2426,7 +2430,7 @@ void thread_ctrl::wait_for_accurate(u64 usec)
|
||||
break;
|
||||
}
|
||||
|
||||
usec = (until - current).count();
|
||||
usec = std::chrono::duration_cast<std::chrono::microseconds>(until - current).count();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -2639,6 +2643,21 @@ void thread_base::exec()
|
||||
sys_log.notice("\n%s", info);
|
||||
}
|
||||
|
||||
std::string reason_buf;
|
||||
|
||||
if (auto ppu = cpu_thread::get_current<ppu_thread>())
|
||||
{
|
||||
if (auto func = ppu->current_function)
|
||||
{
|
||||
fmt::append(reason_buf, "%s (PPU: %s)", reason, func);
|
||||
}
|
||||
}
|
||||
|
||||
if (!reason_buf.empty())
|
||||
{
|
||||
reason = reason_buf;
|
||||
}
|
||||
|
||||
sig_log.fatal("Thread terminated due to fatal error: %s", reason);
|
||||
|
||||
logs::listener::sync_all();
|
||||
|
||||
+8
-3
@@ -130,6 +130,9 @@ public:
|
||||
|
||||
const native_entry entry_point;
|
||||
|
||||
// Set name for debugger
|
||||
static void set_name(std::string);
|
||||
|
||||
private:
|
||||
// Thread handle (platform-specific)
|
||||
atomic_t<u64> m_thread{0};
|
||||
@@ -160,9 +163,6 @@ private:
|
||||
// Cleanup after possibly deleting the thread instance
|
||||
static native_entry finalize(u64 _self) noexcept;
|
||||
|
||||
// Set name for debugger
|
||||
static void set_name(std::string);
|
||||
|
||||
// Make entry point
|
||||
static native_entry make_trampoline(u64(*entry)(thread_base* _base));
|
||||
|
||||
@@ -218,6 +218,11 @@ public:
|
||||
// Get current thread name
|
||||
static std::string get_name()
|
||||
{
|
||||
if (!g_tls_this_thread)
|
||||
{
|
||||
return "not named_thread";
|
||||
}
|
||||
|
||||
return *g_tls_this_thread->m_tname.load();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -60,9 +60,9 @@ public:
|
||||
static constexpr usz bitmax = sizeof(T) * 8;
|
||||
static constexpr usz bitsize = static_cast<under>(T::__bitset_enum_max);
|
||||
|
||||
static_assert(std::is_enum<T>::value, "bs_t<> error: invalid type (must be enum)");
|
||||
static_assert(std::is_enum_v<T>, "bs_t<> error: invalid type (must be enum)");
|
||||
static_assert(bitsize <= bitmax, "bs_t<> error: invalid __bitset_enum_max");
|
||||
static_assert(bitsize != bitmax || std::is_unsigned<under>::value, "bs_t<> error: invalid __bitset_enum_max (sign bit)");
|
||||
static_assert(bitsize != bitmax || std::is_unsigned_v<under>, "bs_t<> error: invalid __bitset_enum_max (sign bit)");
|
||||
|
||||
// Helper function
|
||||
static constexpr under shift(T value)
|
||||
|
||||
+13
-3
@@ -379,8 +379,8 @@ public:
|
||||
return m_head != 0;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void push(Args&&... args)
|
||||
template <bool Notify = true, typename... Args>
|
||||
bool push(Args&&... args)
|
||||
{
|
||||
auto oldv = m_head.load();
|
||||
auto item = new lf_queue_item<T>(load(oldv), std::forward<Args>(args)...);
|
||||
@@ -390,9 +390,19 @@ public:
|
||||
item->m_link = load(oldv);
|
||||
}
|
||||
|
||||
if (!oldv)
|
||||
if (!oldv && Notify)
|
||||
{
|
||||
// Notify only if queue was empty
|
||||
notify(true);
|
||||
}
|
||||
|
||||
return !oldv;
|
||||
}
|
||||
|
||||
void notify(bool force = false)
|
||||
{
|
||||
if (force || operator bool())
|
||||
{
|
||||
utils::bless<atomic_t<u32>>(&m_head)[1].notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -38,13 +38,13 @@ jobs:
|
||||
displayName: ccache
|
||||
|
||||
- bash: |
|
||||
docker pull --quiet rpcs3/rpcs3-ci-focal:1.5
|
||||
docker pull --quiet rpcs3/rpcs3-ci-focal:1.7
|
||||
docker run \
|
||||
-v $(pwd):/rpcs3 \
|
||||
--env-file .ci/docker.env \
|
||||
-v $CCACHE_DIR:/root/.ccache \
|
||||
-v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
|
||||
rpcs3/rpcs3-ci-focal:1.5 \
|
||||
rpcs3/rpcs3-ci-focal:1.7 \
|
||||
/rpcs3/.ci/build-linux.sh
|
||||
displayName: Docker setup and build
|
||||
|
||||
@@ -69,9 +69,9 @@ jobs:
|
||||
variables:
|
||||
COMPILER: msvc
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.6.1'
|
||||
QT_VER: '6.6.3'
|
||||
QT_VER_MSVC: 'msvc2019'
|
||||
QT_DATE: '202311210527'
|
||||
QT_DATE: '202403191840'
|
||||
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
|
||||
VULKAN_VER: '1.3.268.0'
|
||||
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
||||
@@ -132,7 +132,7 @@ jobs:
|
||||
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac"
|
||||
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
|
||||
ARTDIR: $(Build.ArtifactStagingDirectory)
|
||||
QT_VER: '6.6.1'
|
||||
QT_VER: '6.6.3'
|
||||
QT_VER_MAIN: '6'
|
||||
|
||||
pool:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -33,16 +33,17 @@ else()
|
||||
add_compile_options(-fno-exceptions)
|
||||
add_compile_options(-fstack-protector)
|
||||
|
||||
if (COMPILER_X86)
|
||||
add_compile_options(-msse -msse2 -mcx16)
|
||||
endif()
|
||||
|
||||
if (COMPILER_ARM)
|
||||
# This section needs a review. Apple claims armv8.5-a on M-series but doesn't support SVE.
|
||||
# Note that compared to the rest of the 8.x family, 8.1 is very restrictive and we'll have to bump the requirement in future to get anything meaningful.
|
||||
if (APPLE)
|
||||
add_compile_options(-march=armv8.4-a)
|
||||
else()
|
||||
add_compile_options(-march=armv8.1-a)
|
||||
endif()
|
||||
elseif(COMPILER_X86)
|
||||
# Some compilers will set both X86 and ARM, so check explicitly for ARM first
|
||||
add_compile_options(-msse -msse2 -mcx16)
|
||||
endif()
|
||||
|
||||
add_compile_options(-Werror=old-style-cast)
|
||||
@@ -51,6 +52,7 @@ else()
|
||||
add_compile_options(-Werror=return-type)
|
||||
add_compile_options(-Werror=overloaded-virtual)
|
||||
add_compile_options(-Werror=missing-noreturn)
|
||||
add_compile_options(-Werror=implicit-fallthrough)
|
||||
add_compile_options(-Wunused-parameter)
|
||||
add_compile_options(-Wignored-qualifiers)
|
||||
add_compile_options(-Wredundant-move)
|
||||
@@ -69,6 +71,7 @@ else()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
add_compile_options(-Werror=inconsistent-missing-override)
|
||||
add_compile_options(-Werror=delete-non-virtual-dtor)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
add_compile_options(-Werror=suggest-override)
|
||||
add_compile_options(-Wclobbered)
|
||||
@@ -82,7 +85,6 @@ else()
|
||||
add_compile_options(-fconstexpr-steps=16777216)
|
||||
add_compile_options(-Wno-unused-lambda-capture)
|
||||
add_compile_options(-Wno-unused-private-field)
|
||||
add_compile_options(-Wno-delete-non-virtual-dtor)
|
||||
add_compile_options(-Wno-unused-command-line-argument)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
add_compile_options(-Wno-class-memaccess)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<AdditionalOptions>-d2FH4- %(AdditionalOptions)</AdditionalOptions>
|
||||
<RuntimeLibrary Condition = "$(Configuration.Contains('Release'))">MultiThreaded</RuntimeLibrary>
|
||||
<RuntimeLibrary Condition = "$(Configuration.Contains('Debug'))">MultiThreadedDebug</RuntimeLibrary>
|
||||
<RuntimeLibrary Condition = "$(Configuration.Contains('Debug'))">MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>-d2:-FH4- %(AdditionalOptions)</AdditionalOptions>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<AdditionalOptions>%(AdditionalOptions)</AdditionalOptions>
|
||||
<RuntimeLibrary Condition = "$(Configuration.Contains('Release'))">MultiThreaded</RuntimeLibrary>
|
||||
<RuntimeLibrary Condition = "$(Configuration.Contains('Debug'))">MultiThreadedDebug</RuntimeLibrary>
|
||||
<RuntimeLibrary Condition = "$(Configuration.Contains('Debug'))">MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>%(AdditionalOptions)</AdditionalOptions>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>LLVM_AVAILABLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#import <Foundation/Foundation.h>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
namespace Darwin_Version
|
||||
{
|
||||
|
||||
@@ -128,10 +128,10 @@ Global
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.Build.0 = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release|x64.ActiveCfg = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release|x64.Build.0 = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release|x64
|
||||
|
||||
@@ -45,7 +45,8 @@ if(WIN32)
|
||||
target_compile_definitions(rpcs3 PRIVATE UNICODE _UNICODE)
|
||||
elseif(APPLE)
|
||||
add_executable(rpcs3 MACOSX_BUNDLE)
|
||||
target_sources(rpcs3 PRIVATE rpcs3.icns)
|
||||
target_sources(rpcs3 PRIVATE rpcs3.icns update_helper.sh)
|
||||
set_source_files_properties(update_helper.sh PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
set_target_properties(rpcs3
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.plist.in")
|
||||
@@ -70,10 +71,12 @@ target_sources(rpcs3
|
||||
Input/dualsense_pad_handler.cpp
|
||||
Input/evdev_joystick_handler.cpp
|
||||
Input/evdev_gun_handler.cpp
|
||||
Input/gui_pad_thread.cpp
|
||||
Input/hid_pad_handler.cpp
|
||||
Input/keyboard_pad_handler.cpp
|
||||
Input/mm_joystick_handler.cpp
|
||||
Input/pad_thread.cpp
|
||||
Input/raw_mouse_handler.cpp
|
||||
Input/sdl_pad_handler.cpp
|
||||
Input/skateboard_pad_handler.cpp
|
||||
Input/xinput_pad_handler.cpp
|
||||
|
||||
@@ -74,6 +74,7 @@ usz decrypt_binaries_t::decrypt(std::string klic_input)
|
||||
const std::string old_path = _module;
|
||||
|
||||
fs::file elf_file;
|
||||
fs::file internal_file;
|
||||
|
||||
bool invalid = false;
|
||||
usz key_it = 0;
|
||||
@@ -83,6 +84,8 @@ usz decrypt_binaries_t::decrypt(std::string klic_input)
|
||||
{
|
||||
for (; key_it < m_klics.size(); key_it++)
|
||||
{
|
||||
internal_file.close();
|
||||
|
||||
if (!elf_file.open(old_path) || !elf_file.read(file_magic))
|
||||
{
|
||||
file_magic = 0;
|
||||
@@ -106,7 +109,8 @@ usz decrypt_binaries_t::decrypt(std::string klic_input)
|
||||
case "NPD\0"_u32:
|
||||
{
|
||||
// EDAT / SDAT
|
||||
elf_file = DecryptEDAT(elf_file, old_path, key_it != 0 ? 8 : 1, reinterpret_cast<u8*>(&m_klics[key_it]), true);
|
||||
internal_file = std::move(elf_file);
|
||||
elf_file = DecryptEDAT(internal_file, old_path, key_it != 0 ? 8 : 1, reinterpret_cast<u8*>(&m_klics[key_it]));
|
||||
|
||||
if (!elf_file)
|
||||
{
|
||||
@@ -139,7 +143,16 @@ usz decrypt_binaries_t::decrypt(std::string klic_input)
|
||||
|
||||
if (fs::file new_file{new_path, fs::rewrite})
|
||||
{
|
||||
new_file.write(elf_file.to_string());
|
||||
// 16MB buffer
|
||||
std::vector<u8> buffer(std::min<usz>(elf_file.size(), 1u << 24));
|
||||
|
||||
elf_file.seek(0);
|
||||
|
||||
while (usz read_size = elf_file.read(buffer.data(), buffer.size()))
|
||||
{
|
||||
new_file.write(buffer.data(), read_size);
|
||||
}
|
||||
|
||||
dec_log.success("Decrypted %s -> %s", old_path, new_path);
|
||||
std::cout << "Decrypted " << old_path << " -> " << new_path << std::endl; // For CLI
|
||||
m_index++;
|
||||
|
||||
+181
-249
@@ -157,37 +157,30 @@ u128 get_block_key(int block, NPD_HEADER *npd)
|
||||
// for out data, allocate a buffer the size of 'edat->block_size'
|
||||
// Also, set 'in file' to the beginning of the encrypted data, which may be offset if inside another file, but normally just reset to beginning of file
|
||||
// returns number of bytes written, -1 for error
|
||||
s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *npd, u8* crypt_key, u32 block_num, u32 total_blocks, u64 size_left)
|
||||
s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *npd, u8* crypt_key, u32 block_num, u32 total_blocks, u64 size_left, bool is_out_buffer_aligned = false)
|
||||
{
|
||||
// Get metadata info and setup buffers.
|
||||
const int metadata_section_size = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0 || (edat->flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
|
||||
const int metadata_offset = 0x100;
|
||||
|
||||
std::unique_ptr<u8[]> enc_data;
|
||||
std::unique_ptr<u8[]> dec_data;
|
||||
u8 hash[0x10] = { 0 };
|
||||
u8 key_result[0x10] = { 0 };
|
||||
u8 hash_result[0x14] = { 0 };
|
||||
|
||||
u64 offset = 0;
|
||||
u64 metadata_sec_offset = 0;
|
||||
s32 length = 0;
|
||||
u64 length = 0;
|
||||
s32 compression_end = 0;
|
||||
unsigned char empty_iv[0x10] = {};
|
||||
|
||||
const u64 file_offset = in->pos();
|
||||
memset(hash_result, 0, 0x14);
|
||||
|
||||
// Decrypt the metadata.
|
||||
if ((edat->flags & EDAT_COMPRESSED_FLAG) != 0)
|
||||
{
|
||||
metadata_sec_offset = metadata_offset + u64{block_num} * metadata_section_size;
|
||||
|
||||
in->seek(file_offset + metadata_sec_offset);
|
||||
u8 metadata[0x20]{};
|
||||
|
||||
unsigned char metadata[0x20];
|
||||
memset(metadata, 0, 0x20);
|
||||
in->read(metadata, 0x20);
|
||||
in->read_at(metadata_sec_offset, metadata, 0x20);
|
||||
|
||||
// If the data is compressed, decrypt the metadata.
|
||||
// NOTE: For NPD version 1 the metadata is not encrypted.
|
||||
@@ -202,18 +195,17 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
|
||||
std::tie(offset, length, compression_end) = dec_section(metadata);
|
||||
}
|
||||
|
||||
memcpy(hash_result, metadata, 0x10);
|
||||
std::memcpy(hash_result, metadata, 0x10);
|
||||
}
|
||||
else if ((edat->flags & EDAT_FLAG_0x20) != 0)
|
||||
{
|
||||
// If FLAG 0x20, the metadata precedes each data block.
|
||||
metadata_sec_offset = metadata_offset + u64{block_num} * (metadata_section_size + edat->block_size);
|
||||
in->seek(file_offset + metadata_sec_offset);
|
||||
|
||||
unsigned char metadata[0x20];
|
||||
memset(metadata, 0, 0x20);
|
||||
in->read(metadata, 0x20);
|
||||
memcpy(hash_result, metadata, 0x14);
|
||||
u8 metadata[0x20]{};
|
||||
in->read_at(metadata_sec_offset, metadata, 0x20);
|
||||
|
||||
std::memcpy(hash_result, metadata, 0x14);
|
||||
|
||||
// If FLAG 0x20 is set, apply custom xor.
|
||||
for (int j = 0; j < 0x10; j++)
|
||||
@@ -228,9 +220,9 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
|
||||
else
|
||||
{
|
||||
metadata_sec_offset = metadata_offset + u64{block_num} * metadata_section_size;
|
||||
in->seek(file_offset + metadata_sec_offset);
|
||||
|
||||
in->read(hash_result, 0x10);
|
||||
in->read_at(metadata_sec_offset, hash_result, 0x10);
|
||||
|
||||
offset = metadata_offset + u64{block_num} * edat->block_size + total_blocks * metadata_section_size;
|
||||
length = edat->block_size;
|
||||
|
||||
@@ -239,59 +231,82 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
|
||||
}
|
||||
|
||||
// Locate the real data.
|
||||
const int pad_length = length;
|
||||
length = (pad_length + 0xF) & 0xFFFFFFF0;
|
||||
const usz pad_length = length;
|
||||
length = utils::align<usz>(pad_length, 0x10);
|
||||
|
||||
// Setup buffers for decryption and read the data.
|
||||
enc_data.reset(new u8[length]{ 0 });
|
||||
dec_data.reset(new u8[length]{ 0 });
|
||||
memset(hash, 0, 0x10);
|
||||
memset(key_result, 0, 0x10);
|
||||
std::vector<u8> enc_data_buf(is_out_buffer_aligned || length == pad_length ? 0 : length);
|
||||
std::vector<u8> dec_data_buf(length);
|
||||
|
||||
in->seek(file_offset + offset);
|
||||
in->read(enc_data.get(), length);
|
||||
// Try to use out buffer for file reads if no padding is needed instead of a new buffer
|
||||
u8* enc_data = enc_data_buf.empty() ? out : enc_data_buf.data();
|
||||
|
||||
// Variable to avoid copies when possible
|
||||
u8* dec_data = dec_data_buf.data();
|
||||
|
||||
std::memset(hash, 0, 0x10);
|
||||
std::memset(key_result, 0, 0x10);
|
||||
|
||||
in->read_at(offset, enc_data, length);
|
||||
|
||||
// Generate a key for the current block.
|
||||
auto b_key = get_block_key(block_num, npd);
|
||||
|
||||
// Encrypt the block key with the crypto key.
|
||||
aesecb128_encrypt(crypt_key, reinterpret_cast<uchar*>(&b_key), key_result);
|
||||
|
||||
if ((edat->flags & EDAT_FLAG_0x10) != 0)
|
||||
{
|
||||
aesecb128_encrypt(crypt_key, key_result, hash); // If FLAG 0x10 is set, encrypt again to get the final hash.
|
||||
}
|
||||
else
|
||||
memcpy(hash, key_result, 0x10);
|
||||
{
|
||||
std::memcpy(hash, key_result, 0x10);
|
||||
}
|
||||
|
||||
// Setup the crypto and hashing mode based on the extra flags.
|
||||
int crypto_mode = ((edat->flags & EDAT_FLAG_0x02) == 0) ? 0x2 : 0x1;
|
||||
int hash_mode;
|
||||
|
||||
if ((edat->flags & EDAT_FLAG_0x10) == 0)
|
||||
if ((edat->flags & EDAT_FLAG_0x10) == 0)
|
||||
hash_mode = 0x02;
|
||||
else if ((edat->flags & EDAT_FLAG_0x20) == 0)
|
||||
hash_mode = 0x04;
|
||||
else
|
||||
hash_mode = 0x01;
|
||||
|
||||
if ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) != 0)
|
||||
if ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) != 0)
|
||||
{
|
||||
crypto_mode |= 0x10000000;
|
||||
hash_mode |= 0x10000000;
|
||||
}
|
||||
|
||||
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
|
||||
const bool should_decompress = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0) && compression_end;
|
||||
|
||||
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
|
||||
{
|
||||
// Reset the flags.
|
||||
crypto_mode |= 0x01000000;
|
||||
hash_mode |= 0x01000000;
|
||||
|
||||
// Simply copy the data without the header or the footer.
|
||||
memcpy(dec_data.get(), enc_data.get(), length);
|
||||
if (should_decompress)
|
||||
{
|
||||
std::memcpy(dec_data, enc_data, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Optimize when decompression is not needed by avoiding 2 copies
|
||||
dec_data = enc_data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// IV is null if NPD version is 1 or 0.
|
||||
u8* iv = (npd->version <= 1) ? empty_iv : npd->digest;
|
||||
|
||||
// Call main crypto routine on this data block.
|
||||
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), enc_data.get(), dec_data.get(), length, key_result, iv, hash, hash_result))
|
||||
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, length, key_result, iv, hash, hash_result))
|
||||
{
|
||||
edat_log.error("Block at offset 0x%llx has invalid hash!", offset);
|
||||
return -1;
|
||||
@@ -299,9 +314,9 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
|
||||
}
|
||||
|
||||
// Apply additional de-compression if needed and write the decrypted data.
|
||||
if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0) && compression_end)
|
||||
if (should_decompress)
|
||||
{
|
||||
const int res = decompress(out, dec_data.get(), edat->block_size);
|
||||
const int res = decompress(out, dec_data, edat->block_size);
|
||||
|
||||
size_left -= res;
|
||||
|
||||
@@ -313,42 +328,20 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(out, dec_data.get(), pad_length);
|
||||
return pad_length;
|
||||
}
|
||||
}
|
||||
|
||||
// EDAT/SDAT decryption.
|
||||
// reset file to beginning of data before calling
|
||||
int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD_HEADER *npd, unsigned char* crypt_key, bool /*verbose*/)
|
||||
{
|
||||
const int total_blocks = static_cast<int>((edat->file_size + edat->block_size - 1) / edat->block_size);
|
||||
u64 size_left = edat->file_size;
|
||||
std::unique_ptr<u8[]> data(new u8[edat->block_size]);
|
||||
|
||||
for (int i = 0; i < total_blocks; i++)
|
||||
if (dec_data != out)
|
||||
{
|
||||
in->seek(0);
|
||||
memset(data.get(), 0, edat->block_size);
|
||||
u64 res = decrypt_block(in, data.get(), edat, npd, crypt_key, i, total_blocks, size_left);
|
||||
if (res == umax)
|
||||
{
|
||||
edat_log.error("Decrypt Block failed!");
|
||||
return 1;
|
||||
}
|
||||
size_left -= res;
|
||||
out->write(data.get(), res);
|
||||
std::memcpy(out, dec_data, pad_length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return pad_length;
|
||||
}
|
||||
|
||||
// set file offset to beginning before calling
|
||||
int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs::file* f, bool verbose)
|
||||
bool check_data(u8* key, EDAT_HEADER* edat, NPD_HEADER* npd, const fs::file* f, bool verbose)
|
||||
{
|
||||
u8 header[0xA0] = { 0 };
|
||||
u8 empty_header[0xA0] = { 0 };
|
||||
@@ -363,7 +356,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
if (edat->flags & 0x7EFFFFFE)
|
||||
{
|
||||
edat_log.error("Bad header flags!");
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (npd->version == 2)
|
||||
@@ -371,7 +364,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
if (edat->flags & 0x7EFFFFE0)
|
||||
{
|
||||
edat_log.error("Bad header flags!");
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ((npd->version == 3) || (npd->version == 4))
|
||||
@@ -379,13 +372,13 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
if (edat->flags & 0x7EFFFFC0)
|
||||
{
|
||||
edat_log.error("Bad header flags!");
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
edat_log.error("Unknown version!");
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read in the file header.
|
||||
@@ -421,7 +414,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
|
||||
{
|
||||
edat_log.error("RAP/RIF/KLIC key is invalid!");
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +428,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
|
||||
if (!edat->block_size)
|
||||
{
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
const usz block_num = utils::aligned_div<u64>(edat->file_size, edat->block_size);
|
||||
@@ -445,7 +438,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
|
||||
if (utils::add_saturate<u64>(utils::add_saturate<u64>(file_offset, metadata_section_offset), metadata_size) > f->size())
|
||||
{
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 bytes_read = 0;
|
||||
@@ -455,10 +448,10 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
while (bytes_read < metadata_size)
|
||||
{
|
||||
// Locate the metadata blocks.
|
||||
f->seek(file_offset + metadata_section_offset);
|
||||
const usz offset = file_offset + metadata_section_offset;
|
||||
|
||||
// Read in the metadata.
|
||||
f->read(metadata.get() + bytes_read, metadata_section_size);
|
||||
f->read_at(offset, metadata.get() + bytes_read, metadata_section_size);
|
||||
|
||||
// Adjust sizes.
|
||||
bytes_read += metadata_section_size;
|
||||
@@ -492,15 +485,17 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
ecdsa_set_pub(VSH_PUB);
|
||||
|
||||
// Read in the metadata and header signatures.
|
||||
f->seek(file_offset + 0xB0);
|
||||
f->seek(0xB0);
|
||||
f->read(metadata_signature, 0x28);
|
||||
f->read(header_signature, 0x28);
|
||||
|
||||
// Checking metadata signature.
|
||||
// Setup signature r and s.
|
||||
memcpy(signature_r + 01, metadata_signature, 0x14);
|
||||
memcpy(signature_s + 01, metadata_signature + 0x14, 0x14);
|
||||
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
|
||||
signature_r[0] = 0;
|
||||
signature_s[0] = 0;
|
||||
std::memcpy(signature_r + 1, metadata_signature, 0x14);
|
||||
std::memcpy(signature_s + 1, metadata_signature + 0x14, 0x14);
|
||||
if ((!std::memcmp(signature_r, zero_buf, 0x15)) || (!std::memcmp(signature_s, zero_buf, 0x15)))
|
||||
{
|
||||
edat_log.warning("Metadata signature is invalid!");
|
||||
}
|
||||
@@ -510,10 +505,12 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
if ((edat->flags & EDAT_FLAG_0x20) != 0) //Sony failed again, they used buffer from 0x100 with half size of real metadata.
|
||||
{
|
||||
const usz metadata_buf_size = block_num * 0x10;
|
||||
std::unique_ptr<u8[]> metadata_buf(new u8[metadata_buf_size]);
|
||||
f->seek(file_offset + metadata_offset);
|
||||
f->read(metadata_buf.get(), metadata_buf_size);
|
||||
sha1(metadata_buf.get(), metadata_buf_size, signature_hash);
|
||||
|
||||
std::vector<u8> metadata_buf(metadata_buf_size);
|
||||
|
||||
f->read_at(file_offset + metadata_offset, metadata_buf.data(), metadata_buf_size);
|
||||
|
||||
sha1(metadata_buf.data(), metadata_buf_size, signature_hash);
|
||||
}
|
||||
else
|
||||
sha1(metadata.get(), metadata_size, signature_hash);
|
||||
@@ -528,22 +525,23 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
|
||||
// Checking header signature.
|
||||
// Setup header signature r and s.
|
||||
memset(signature_r, 0, 0x15);
|
||||
memset(signature_s, 0, 0x15);
|
||||
memcpy(signature_r + 01, header_signature, 0x14);
|
||||
memcpy(signature_s + 01, header_signature + 0x14, 0x14);
|
||||
signature_r[0] = 0;
|
||||
signature_s[0] = 0;
|
||||
std::memcpy(signature_r + 1, header_signature, 0x14);
|
||||
std::memcpy(signature_s + 1, header_signature + 0x14, 0x14);
|
||||
|
||||
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
|
||||
if ((!std::memcmp(signature_r, zero_buf, 0x15)) || (!std::memcmp(signature_s, zero_buf, 0x15)))
|
||||
{
|
||||
edat_log.warning("Header signature is invalid!");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Setup header signature hash.
|
||||
memset(signature_hash, 0, 20);
|
||||
u8 header_buf[0xD8];
|
||||
f->seek(file_offset);
|
||||
f->read(header_buf, 0xD8);
|
||||
std::memset(signature_hash, 0, 20);
|
||||
|
||||
u8 header_buf[0xD8]{};
|
||||
|
||||
f->read_at(file_offset, header_buf, 0xD8);
|
||||
sha1(header_buf, 0xD8, signature_hash);
|
||||
|
||||
if (!ecdsa_verify(signature_hash, signature_r, signature_s))
|
||||
@@ -551,7 +549,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
|
||||
@@ -585,21 +583,25 @@ bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
|
||||
return cmac_hash_compare(reinterpret_cast<uchar*>(&key), 0x10, dev, 0x60, npd->dev_hash, 0x10);
|
||||
}
|
||||
|
||||
bool validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *npd, EDAT_HEADER* edat, bool verbose)
|
||||
bool validate_npd_hashes(std::string_view file_name, const u8* klicensee, NPD_HEADER* npd, EDAT_HEADER* edat, bool verbose)
|
||||
{
|
||||
if (!file_name)
|
||||
{
|
||||
fmt::throw_exception("Empty filename");
|
||||
}
|
||||
|
||||
// Ignore header validation in DEBUG data.
|
||||
if (edat->flags & EDAT_DEBUG_DATA_FLAG)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const usz file_name_length = std::strlen(file_name);
|
||||
const usz buf_len = 0x30 + file_name_length;
|
||||
if (!validate_dev_klic(klicensee, npd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_name.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const usz buf_len = 0x30 + file_name.size();
|
||||
|
||||
std::unique_ptr<u8[]> buf(new u8[buf_len]);
|
||||
std::unique_ptr<u8[]> buf_lower(new u8[buf_len]);
|
||||
@@ -607,12 +609,12 @@ bool validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER
|
||||
|
||||
// Build the title buffer (content_id + file_name).
|
||||
std::memcpy(buf.get(), npd->content_id, 0x30);
|
||||
std::memcpy(buf.get() + 0x30, file_name, file_name_length);
|
||||
std::memcpy(buf.get() + 0x30, file_name.data(), file_name.size());
|
||||
|
||||
std::memcpy(buf_lower.get(), buf.get(), buf_len);
|
||||
std::memcpy(buf_upper.get(), buf.get(), buf_len);
|
||||
|
||||
for (usz i = std::basic_string_view<u8>(buf.get() + 0x30, file_name_length).find_last_of('.'); i < buf_len; i++)
|
||||
for (usz i = std::basic_string_view<u8>(buf.get() + 0x30, file_name.size()).find_last_of('.'); i < buf_len; i++)
|
||||
{
|
||||
const u8 c = static_cast<u8>(buf[i]);
|
||||
buf_upper[i] = std::toupper(c);
|
||||
@@ -634,17 +636,17 @@ bool validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER
|
||||
edat_log.warning("NPD title hash is invalid!");
|
||||
}
|
||||
|
||||
const bool dev_hash_result = validate_dev_klic(klicensee, npd);
|
||||
|
||||
return title_hash_result && dev_hash_result;
|
||||
return title_hash_result;
|
||||
}
|
||||
|
||||
void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& EDAT)
|
||||
{
|
||||
char npd_header[0x80];
|
||||
char edat_header[0x10];
|
||||
input->read(npd_header, sizeof(npd_header));
|
||||
input->read(edat_header, sizeof(edat_header));
|
||||
char npd_header[0x80]{};
|
||||
char edat_header[0x10]{};
|
||||
|
||||
usz pos = input->pos();
|
||||
pos += input->read_at(pos, npd_header, sizeof(npd_header));
|
||||
input->read_at(pos, edat_header, sizeof(edat_header));
|
||||
|
||||
std::memcpy(&NPD.magic, npd_header, 4);
|
||||
NPD.version = read_from_ptr<be_t<s32>>(npd_header, 4);
|
||||
@@ -662,124 +664,6 @@ void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& E
|
||||
EDAT.file_size = read_from_ptr<be_t<u64>>(edat_header, 8);
|
||||
}
|
||||
|
||||
bool extract_all_data(const fs::file* input, const fs::file* output, const char* input_file_name, unsigned char* devklic, bool verbose)
|
||||
{
|
||||
// Setup NPD and EDAT/SDAT structs.
|
||||
NPD_HEADER NPD;
|
||||
EDAT_HEADER EDAT;
|
||||
|
||||
// Read in the NPD and EDAT/SDAT headers.
|
||||
read_npd_edat_header(input, NPD, EDAT);
|
||||
|
||||
if (NPD.magic != "NPD\0"_u32)
|
||||
{
|
||||
edat_log.error("%s has invalid NPD header or already decrypted.", input_file_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
edat_log.notice("NPD HEADER");
|
||||
edat_log.notice("NPD version: %d", NPD.version);
|
||||
edat_log.notice("NPD license: %d", NPD.license);
|
||||
edat_log.notice("NPD type: %d", NPD.type);
|
||||
edat_log.notice("NPD content_id: %s", NPD.content_id);
|
||||
}
|
||||
|
||||
// Set decryption key.
|
||||
u128 key{};
|
||||
|
||||
// Check EDAT/SDAT flag.
|
||||
if ((EDAT.flags & SDAT_FLAG) == SDAT_FLAG)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
edat_log.notice("SDAT HEADER");
|
||||
edat_log.notice("SDAT flags: 0x%08X", EDAT.flags);
|
||||
edat_log.notice("SDAT block size: 0x%08X", EDAT.block_size);
|
||||
edat_log.notice("SDAT file size: 0x%08X", EDAT.file_size);
|
||||
}
|
||||
|
||||
// Generate SDAT key.
|
||||
key = std::bit_cast<u128>(NPD.dev_hash) ^ std::bit_cast<u128>(SDAT_KEY);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
edat_log.notice("EDAT HEADER");
|
||||
edat_log.notice("EDAT flags: 0x%08X", EDAT.flags);
|
||||
edat_log.notice("EDAT block size: 0x%08X", EDAT.block_size);
|
||||
edat_log.notice("EDAT file size: 0x%08X", EDAT.file_size);
|
||||
}
|
||||
|
||||
// Perform header validation (EDAT only).
|
||||
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, &EDAT, verbose))
|
||||
{
|
||||
edat_log.error("NPD hash validation failed!");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Select EDAT key.
|
||||
if ((NPD.license & 0x3) == 0x3) // Type 3: Use supplied devklic.
|
||||
{
|
||||
std::memcpy(&key, devklic, 0x10);
|
||||
}
|
||||
else // Type 2: Use key from RAP file (RIF key). (also used for type 1 at the moment)
|
||||
{
|
||||
const std::string rap_path = rpcs3::utils::get_rap_file_path(NPD.content_id);
|
||||
|
||||
if (fs::file rap{rap_path}; rap && rap.size() >= sizeof(key))
|
||||
{
|
||||
key = GetEdatRifKeyFromRapFile(rap);
|
||||
}
|
||||
|
||||
// Make sure we don't have an empty RIF key.
|
||||
if (!key)
|
||||
{
|
||||
edat_log.error("A valid RAP file is needed for this EDAT file! (license=%d)", NPD.license);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
edat_log.notice("RIFKEY: %s", std::bit_cast<be_t<u128>>(key));
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
be_t<u128> data;
|
||||
|
||||
std::memcpy(&data, devklic, sizeof(data));
|
||||
edat_log.notice("DEVKLIC: %s", data);
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
edat_log.notice("DECRYPTION KEY: %s", std::bit_cast<be_t<u128>>(key));
|
||||
}
|
||||
|
||||
input->seek(0);
|
||||
if (check_data(reinterpret_cast<uchar*>(&key), &EDAT, &NPD, input, verbose))
|
||||
{
|
||||
edat_log.error("Data parsing failed!");
|
||||
return true;
|
||||
}
|
||||
|
||||
input->seek(0);
|
||||
if (decrypt_data(input, output, &EDAT, &NPD, reinterpret_cast<uchar*>(&key), verbose))
|
||||
{
|
||||
edat_log.error("Data decryption failed!");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
|
||||
{
|
||||
u128 rapkey{};
|
||||
@@ -814,7 +698,7 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
|
||||
}
|
||||
|
||||
// Perform header validation (EDAT only).
|
||||
char real_file_name[CRYPTO_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, &EDAT, false))
|
||||
{
|
||||
@@ -834,7 +718,7 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
|
||||
}
|
||||
|
||||
// Decrypts full file
|
||||
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic, bool verbose)
|
||||
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic)
|
||||
{
|
||||
if (!input)
|
||||
{
|
||||
@@ -890,25 +774,29 @@ fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name,
|
||||
}
|
||||
|
||||
// Delete the bad output file if any errors arise.
|
||||
fs::file output = fs::make_stream<std::vector<u8>>();
|
||||
if (extract_all_data(&input, &output, input_file_name.c_str(), reinterpret_cast<uchar*>(&devklic), verbose))
|
||||
auto data = std::make_unique<EDATADecrypter>(input, devklic, input_file_name, false);
|
||||
|
||||
if (!data->ReadHeader())
|
||||
{
|
||||
output.release();
|
||||
return fs::file{};
|
||||
}
|
||||
|
||||
output.seek(0);
|
||||
fs::file output;
|
||||
output.reset(std::move(data));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
bool EDATADecrypter::ReadHeader()
|
||||
{
|
||||
edata_file.seek(0);
|
||||
|
||||
// Read in the NPD and EDAT/SDAT headers.
|
||||
read_npd_edat_header(&edata_file, npdHeader, edatHeader);
|
||||
|
||||
if (npdHeader.magic != "NPD\0"_u32)
|
||||
{
|
||||
edat_log.error("Not an NPDRM file");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -920,25 +808,56 @@ bool EDATADecrypter::ReadHeader()
|
||||
}
|
||||
else
|
||||
{
|
||||
// verify key
|
||||
if (!validate_dev_klic(reinterpret_cast<uchar*>(&dec_key), &npdHeader))
|
||||
// extract key from RIF
|
||||
char real_file_name[CRYPTO_MAX_PATH]{};
|
||||
extract_file_name(m_file_name.c_str(), real_file_name);
|
||||
|
||||
if (!validate_npd_hashes(real_file_name, reinterpret_cast<const u8*>(&dec_key), &npdHeader, &edatHeader, false))
|
||||
{
|
||||
edat_log.error("Failed validating klic");
|
||||
return false;
|
||||
edat_log.error("NPD hash validation failed!");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use provided dec_key
|
||||
// Select EDAT key.
|
||||
if (m_is_key_final)
|
||||
{
|
||||
// Already provided
|
||||
}
|
||||
// Type 3: Use supplied dec_key.
|
||||
else if ((npdHeader.license & 0x3) == 0x3)
|
||||
{
|
||||
//
|
||||
}
|
||||
// Type 2: Use key from RAP file (RIF key). (also used for type 1 at the moment)
|
||||
else
|
||||
{
|
||||
const std::string rap_path = rpcs3::utils::get_rap_file_path(npdHeader.content_id);
|
||||
|
||||
if (fs::file rap{rap_path}; rap && rap.size() >= sizeof(dec_key))
|
||||
{
|
||||
dec_key = GetEdatRifKeyFromRapFile(rap);
|
||||
}
|
||||
|
||||
// Make sure we don't have an empty RIF key.
|
||||
if (!dec_key)
|
||||
{
|
||||
edat_log.error("A valid RAP file is needed for this EDAT file! (license=%d)", npdHeader.license);
|
||||
return true;
|
||||
}
|
||||
|
||||
edat_log.trace("RIFKEY: %s", std::bit_cast<be_t<u128>>(dec_key));
|
||||
}
|
||||
}
|
||||
|
||||
edata_file.seek(0);
|
||||
|
||||
// k the ecdsa_verify function in this check_data function takes a ridiculous amount of time
|
||||
// like it slows down load time by a factor of x20, at least, so its ignored for now
|
||||
|
||||
/*if (check_data(dec_key._bytes, &edatHeader, &npdHeader, &sdata_file, false))
|
||||
{
|
||||
return false;
|
||||
}*/
|
||||
//if (!check_data(reinterpret_cast<u8*>(&dec_key), &edatHeader, &npdHeader, &edata_file, false))
|
||||
//{
|
||||
// edat_log.error("NPDRM check_data() failed!");
|
||||
// return false;
|
||||
//}
|
||||
|
||||
file_size = edatHeader.file_size;
|
||||
total_blocks = ::narrow<u32>(utils::aligned_div(edatHeader.file_size, edatHeader.block_size));
|
||||
@@ -948,6 +867,7 @@ bool EDATADecrypter::ReadHeader()
|
||||
|
||||
if (file_size && !ReadData(0, data_sample, 1))
|
||||
{
|
||||
edat_log.error("NPDRM ReadData() failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -967,28 +887,40 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
|
||||
const u64 startOffset = pos % edatHeader.block_size;
|
||||
|
||||
const u64 num_blocks = utils::aligned_div(startOffset + size, edatHeader.block_size);
|
||||
data_buf.resize(num_blocks * edatHeader.block_size);
|
||||
|
||||
// Find and decrypt block range covering pos + size
|
||||
const u32 starting_block = ::narrow<u32>(pos / edatHeader.block_size);
|
||||
const u32 ending_block = ::narrow<u32>(std::min<u64>(starting_block + num_blocks, total_blocks));
|
||||
|
||||
u64 writeOffset = 0;
|
||||
|
||||
for (u32 i = starting_block; i < ending_block; ++i)
|
||||
std::vector<u8> data_buf(edatHeader.block_size + 16);
|
||||
|
||||
for (u32 i = starting_block; i < ending_block; i++)
|
||||
{
|
||||
edata_file.seek(0);
|
||||
u64 res = decrypt_block(&edata_file, &data_buf[writeOffset], &edatHeader, &npdHeader, reinterpret_cast<uchar*>(&dec_key), i, total_blocks, edatHeader.file_size);
|
||||
u64 res = decrypt_block(&edata_file, data_buf.data(), &edatHeader, &npdHeader, reinterpret_cast<uchar*>(&dec_key), i, total_blocks, edatHeader.file_size, true);
|
||||
|
||||
if (res == umax)
|
||||
{
|
||||
edat_log.error("Error Decrypting data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
writeOffset += res;
|
||||
const usz skip_start = (i == starting_block ? startOffset : 0);
|
||||
|
||||
if (skip_start >= res)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const usz end_pos = (i != total_blocks - 1 ? edatHeader.block_size : (edatHeader.file_size - 1) % edatHeader.block_size + 1);
|
||||
const usz read_end = std::min<usz>(res, i == ending_block - 1 ? std::min<usz>(end_pos, (startOffset + size - 1) % edatHeader.block_size + 1) : end_pos);
|
||||
|
||||
std::memcpy(data + writeOffset, data_buf.data() + skip_start, read_end - skip_start);
|
||||
std::memset(data_buf.data(), 0, read_end - skip_start);
|
||||
|
||||
writeOffset += read_end - skip_start;
|
||||
}
|
||||
|
||||
const u64 bytesWrote = std::min<u64>(writeOffset - startOffset, size);
|
||||
|
||||
memcpy(data, &data_buf[startOffset], bytesWrote);
|
||||
return bytesWrote;
|
||||
return writeOffset;
|
||||
}
|
||||
|
||||
+25
-7
@@ -18,6 +18,7 @@ struct loaded_npdrm_keys
|
||||
{
|
||||
atomic_t<u128> dec_keys[16]{};
|
||||
atomic_t<u64> dec_keys_pos = 0;
|
||||
u128 one_time_key{}; // For savestates
|
||||
atomic_t<u32> npdrm_fds{0};
|
||||
|
||||
void install_decryption_key(u128 key)
|
||||
@@ -61,7 +62,7 @@ struct EDAT_HEADER
|
||||
};
|
||||
|
||||
// Decrypts full file, or null/empty file
|
||||
extern fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic, bool verbose);
|
||||
extern fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic);
|
||||
|
||||
extern void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& EDAT);
|
||||
extern bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, NPD_HEADER *npd_out = nullptr);
|
||||
@@ -71,7 +72,10 @@ u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);
|
||||
struct EDATADecrypter final : fs::file_base
|
||||
{
|
||||
// file stream
|
||||
fs::file edata_file;
|
||||
fs::file m_edata_file;
|
||||
const fs::file& edata_file;
|
||||
std::string m_file_name;
|
||||
bool m_is_key_final = true;
|
||||
u64 file_size{0};
|
||||
u32 total_blocks{0};
|
||||
u64 pos{0};
|
||||
@@ -79,14 +83,23 @@ struct EDATADecrypter final : fs::file_base
|
||||
NPD_HEADER npdHeader{};
|
||||
EDAT_HEADER edatHeader{};
|
||||
|
||||
// Internal data buffers.
|
||||
std::vector<u8> data_buf{};
|
||||
|
||||
u128 dec_key{};
|
||||
|
||||
public:
|
||||
EDATADecrypter(fs::file&& input, u128 dec_key = {})
|
||||
: edata_file(std::move(input))
|
||||
EDATADecrypter(fs::file&& input, u128 dec_key = {}, std::string file_name = {}, bool is_key_final = true) noexcept
|
||||
: m_edata_file(std::move(input))
|
||||
, edata_file(m_edata_file)
|
||||
, m_file_name(std::move(file_name))
|
||||
, m_is_key_final(is_key_final)
|
||||
, dec_key(dec_key)
|
||||
{
|
||||
}
|
||||
|
||||
EDATADecrypter(const fs::file& input, u128 dec_key = {}, std::string file_name = {}, bool is_key_final = true) noexcept
|
||||
: m_edata_file(fs::file{})
|
||||
, edata_file(input)
|
||||
, m_file_name(std::move(file_name))
|
||||
, m_is_key_final(is_key_final)
|
||||
, dec_key(dec_key)
|
||||
{
|
||||
}
|
||||
@@ -150,4 +163,9 @@ public:
|
||||
id.type.insert(0, "EDATADecrypter: "sv);
|
||||
return id;
|
||||
}
|
||||
|
||||
u128 get_key() const
|
||||
{
|
||||
return dec_key;
|
||||
}
|
||||
};
|
||||
|
||||
+178
-23
@@ -862,10 +862,12 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
|
||||
return true;
|
||||
}
|
||||
|
||||
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic, bool verbose = false);
|
||||
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic);
|
||||
|
||||
void package_reader::extract_worker(thread_key thread_data_key)
|
||||
{
|
||||
std::vector<u8> read_cache;
|
||||
|
||||
while (m_num_failures == 0 && !m_aborted)
|
||||
{
|
||||
// Make sure m_entry_indexer does not exceed m_install_entries
|
||||
@@ -941,42 +943,195 @@ void package_reader::extract_worker(thread_key thread_data_key)
|
||||
pkg_log.warning("NPDRM EDAT!");
|
||||
}
|
||||
|
||||
if (fs::file out = is_buffered ? fs::make_stream<std::vector<u8>>() : fs::file{ path, did_overwrite ? fs::rewrite : fs::write_new })
|
||||
if (fs::file out{ path, did_overwrite ? fs::rewrite : fs::write_new })
|
||||
{
|
||||
bool extract_success = true;
|
||||
for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE)
|
||||
|
||||
struct pkg_file_reader : fs::file_base
|
||||
{
|
||||
const u64 block_size = std::min<u64>(BUF_SIZE, entry.file_size - pos);
|
||||
const std::function<u64(u64, void*, u64)> m_read_func;
|
||||
const install_entry& m_entry;
|
||||
usz m_pos;
|
||||
|
||||
const std::span<const char> data_span = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), thread_data_key);
|
||||
|
||||
if (data_span.size() != block_size)
|
||||
explicit pkg_file_reader(std::function<u64(u64, void* buffer, u64)> read_func, const install_entry& entry) noexcept
|
||||
: m_read_func(std::move(read_func))
|
||||
, m_entry(entry)
|
||||
, m_pos(0)
|
||||
{
|
||||
extract_success = false;
|
||||
pkg_log.error("Failed to extract file %s (data_span.size=%d, block_size=%d)", path, data_span.size(), block_size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (out.write(data_span.data(), block_size) != block_size)
|
||||
fs::stat_t get_stat() override
|
||||
{
|
||||
extract_success = false;
|
||||
pkg_log.error("Failed to write file %s (error=%s)", path, fs::g_tls_error);
|
||||
break;
|
||||
fs::stat_t stat{};
|
||||
stat.size = m_entry.file_size;
|
||||
return stat;
|
||||
}
|
||||
|
||||
m_written_bytes += block_size;
|
||||
}
|
||||
bool trunc(u64) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 read(void* buffer, u64 size) override
|
||||
{
|
||||
const u64 result = pkg_file_reader::read_at(m_pos, buffer, size);
|
||||
m_pos += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
u64 read_at(u64 offset, void* buffer, u64 size) override
|
||||
{
|
||||
return m_read_func(offset, buffer, size);
|
||||
}
|
||||
|
||||
u64 write(const void*, u64) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 seek(s64 offset, fs::seek_mode whence) override
|
||||
{
|
||||
const s64 new_pos =
|
||||
whence == fs::seek_set ? offset :
|
||||
whence == fs::seek_cur ? offset + m_pos :
|
||||
whence == fs::seek_end ? offset + size() : -1;
|
||||
|
||||
if (new_pos < 0)
|
||||
{
|
||||
fs::g_tls_error = fs::error::inval;
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_pos = new_pos;
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
u64 size() override
|
||||
{
|
||||
return m_entry.file_size;
|
||||
}
|
||||
|
||||
fs::file_id get_id() override
|
||||
{
|
||||
fs::file_id id{};
|
||||
|
||||
id.type.insert(0, "pkg_file_reader: "sv);
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
read_cache.clear();
|
||||
|
||||
auto reader = std::make_unique<pkg_file_reader>([&, cache_off = u64{umax}](usz pos, void* ptr, usz size) mutable -> u64
|
||||
{
|
||||
if (pos >= entry.file_size || !size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = std::min<u64>(entry.file_size - pos, size);
|
||||
|
||||
u64 size_cache_end = 0;
|
||||
u64 read_size = 0;
|
||||
|
||||
// Check if exists in cache
|
||||
if (!read_cache.empty() && cache_off <= pos && pos < cache_off + read_cache.size())
|
||||
{
|
||||
read_size = std::min<u64>(pos + size, cache_off + read_cache.size()) - pos;
|
||||
|
||||
std::memcpy(ptr, read_cache.data() + (pos - cache_off), read_size);
|
||||
pos += read_size;
|
||||
}
|
||||
else if (!read_cache.empty() && cache_off < pos + size && cache_off + read_cache.size() >= pos + size)
|
||||
{
|
||||
size_cache_end = size - (std::max<u64>(cache_off, pos) - pos);
|
||||
|
||||
std::memcpy(static_cast<u8*>(ptr) + (cache_off - pos), read_cache.data(), size_cache_end);
|
||||
size -= size_cache_end;
|
||||
}
|
||||
|
||||
if (pos >= entry.file_size || !size)
|
||||
{
|
||||
return read_size + size_cache_end;
|
||||
}
|
||||
|
||||
// Try to cache for later
|
||||
if (size <= BUF_SIZE && !size_cache_end && !read_size)
|
||||
{
|
||||
const u64 block_size = std::min<u64>({BUF_SIZE, std::max<u64>(size * 5 / 3, 65536), entry.file_size - pos});
|
||||
|
||||
read_cache.resize(block_size);
|
||||
cache_off = pos;
|
||||
|
||||
const std::span<const char> data_span = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), thread_data_key);
|
||||
|
||||
if (data_span.empty())
|
||||
{
|
||||
cache_off = umax;
|
||||
read_cache.clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
read_cache.resize(data_span.size());
|
||||
std::memcpy(read_cache.data(), data_span.data(), data_span.size());
|
||||
|
||||
size = std::min<usz>(data_span.size(), size);
|
||||
std::memcpy(ptr, data_span.data(), size);
|
||||
return size;
|
||||
}
|
||||
|
||||
while (read_size < size)
|
||||
{
|
||||
const u64 block_size = std::min<u64>(BUF_SIZE, size - read_size);
|
||||
|
||||
const std::span<const char> data_span = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), thread_data_key);
|
||||
|
||||
if (data_span.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
std::memcpy(static_cast<u8*>(ptr) + read_size, data_span.data(), data_span.size());
|
||||
|
||||
read_size += data_span.size();
|
||||
pos += data_span.size();
|
||||
}
|
||||
|
||||
return read_size + size_cache_end;
|
||||
}, entry);
|
||||
|
||||
fs::file in_data;
|
||||
in_data.reset(std::move(reader));
|
||||
|
||||
fs::file final_data;
|
||||
|
||||
if (is_buffered)
|
||||
{
|
||||
out = DecryptEDAT(out, name, 1, reinterpret_cast<u8*>(&m_header.klicensee), true);
|
||||
if (!out || !fs::write_file(path, fs::rewrite, static_cast<fs::container_stream<std::vector<u8>>*>(out.release().get())->obj))
|
||||
{
|
||||
m_num_failures++;
|
||||
pkg_log.error("Failed to create file %s (error=%s)", path, fs::g_tls_error);
|
||||
break;
|
||||
}
|
||||
final_data = DecryptEDAT(in_data, name, 1, reinterpret_cast<u8*>(&m_header.klicensee));
|
||||
}
|
||||
else
|
||||
{
|
||||
final_data = std::move(in_data);
|
||||
}
|
||||
|
||||
if (!final_data)
|
||||
{
|
||||
m_num_failures++;
|
||||
pkg_log.error("Failed to decrypt EDAT file %s (error=%s)", path, fs::g_tls_error);
|
||||
break;
|
||||
}
|
||||
|
||||
// 16MB buffer
|
||||
std::vector<u8> buffer(std::min<usz>(entry.file_size, 1u << 24));
|
||||
|
||||
while (usz read_size = final_data.read(buffer.data(), buffer.size()))
|
||||
{
|
||||
out.write(buffer.data(), read_size);
|
||||
m_written_bytes += read_size;
|
||||
}
|
||||
|
||||
final_data.close();
|
||||
out.close();
|
||||
|
||||
if (extract_success)
|
||||
{
|
||||
|
||||
@@ -139,7 +139,8 @@ bool zip(const void* src, usz size, fs::file& out, bool multi_thread_it)
|
||||
return false;
|
||||
}
|
||||
|
||||
utils::serial compressor(!multi_thread_it || size < 0x40'0000);
|
||||
utils::serial compressor;
|
||||
compressor.set_expect_little_data(!multi_thread_it || size < 0x40'0000);
|
||||
compressor.m_file_handler = make_compressed_serialization_file_handler(out);
|
||||
|
||||
std::string_view buffer_view{static_cast<const char*>(src), size};
|
||||
|
||||
@@ -33,7 +33,12 @@ u32 AudioBackend::get_sample_size() const
|
||||
|
||||
u32 AudioBackend::get_channels() const
|
||||
{
|
||||
return static_cast<std::underlying_type_t<decltype(m_channels)>>(m_channels);
|
||||
return m_channels;
|
||||
}
|
||||
|
||||
audio_channel_layout AudioBackend::get_channel_layout() const
|
||||
{
|
||||
return m_layout;
|
||||
}
|
||||
|
||||
bool AudioBackend::get_convert_to_s16() const
|
||||
@@ -141,23 +146,63 @@ AudioChannelCnt AudioBackend::get_max_channel_count(u32 device_index)
|
||||
return count;
|
||||
}
|
||||
|
||||
AudioChannelCnt AudioBackend::convert_channel_count(u64 raw)
|
||||
u32 AudioBackend::default_layout_channel_count(audio_channel_layout layout)
|
||||
{
|
||||
switch (raw)
|
||||
switch (layout)
|
||||
{
|
||||
default:
|
||||
case 8:
|
||||
return AudioChannelCnt::SURROUND_7_1;
|
||||
case 7:
|
||||
case 6:
|
||||
return AudioChannelCnt::SURROUND_5_1;
|
||||
case 5:
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
case 1:
|
||||
return AudioChannelCnt::STEREO;
|
||||
case 0:
|
||||
fmt::throw_exception("Unsupported channel count");
|
||||
case audio_channel_layout::mono: return 1;
|
||||
case audio_channel_layout::stereo: return 2;
|
||||
case audio_channel_layout::stereo_lfe: return 3;
|
||||
case audio_channel_layout::quadraphonic: return 4;
|
||||
case audio_channel_layout::quadraphonic_lfe: return 5;
|
||||
case audio_channel_layout::surround_5_1: return 6;
|
||||
case audio_channel_layout::surround_7_1: return 8;
|
||||
default: fmt::throw_exception("Unsupported layout %d", static_cast<u32>(layout));
|
||||
}
|
||||
}
|
||||
|
||||
u32 AudioBackend::layout_channel_count(u32 channels, audio_channel_layout layout)
|
||||
{
|
||||
if (channels == 0)
|
||||
{
|
||||
fmt::throw_exception("Unsupported channel count");
|
||||
}
|
||||
|
||||
return std::min(channels, default_layout_channel_count(layout));
|
||||
}
|
||||
|
||||
audio_channel_layout AudioBackend::default_layout(u32 channels)
|
||||
{
|
||||
switch (channels)
|
||||
{
|
||||
case 1: return audio_channel_layout::mono;
|
||||
case 2: return audio_channel_layout::stereo;
|
||||
case 3: return audio_channel_layout::stereo_lfe;
|
||||
case 4: return audio_channel_layout::quadraphonic;
|
||||
case 5: return audio_channel_layout::quadraphonic_lfe;
|
||||
case 6: return audio_channel_layout::surround_5_1;
|
||||
case 7: return audio_channel_layout::surround_5_1;
|
||||
case 8: return audio_channel_layout::surround_7_1;
|
||||
default: return audio_channel_layout::stereo;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackend::setup_channel_layout(u32 input_channel_count, u32 output_channel_count, audio_channel_layout layout, logs::channel& log)
|
||||
{
|
||||
const u32 channels = std::min(input_channel_count, output_channel_count);
|
||||
|
||||
if (layout != audio_channel_layout::automatic && output_channel_count > input_channel_count)
|
||||
{
|
||||
log.warning("Mixing from %d to %d channels is not implemented. Falling back to automatic layout.", input_channel_count, output_channel_count);
|
||||
layout = audio_channel_layout::automatic;
|
||||
}
|
||||
|
||||
if (layout != audio_channel_layout::automatic && channels < default_layout_channel_count(layout))
|
||||
{
|
||||
log.warning("Can't use layout %s with %d channels. Falling back to automatic layout.", layout, channels);
|
||||
layout = audio_channel_layout::automatic;
|
||||
}
|
||||
|
||||
m_layout = layout == audio_channel_layout::automatic ? default_layout(channels) : layout;
|
||||
m_channels = layout_channel_count(channels, m_layout);
|
||||
}
|
||||
|
||||
+156
-45
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "util/logs.hpp"
|
||||
#include "Utilities/mutex.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Emu/system_config_types.h"
|
||||
#include <numbers>
|
||||
|
||||
enum : u32
|
||||
@@ -30,6 +32,7 @@ enum class AudioSampleSize : u32
|
||||
S16 = sizeof(s16),
|
||||
};
|
||||
|
||||
// This enum is only used for emulation
|
||||
enum class AudioChannelCnt : u32
|
||||
{
|
||||
STEREO = 2,
|
||||
@@ -69,7 +72,7 @@ public:
|
||||
// If dev_id is empty, then default device will be selected.
|
||||
// May override channel count if device has smaller number of channels.
|
||||
// Should return 'true' on success.
|
||||
virtual bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) = 0;
|
||||
virtual bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout) = 0;
|
||||
|
||||
// Reset backend state. Blocks until data callback returns.
|
||||
virtual void Close() = 0;
|
||||
@@ -122,6 +125,7 @@ public:
|
||||
u32 get_sample_size() const;
|
||||
|
||||
u32 get_channels() const;
|
||||
audio_channel_layout get_channel_layout() const;
|
||||
|
||||
bool get_convert_to_s16() const;
|
||||
|
||||
@@ -158,51 +162,91 @@ public:
|
||||
*/
|
||||
static AudioChannelCnt get_max_channel_count(u32 device_index);
|
||||
|
||||
/*
|
||||
* Get default channel count for a layout
|
||||
*/
|
||||
static u32 default_layout_channel_count(audio_channel_layout layout);
|
||||
|
||||
/*
|
||||
* Converts raw channel count to value usable by backends
|
||||
*/
|
||||
static AudioChannelCnt convert_channel_count(u64 raw);
|
||||
static u32 layout_channel_count(u32 channels, audio_channel_layout layout);
|
||||
|
||||
/*
|
||||
* Get the default layout for raw channel count
|
||||
*/
|
||||
static audio_channel_layout default_layout(u32 channels);
|
||||
|
||||
/*
|
||||
* Downmix audio stream.
|
||||
*/
|
||||
template<AudioChannelCnt from, AudioChannelCnt to>
|
||||
template<AudioChannelCnt src_ch_cnt, audio_channel_layout dst_layout>
|
||||
static void downmix(u32 sample_cnt, const f32* src, f32* dst)
|
||||
{
|
||||
static_assert(from == AudioChannelCnt::SURROUND_5_1 || from == AudioChannelCnt::SURROUND_7_1, "Cannot downmix FROM channel count");
|
||||
static_assert(static_cast<u32>(from) > static_cast<u32>(to), "FROM channel count must be bigger than TO");
|
||||
const u32 dst_ch_cnt = default_layout_channel_count(dst_layout);
|
||||
if (static_cast<u32>(src_ch_cnt) <= dst_ch_cnt) fmt::throw_exception("src channel count must be bigger than dst channel count");
|
||||
|
||||
static constexpr f32 center_coef = std::numbers::sqrt2_v<f32> / 2;
|
||||
static constexpr f32 surround_coef = std::numbers::sqrt2_v<f32> / 2;
|
||||
|
||||
for (u32 src_sample = 0, dst_sample = 0; src_sample < sample_cnt; src_sample += static_cast<u32>(from), dst_sample += static_cast<u32>(to))
|
||||
for (u32 src_sample = 0, dst_sample = 0; src_sample < sample_cnt; src_sample += static_cast<u32>(src_ch_cnt), dst_sample += dst_ch_cnt)
|
||||
{
|
||||
const f32 left = src[src_sample + 0];
|
||||
const f32 right = src[src_sample + 1];
|
||||
const f32 center = src[src_sample + 2];
|
||||
const f32 low_freq = src[src_sample + 3];
|
||||
|
||||
if constexpr (from == AudioChannelCnt::SURROUND_5_1)
|
||||
const f32 left = src[src_sample + 0];
|
||||
const f32 right = src[src_sample + 1];
|
||||
|
||||
if constexpr (src_ch_cnt == AudioChannelCnt::STEREO)
|
||||
{
|
||||
static_assert(to == AudioChannelCnt::STEREO, "Invalid TO channel count");
|
||||
|
||||
if constexpr (dst_layout == audio_channel_layout::mono)
|
||||
{
|
||||
dst[dst_sample + 0] = left + right;
|
||||
}
|
||||
}
|
||||
else if constexpr (src_ch_cnt == AudioChannelCnt::SURROUND_5_1)
|
||||
{
|
||||
const f32 center = src[src_sample + 2];
|
||||
const f32 low_freq = src[src_sample + 3];
|
||||
const f32 side_left = src[src_sample + 4];
|
||||
const f32 side_right = src[src_sample + 5];
|
||||
|
||||
const f32 mid = center * center_coef;
|
||||
dst[dst_sample + 0] = left + mid + side_left * surround_coef;
|
||||
dst[dst_sample + 1] = right + mid + side_right * surround_coef;
|
||||
}
|
||||
else if constexpr (from == AudioChannelCnt::SURROUND_7_1)
|
||||
{
|
||||
static_assert(to == AudioChannelCnt::STEREO || to == AudioChannelCnt::SURROUND_5_1, "Invalid TO channel count");
|
||||
if constexpr (dst_layout == audio_channel_layout::quadraphonic || dst_layout == audio_channel_layout::quadraphonic_lfe)
|
||||
{
|
||||
const f32 mid = center * center_coef;
|
||||
dst[dst_sample + 0] = left + mid;
|
||||
dst[dst_sample + 1] = right + mid;
|
||||
dst[dst_sample + 2] = side_left;
|
||||
dst[dst_sample + 3] = side_right;
|
||||
|
||||
if constexpr (dst_layout == audio_channel_layout::quadraphonic_lfe)
|
||||
{
|
||||
dst[dst_sample + 4] = low_freq;
|
||||
}
|
||||
}
|
||||
else if constexpr (dst_layout == audio_channel_layout::stereo || dst_layout == audio_channel_layout::stereo_lfe)
|
||||
{
|
||||
const f32 mid = center * center_coef;
|
||||
dst[dst_sample + 0] = left + mid + side_left * surround_coef;
|
||||
dst[dst_sample + 1] = right + mid + side_right * surround_coef;
|
||||
|
||||
if constexpr (dst_layout == audio_channel_layout::stereo_lfe)
|
||||
{
|
||||
dst[dst_sample + 2] = low_freq;
|
||||
}
|
||||
}
|
||||
else if constexpr (dst_layout == audio_channel_layout::mono)
|
||||
{
|
||||
dst[dst_sample + 0] = left + right + center + side_left + side_right;
|
||||
}
|
||||
}
|
||||
else if constexpr (src_ch_cnt == AudioChannelCnt::SURROUND_7_1)
|
||||
{
|
||||
const f32 center = src[src_sample + 2];
|
||||
const f32 low_freq = src[src_sample + 3];
|
||||
const f32 rear_left = src[src_sample + 4];
|
||||
const f32 rear_right = src[src_sample + 5];
|
||||
const f32 side_left = src[src_sample + 6];
|
||||
const f32 side_right = src[src_sample + 7];
|
||||
|
||||
if constexpr (to == AudioChannelCnt::SURROUND_5_1)
|
||||
if constexpr (dst_layout == audio_channel_layout::surround_5_1)
|
||||
{
|
||||
dst[dst_sample + 0] = left;
|
||||
dst[dst_sample + 1] = right;
|
||||
@@ -211,59 +255,126 @@ public:
|
||||
dst[dst_sample + 4] = side_left + rear_left;
|
||||
dst[dst_sample + 5] = side_right + rear_right;
|
||||
}
|
||||
else
|
||||
else if constexpr (dst_layout == audio_channel_layout::quadraphonic || dst_layout == audio_channel_layout::quadraphonic_lfe)
|
||||
{
|
||||
const f32 mid = center * center_coef;
|
||||
dst[dst_sample + 0] = left + mid;
|
||||
dst[dst_sample + 1] = right + mid;
|
||||
dst[dst_sample + 2] = side_left + rear_left;
|
||||
dst[dst_sample + 3] = side_right + rear_right;
|
||||
|
||||
if constexpr (dst_layout == audio_channel_layout::quadraphonic_lfe)
|
||||
{
|
||||
dst[dst_sample + 4] = low_freq;
|
||||
}
|
||||
}
|
||||
else if constexpr (dst_layout == audio_channel_layout::stereo || dst_layout == audio_channel_layout::stereo_lfe)
|
||||
{
|
||||
const f32 mid = center * center_coef;
|
||||
dst[dst_sample + 0] = left + mid + (side_left + rear_left) * surround_coef;
|
||||
dst[dst_sample + 1] = right + mid + (side_right + rear_right) * surround_coef;
|
||||
|
||||
if constexpr (dst_layout == audio_channel_layout::stereo_lfe)
|
||||
{
|
||||
dst[dst_sample + 2] = low_freq;
|
||||
}
|
||||
}
|
||||
else if constexpr (dst_layout == audio_channel_layout::mono)
|
||||
{
|
||||
dst[dst_sample + 0] = left + right + center + side_left + rear_left + side_right + rear_right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void downmix(u32 sample_cnt, u32 src_ch_cnt, u32 dst_ch_cnt, const f32* src, f32* dst)
|
||||
static void downmix(u32 sample_cnt, u32 src_ch_cnt, audio_channel_layout dst_layout, const f32* src, f32* dst)
|
||||
{
|
||||
const u32 dst_ch_cnt = default_layout_channel_count(dst_layout);
|
||||
|
||||
if (src_ch_cnt <= dst_ch_cnt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (src_ch_cnt == static_cast<u32>(AudioChannelCnt::SURROUND_7_1))
|
||||
switch (src_ch_cnt)
|
||||
{
|
||||
if (dst_ch_cnt == static_cast<u32>(AudioChannelCnt::SURROUND_5_1))
|
||||
case static_cast<u32>(AudioChannelCnt::SURROUND_7_1):
|
||||
{
|
||||
switch (dst_layout)
|
||||
{
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_5_1>(sample_cnt, src, dst);
|
||||
}
|
||||
else if (dst_ch_cnt == static_cast<u32>(AudioChannelCnt::STEREO))
|
||||
{
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::STEREO>(sample_cnt, src, dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Invalid downmix combination: %u -> %u", src_ch_cnt, dst_ch_cnt);
|
||||
case audio_channel_layout::mono:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::mono>(sample_cnt, src, dst);
|
||||
break;
|
||||
case audio_channel_layout::stereo:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::stereo>(sample_cnt, src, dst);
|
||||
break;
|
||||
case audio_channel_layout::stereo_lfe:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::stereo_lfe>(sample_cnt, src, dst);
|
||||
break;
|
||||
case audio_channel_layout::quadraphonic:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::quadraphonic>(sample_cnt, src, dst);
|
||||
break;
|
||||
case audio_channel_layout::quadraphonic_lfe:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::quadraphonic_lfe>(sample_cnt, src, dst);
|
||||
break;
|
||||
case audio_channel_layout::surround_5_1:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_7_1, audio_channel_layout::surround_5_1>(sample_cnt, src, dst);
|
||||
break;
|
||||
default:
|
||||
fmt::throw_exception("Invalid downmix combination: %u -> %s", src_ch_cnt, dst_layout);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (src_ch_cnt == static_cast<u32>(AudioChannelCnt::SURROUND_5_1))
|
||||
case static_cast<u32>(AudioChannelCnt::SURROUND_5_1):
|
||||
{
|
||||
if (dst_ch_cnt == static_cast<u32>(AudioChannelCnt::STEREO))
|
||||
switch (dst_layout)
|
||||
{
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::STEREO>(sample_cnt, src, dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Invalid downmix combination: %u -> %u", src_ch_cnt, dst_ch_cnt);
|
||||
case audio_channel_layout::mono:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::mono>(sample_cnt, src, dst);
|
||||
break;
|
||||
case audio_channel_layout::stereo:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::stereo>(sample_cnt, src, dst);
|
||||
break;
|
||||
case audio_channel_layout::stereo_lfe:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::stereo_lfe>(sample_cnt, src, dst);
|
||||
break;
|
||||
case audio_channel_layout::quadraphonic:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::quadraphonic>(sample_cnt, src, dst);
|
||||
break;
|
||||
case audio_channel_layout::quadraphonic_lfe:
|
||||
AudioBackend::downmix<AudioChannelCnt::SURROUND_5_1, audio_channel_layout::quadraphonic_lfe>(sample_cnt, src, dst);
|
||||
break;
|
||||
default:
|
||||
fmt::throw_exception("Invalid downmix combination: %u -> %s", src_ch_cnt, dst_layout);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
case static_cast<u32>(AudioChannelCnt::STEREO):
|
||||
{
|
||||
fmt::throw_exception("Invalid downmix combination: %u -> %u", src_ch_cnt, dst_ch_cnt);
|
||||
switch (dst_layout)
|
||||
{
|
||||
case audio_channel_layout::mono:
|
||||
AudioBackend::downmix<AudioChannelCnt::STEREO, audio_channel_layout::mono>(sample_cnt, src, dst);
|
||||
break;
|
||||
default:
|
||||
fmt::throw_exception("Invalid downmix combination: %u -> %s", src_ch_cnt, dst_layout);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fmt::throw_exception("Invalid downmix combination: %u -> %s", src_ch_cnt, dst_layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void setup_channel_layout(u32 input_channel_count, u32 output_channel_count, audio_channel_layout layout, logs::channel& log);
|
||||
|
||||
AudioSampleSize m_sample_size = AudioSampleSize::FLOAT;
|
||||
AudioFreq m_sampling_rate = AudioFreq::FREQ_48K;
|
||||
AudioChannelCnt m_channels = AudioChannelCnt::STEREO;
|
||||
u32 m_channels = 2;
|
||||
audio_channel_layout m_layout = audio_channel_layout::automatic;
|
||||
|
||||
std::timed_mutex m_cb_mutex{};
|
||||
std::function<u32(u32, void *)> m_write_callback{};
|
||||
|
||||
@@ -96,7 +96,7 @@ bool CubebBackend::DefaultDeviceChanged()
|
||||
return !device.handle || device.id != m_default_device;
|
||||
}
|
||||
|
||||
bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
|
||||
bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout)
|
||||
{
|
||||
if (!Initialized())
|
||||
{
|
||||
@@ -118,7 +118,7 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
|
||||
{
|
||||
if (use_default_device)
|
||||
{
|
||||
device = GetDefaultDeviceAlt(freq, sample_size, ch_cnt);
|
||||
device = GetDefaultDeviceAlt(freq, sample_size, static_cast<u32>(ch_cnt));
|
||||
|
||||
if (!device.handle)
|
||||
{
|
||||
@@ -138,6 +138,8 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
|
||||
device.ch_cnt = 2;
|
||||
}
|
||||
|
||||
Cubeb.notice("Channel count is %d", device.ch_cnt);
|
||||
|
||||
if (use_default_device)
|
||||
{
|
||||
std::lock_guard lock{m_state_cb_mutex};
|
||||
@@ -146,7 +148,9 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
|
||||
|
||||
m_sampling_rate = freq;
|
||||
m_sample_size = sample_size;
|
||||
m_channels = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(device.ch_cnt)), static_cast<u32>(ch_cnt)));
|
||||
|
||||
setup_channel_layout(static_cast<u32>(ch_cnt), device.ch_cnt, layout, Cubeb);
|
||||
|
||||
full_sample_size = get_channels() * get_sample_size();
|
||||
|
||||
cubeb_stream_params stream_param{};
|
||||
@@ -155,14 +159,19 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize
|
||||
stream_param.channels = get_channels();
|
||||
stream_param.layout = [&]()
|
||||
{
|
||||
switch (m_channels)
|
||||
switch (m_layout)
|
||||
{
|
||||
case AudioChannelCnt::STEREO: return CUBEB_LAYOUT_STEREO;
|
||||
case AudioChannelCnt::SURROUND_5_1: return CUBEB_LAYOUT_3F2_LFE;
|
||||
case AudioChannelCnt::SURROUND_7_1: return CUBEB_LAYOUT_3F4_LFE;
|
||||
default:
|
||||
fmt::throw_exception("Invalid audio channel count");
|
||||
case audio_channel_layout::automatic: break;
|
||||
case audio_channel_layout::mono: return CUBEB_LAYOUT_MONO;
|
||||
case audio_channel_layout::stereo: return CUBEB_LAYOUT_STEREO;
|
||||
case audio_channel_layout::stereo_lfe: return CUBEB_LAYOUT_STEREO_LFE;
|
||||
case audio_channel_layout::quadraphonic: return CUBEB_LAYOUT_QUAD;
|
||||
case audio_channel_layout::quadraphonic_lfe: return CUBEB_LAYOUT_QUAD_LFE;
|
||||
case audio_channel_layout::surround_5_1: return CUBEB_LAYOUT_3F2_LFE;
|
||||
case audio_channel_layout::surround_7_1: return CUBEB_LAYOUT_3F4_LFE;
|
||||
}
|
||||
|
||||
fmt::throw_exception("Invalid audio layout %d", static_cast<u32>(m_layout));
|
||||
}();
|
||||
stream_param.prefs = m_dev_collection_cb_enabled && device.handle ? CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING : CUBEB_STREAM_PREF_NONE;
|
||||
|
||||
@@ -346,7 +355,7 @@ CubebBackend::device_handle CubebBackend::GetDevice(std::string_view dev_id)
|
||||
return result;
|
||||
};
|
||||
|
||||
CubebBackend::device_handle CubebBackend::GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
|
||||
CubebBackend::device_handle CubebBackend::GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, u32 ch_cnt)
|
||||
{
|
||||
Cubeb.notice("Starting alternative search for default device with freq=%d, sample_size=%d and ch_cnt=%d", static_cast<u32>(freq), static_cast<u32>(sample_size), static_cast<u32>(ch_cnt));
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
bool Operational() override;
|
||||
bool DefaultDeviceChanged() override;
|
||||
|
||||
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
|
||||
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout) override;
|
||||
void Close() override;
|
||||
|
||||
f64 GetCallbackFrameLen() override;
|
||||
@@ -62,5 +62,5 @@ private:
|
||||
};
|
||||
|
||||
device_handle GetDevice(std::string_view dev_id = "");
|
||||
device_handle GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt);
|
||||
device_handle GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, u32 ch_cnt);
|
||||
};
|
||||
|
||||
@@ -122,7 +122,7 @@ bool FAudioBackend::Operational()
|
||||
return m_source_voice != nullptr && !m_reset_req.observe();
|
||||
}
|
||||
|
||||
bool FAudioBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
|
||||
bool FAudioBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout)
|
||||
{
|
||||
if (!Initialized())
|
||||
{
|
||||
@@ -161,9 +161,12 @@ bool FAudioBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSiz
|
||||
return false;
|
||||
}
|
||||
|
||||
FAudio_.notice("Channel count is %d", vd.InputChannels);
|
||||
|
||||
m_sampling_rate = freq;
|
||||
m_sample_size = sample_size;
|
||||
m_channels = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(vd.InputChannels)), static_cast<u32>(ch_cnt)));;
|
||||
|
||||
setup_channel_layout(static_cast<u32>(ch_cnt), vd.InputChannels, layout, FAudio_);
|
||||
|
||||
FAudioWaveFormatEx waveformatex;
|
||||
waveformatex.wFormatTag = get_convert_to_s16() ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
bool Initialized() override;
|
||||
bool Operational() override;
|
||||
|
||||
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
|
||||
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout) override;
|
||||
void Close() override;
|
||||
|
||||
f64 GetCallbackFrameLen() override;
|
||||
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
|
||||
std::string_view GetName() const override { return "Null"sv; }
|
||||
|
||||
bool Open(std::string_view /* dev_id */, AudioFreq /* freq */, AudioSampleSize /* sample_size */, AudioChannelCnt /* ch_cnt */) override
|
||||
bool Open(std::string_view /* dev_id */, AudioFreq /* freq */, AudioSampleSize /* sample_size */, AudioChannelCnt /* ch_cnt */, audio_channel_layout /*layout*/) override
|
||||
{
|
||||
Close();
|
||||
return true;
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
#include <Windows.h>
|
||||
#include <system_error>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "xaudio2_9redist.lib")
|
||||
#endif
|
||||
|
||||
#ifndef XAUDIO2_USE_DEFAULT_PROCESSOR
|
||||
#define XAUDIO2_USE_DEFAULT_PROCESSOR XAUDIO2_DEFAULT_PROCESSOR
|
||||
#endif
|
||||
@@ -202,7 +198,7 @@ void XAudio2Backend::Pause()
|
||||
}
|
||||
}
|
||||
|
||||
bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
|
||||
bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout)
|
||||
{
|
||||
if (!Initialized())
|
||||
{
|
||||
@@ -258,9 +254,12 @@ bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSi
|
||||
return false;
|
||||
}
|
||||
|
||||
XAudio.notice("Channel count is %d", vd.InputChannels);
|
||||
|
||||
m_sampling_rate = freq;
|
||||
m_sample_size = sample_size;
|
||||
m_channels = static_cast<AudioChannelCnt>(std::min(static_cast<u32>(convert_channel_count(vd.InputChannels)), static_cast<u32>(ch_cnt)));
|
||||
|
||||
setup_channel_layout(static_cast<u32>(ch_cnt), vd.InputChannels, layout, XAudio);
|
||||
|
||||
WAVEFORMATEX waveformatex{};
|
||||
waveformatex.wFormatTag = get_convert_to_s16() ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
|
||||
@@ -8,12 +8,8 @@
|
||||
#include "Utilities/mutex.h"
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <xaudio2redist.h>
|
||||
#else
|
||||
#include <initguid.h>
|
||||
#include <xaudio2.h>
|
||||
#endif
|
||||
#include <wrl/client.h>
|
||||
#include <MMDeviceAPI.h>
|
||||
|
||||
@@ -32,7 +28,7 @@ public:
|
||||
bool Operational() override;
|
||||
bool DefaultDeviceChanged() override;
|
||||
|
||||
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
|
||||
bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt, audio_channel_layout layout) override;
|
||||
void Close() override;
|
||||
|
||||
f64 GetCallbackFrameLen() override;
|
||||
|
||||
+85
-84
@@ -42,6 +42,7 @@ target_include_directories(rpcs3_emu
|
||||
# Utilities
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
../util/atomic.cpp
|
||||
../util/console.cpp
|
||||
../util/media_utils.cpp
|
||||
../util/video_provider.cpp
|
||||
../util/logs.cpp
|
||||
@@ -56,7 +57,8 @@ target_sources(rpcs3_emu PRIVATE
|
||||
../../Utilities/cond.cpp
|
||||
../../Utilities/Config.cpp
|
||||
../../Utilities/File.cpp
|
||||
../../Utilities/JIT.cpp
|
||||
../../Utilities/JITASM.cpp
|
||||
../../Utilities/JITLLVM.cpp
|
||||
../../Utilities/LUrlParser.cpp
|
||||
../../Utilities/mutex.cpp
|
||||
../../Utilities/rXml.cpp
|
||||
@@ -79,29 +81,15 @@ target_link_libraries(rpcs3_emu
|
||||
PUBLIC
|
||||
3rdparty::pugixml)
|
||||
|
||||
if(MSVC)
|
||||
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES
|
||||
COMPILE_FLAGS /GR-
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
else()
|
||||
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES
|
||||
COMPILE_FLAGS -fno-rtti
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
endif()
|
||||
set_source_files_properties("../../Utilities/JITLLVM.cpp" "../../Utilities/JITASM.cpp" PROPERTIES
|
||||
COMPILE_FLAGS "$<IF:$<CXX_COMPILER_ID:MSVC>,/GR-,-fno-rtti>"
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
set_source_files_properties("../util/yaml.cpp" PROPERTIES
|
||||
COMPILE_FLAGS /EHsc
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
else()
|
||||
set_source_files_properties("../util/yaml.cpp" PROPERTIES
|
||||
COMPILE_FLAGS -fexceptions
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
endif()
|
||||
set_source_files_properties("../util/yaml.cpp" PROPERTIES
|
||||
COMPILE_FLAGS "$<IF:$<CXX_COMPILER_ID:MSVC>,/EHsc,-fexceptions>"
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
|
||||
# Crypto
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
@@ -154,18 +142,14 @@ if(USE_FAUDIO)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_include_directories(rpcs3_emu PUBLIC "${PROJECT_SOURCE_DIR}/3rdparty/XAudio2Redist/include")
|
||||
if(MSVC)
|
||||
target_link_libraries(rpcs3_emu PRIVATE "${PROJECT_SOURCE_DIR}/3rdparty/XAudio2Redist/libs/xaudio2_9redist.lib")
|
||||
target_link_options(rpcs3_emu PRIVATE /DELAYLOAD:xaudio2_9redist.dll)
|
||||
else()
|
||||
target_link_libraries(rpcs3_emu PRIVATE xaudio2_8)
|
||||
if(NOT MSVC)
|
||||
target_link_libraries(rpcs3_emu PRIVATE xaudio2_9)
|
||||
endif()
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
Audio/XAudio2/XAudio2Backend.cpp
|
||||
Audio/XAudio2/xaudio2_enumerator.cpp
|
||||
)
|
||||
target_compile_definitions(rpcs3_emu PRIVATE UNICODE _UNICODE _WIN32_WINNT=0x0602)
|
||||
target_compile_definitions(rpcs3_emu PRIVATE UNICODE _UNICODE _WIN32_WINNT=0x0A00)
|
||||
endif()
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
@@ -199,7 +183,8 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Cell/SPUASMJITRecompiler.cpp
|
||||
Cell/SPUDisAsm.cpp
|
||||
Cell/SPUInterpreter.cpp
|
||||
Cell/SPURecompiler.cpp
|
||||
Cell/SPUCommonRecompiler.cpp
|
||||
Cell/SPULLVMRecompiler.cpp
|
||||
Cell/SPUThread.cpp
|
||||
Cell/lv2/lv2.cpp
|
||||
Cell/lv2/sys_bdemu.cpp
|
||||
@@ -359,6 +344,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Cell/Modules/sceNpCommerce2.cpp
|
||||
Cell/Modules/sceNp.cpp
|
||||
Cell/Modules/sceNpMatchingInt.cpp
|
||||
Cell/Modules/sceNpPlus.cpp
|
||||
Cell/Modules/sceNpSns.cpp
|
||||
Cell/Modules/sceNpTrophy.cpp
|
||||
Cell/Modules/sceNpTus.cpp
|
||||
@@ -409,24 +395,28 @@ target_link_libraries(rpcs3_emu
|
||||
|
||||
# Io
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
Io/Buzz.cpp
|
||||
Io/camera_config.cpp
|
||||
Io/recording_config.cpp
|
||||
Io/GameTablet.cpp
|
||||
Io/GHLtar.cpp
|
||||
Io/GunCon3.cpp
|
||||
Io/Infinity.cpp
|
||||
Io/interception.cpp
|
||||
Io/KeyboardHandler.cpp
|
||||
Io/midi_config_types.cpp
|
||||
Io/pad_config.cpp
|
||||
Io/pad_config_types.cpp
|
||||
Io/PadHandler.cpp
|
||||
Io/pad_types.cpp
|
||||
Io/PadHandler.cpp
|
||||
Io/rb3drums_config.cpp
|
||||
Io/RB3MidiDrums.cpp
|
||||
Io/RB3MidiGuitar.cpp
|
||||
Io/RB3MidiKeyboard.cpp
|
||||
Io/recording_config.cpp
|
||||
Io/Skylander.cpp
|
||||
Io/Turntable.cpp
|
||||
Io/usb_device.cpp
|
||||
Io/usb_vfs.cpp
|
||||
Io/Infinity.cpp
|
||||
Io/Skylander.cpp
|
||||
Io/GHLtar.cpp
|
||||
Io/midi_config_types.cpp
|
||||
Io/RB3MidiKeyboard.cpp
|
||||
Io/RB3MidiGuitar.cpp
|
||||
Io/Buzz.cpp
|
||||
Io/Turntable.cpp
|
||||
Io/usio.cpp
|
||||
)
|
||||
|
||||
@@ -459,32 +449,62 @@ target_sources(rpcs3_emu PRIVATE
|
||||
|
||||
# RSX
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
RSX/gcm_enums.cpp
|
||||
RSX/gcm_printing.cpp
|
||||
RSX/GSRender.cpp
|
||||
RSX/RSXFIFO.cpp
|
||||
RSX/rsx_methods.cpp
|
||||
RSX/rsx_vertex_data.cpp
|
||||
RSX/RSXOffload.cpp
|
||||
RSX/RSXTexture.cpp
|
||||
RSX/RSXThread.cpp
|
||||
RSX/RSXZCULL.cpp
|
||||
RSX/rsx_utils.cpp
|
||||
RSX/RSXDisAsm.cpp
|
||||
RSX/Capture/rsx_capture.cpp
|
||||
RSX/Capture/rsx_replay.cpp
|
||||
RSX/Common/BufferUtils.cpp
|
||||
RSX/Common/surface_store.cpp
|
||||
RSX/Common/TextureUtils.cpp
|
||||
RSX/Common/texture_cache.cpp
|
||||
RSX/Core/RSXContext.cpp
|
||||
RSX/gcm_enums.cpp
|
||||
RSX/gcm_printing.cpp
|
||||
RSX/GL/GLCommonDecompiler.cpp
|
||||
RSX/GL/GLCompute.cpp
|
||||
RSX/GL/GLDraw.cpp
|
||||
RSX/GL/GLFragmentProgram.cpp
|
||||
RSX/GL/GLGSRender.cpp
|
||||
RSX/GL/GLHelpers.cpp
|
||||
RSX/GL/GLOverlays.cpp
|
||||
RSX/GL/GLPipelineCompiler.cpp
|
||||
RSX/GL/GLPresent.cpp
|
||||
RSX/GL/GLRenderTargets.cpp
|
||||
RSX/GL/GLShaderInterpreter.cpp
|
||||
RSX/GL/GLTexture.cpp
|
||||
RSX/GL/GLTextureCache.cpp
|
||||
RSX/GL/glutils/blitter.cpp
|
||||
RSX/GL/glutils/buffer_object.cpp
|
||||
RSX/GL/glutils/capabilities.cpp
|
||||
RSX/GL/glutils/common.cpp
|
||||
RSX/GL/glutils/fbo.cpp
|
||||
RSX/GL/glutils/image.cpp
|
||||
RSX/GL/glutils/program.cpp
|
||||
RSX/GL/glutils/ring_buffer.cpp
|
||||
RSX/GL/glutils/sampler.cpp
|
||||
RSX/GL/GLVertexBuffers.cpp
|
||||
RSX/GL/GLVertexProgram.cpp
|
||||
RSX/GL/OpenGL.cpp
|
||||
RSX/GL/upscalers/fsr1/fsr_pass.cpp
|
||||
RSX/GSRender.cpp
|
||||
RSX/Null/NullGSRender.cpp
|
||||
RSX/NV47/FW/reg_context.cpp
|
||||
RSX/NV47/HW/common.cpp
|
||||
RSX/NV47/HW/nv0039.cpp
|
||||
RSX/NV47/HW/nv3089.cpp
|
||||
RSX/NV47/HW/nv308a.cpp
|
||||
RSX/NV47/HW/nv406e.cpp
|
||||
RSX/NV47/HW/nv4097.cpp
|
||||
RSX/Overlays/HomeMenu/overlay_home_menu.cpp
|
||||
RSX/Overlays/HomeMenu/overlay_home_menu_components.cpp
|
||||
RSX/Overlays/HomeMenu/overlay_home_menu_main_menu.cpp
|
||||
RSX/Overlays/HomeMenu/overlay_home_menu_message_box.cpp
|
||||
RSX/Overlays/HomeMenu/overlay_home_menu_page.cpp
|
||||
RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp
|
||||
RSX/Overlays/Network/overlay_recvmessage_dialog.cpp
|
||||
RSX/Overlays/Network/overlay_sendmessage_dialog.cpp
|
||||
RSX/Overlays/overlays.cpp
|
||||
RSX/Overlays/overlay_animated_icon.cpp
|
||||
RSX/Overlays/overlay_animation.cpp
|
||||
RSX/Overlays/overlay_compile_notification.cpp
|
||||
RSX/Overlays/overlay_controls.cpp
|
||||
RSX/Overlays/overlay_cursor.cpp
|
||||
RSX/Overlays/overlay_debug_overlay.cpp
|
||||
@@ -500,47 +520,28 @@ target_sources(rpcs3_emu PRIVATE
|
||||
RSX/Overlays/overlay_perf_metrics.cpp
|
||||
RSX/Overlays/overlay_progress_bar.cpp
|
||||
RSX/Overlays/overlay_save_dialog.cpp
|
||||
RSX/Overlays/overlay_compile_notification.cpp
|
||||
RSX/Overlays/overlay_trophy_notification.cpp
|
||||
RSX/Overlays/overlay_user_list_dialog.cpp
|
||||
RSX/Overlays/overlay_utils.cpp
|
||||
RSX/Overlays/overlays.cpp
|
||||
RSX/Overlays/overlay_trophy_notification.cpp
|
||||
RSX/Overlays/Shaders/shader_loading_dialog.cpp
|
||||
RSX/Overlays/Shaders/shader_loading_dialog_native.cpp
|
||||
RSX/Program/CgBinaryFragmentProgram.cpp
|
||||
RSX/Program/CgBinaryVertexProgram.cpp
|
||||
RSX/Program/FragmentProgramDecompiler.cpp
|
||||
RSX/Program/GLSLCommon.cpp
|
||||
RSX/Program/program_util.cpp
|
||||
RSX/Program/ProgramStateCache.cpp
|
||||
RSX/Program/program_util.cpp
|
||||
RSX/Program/SPIRVCommon.cpp
|
||||
RSX/Program/VertexProgramDecompiler.cpp
|
||||
RSX/Capture/rsx_capture.cpp
|
||||
RSX/Capture/rsx_replay.cpp
|
||||
RSX/GL/glutils/blitter.cpp
|
||||
RSX/GL/glutils/buffer_object.cpp
|
||||
RSX/GL/glutils/capabilities.cpp
|
||||
RSX/GL/glutils/common.cpp
|
||||
RSX/GL/glutils/fbo.cpp
|
||||
RSX/GL/glutils/image.cpp
|
||||
RSX/GL/glutils/program.cpp
|
||||
RSX/GL/glutils/ring_buffer.cpp
|
||||
RSX/GL/glutils/sampler.cpp
|
||||
RSX/GL/GLCommonDecompiler.cpp
|
||||
RSX/GL/GLCompute.cpp
|
||||
RSX/GL/GLDraw.cpp
|
||||
RSX/GL/GLFragmentProgram.cpp
|
||||
RSX/GL/GLGSRender.cpp
|
||||
RSX/GL/GLHelpers.cpp
|
||||
RSX/GL/GLOverlays.cpp
|
||||
RSX/GL/GLPipelineCompiler.cpp
|
||||
RSX/GL/GLPresent.cpp
|
||||
RSX/GL/GLRenderTargets.cpp
|
||||
RSX/GL/GLShaderInterpreter.cpp
|
||||
RSX/GL/GLTexture.cpp
|
||||
RSX/GL/GLVertexBuffers.cpp
|
||||
RSX/GL/GLVertexProgram.cpp
|
||||
RSX/GL/GLTextureCache.cpp
|
||||
RSX/GL/OpenGL.cpp
|
||||
RSX/RSXDisAsm.cpp
|
||||
RSX/RSXFIFO.cpp
|
||||
RSX/RSXOffload.cpp
|
||||
RSX/RSXTexture.cpp
|
||||
RSX/RSXThread.cpp
|
||||
RSX/RSXZCULL.cpp
|
||||
RSX/rsx_methods.cpp
|
||||
RSX/rsx_utils.cpp
|
||||
RSX/rsx_vertex_data.cpp
|
||||
)
|
||||
|
||||
if(TARGET 3rdparty_vulkan)
|
||||
|
||||
+88
-16
@@ -89,6 +89,9 @@ struct cpu_prof
|
||||
// Total number of samples
|
||||
u64 samples = 0, idle = 0;
|
||||
|
||||
// Total number of sample collected in reservation operation
|
||||
u64 reservation_samples = 0;
|
||||
|
||||
// Avoid printing replicas or when not much changed
|
||||
u64 new_samples = 0;
|
||||
|
||||
@@ -101,6 +104,7 @@ struct cpu_prof
|
||||
samples = 0;
|
||||
idle = 0;
|
||||
new_samples = 0;
|
||||
reservation_samples = 0;
|
||||
}
|
||||
|
||||
static std::string format(const std::multimap<u64, u64, std::greater<u64>>& chart, u64 samples, u64 idle, bool extended_print = false)
|
||||
@@ -140,7 +144,7 @@ struct cpu_prof
|
||||
{
|
||||
if (cpu_flag::exit - ptr->state)
|
||||
{
|
||||
profiler.notice("Thread \"%s\" [0x%08x]: %u samples, %u new (%.4f%% idle): Not enough new samples have been collected since the last print.", ptr->get_name(), ptr->id, samples, new_samples, 100. * idle / samples);
|
||||
profiler.notice("Thread \"%s\" [0x%08x]: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%): Not enough new samples have been collected since the last print.", ptr->get_name(), ptr->id, samples, 100. * idle / samples, new_samples, reservation_samples, 100. * reservation_samples / samples);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -156,7 +160,7 @@ struct cpu_prof
|
||||
|
||||
// Print results
|
||||
const std::string results = format(chart, samples, idle);
|
||||
profiler.notice("Thread \"%s\" [0x%08x]: %u samples, %u new (%.4f%% idle):%s", ptr->get_name(), ptr->id, samples, new_samples, 100. * idle / samples, results);
|
||||
profiler.notice("Thread \"%s\" [0x%08x]: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):\n%s", ptr->get_name(), ptr->id, samples, 100. * idle / samples, new_samples, reservation_samples, 100. * reservation_samples / samples, results);
|
||||
|
||||
new_samples = 0;
|
||||
}
|
||||
@@ -177,6 +181,7 @@ struct cpu_prof
|
||||
std::unordered_map<u64, u64, value_hash<u64>> freq;
|
||||
|
||||
u64 samples = 0, idle = 0;
|
||||
u64 reservation = 0;
|
||||
|
||||
for (auto& [_, info] : threads)
|
||||
{
|
||||
@@ -188,6 +193,7 @@ struct cpu_prof
|
||||
|
||||
samples += info.samples;
|
||||
idle += info.idle;
|
||||
reservation += info.reservation_samples;
|
||||
}
|
||||
|
||||
if (samples == idle)
|
||||
@@ -197,7 +203,7 @@ struct cpu_prof
|
||||
|
||||
if (new_samples < min_print_all_samples && thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
profiler.notice("All Threads: %u samples, %u new (%.4f%% idle): Not enough new samples have been collected since the last print.", samples, new_samples, 100. * idle / samples);
|
||||
profiler.notice("All Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%): Not enough new samples have been collected since the last print.", samples, 100. * idle / samples, new_samples, reservation, 100. * reservation / samples);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -207,7 +213,7 @@ struct cpu_prof
|
||||
}
|
||||
|
||||
const std::string results = format(chart, samples, idle, true);
|
||||
profiler.notice("All Threads: %u samples, %u new (%.4f%% idle):%s", samples, new_samples, 100. * idle / samples, results);
|
||||
profiler.notice("All Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):%s", samples, 100. * idle / samples, new_samples, reservation, 100. * reservation / samples, results);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -281,6 +287,14 @@ struct cpu_prof
|
||||
info.freq[name]++;
|
||||
info.new_samples++;
|
||||
|
||||
if (auto spu = ptr->try_get<spu_thread>())
|
||||
{
|
||||
if (spu->raddr)
|
||||
{
|
||||
info.reservation_samples++;
|
||||
}
|
||||
}
|
||||
|
||||
// Append verification time to fixed common name 0000000...chunk-0x3fffc
|
||||
if (name >> 16 && (name & 0xffff) == 0)
|
||||
info.freq[0xffff]++;
|
||||
@@ -315,6 +329,13 @@ struct cpu_prof
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!g_cfg.core.spu_debug)
|
||||
{
|
||||
// Reduce accuracy in favor of performance when enabled alone
|
||||
thread_ctrl::wait_for(60, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wait, roughly for 20µs
|
||||
thread_ctrl::wait_for(20, false);
|
||||
}
|
||||
@@ -952,7 +973,7 @@ bool cpu_thread::check_state() noexcept
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state0 & cpu_flag::yield && cpu_flag::wait - state0 && cpu_can_stop)
|
||||
if (state0 & cpu_flag::yield && cpu_can_stop)
|
||||
{
|
||||
if (auto spu = try_get<spu_thread>())
|
||||
{
|
||||
@@ -964,6 +985,14 @@ bool cpu_thread::check_state() noexcept
|
||||
}
|
||||
else if (auto ppu = try_get<ppu_thread>())
|
||||
{
|
||||
if (u32 usec = ppu->hw_sleep_time)
|
||||
{
|
||||
thread_ctrl::wait_for_accurate(usec);
|
||||
ppu->hw_sleep_time = 0;
|
||||
ppu->raddr = 0; // Also lose reservation if there is any (reservation is unsaved on hw thread switch)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ppu->raddr && ppu->rtime == vm::reservation_acquire(ppu->raddr))
|
||||
{
|
||||
// Same
|
||||
@@ -1064,17 +1093,31 @@ void cpu_thread::add_remove_flags(bs_t<cpu_flag> to_add, bs_t<cpu_flag> to_remov
|
||||
std::string cpu_thread::get_name() const
|
||||
{
|
||||
// Downcast to correct type
|
||||
if (id_type() == 1)
|
||||
switch (id_type())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
return thread_ctrl::get_name(*static_cast<const named_thread<ppu_thread>*>(this));
|
||||
}
|
||||
|
||||
if (id_type() == 2)
|
||||
case 2:
|
||||
{
|
||||
return thread_ctrl::get_name(*static_cast<const named_thread<spu_thread>*>(this));
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (cpu_thread::get_current() == this && thread_ctrl::get_current())
|
||||
{
|
||||
return thread_ctrl::get_name();
|
||||
}
|
||||
|
||||
fmt::throw_exception("Invalid cpu_thread type");
|
||||
if (id_type() == 0x55)
|
||||
{
|
||||
return fmt::format("rsx::thread");
|
||||
}
|
||||
|
||||
return fmt::format("Invalid cpu_thread type (0x%x)", id_type());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 cpu_thread::get_pc() const
|
||||
@@ -1403,7 +1446,7 @@ u32 CPUDisAsm::DisAsmBranchTarget(s32 /*imm*/)
|
||||
|
||||
extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock)
|
||||
{
|
||||
auto get_spus = [old_counter = u64{umax}, spu_list = std::vector<std::shared_ptr<named_thread<spu_thread>>>()](bool can_collect) mutable
|
||||
auto get_spus = [old_counter = u64{umax}, spu_list = std::vector<std::shared_ptr<named_thread<spu_thread>>>()](bool can_collect, bool force_collect) mutable
|
||||
{
|
||||
const u64 new_counter = cpu_thread::g_threads_created + cpu_thread::g_threads_deleted;
|
||||
|
||||
@@ -1414,14 +1457,34 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
||||
return decltype(&spu_list){};
|
||||
}
|
||||
|
||||
const u64 current = get_system_time();
|
||||
|
||||
// Fetch SPU contexts
|
||||
spu_list.clear();
|
||||
|
||||
idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread&)
|
||||
bool give_up = false;
|
||||
|
||||
idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread& spu)
|
||||
{
|
||||
spu_list.emplace_back(ensure(idm::get_unlocked<named_thread<spu_thread>>(id)));
|
||||
|
||||
if (spu.current_func && spu.unsavable)
|
||||
{
|
||||
const u64 start = spu.start_time;
|
||||
|
||||
// Automatically give up if it is asleep 15 seconds or more
|
||||
if (start && current > start && current - start >= 15'000'000)
|
||||
{
|
||||
give_up = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!force_collect && give_up)
|
||||
{
|
||||
return decltype(&spu_list){};
|
||||
}
|
||||
|
||||
old_counter = new_counter;
|
||||
}
|
||||
|
||||
@@ -1429,7 +1492,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
||||
};
|
||||
|
||||
// Attempt to lock for a second, if somehow takes longer abort it
|
||||
for (u64 start = 0, passed_count = 0; passed_count < 10;)
|
||||
for (u64 start = 0, passed_count = 0; passed_count < 15;)
|
||||
{
|
||||
if (revert_lock)
|
||||
{
|
||||
@@ -1441,7 +1504,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
||||
{
|
||||
start = get_system_time();
|
||||
}
|
||||
else if (get_system_time() - start >= 100'000)
|
||||
else if (get_system_time() - start >= 150'000)
|
||||
{
|
||||
passed_count++;
|
||||
start = 0;
|
||||
@@ -1449,7 +1512,16 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
||||
}
|
||||
|
||||
// Try to fetch SPUs out of critical section
|
||||
const auto spu_list = get_spus(true);
|
||||
const auto spu_list = get_spus(true, false);
|
||||
|
||||
if (!spu_list)
|
||||
{
|
||||
// Give up for now
|
||||
std::this_thread::sleep_for(10ms);
|
||||
passed_count++;
|
||||
start = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Avoid using suspend_all when more than 2 threads known to be unsavable
|
||||
u32 unsavable_threads = 0;
|
||||
@@ -1478,7 +1550,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
||||
|
||||
if (cpu_thread::suspend_all(nullptr, {}, [&]()
|
||||
{
|
||||
if (!get_spus(false))
|
||||
if (!get_spus(false, true))
|
||||
{
|
||||
// Avoid locking IDM here because this is a critical section
|
||||
return true;
|
||||
@@ -1550,7 +1622,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto& spu : *get_spus(true))
|
||||
for (auto& spu : *get_spus(true, true))
|
||||
{
|
||||
if (spu->state.test_and_reset(cpu_flag::dbg_global_pause))
|
||||
{
|
||||
|
||||
@@ -171,7 +171,7 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
|
||||
cpu == "tigerlake" ||
|
||||
cpu == "rocketlake" ||
|
||||
cpu == "sapphirerapids" ||
|
||||
(cpu.startswith("znver") && cpu != "znver1" && cpu != "znver2" && cpu != "znver3"))
|
||||
(cpu.starts_with("znver") && cpu != "znver1" && cpu != "znver2" && cpu != "znver3"))
|
||||
{
|
||||
m_use_avx = true;
|
||||
m_use_fma = true;
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
// Helper function
|
||||
llvm::Value* peek_through_bitcasts(llvm::Value*);
|
||||
|
||||
enum class i2 : char
|
||||
{
|
||||
};
|
||||
@@ -122,7 +125,7 @@ using get_int_vt = typename get_int_bits<Bits>::utype;
|
||||
template <typename T = void>
|
||||
struct llvm_value_t
|
||||
{
|
||||
static_assert(std::is_same<T, void>::value, "llvm_value_t<> error: unknown type");
|
||||
static_assert(std::is_same_v<T, void>, "llvm_value_t<> error: unknown type");
|
||||
|
||||
using type = void;
|
||||
using base = llvm_value_t;
|
||||
@@ -147,7 +150,7 @@ struct llvm_value_t
|
||||
|
||||
std::tuple<> match(llvm::Value*& value, llvm::Module*) const
|
||||
{
|
||||
if (value != this->value)
|
||||
if (peek_through_bitcasts(value) != peek_through_bitcasts(this->value))
|
||||
{
|
||||
value = nullptr;
|
||||
}
|
||||
@@ -414,7 +417,7 @@ struct llvm_value_t<f64> : llvm_value_t<void>
|
||||
template <typename T>
|
||||
struct llvm_value_t<T*> : llvm_value_t<T>
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "llvm_value_t<> error: invalid pointer to void type");
|
||||
static_assert(!std::is_void_v<T>, "llvm_value_t<> error: invalid pointer to void type");
|
||||
|
||||
using type = T*;
|
||||
using base = llvm_value_t<T>;
|
||||
@@ -503,9 +506,6 @@ using llvm_common_t = std::enable_if_t<(is_llvm_expr_of<T, Types>::ok && ...), t
|
||||
template <typename... Args>
|
||||
using llvm_match_tuple = decltype(std::tuple_cat(std::declval<llvm_expr_t<Args>&>().match(std::declval<llvm::Value*&>(), nullptr)...));
|
||||
|
||||
// Helper function
|
||||
llvm::Value* peek_through_bitcasts(llvm::Value*);
|
||||
|
||||
template <typename T, typename U = llvm_common_t<llvm_value_t<T>>>
|
||||
struct llvm_match_t
|
||||
{
|
||||
@@ -532,7 +532,7 @@ struct llvm_match_t
|
||||
|
||||
std::tuple<> match(llvm::Value*& value, llvm::Module*) const
|
||||
{
|
||||
if (value != this->value)
|
||||
if (peek_through_bitcasts(value) != peek_through_bitcasts(this->value))
|
||||
{
|
||||
value = nullptr;
|
||||
}
|
||||
@@ -685,6 +685,18 @@ struct llvm_add
|
||||
return std::tuple_cat(r1, r2);
|
||||
}
|
||||
}
|
||||
|
||||
v1 = i->getOperand(0);
|
||||
v2 = i->getOperand(1);
|
||||
|
||||
// Argument order does not matter here, try when swapped
|
||||
if (auto r1 = a1.match(v2, _m); v2)
|
||||
{
|
||||
if (auto r2 = a2.match(v1, _m); v1)
|
||||
{
|
||||
return std::tuple_cat(r1, r2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value = nullptr;
|
||||
@@ -858,6 +870,18 @@ struct llvm_mul
|
||||
return std::tuple_cat(r1, r2);
|
||||
}
|
||||
}
|
||||
|
||||
v1 = i->getOperand(0);
|
||||
v2 = i->getOperand(1);
|
||||
|
||||
// Argument order does not matter here, try when swapped
|
||||
if (auto r1 = a1.match(v2, _m); v2)
|
||||
{
|
||||
if (auto r2 = a2.match(v1, _m); v1)
|
||||
{
|
||||
return std::tuple_cat(r1, r2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value = nullptr;
|
||||
@@ -2239,6 +2263,18 @@ struct llvm_add_sat
|
||||
return std::tuple_cat(r1, r2);
|
||||
}
|
||||
}
|
||||
|
||||
v1 = i->getOperand(0);
|
||||
v2 = i->getOperand(1);
|
||||
|
||||
// Argument order does not matter here, try when swapped
|
||||
if (auto r1 = a1.match(v2, _m); v2)
|
||||
{
|
||||
if (auto r2 = a2.match(v1, _m); v1)
|
||||
{
|
||||
return std::tuple_cat(r1, r2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value = nullptr;
|
||||
@@ -2868,6 +2904,22 @@ struct llvm_fmuladd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v1 = i->getOperand(0);
|
||||
v2 = i->getOperand(1);
|
||||
v3 = i->getOperand(2);
|
||||
|
||||
// With multiplication args swapped
|
||||
if (auto r1 = a1.match(v2, _m); v2)
|
||||
{
|
||||
if (auto r2 = a2.match(v1, _m); v1)
|
||||
{
|
||||
if (auto r3 = a3.match(v3, _m); v3)
|
||||
{
|
||||
return std::tuple_cat(r1, r2, r3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value = nullptr;
|
||||
@@ -2884,6 +2936,18 @@ struct llvm_calli
|
||||
|
||||
std::tuple<llvm_expr_t<A>...> a;
|
||||
|
||||
std::array<usz, sizeof...(A)> order_equality_hint = []()
|
||||
{
|
||||
std::array<usz, sizeof...(A)> r{};
|
||||
|
||||
for (usz i = 0; i < r.size(); i++)
|
||||
{
|
||||
r[i] = i;
|
||||
}
|
||||
|
||||
return r;
|
||||
}();
|
||||
|
||||
llvm::Value*(*c)(llvm::Value**, llvm::IRBuilder<>*){};
|
||||
|
||||
llvm::Value* eval(llvm::IRBuilder<>* ir) const
|
||||
@@ -2917,6 +2981,13 @@ struct llvm_calli
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... Args> requires (sizeof...(Args) == sizeof...(A))
|
||||
llvm_calli& set_order_equality_hint(Args... args)
|
||||
{
|
||||
order_equality_hint = {static_cast<usz>(args)...};
|
||||
return *this;
|
||||
}
|
||||
|
||||
llvm_match_tuple<A...> match(llvm::Value*& value, llvm::Module* _m) const
|
||||
{
|
||||
return match(value, _m, std::make_index_sequence<sizeof...(A)>());
|
||||
@@ -2939,6 +3010,20 @@ struct llvm_calli
|
||||
{
|
||||
return std::tuple_cat(std::get<I>(r)...);
|
||||
}
|
||||
|
||||
if constexpr (sizeof...(A) >= 2)
|
||||
{
|
||||
if (order_equality_hint[0] == order_equality_hint[1])
|
||||
{
|
||||
// Test if it works with the first pair swapped
|
||||
((v[I <= 1 ? I ^ 1 : I] = i->getOperand(I)), ...);
|
||||
|
||||
if (((std::get<I>(r) = std::get<I>(a).match(v[I], _m), v[I]) && ...))
|
||||
{
|
||||
return std::tuple_cat(std::get<I>(r)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3618,13 +3703,18 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
llvm::Value* load_const(llvm::GlobalVariable* g, llvm::Value* i, llvm::Type* type = nullptr)
|
||||
{
|
||||
return m_ir->CreateLoad(type ? type : g->getValueType(), m_ir->CreateGEP(g->getValueType(), g, {m_ir->getInt64(0), m_ir->CreateZExtOrTrunc(i, get_type<u64>())}));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
llvm::Value* load_const(llvm::GlobalVariable* g, llvm::Value* i)
|
||||
{
|
||||
return m_ir->CreateLoad(get_type<T>(), m_ir->CreateGEP(g->getValueType(), g, {m_ir->getInt64(0), m_ir->CreateZExtOrTrunc(i, get_type<u64>())}));
|
||||
return load_const(g, i, get_type<T>());
|
||||
}
|
||||
|
||||
template <typename T, typename I>
|
||||
template <typename T, typename I> requires requires () { std::declval<I>().eval(std::declval<llvm::IRBuilder<>*>()); }
|
||||
value_t<T> load_const(llvm::GlobalVariable* g, I i)
|
||||
{
|
||||
value_t<T> result;
|
||||
@@ -3632,6 +3722,12 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
llvm::GlobalVariable* make_local_variable(T initializing_value)
|
||||
{
|
||||
return new llvm::GlobalVariable(*m_module, get_type<T>(), false, llvm::GlobalVariable::PrivateLinkage, llvm::ConstantInt::get(get_type<T>(), initializing_value));
|
||||
}
|
||||
|
||||
template <typename R = v128>
|
||||
std::pair<bool, R> get_const_vector(llvm::Value*, u32 pos, u32 = __builtin_LINE());
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ public:
|
||||
#endif
|
||||
AVCodecContext* ctx = nullptr;
|
||||
AVFormatContext* fmt = nullptr;
|
||||
u8* io_buf;
|
||||
u8* io_buf = nullptr;
|
||||
|
||||
struct AudioReader
|
||||
{
|
||||
@@ -371,17 +371,16 @@ public:
|
||||
}
|
||||
if (ctx)
|
||||
{
|
||||
avcodec_close(ctx);
|
||||
avformat_close_input(&fmt);
|
||||
avcodec_free_context(&ctx);
|
||||
}
|
||||
if (io_buf)
|
||||
{
|
||||
av_freep(&io_buf);
|
||||
}
|
||||
if (fmt)
|
||||
{
|
||||
if (io_buf)
|
||||
{
|
||||
av_free(io_buf);
|
||||
}
|
||||
if (fmt->pb) av_free(fmt->pb);
|
||||
avformat_free_context(fmt);
|
||||
if (fmt->pb) av_freep(&fmt->pb);
|
||||
avformat_close_input(&fmt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,7 +450,11 @@ public:
|
||||
}
|
||||
|
||||
AVPacket* packet = av_packet_alloc();
|
||||
std::unique_ptr<AVPacket, decltype([](AVPacket* p){av_packet_unref(p);})> packet_(packet);
|
||||
std::unique_ptr<AVPacket, decltype([](AVPacket* p)
|
||||
{
|
||||
av_packet_unref(p);
|
||||
av_packet_free(&p);
|
||||
})> packet_(packet);
|
||||
|
||||
if (just_started && just_finished)
|
||||
{
|
||||
|
||||
@@ -76,11 +76,14 @@ void cell_audio_config::reset(bool backend_changed)
|
||||
const auto& [req_ch_cnt, downmix] = AudioBackend::get_channel_count_and_downmixer(0); // CELL_AUDIO_OUT_PRIMARY
|
||||
f64 cb_frame_len = 0.0;
|
||||
u32 ch_cnt = 2;
|
||||
audio_channel_layout ch_layout = audio_channel_layout::stereo;
|
||||
|
||||
if (backend->Open(raw.audio_device, freq, sample_size, req_ch_cnt))
|
||||
if (backend->Open(raw.audio_device, freq, sample_size, req_ch_cnt, raw.channel_layout))
|
||||
{
|
||||
cb_frame_len = backend->GetCallbackFrameLen();
|
||||
ch_cnt = backend->get_channels();
|
||||
ch_layout = backend->get_channel_layout();
|
||||
cellAudio.notice("Opened audio backend (sampling_rate=%d, sample_size=%d, channels=%d, layout=%s)", backend->get_sampling_rate(), backend->get_sample_size(), backend->get_channels(), backend->get_channel_layout());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -88,7 +91,8 @@ void cell_audio_config::reset(bool backend_changed)
|
||||
}
|
||||
|
||||
audio_downmix = downmix;
|
||||
backend_ch_cnt = AudioChannelCnt{ch_cnt};
|
||||
backend_ch_cnt = ch_cnt;
|
||||
backend_channel_layout = ch_layout;
|
||||
audio_channels = static_cast<u32>(req_ch_cnt);
|
||||
audio_sampling_rate = static_cast<u32>(freq);
|
||||
audio_block_period = AUDIO_BUFFER_SAMPLES * 1'000'000 / audio_sampling_rate;
|
||||
@@ -162,7 +166,7 @@ audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
|
||||
return cfg.audio_min_buffer_duration;
|
||||
}();
|
||||
|
||||
cb_ringbuf.set_buf_size(static_cast<u32>(static_cast<u32>(cfg.backend_ch_cnt) * cfg.audio_sampling_rate * cfg.audio_sample_size * buffer_dur_mult));
|
||||
cb_ringbuf.set_buf_size(static_cast<u32>(cfg.backend_ch_cnt * cfg.audio_sampling_rate * cfg.audio_sample_size * buffer_dur_mult));
|
||||
backend->SetWriteCallback(std::bind(&audio_ringbuffer::backend_write_callback, this, std::placeholders::_1, std::placeholders::_2));
|
||||
backend->SetStateCallback(std::bind(&audio_ringbuffer::backend_state_callback, this, std::placeholders::_1));
|
||||
}
|
||||
@@ -219,7 +223,7 @@ float* audio_ringbuffer::get_current_buffer() const
|
||||
u64 audio_ringbuffer::get_enqueued_samples() const
|
||||
{
|
||||
AUDIT(cfg.buffering_enabled);
|
||||
const u64 ringbuf_samples = cb_ringbuf.get_used_size() / (cfg.audio_sample_size * static_cast<u32>(cfg.backend_ch_cnt));
|
||||
const u64 ringbuf_samples = cb_ringbuf.get_used_size() / (cfg.audio_sample_size * cfg.backend_ch_cnt);
|
||||
|
||||
if (cfg.time_stretching_enabled)
|
||||
{
|
||||
@@ -280,14 +284,14 @@ void audio_ringbuffer::process_resampled_data()
|
||||
{
|
||||
if (!cfg.time_stretching_enabled) return;
|
||||
|
||||
const auto& [buffer, samples] = resampler.get_samples(static_cast<u32>(cb_ringbuf.get_free_size() / (cfg.audio_sample_size * static_cast<u32>(cfg.backend_ch_cnt))));
|
||||
const auto& [buffer, samples] = resampler.get_samples(static_cast<u32>(cb_ringbuf.get_free_size() / (cfg.audio_sample_size * cfg.backend_ch_cnt)));
|
||||
commit_data(buffer, samples);
|
||||
}
|
||||
|
||||
void audio_ringbuffer::commit_data(f32* buf, u32 sample_cnt)
|
||||
{
|
||||
const u32 sample_cnt_in = sample_cnt * cfg.audio_channels;
|
||||
const u32 sample_cnt_out = sample_cnt * static_cast<u32>(cfg.backend_ch_cnt);
|
||||
const u32 sample_cnt_out = sample_cnt * cfg.backend_ch_cnt;
|
||||
|
||||
// Dump audio if enabled
|
||||
m_dump.WriteData(buf, sample_cnt_in * static_cast<u32>(AudioSampleSize::FLOAT));
|
||||
@@ -300,7 +304,7 @@ void audio_ringbuffer::commit_data(f32* buf, u32 sample_cnt)
|
||||
}
|
||||
|
||||
// Downmix if necessary
|
||||
AudioBackend::downmix(sample_cnt_in, cfg.audio_channels, static_cast<u32>(cfg.backend_ch_cnt), buf, buf);
|
||||
AudioBackend::downmix(sample_cnt_in, cfg.audio_channels, cfg.backend_channel_layout, buf, buf);
|
||||
|
||||
if (cfg.backend->get_convert_to_s16())
|
||||
{
|
||||
@@ -614,6 +618,7 @@ namespace audio
|
||||
.time_stretching_threshold = g_cfg.audio.time_stretching_threshold,
|
||||
.convert_to_s16 = static_cast<bool>(g_cfg.audio.convert_to_s16),
|
||||
.dump_to_file = static_cast<bool>(g_cfg.audio.dump_to_file),
|
||||
.channel_layout = g_cfg.audio.channel_layout,
|
||||
.renderer = g_cfg.audio.renderer,
|
||||
.provider = g_cfg.audio.provider
|
||||
};
|
||||
|
||||
@@ -212,6 +212,7 @@ struct cell_audio_config
|
||||
s64 time_stretching_threshold = 0;
|
||||
bool convert_to_s16 = false;
|
||||
bool dump_to_file = false;
|
||||
audio_channel_layout channel_layout = audio_channel_layout::automatic;
|
||||
audio_renderer renderer = audio_renderer::null;
|
||||
audio_provider provider = audio_provider::none;
|
||||
};
|
||||
@@ -222,7 +223,8 @@ struct cell_audio_config
|
||||
std::shared_ptr<AudioBackend> backend = nullptr;
|
||||
|
||||
AudioChannelCnt audio_downmix = AudioChannelCnt::SURROUND_7_1;
|
||||
AudioChannelCnt backend_ch_cnt = AudioChannelCnt::SURROUND_7_1;
|
||||
audio_channel_layout backend_channel_layout = audio_channel_layout::surround_7_1;
|
||||
u32 backend_ch_cnt = 8;
|
||||
u32 audio_channels = 2;
|
||||
u32 audio_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
u32 audio_block_period = 0;
|
||||
|
||||
@@ -498,7 +498,7 @@ error_code cellCameraEnd()
|
||||
|
||||
error_code cellCameraOpen(s32 dev_num, vm::ptr<CellCameraInfo> info)
|
||||
{
|
||||
cellCamera.todo("cellCameraOpen(dev_num=%d, info=*0x%x)", dev_num, info);
|
||||
cellCamera.notice("cellCameraOpen(dev_num=%d, info=*0x%x)", dev_num, info);
|
||||
|
||||
if (!info)
|
||||
{
|
||||
@@ -639,7 +639,7 @@ error_code cellCameraOpenPost()
|
||||
|
||||
error_code cellCameraClose(s32 dev_num)
|
||||
{
|
||||
cellCamera.todo("cellCameraClose(dev_num=%d)", dev_num);
|
||||
cellCamera.notice("cellCameraClose(dev_num=%d)", dev_num);
|
||||
|
||||
if (error_code error = check_init_and_open(dev_num))
|
||||
{
|
||||
@@ -714,7 +714,7 @@ error_code cellCameraGetDeviceGUID(s32 dev_num, vm::ptr<u32> guid)
|
||||
|
||||
error_code cellCameraGetType(s32 dev_num, vm::ptr<s32> type)
|
||||
{
|
||||
cellCamera.todo("cellCameraGetType(dev_num=%d, type=*0x%x)", dev_num, type);
|
||||
cellCamera.trace("cellCameraGetType(dev_num=%d, type=*0x%x)", dev_num, type);
|
||||
|
||||
auto& g_camera = g_fxo->get<camera_thread>();
|
||||
|
||||
@@ -780,7 +780,7 @@ s32 cellCameraIsAvailable(s32 dev_num)
|
||||
|
||||
s32 cellCameraIsAttached(s32 dev_num)
|
||||
{
|
||||
cellCamera.warning("cellCameraIsAttached(dev_num=%d)", dev_num);
|
||||
cellCamera.trace("cellCameraIsAttached(dev_num=%d)", dev_num);
|
||||
|
||||
if (g_cfg.io.camera == camera_handler::null)
|
||||
{
|
||||
@@ -879,7 +879,7 @@ s32 cellCameraIsStarted(s32 dev_num)
|
||||
error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm::ptr<u32> arg2)
|
||||
{
|
||||
const auto attr_name = get_camera_attr_name(attrib);
|
||||
cellCamera.todo("cellCameraGetAttribute(dev_num=%d, attrib=%d=%s, arg1=*0x%x, arg2=*0x%x)", dev_num, attrib, attr_name, arg1, arg2);
|
||||
cellCamera.notice("cellCameraGetAttribute(dev_num=%d, attrib=%d=%s, arg1=*0x%x, arg2=*0x%x)", dev_num, attrib, attr_name, arg1, arg2);
|
||||
|
||||
auto& g_camera = g_fxo->get<camera_thread>();
|
||||
|
||||
@@ -991,7 +991,7 @@ error_code cellCameraResetAttribute()
|
||||
|
||||
error_code cellCameraGetBufferSize(s32 dev_num, vm::ptr<CellCameraInfoEx> info)
|
||||
{
|
||||
cellCamera.todo("cellCameraGetBufferSize(dev_num=%d, info=*0x%x)", dev_num, info);
|
||||
cellCamera.notice("cellCameraGetBufferSize(dev_num=%d, info=*0x%x)", dev_num, info);
|
||||
|
||||
auto& g_camera = g_fxo->get<camera_thread>();
|
||||
|
||||
@@ -1085,7 +1085,7 @@ error_code check_get_camera_info(s32 dev_num, bool is_valid_info_struct)
|
||||
|
||||
error_code cellCameraGetBufferInfo(s32 dev_num, vm::ptr<CellCameraInfo> info)
|
||||
{
|
||||
cellCamera.todo("cellCameraGetBufferInfo(dev_num=%d, info=0x%x)", dev_num, info);
|
||||
cellCamera.notice("cellCameraGetBufferInfo(dev_num=%d, info=0x%x)", dev_num, info);
|
||||
|
||||
// called by cellCameraGetBufferInfoEx
|
||||
|
||||
@@ -1112,7 +1112,7 @@ error_code cellCameraGetBufferInfo(s32 dev_num, vm::ptr<CellCameraInfo> info)
|
||||
|
||||
error_code cellCameraGetBufferInfoEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info)
|
||||
{
|
||||
cellCamera.todo("cellCameraGetBufferInfoEx(dev_num=%d, info=0x%x)", dev_num, info);
|
||||
cellCamera.notice("cellCameraGetBufferInfoEx(dev_num=%d, info=0x%x)", dev_num, info);
|
||||
|
||||
// calls cellCameraGetBufferInfo
|
||||
|
||||
@@ -1244,7 +1244,7 @@ error_code cellCameraResetPost()
|
||||
|
||||
error_code cellCameraStart(s32 dev_num)
|
||||
{
|
||||
cellCamera.todo("cellCameraStart(dev_num=%d)", dev_num);
|
||||
cellCamera.notice("cellCameraStart(dev_num=%d)", dev_num);
|
||||
|
||||
if (error_code error = check_init_and_open(dev_num))
|
||||
{
|
||||
@@ -1291,7 +1291,7 @@ error_code cellCameraStartPost()
|
||||
|
||||
error_code cellCameraRead(s32 dev_num, vm::ptr<u32> frame_num, vm::ptr<u32> bytes_read)
|
||||
{
|
||||
cellCamera.notice("cellCameraRead(dev_num=%d, frame_num=*0x%x, bytes_read=*0x%x)", dev_num, frame_num, bytes_read);
|
||||
cellCamera.trace("cellCameraRead(dev_num=%d, frame_num=*0x%x, bytes_read=*0x%x)", dev_num, frame_num, bytes_read);
|
||||
|
||||
vm::ptr<CellCameraReadEx> read_ex = vm::make_var<CellCameraReadEx>({});
|
||||
|
||||
@@ -1321,7 +1321,7 @@ error_code cellCameraRead2()
|
||||
|
||||
error_code cellCameraReadEx(s32 dev_num, vm::ptr<CellCameraReadEx> read)
|
||||
{
|
||||
cellCamera.notice("cellCameraReadEx(dev_num=%d, read=0x%x)", dev_num, read);
|
||||
cellCamera.trace("cellCameraReadEx(dev_num=%d, read=0x%x)", dev_num, read);
|
||||
|
||||
auto& g_camera = g_fxo->get<camera_thread>();
|
||||
|
||||
@@ -1421,7 +1421,7 @@ error_code cellCameraReadComplete(s32 dev_num, u32 bufnum, u32 arg2)
|
||||
|
||||
error_code cellCameraStop(s32 dev_num)
|
||||
{
|
||||
cellCamera.todo("cellCameraStop(dev_num=%d)", dev_num);
|
||||
cellCamera.notice("cellCameraStop(dev_num=%d)", dev_num);
|
||||
|
||||
if (error_code error = check_init_and_open(dev_num))
|
||||
{
|
||||
@@ -1466,7 +1466,7 @@ error_code cellCameraStopPost()
|
||||
|
||||
error_code cellCameraSetNotifyEventQueue(u64 key)
|
||||
{
|
||||
cellCamera.todo("cellCameraSetNotifyEventQueue(key=0x%x)", key);
|
||||
cellCamera.notice("cellCameraSetNotifyEventQueue(key=0x%x)", key);
|
||||
|
||||
auto& g_camera = g_fxo->get<camera_thread>();
|
||||
|
||||
@@ -1492,7 +1492,7 @@ error_code cellCameraSetNotifyEventQueue(u64 key)
|
||||
|
||||
error_code cellCameraRemoveNotifyEventQueue(u64 key)
|
||||
{
|
||||
cellCamera.todo("cellCameraRemoveNotifyEventQueue(key=0x%x)", key);
|
||||
cellCamera.notice("cellCameraRemoveNotifyEventQueue(key=0x%x)", key);
|
||||
|
||||
auto& g_camera = g_fxo->get<camera_thread>();
|
||||
|
||||
@@ -1518,7 +1518,7 @@ error_code cellCameraRemoveNotifyEventQueue(u64 key)
|
||||
|
||||
error_code cellCameraSetNotifyEventQueue2(u64 key, u64 source, u64 flag)
|
||||
{
|
||||
cellCamera.todo("cellCameraSetNotifyEventQueue2(key=0x%x, source=%d, flag=%d)", key, source, flag);
|
||||
cellCamera.notice("cellCameraSetNotifyEventQueue2(key=0x%x, source=%d, flag=%d)", key, source, flag);
|
||||
|
||||
auto& g_camera = g_fxo->get<camera_thread>();
|
||||
|
||||
@@ -1544,7 +1544,7 @@ error_code cellCameraSetNotifyEventQueue2(u64 key, u64 source, u64 flag)
|
||||
|
||||
error_code cellCameraRemoveNotifyEventQueue2(u64 key)
|
||||
{
|
||||
cellCamera.todo("cellCameraRemoveNotifyEventQueue2(key=0x%x)", key);
|
||||
cellCamera.notice("cellCameraRemoveNotifyEventQueue2(key=0x%x)", key);
|
||||
|
||||
return cellCameraRemoveNotifyEventQueue(key);
|
||||
}
|
||||
|
||||
+1560
-152
File diff suppressed because it is too large
Load Diff
@@ -94,12 +94,30 @@ enum
|
||||
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_VAGR2_SET = 0x00300224,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_FONT_LIBRARY_TYPE_NONE = 0
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_FONT_MAP_FONT = 0,
|
||||
CELL_FONT_MAP_UNICODE = 1,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_FONT_OPEN_MODE_DEFAULT = 0,
|
||||
CELL_FONT_OPEN_MODE_IGNORE_VERTICAL_METRICS = 1,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_FONT_GRAPHICS_DRAW_TYPE_MONO = 0,
|
||||
CELL_FONT_GRAPHICS_DRAW_TYPE_COLOR = 1,
|
||||
CELL_FONT_GRAPHICS_DRAW_TYPE_COLOR_REVERSE = 2,
|
||||
};
|
||||
|
||||
//Custom enum to determine the origin of a CellFont object
|
||||
enum
|
||||
{
|
||||
@@ -109,6 +127,8 @@ enum
|
||||
CELL_FONT_OPEN_MEMORY,
|
||||
};
|
||||
|
||||
constexpr f32 CELL_FONT_GLYPH_OUTLINE_CONTROL_DISTANCE_DEFAULT = 0.125f;
|
||||
|
||||
|
||||
using CellFontMallocCallback = vm::ptr<void>(vm::ptr<void> arg, u32 size);
|
||||
using CellFontFreeCallback = void(vm::ptr<void> arg, vm::ptr<void> ptr);
|
||||
@@ -148,7 +168,7 @@ struct CellFontLibrary
|
||||
{
|
||||
be_t<u32> libraryType;
|
||||
be_t<u32> libraryVersion;
|
||||
// ...
|
||||
vm::bptr<u32> SystemClosed;
|
||||
};
|
||||
|
||||
struct CellFontType
|
||||
@@ -171,6 +191,24 @@ struct CellFontVerticalLayout
|
||||
be_t<f32> effectWidth;
|
||||
};
|
||||
|
||||
struct CellFontVertexesGlyphSubHeader
|
||||
{
|
||||
be_t<u32> size;
|
||||
be_t<f32> SystemReserved[11];
|
||||
};
|
||||
|
||||
struct CellFontVertexesGlyphData
|
||||
{
|
||||
const be_t<u32> size;
|
||||
vm::bptr<f32> SystemClosed;
|
||||
};
|
||||
|
||||
struct CellFontVertexesGlyph
|
||||
{
|
||||
vm::bptr<CellFontVertexesGlyphData> data;
|
||||
vm::bptr<CellFontVertexesGlyphSubHeader> subHeader;
|
||||
};
|
||||
|
||||
struct CellFontGlyphMetrics
|
||||
{
|
||||
be_t<f32> width;
|
||||
@@ -185,6 +223,64 @@ struct CellFontGlyphMetrics
|
||||
be_t<f32> v_advance;
|
||||
};
|
||||
|
||||
struct CellFontGlyphOutline
|
||||
{
|
||||
be_t<s16> contoursCount;
|
||||
be_t<s16> pointsCount;
|
||||
|
||||
struct Point
|
||||
{
|
||||
be_t<f32> x;
|
||||
be_t<f32> y;
|
||||
};
|
||||
vm::bptr<Point> points;
|
||||
vm::bptr<u8> pointTags;
|
||||
vm::bptr<u16> contourIndexs;
|
||||
|
||||
be_t<u32> flags;
|
||||
|
||||
vm::bptr<void> generateEnv;
|
||||
};
|
||||
|
||||
using CellFontGetOutlineVertexCallback = vm::ptr<void>(vm::ptr<void> arg, s32 contourN, s32 vertexNumber, s32 vertexAttr, f32 x, f32 y);
|
||||
|
||||
struct CellFontGetOutlineVertexesIF
|
||||
{
|
||||
vm::bptr<CellFontGetOutlineVertexCallback> callback;
|
||||
vm::bptr<void> arg;
|
||||
};
|
||||
|
||||
struct CellFontGlyphBoundingBox
|
||||
{
|
||||
be_t<f32> min_x;
|
||||
be_t<f32> min_y;
|
||||
be_t<f32> max_x;
|
||||
be_t<f32> max_y;
|
||||
};
|
||||
|
||||
struct CellFontKerning
|
||||
{
|
||||
be_t<f32> offsetX;
|
||||
be_t<f32> offsetY;
|
||||
};
|
||||
|
||||
struct CellFontGlyphStyle
|
||||
{
|
||||
be_t<f32> scale_widthPixel;
|
||||
be_t<f32> scale_heightPixel;
|
||||
be_t<f32> effect_weight;
|
||||
be_t<f32> effect_slant;
|
||||
};
|
||||
|
||||
struct CellFontGlyph
|
||||
{
|
||||
be_t<u16> CF_type;
|
||||
be_t<u16> type;
|
||||
be_t<u32> size;
|
||||
CellFontGlyphMetrics Metrics;
|
||||
CellFontGlyphOutline Outline;
|
||||
};
|
||||
|
||||
struct CellFontRenderSurface
|
||||
{
|
||||
vm::bptr<void> buffer;
|
||||
@@ -235,11 +331,16 @@ struct CellFontRendererConfig
|
||||
|
||||
struct CellFontRenderer
|
||||
{
|
||||
void *systemReserved[64];
|
||||
vm::bptr<void> systemReserved[64];
|
||||
};
|
||||
|
||||
struct CellFontGraphics
|
||||
{
|
||||
be_t<u32> graphicsType;
|
||||
// ...
|
||||
vm::bptr<uint32_t> SystemClosed;
|
||||
};
|
||||
|
||||
struct CellFontGraphicsDrawContext
|
||||
{
|
||||
vm::bptr<void> SystemReserved[64];
|
||||
};
|
||||
|
||||
@@ -5,30 +5,67 @@
|
||||
|
||||
LOG_CHANNEL(cellFontFT);
|
||||
|
||||
error_code cellFontInitLibraryFreeType()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
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);
|
||||
cellFontFT.todo("cellFontInitLibraryFreeTypeWithRevision(revisionFlags=0x%llx, config=*0x%x, lib=**0x%x)", revisionFlags, config, lib);
|
||||
|
||||
if (!lib)
|
||||
{
|
||||
return CELL_FONT_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*lib = {};
|
||||
|
||||
if (!config)
|
||||
{
|
||||
return CELL_FONT_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (false) // TODO
|
||||
{
|
||||
return CELL_FONT_ERROR_UNINITIALIZED;
|
||||
}
|
||||
|
||||
lib->set(vm::alloc(sizeof(CellFontLibrary), vm::main));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellFontFTGetRevisionFlags()
|
||||
error_code cellFontInitLibraryFreeType(vm::ptr<CellFontLibraryConfigFT> config, vm::pptr<CellFontLibrary> lib)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
return CELL_OK;
|
||||
cellFontFT.todo("cellFontInitLibraryFreeType(config=*0x%x, lib=**0x%x)", config, lib);
|
||||
|
||||
uint64_t revisionFlags = 0LL;
|
||||
//cellFontFTGetStubRevisionFlags(&revisionFlags);
|
||||
return cellFontInitLibraryFreeTypeWithRevision(revisionFlags, config, lib);
|
||||
}
|
||||
|
||||
error_code cellFontFTGetInitializedRevisionFlags()
|
||||
void cellFontFTGetRevisionFlags(vm::ptr<u64> revisionFlags)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellFontFT);
|
||||
cellFontFT.notice("cellFontFTGetRevisionFlags(revisionFlags=*0x%x)", revisionFlags);
|
||||
|
||||
if (revisionFlags)
|
||||
{
|
||||
*revisionFlags = 0x43;
|
||||
}
|
||||
}
|
||||
|
||||
error_code cellFontFTGetInitializedRevisionFlags(vm::ptr<u64> revisionFlags)
|
||||
{
|
||||
cellFontFT.notice("cellFontFTGetInitializedRevisionFlags(revisionFlags=*0x%x)", revisionFlags);
|
||||
|
||||
if (!revisionFlags)
|
||||
{
|
||||
return CELL_FONT_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (false) // TODO
|
||||
{
|
||||
return CELL_FONT_ERROR_UNINITIALIZED;
|
||||
}
|
||||
|
||||
//*revisionFlags = something; // TODO
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ vm::gvar<CellHddGameStatSet> g_stat_set;
|
||||
vm::gvar<CellHddGameSystemFileParam> g_file_param;
|
||||
vm::gvar<CellHddGameCBResult> g_cb_result;
|
||||
|
||||
stx::init_lock acquire_lock(stx::init_mutex& mtx, ppu_thread* ppu = nullptr);
|
||||
stx::access_lock acquire_access_lock(stx::init_mutex& mtx, ppu_thread* ppu = nullptr);
|
||||
stx::reset_lock acquire_reset_lock(stx::init_mutex& mtx, ppu_thread* ppu = nullptr);
|
||||
|
||||
template<>
|
||||
void fmt_class_string<CellGameError>::format(std::string& out, u64 arg)
|
||||
{
|
||||
@@ -206,6 +210,7 @@ void fmt_class_string<disc_change_manager::eject_state>::format(std::string& out
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
STR_CASE(disc_change_manager::eject_state::unknown);
|
||||
STR_CASE(disc_change_manager::eject_state::inserted);
|
||||
STR_CASE(disc_change_manager::eject_state::ejected);
|
||||
STR_CASE(disc_change_manager::eject_state::busy);
|
||||
@@ -215,6 +220,22 @@ void fmt_class_string<disc_change_manager::eject_state>::format(std::string& out
|
||||
});
|
||||
}
|
||||
|
||||
static bool check_system_ver(vm::cptr<char> systemVersion)
|
||||
{
|
||||
// Only allow something like "04.8300".
|
||||
// The disassembly shows that "04.83" would also be considered valid, but the initial strlen check makes this void.
|
||||
return (
|
||||
systemVersion &&
|
||||
std::strlen(systemVersion.get_ptr()) == 7 &&
|
||||
std::isdigit(systemVersion[0]) &&
|
||||
std::isdigit(systemVersion[1]) &&
|
||||
systemVersion[2] == '.' &&
|
||||
std::isdigit(systemVersion[3]) &&
|
||||
std::isdigit(systemVersion[4]) &&
|
||||
std::isdigit(systemVersion[5]) &&
|
||||
std::isdigit(systemVersion[6])
|
||||
);
|
||||
}
|
||||
|
||||
disc_change_manager::disc_change_manager()
|
||||
{
|
||||
@@ -235,8 +256,15 @@ error_code disc_change_manager::register_callbacks(vm::ptr<CellGameDiscEjectCall
|
||||
eject_callback = func_eject;
|
||||
insert_callback = func_insert;
|
||||
|
||||
Emu.GetCallbacks().enable_disc_eject(!!func_eject);
|
||||
Emu.GetCallbacks().enable_disc_insert(false);
|
||||
const bool is_disc_mounted = fs::is_dir(vfs::get("/dev_bdvd/PS3_GAME"));
|
||||
|
||||
if (state == eject_state::unknown)
|
||||
{
|
||||
state = is_disc_mounted ? eject_state::inserted : eject_state::ejected;
|
||||
}
|
||||
|
||||
Emu.GetCallbacks().enable_disc_eject(!!func_eject && is_disc_mounted);
|
||||
Emu.GetCallbacks().enable_disc_insert(!!func_insert && !is_disc_mounted);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -296,7 +324,8 @@ void disc_change_manager::eject_disc()
|
||||
ensure(vfs::unmount("/dev_ps2disc"));
|
||||
dcm.state = eject_state::ejected;
|
||||
|
||||
Emu.GetCallbacks().enable_disc_insert(true);
|
||||
// Re-enable disc insertion only if the callback is still registered
|
||||
Emu.GetCallbacks().enable_disc_insert(!!dcm.insert_callback);
|
||||
|
||||
return CELL_OK;
|
||||
});
|
||||
@@ -377,7 +406,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
||||
{
|
||||
cellGame.warning("cellHddGameCheck(version=%d, dirName=%s, errDialog=%d, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container);
|
||||
|
||||
if (!dirName || !funcStat || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
|
||||
if (version != CELL_GAMEDATA_VERSION_CURRENT || !dirName || !funcStat || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
|
||||
{
|
||||
return CELL_HDDGAME_ERROR_PARAM;
|
||||
}
|
||||
@@ -414,10 +443,10 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
||||
|
||||
const std::string local_dir = vfs::get(dir);
|
||||
|
||||
// 40 GB - 1 kilobyte. The reasoning is that many games take this number and multiply it by 1024, to get the amount of bytes. With 40GB exactly,
|
||||
// this will result in an overflow, and the size would be 0, preventing the game from running. By reducing 1 kilobyte, we make sure that even
|
||||
// 40 GB - 256 kilobytes. The reasoning is that many games take this number and multiply it by 1024, to get the amount of bytes. With 40GB exactly,
|
||||
// this will result in an overflow, and the size would be 0, preventing the game from running. By reducing 256 kilobytes, we make sure that even
|
||||
// after said overflow, the number would still be high enough to contain the game's data.
|
||||
get->hddFreeSizeKB = 40 * 1024 * 1024 - 1;
|
||||
get->hddFreeSizeKB = 40 * 1024 * 1024 - 256;
|
||||
get->isNewData = CELL_HDDGAME_ISNEWDATA_EXIST;
|
||||
get->sysSizeKB = 0; // TODO
|
||||
get->st_atime_ = 0; // TODO
|
||||
@@ -585,6 +614,11 @@ error_code cellHddGameGetSizeKB(ppu_thread& ppu, vm::ptr<u32> size)
|
||||
|
||||
cellGame.warning("cellHddGameGetSizeKB(size=*0x%x)", size);
|
||||
|
||||
if (!size)
|
||||
{
|
||||
return CELL_HDDGAME_ERROR_PARAM;
|
||||
}
|
||||
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
const u64 start_sleep = ppu.start_time;
|
||||
@@ -619,7 +653,7 @@ error_code cellHddGameSetSystemVer(vm::cptr<char> systemVersion)
|
||||
{
|
||||
cellGame.todo("cellHddGameSetSystemVer(systemVersion=%s)", systemVersion);
|
||||
|
||||
if (!systemVersion)
|
||||
if (!check_system_ver(systemVersion))
|
||||
{
|
||||
return CELL_HDDGAME_ERROR_PARAM;
|
||||
}
|
||||
@@ -678,7 +712,7 @@ error_code cellGameDataSetSystemVer(vm::cptr<char> systemVersion)
|
||||
{
|
||||
cellGame.todo("cellGameDataSetSystemVer(systemVersion=%s)", systemVersion);
|
||||
|
||||
if (!systemVersion)
|
||||
if (!check_system_ver(systemVersion))
|
||||
{
|
||||
return CELL_GAMEDATA_ERROR_PARAM;
|
||||
}
|
||||
@@ -705,7 +739,7 @@ error_code cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr
|
||||
|
||||
lv2_sleep(500);
|
||||
|
||||
const auto init = perm.init.init();
|
||||
const auto init = acquire_lock(perm.init);
|
||||
|
||||
if (!init)
|
||||
{
|
||||
@@ -754,7 +788,7 @@ error_code cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr
|
||||
if (size)
|
||||
{
|
||||
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
|
||||
size->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
|
||||
size->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
|
||||
|
||||
// TODO: Calculate data size for HG and DG games, if necessary.
|
||||
size->sizeKB = CELL_GAME_SIZEKB_NOTCALC;
|
||||
@@ -789,7 +823,7 @@ error_code cellGamePatchCheck(vm::ptr<CellGameContentSize> size, vm::ptr<void> r
|
||||
|
||||
auto& perm = g_fxo->get<content_permission>();
|
||||
|
||||
const auto init = perm.init.init();
|
||||
const auto init = acquire_lock(perm.init);
|
||||
|
||||
if (!init)
|
||||
{
|
||||
@@ -799,7 +833,7 @@ error_code cellGamePatchCheck(vm::ptr<CellGameContentSize> size, vm::ptr<void> r
|
||||
if (size)
|
||||
{
|
||||
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
|
||||
size->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
|
||||
size->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
|
||||
|
||||
// TODO: Calculate data size for patch data, if necessary.
|
||||
size->sizeKB = CELL_GAME_SIZEKB_NOTCALC;
|
||||
@@ -836,7 +870,7 @@ error_code cellGameDataCheck(u32 type, vm::cptr<char> dirName, vm::ptr<CellGameC
|
||||
|
||||
auto& perm = g_fxo->get<content_permission>();
|
||||
|
||||
auto init = perm.init.init();
|
||||
auto init = acquire_lock(perm.init);
|
||||
|
||||
if (!init)
|
||||
{
|
||||
@@ -871,7 +905,7 @@ error_code cellGameDataCheck(u32 type, vm::cptr<char> dirName, vm::ptr<CellGameC
|
||||
if (size)
|
||||
{
|
||||
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
|
||||
size->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
|
||||
size->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
|
||||
|
||||
// TODO: Calculate data size for game data, if necessary.
|
||||
size->sizeKB = sfo.empty() ? 0 : CELL_GAME_SIZEKB_NOTCALC;
|
||||
@@ -904,7 +938,7 @@ error_code cellGameContentPermit(ppu_thread& ppu, vm::ptr<char[CELL_GAME_PATH_MA
|
||||
|
||||
auto& perm = g_fxo->get<content_permission>();
|
||||
|
||||
const auto init = perm.init.reset();
|
||||
const auto init = acquire_reset_lock(perm.init);
|
||||
|
||||
if (!init)
|
||||
{
|
||||
@@ -1004,7 +1038,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
|
||||
|
||||
//older sdk. it might not care about game type.
|
||||
|
||||
if (version != CELL_GAMEDATA_VERSION_CURRENT || errDialog > 1 || !funcStat || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
|
||||
if (version != CELL_GAMEDATA_VERSION_CURRENT || !funcStat || !dirName || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
|
||||
{
|
||||
return CELL_GAMEDATA_ERROR_PARAM;
|
||||
}
|
||||
@@ -1038,7 +1072,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
|
||||
cbGet->isNewData = new_data;
|
||||
|
||||
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
|
||||
cbGet->hddFreeSizeKB = 40 * 1024 * 1024 - 1; // Read explanation in cellHddGameCheck
|
||||
cbGet->hddFreeSizeKB = 40 * 1024 * 1024 - 256; // Read explanation in cellHddGameCheck
|
||||
|
||||
strcpy_trunc(cbGet->contentInfoPath, dir);
|
||||
strcpy_trunc(cbGet->gameDataPath, usrdir);
|
||||
@@ -1158,7 +1192,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
|
||||
break;
|
||||
}
|
||||
|
||||
if (errDialog == CELL_GAMEDATA_ERRDIALOG_ALWAYS) // Maybe != CELL_GAMEDATA_ERRDIALOG_NONE
|
||||
if (errDialog == CELL_GAMEDATA_ERRDIALOG_ALWAYS)
|
||||
{
|
||||
// Yield before a blocking dialog is being spawned
|
||||
lv2_obj::sleep(ppu);
|
||||
@@ -1204,7 +1238,7 @@ error_code cellGameCreateGameData(vm::ptr<CellGameSetInitParams> init, vm::ptr<c
|
||||
|
||||
auto& perm = g_fxo->get<content_permission>();
|
||||
|
||||
const auto _init = perm.init.access();
|
||||
const auto _init = acquire_access_lock(perm.init);
|
||||
|
||||
lv2_sleep(2000);
|
||||
|
||||
@@ -1319,7 +1353,7 @@ error_code cellGameDeleteGameData(vm::cptr<char> dirName)
|
||||
if (!_init)
|
||||
{
|
||||
// Or access it
|
||||
if (auto access = perm.init.access(); access)
|
||||
if (auto access = acquire_access_lock(perm.init); access)
|
||||
{
|
||||
// Cannot remove it when it is accessed by cellGameDataCheck
|
||||
// If it is HG data then resort to remove_gd for ERROR_BROKEN
|
||||
@@ -1356,7 +1390,7 @@ error_code cellGameGetParamInt(s32 id, vm::ptr<s32> value)
|
||||
|
||||
auto& perm = g_fxo->get<content_permission>();
|
||||
|
||||
const auto init = perm.init.access();
|
||||
const auto init = acquire_access_lock(perm.init);
|
||||
|
||||
if (!init)
|
||||
{
|
||||
@@ -1484,7 +1518,7 @@ error_code cellGameGetParamString(s32 id, vm::ptr<char> buf, u32 bufsize)
|
||||
|
||||
lv2_sleep(2000);
|
||||
|
||||
const auto init = perm.init.access();
|
||||
const auto init = acquire_access_lock(perm.init);
|
||||
|
||||
if (!init || perm.mode == content_permission::check_mode::not_set)
|
||||
{
|
||||
@@ -1530,7 +1564,7 @@ error_code cellGameSetParamString(s32 id, vm::cptr<char> buf)
|
||||
|
||||
auto& perm = g_fxo->get<content_permission>();
|
||||
|
||||
const auto init = perm.init.access();
|
||||
const auto init = acquire_access_lock(perm.init);
|
||||
|
||||
if (!init || perm.mode == content_permission::check_mode::not_set)
|
||||
{
|
||||
@@ -1569,7 +1603,7 @@ error_code cellGameGetSizeKB(ppu_thread& ppu, vm::ptr<s32> size)
|
||||
|
||||
auto& perm = g_fxo->get<content_permission>();
|
||||
|
||||
const auto init = perm.init.access();
|
||||
const auto init = acquire_access_lock(perm.init);
|
||||
|
||||
if (!init)
|
||||
{
|
||||
|
||||
@@ -338,11 +338,12 @@ struct disc_change_manager
|
||||
|
||||
enum class eject_state
|
||||
{
|
||||
unknown,
|
||||
inserted,
|
||||
ejected,
|
||||
busy
|
||||
};
|
||||
atomic_t<eject_state> state = eject_state::inserted;
|
||||
atomic_t<eject_state> state = eject_state::unknown;
|
||||
|
||||
error_code register_callbacks(vm::ptr<CellGameDiscEjectCallback> func_eject, vm::ptr<CellGameDiscInsertCallback> func_insert);
|
||||
error_code unregister_callbacks();
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
|
||||
LOG_CHANNEL(cellGem);
|
||||
|
||||
static inline constexpr u32 rgba(u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
return ((r & 0xffu) << 24) | ((g & 0xffu) << 16) | ((b & 0xffu) << 8) | (a & 0xffu);
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<gem_btn>::format(std::string& out, u64 arg)
|
||||
{
|
||||
@@ -114,6 +119,20 @@ void fmt_class_string<CellGemVideoConvertFormatEnum>::format(std::string& out, u
|
||||
});
|
||||
}
|
||||
|
||||
// last 4 out of 7 ports (7,6,5,4). index starts at 1
|
||||
static u32 port_num(u32 gem_num)
|
||||
{
|
||||
ensure(gem_num < CELL_GEM_MAX_NUM);
|
||||
return CELL_PAD_MAX_PORT_NUM - gem_num;
|
||||
}
|
||||
|
||||
// last 4 out of 7 ports (6,5,4,3). index starts at 0
|
||||
static u32 pad_num(u32 gem_num)
|
||||
{
|
||||
ensure(gem_num < CELL_GEM_MAX_NUM);
|
||||
return (CELL_PAD_MAX_PORT_NUM - 1) - gem_num;
|
||||
}
|
||||
|
||||
// **********************
|
||||
// * HLE helper structs *
|
||||
// **********************
|
||||
@@ -278,12 +297,44 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_connected = false;
|
||||
|
||||
switch (g_cfg.io.move)
|
||||
{
|
||||
case move_handler::fake:
|
||||
case move_handler::mouse:
|
||||
{
|
||||
connected_controllers = 1;
|
||||
connected_controllers = 0;
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
const auto handler = pad::get_current_handler();
|
||||
for (u32 i = 0; i < std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM); i++)
|
||||
{
|
||||
const auto& pad = ::at32(handler->GetPads(), pad_num(i));
|
||||
if (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
|
||||
{
|
||||
connected_controllers++;
|
||||
|
||||
if (gem_num == i)
|
||||
{
|
||||
is_connected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case move_handler::mouse:
|
||||
case move_handler::raw_mouse:
|
||||
{
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
// Make sure that the mouse handler is initialized
|
||||
handler.Init(std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM));
|
||||
|
||||
const MouseInfo& info = handler.GetInfo();
|
||||
connected_controllers = std::min<u32>({ info.now_connect, attribute.max_connect, CELL_GEM_MAX_NUM });
|
||||
if (gem_num < connected_controllers)
|
||||
{
|
||||
is_connected = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_LIBEVDEV
|
||||
@@ -291,8 +342,13 @@ public:
|
||||
{
|
||||
gun_thread& gun = g_fxo->get<gun_thread>();
|
||||
std::scoped_lock lock(gun.handler.mutex);
|
||||
connected_controllers = gun.handler.init() ? gun.handler.get_num_guns() : 0;
|
||||
gun.num_devices = connected_controllers;
|
||||
gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0;
|
||||
connected_controllers = std::min<u32>(std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM), gun.num_devices);
|
||||
|
||||
if (gem_num < connected_controllers)
|
||||
{
|
||||
is_connected = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -306,10 +362,10 @@ public:
|
||||
controller.sphere_rgb = gem_color::get_default_color(gem_num);
|
||||
|
||||
// Assign status and port number
|
||||
if (gem_num < connected_controllers)
|
||||
if (is_connected)
|
||||
{
|
||||
controller.status = CELL_GEM_STATUS_READY;
|
||||
controller.port = CELL_PAD_MAX_PORT_NUM - gem_num;
|
||||
controller.port = port_num(gem_num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,42 +498,39 @@ void gem_config_data::operator()()
|
||||
{
|
||||
constexpr u32 in_pitch = 640;
|
||||
constexpr u32 out_pitch = 640 * 4;
|
||||
u8* dst = vc_attribute.video_data_out.get_ptr();
|
||||
|
||||
for (u32 y = 0; y < 480 - 1; y += 2)
|
||||
{
|
||||
const u8* src = &video_data_in[y * in_pitch];
|
||||
const u16* src0 = reinterpret_cast<const u16*>(src);
|
||||
const u16* src1 = reinterpret_cast<const u16*>(src + in_pitch);
|
||||
|
||||
u8* dst_row = dst + y * out_pitch;
|
||||
u32* dst0 = reinterpret_cast<u32*>(dst_row);
|
||||
u32* dst1 = reinterpret_cast<u32*>(dst_row + out_pitch);
|
||||
|
||||
for (u32 x = 0; x < 640 - 1; x += 2)
|
||||
{
|
||||
const u32 in_offset = 1 * (y * 640 + x);
|
||||
const u32 out_offset = 4 * (y * 640 + x);
|
||||
const u16 top = *src0++;
|
||||
const u16 bottom = *src1++;
|
||||
|
||||
const u8 b = video_data_in[in_offset + 0];
|
||||
const u8 g0 = video_data_in[in_offset + 1];
|
||||
const u8 g1 = video_data_in[in_offset + in_pitch + 0];
|
||||
const u8 r = video_data_in[in_offset + in_pitch + 1];
|
||||
const u8 b = (top & 0xFF);
|
||||
const u8 g0 = ((top >> 8) & 0xFF);
|
||||
const u8 g1 = (bottom & 0xFF);
|
||||
const u8 r = ((bottom >> 8) & 0xFF);
|
||||
|
||||
// Top-Left
|
||||
vc_attribute.video_data_out[out_offset + 0] = r; // R
|
||||
vc_attribute.video_data_out[out_offset + 1] = g0; // G
|
||||
vc_attribute.video_data_out[out_offset + 2] = b; // B
|
||||
vc_attribute.video_data_out[out_offset + 3] = 255; // A
|
||||
*dst0++ = rgba(r, g0, b, 255);
|
||||
|
||||
// Top-Right Pixel
|
||||
vc_attribute.video_data_out[out_offset + 4] = r; // R
|
||||
vc_attribute.video_data_out[out_offset + 5] = g0; // G
|
||||
vc_attribute.video_data_out[out_offset + 6] = b; // B
|
||||
vc_attribute.video_data_out[out_offset + 7] = 255; // A
|
||||
*dst0++ = rgba(r, g0, b, 255);
|
||||
|
||||
// Bottom-Left Pixel
|
||||
vc_attribute.video_data_out[out_offset + out_pitch + 0] = r; // R
|
||||
vc_attribute.video_data_out[out_offset + out_pitch + 1] = g1; // G
|
||||
vc_attribute.video_data_out[out_offset + out_pitch + 2] = b; // B
|
||||
vc_attribute.video_data_out[out_offset + out_pitch + 3] = 255; // A
|
||||
*dst1++ = rgba(r, g1, b, 255);
|
||||
|
||||
// Bottom-Right Pixel
|
||||
vc_attribute.video_data_out[out_offset + out_pitch + 4] = r; // R
|
||||
vc_attribute.video_data_out[out_offset + out_pitch + 5] = g1; // G
|
||||
vc_attribute.video_data_out[out_offset + out_pitch + 6] = b; // B
|
||||
vc_attribute.video_data_out[out_offset + out_pitch + 7] = 255; // A
|
||||
*dst1++ = rgba(r, g1, b, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -541,8 +594,8 @@ static bool check_gem_num(const u32 gem_num)
|
||||
|
||||
static inline void draw_overlay_cursor(u32 gem_num, const gem_config::gem_controller&, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max)
|
||||
{
|
||||
const u16 x = static_cast<u16>(x_pos / (x_max / static_cast<f32>(rsx::overlays::overlay::virtual_width)));
|
||||
const u16 y = static_cast<u16>(y_pos / (y_max / static_cast<f32>(rsx::overlays::overlay::virtual_height)));
|
||||
const s16 x = static_cast<s16>(x_pos / (x_max / static_cast<f32>(rsx::overlays::overlay::virtual_width)));
|
||||
const s16 y = static_cast<s16>(y_pos / (y_max / static_cast<f32>(rsx::overlays::overlay::virtual_height)));
|
||||
|
||||
// Note: We shouldn't use sphere_rgb here. The game will set it to black in many cases.
|
||||
const gem_config_data::gem_color& rgb = gem_config_data::gem_color::get_default_color(gem_num);
|
||||
@@ -638,12 +691,12 @@ extern bool is_input_allowed();
|
||||
/**
|
||||
* \brief Maps Move controller data (digital buttons, and analog Trigger data) to DS3 pad input.
|
||||
* Unavoidably buttons conflict with DS3 mappings, which is problematic for some games.
|
||||
* \param port_no DS3 port number to use
|
||||
* \param gem_num gem index to use
|
||||
* \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values
|
||||
* \param analog_t Analog value of Move's Trigger. Currently mapped to R2.
|
||||
* \return true on success, false if port_no controller is invalid
|
||||
* \return true on success, false if controller is disconnected
|
||||
*/
|
||||
static void ds3_input_to_pad(const u32 port_no, be_t<u16>& digital_buttons, be_t<u16>& analog_t)
|
||||
static void ds3_input_to_pad(const u32 gem_num, be_t<u16>& digital_buttons, be_t<u16>& analog_t)
|
||||
{
|
||||
digital_buttons = 0;
|
||||
analog_t = 0;
|
||||
@@ -656,14 +709,14 @@ static void ds3_input_to_pad(const u32 port_no, be_t<u16>& digital_buttons, be_t
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
const auto handler = pad::get_current_handler();
|
||||
const auto& pad = ::at32(handler->GetPads(), port_no);
|
||||
const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num));
|
||||
|
||||
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& cfg = ::at32(g_cfg_gem.players, port_no);
|
||||
const auto& cfg = ::at32(g_cfg_gem.players, gem_num);
|
||||
cfg->handle_input(pad, true, [&](gem_btn btn, u16 value, bool pressed)
|
||||
{
|
||||
if (!pressed)
|
||||
@@ -707,12 +760,12 @@ static void ds3_input_to_pad(const u32 port_no, be_t<u16>& digital_buttons, be_t
|
||||
constexpr u16 ds3_max_x = 255;
|
||||
constexpr u16 ds3_max_y = 255;
|
||||
|
||||
static inline void ds3_get_stick_values(u32 port_no, const std::shared_ptr<Pad>& pad, s32& x_pos, s32& y_pos)
|
||||
static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr<Pad>& pad, s32& x_pos, s32& y_pos)
|
||||
{
|
||||
x_pos = 0;
|
||||
y_pos = 0;
|
||||
|
||||
const auto& cfg = ::at32(g_cfg_gem.players, port_no);
|
||||
const auto& cfg = ::at32(g_cfg_gem.players, gem_num);
|
||||
cfg->handle_input(pad, true, [&](gem_btn btn, u16 value, bool pressed)
|
||||
{
|
||||
if (!pressed)
|
||||
@@ -733,7 +786,7 @@ static inline void ds3_get_stick_values(u32 port_no, const std::shared_ptr<Pad>&
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_controller& controller, T& gem_state)
|
||||
static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& controller, T& gem_state)
|
||||
{
|
||||
if (!gem_state || !is_input_allowed())
|
||||
{
|
||||
@@ -743,7 +796,7 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
const auto handler = pad::get_current_handler();
|
||||
const auto& pad = ::at32(handler->GetPads(), port_no);
|
||||
const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num));
|
||||
|
||||
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
|
||||
{
|
||||
@@ -751,15 +804,15 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro
|
||||
}
|
||||
|
||||
s32 ds3_pos_x, ds3_pos_y;
|
||||
ds3_get_stick_values(port_no, pad, ds3_pos_x, ds3_pos_y);
|
||||
ds3_get_stick_values(gem_num, pad, ds3_pos_x, ds3_pos_y);
|
||||
|
||||
if constexpr (std::is_same<T, vm::ptr<CellGemState>>::value)
|
||||
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
|
||||
{
|
||||
pos_to_gem_state(port_no, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
|
||||
pos_to_gem_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
|
||||
}
|
||||
else if constexpr (std::is_same<T, vm::ptr<CellGemImageState>>::value)
|
||||
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
|
||||
{
|
||||
pos_to_gem_image_state(port_no, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
|
||||
pos_to_gem_image_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,11 +820,11 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro
|
||||
* \brief Maps external Move controller data to DS3 input. (This can be input from any physical pad, not just the DS3)
|
||||
* Implementation detail: CellGemExtPortData's digital/analog fields map the same way as
|
||||
* libPad, so no translation is needed.
|
||||
* \param port_no DS3 port number to use
|
||||
* \param gem_num gem index to use
|
||||
* \param ext External data to modify
|
||||
* \return true on success, false if port_no controller is invalid
|
||||
* \return true on success, false if controller is disconnected
|
||||
*/
|
||||
static void ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller& controller, CellGemExtPortData& ext)
|
||||
static void ds3_input_to_ext(const u32 gem_num, const gem_config::gem_controller& controller, CellGemExtPortData& ext)
|
||||
{
|
||||
ext = {};
|
||||
|
||||
@@ -783,7 +836,7 @@ static void ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
|
||||
const auto handler = pad::get_current_handler();
|
||||
const auto& pad = ::at32(handler->GetPads(), port_no);
|
||||
const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num));
|
||||
|
||||
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
|
||||
{
|
||||
@@ -896,11 +949,11 @@ static void mouse_pos_to_gem_state(const u32 mouse_no, const gem_config::gem_con
|
||||
|
||||
const auto& mouse = ::at32(handler.GetMice(), mouse_no);
|
||||
|
||||
if constexpr (std::is_same<T, vm::ptr<CellGemState>>::value)
|
||||
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
|
||||
{
|
||||
pos_to_gem_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max);
|
||||
}
|
||||
else if constexpr (std::is_same<T, vm::ptr<CellGemImageState>>::value)
|
||||
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
|
||||
{
|
||||
pos_to_gem_image_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max);
|
||||
}
|
||||
@@ -964,11 +1017,11 @@ static void gun_pos_to_gem_state(const u32 gem_no, const gem_config::gem_control
|
||||
y_max = gun.handler.get_axis_y_max(gem_no);
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, vm::ptr<CellGemState>>::value)
|
||||
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
|
||||
{
|
||||
pos_to_gem_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max);
|
||||
}
|
||||
else if constexpr (std::is_same<T, vm::ptr<CellGemImageState>>::value)
|
||||
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
|
||||
{
|
||||
pos_to_gem_image_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max);
|
||||
}
|
||||
@@ -1372,6 +1425,7 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> gem_imag
|
||||
ds3_pos_to_gem_state(gem_num, gem.controllers[gem_num], gem_image_state);
|
||||
break;
|
||||
case move_handler::mouse:
|
||||
case move_handler::raw_mouse:
|
||||
mouse_pos_to_gem_state(gem_num, gem.controllers[gem_num], gem_image_state);
|
||||
break;
|
||||
#ifdef HAVE_LIBEVDEV
|
||||
@@ -1426,6 +1480,7 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v
|
||||
ds3_input_to_pad(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T);
|
||||
break;
|
||||
case move_handler::mouse:
|
||||
case move_handler::raw_mouse:
|
||||
mouse_input_to_pad(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T);
|
||||
break;
|
||||
#ifdef HAVE_LIBEVDEV
|
||||
@@ -1443,7 +1498,7 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v
|
||||
|
||||
error_code cellGemGetInfo(vm::ptr<CellGemInfo> info)
|
||||
{
|
||||
cellGem.warning("cellGemGetInfo(info=*0x%x)", info);
|
||||
cellGem.trace("cellGemGetInfo(info=*0x%x)", info);
|
||||
|
||||
auto& gem = g_fxo->get<gem_config>();
|
||||
|
||||
@@ -1460,6 +1515,33 @@ error_code cellGemGetInfo(vm::ptr<CellGemInfo> info)
|
||||
}
|
||||
|
||||
// TODO: Support connecting PlayStation Move controllers
|
||||
|
||||
if (g_cfg.io.move == move_handler::fake)
|
||||
{
|
||||
gem.connected_controllers = 0;
|
||||
|
||||
std::lock_guard lock(pad::g_pad_mutex);
|
||||
const auto handler = pad::get_current_handler();
|
||||
|
||||
for (u32 i = 0; i < CELL_GEM_MAX_NUM; i++)
|
||||
{
|
||||
const auto& pad = ::at32(handler->GetPads(), pad_num(i));
|
||||
const bool connected = (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && i < gem.attribute.max_connect);
|
||||
|
||||
if (connected)
|
||||
{
|
||||
gem.connected_controllers++;
|
||||
gem.controllers[i].status = CELL_GEM_STATUS_READY;
|
||||
gem.controllers[i].port = port_num(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
gem.controllers[i].status = CELL_GEM_STATUS_DISCONNECTED;
|
||||
gem.controllers[i].port = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->max_connect = gem.attribute.max_connect;
|
||||
info->now_connect = gem.connected_controllers;
|
||||
|
||||
@@ -1558,7 +1640,7 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr<Ce
|
||||
|
||||
if (!gem.is_controller_ready(gem_num))
|
||||
{
|
||||
return CELL_GEM_NOT_CONNECTED;
|
||||
return not_an_error(CELL_GEM_NOT_CONNECTED);
|
||||
}
|
||||
|
||||
// TODO: Get the gem state at the specified time
|
||||
@@ -1603,6 +1685,7 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr<Ce
|
||||
ds3_pos_to_gem_state(gem_num, gem.controllers[gem_num], gem_state);
|
||||
break;
|
||||
case move_handler::mouse:
|
||||
case move_handler::raw_mouse:
|
||||
mouse_input_to_pad(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T);
|
||||
mouse_pos_to_gem_state(gem_num, gem.controllers[gem_num], gem_state);
|
||||
break;
|
||||
|
||||
@@ -40,7 +40,7 @@ ime_jp_manager::ime_jp_manager()
|
||||
|
||||
bool ime_jp_manager::addChar(u16 c)
|
||||
{
|
||||
if (!c || cursor >= (CELL_IMEJP_STRING_MAXLENGTH - 1) || cursor > input_string.length())
|
||||
if (!c || cursor >= (CELL_IMEJP_STRING_MAXLENGTH - 1ULL) || cursor > input_string.length())
|
||||
return false;
|
||||
|
||||
std::u16string tmp;
|
||||
@@ -49,11 +49,29 @@ bool ime_jp_manager::addChar(u16 c)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wrestrict"
|
||||
#endif
|
||||
input_string.insert(cursor++, tmp);
|
||||
input_string.insert(cursor, tmp);
|
||||
#if defined(__GNUG__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
cursor_end = cursor;
|
||||
|
||||
const usz cursor_old = cursor;
|
||||
const bool cursor_was_in_focus = cursor >= focus_begin && cursor <= (focus_begin + focus_length);
|
||||
|
||||
move_cursor(1);
|
||||
|
||||
if (cursor_was_in_focus)
|
||||
{
|
||||
// Add this char to the focus
|
||||
move_focus_end(1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's just move the focus to the cursor, so that it contains the new char.
|
||||
focus_begin = cursor_old;
|
||||
focus_length = 1;
|
||||
move_focus(0); // Sanitize focus
|
||||
}
|
||||
|
||||
input_state = CELL_IMEJP_BEFORE_CONVERT;
|
||||
return true;
|
||||
}
|
||||
@@ -74,59 +92,138 @@ bool ime_jp_manager::addString(vm::cptr<u16> str)
|
||||
|
||||
bool ime_jp_manager::backspaceWord()
|
||||
{
|
||||
if (!cursor || cursor > CELL_IMEJP_STRING_MAXLENGTH || cursor > input_string.length())
|
||||
return false;
|
||||
|
||||
input_string.erase(--cursor);
|
||||
cursor_end = cursor;
|
||||
|
||||
if (input_string.empty())
|
||||
input_state = CELL_IMEJP_BEFORE_INPUT;
|
||||
|
||||
return true;
|
||||
return remove_character(false);
|
||||
}
|
||||
|
||||
bool ime_jp_manager::deleteWord()
|
||||
{
|
||||
if (cursor >= (CELL_IMEJP_STRING_MAXLENGTH - 1) || cursor > (input_string.length() - 1))
|
||||
return false;
|
||||
return remove_character(true);
|
||||
}
|
||||
|
||||
input_string.erase(cursor);
|
||||
cursor_end = cursor;
|
||||
bool ime_jp_manager::remove_character(bool forward)
|
||||
{
|
||||
if (!forward && !cursor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const usz pos = forward ? cursor : (cursor - 1);
|
||||
|
||||
if (pos >= (CELL_IMEJP_STRING_MAXLENGTH - 1ULL) || pos >= input_string.length())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete the character at the position
|
||||
input_string.erase(pos, 1);
|
||||
|
||||
// Move cursor and focus
|
||||
const bool deleted_part_of_focus = pos > focus_begin && pos <= (focus_begin + focus_length);
|
||||
|
||||
if (!forward)
|
||||
{
|
||||
move_cursor(-1);
|
||||
}
|
||||
|
||||
if (deleted_part_of_focus)
|
||||
{
|
||||
move_focus_end(-1, false);
|
||||
}
|
||||
else if (focus_begin > pos)
|
||||
{
|
||||
move_focus(-1);
|
||||
}
|
||||
|
||||
if (input_string.empty())
|
||||
{
|
||||
input_state = CELL_IMEJP_BEFORE_INPUT;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ime_jp_manager::moveCursor(s8 amount)
|
||||
void ime_jp_manager::clear_input()
|
||||
{
|
||||
cursor = 0;
|
||||
focus_begin = 0;
|
||||
focus_length = 0;
|
||||
input_string.clear();
|
||||
converted_string.clear();
|
||||
}
|
||||
|
||||
void ime_jp_manager::move_cursor(s8 amount)
|
||||
{
|
||||
cursor = std::max(0, std::min(static_cast<s32>(cursor) + amount, ::narrow<s32>(input_string.length())));
|
||||
}
|
||||
|
||||
void ime_jp_manager::move_focus(s8 amount)
|
||||
{
|
||||
focus_begin = std::max(0, std::min(static_cast<s32>(focus_begin) + amount, ::narrow<s32>(input_string.length())));
|
||||
move_focus_end(amount, false);
|
||||
}
|
||||
|
||||
void ime_jp_manager::move_focus_end(s8 amount, bool wrap_around)
|
||||
{
|
||||
if (focus_begin >= input_string.length())
|
||||
{
|
||||
focus_length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr usz min_length = 1;
|
||||
const usz max_length = input_string.length() - focus_begin;
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
cursor = std::min(cursor + amount, input_string.length() - 1);
|
||||
cursor_end = std::min(cursor_end + amount, input_string.length() - 1);
|
||||
if (wrap_around && focus_length >= max_length)
|
||||
{
|
||||
focus_length = min_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
focus_length += static_cast<usz>(amount);
|
||||
}
|
||||
}
|
||||
else if (amount < 0)
|
||||
{
|
||||
cursor = std::max(0, static_cast<s32>(cursor) + amount);
|
||||
cursor_end = std::max(static_cast<s32>(cursor), static_cast<s32>(cursor_end) + amount);
|
||||
if (wrap_around && focus_length <= min_length)
|
||||
{
|
||||
focus_length = max_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
focus_length = std::max(0, static_cast<s32>(focus_length) + amount);
|
||||
}
|
||||
}
|
||||
|
||||
focus_length = std::max(min_length, std::min(max_length, focus_length));
|
||||
}
|
||||
|
||||
void ime_jp_manager::moveCursorEnd(s8 amount)
|
||||
std::vector<ime_jp_manager::candidate> ime_jp_manager::get_candidate_list() const
|
||||
{
|
||||
if (amount > 0)
|
||||
{
|
||||
cursor_end = std::max(static_cast<s32>(cursor), std::min<s32>(static_cast<s32>(cursor_end) + amount, ::narrow<s32>(input_string.length()) - 1));
|
||||
}
|
||||
else if (amount < 0)
|
||||
{
|
||||
cursor_end = std::max(static_cast<s32>(cursor), static_cast<s32>(cursor_end) + amount);
|
||||
}
|
||||
std::vector<candidate> candidates;
|
||||
if (input_string.empty() || focus_length == 0 || focus_begin >= input_string.length())
|
||||
return candidates;
|
||||
|
||||
// TODO: we just fake this with one candidate for now
|
||||
candidates.push_back(candidate{
|
||||
.text = get_focus_string(),
|
||||
.offset = 0
|
||||
});
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
error_code cellImeJpOpen(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cptr<CellImeJpAddDic> addDicPath)
|
||||
std::u16string ime_jp_manager::get_focus_string() const
|
||||
{
|
||||
if (input_string.empty() || focus_length == 0 || focus_begin >= input_string.length())
|
||||
return {};
|
||||
|
||||
return input_string.substr(focus_begin, focus_length);
|
||||
}
|
||||
|
||||
|
||||
static error_code cellImeJpOpen(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cptr<CellImeJpAddDic> addDicPath)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpOpen(container_id=*0x%x, hImeJpHandle=*0x%x, addDicPath=*0x%x)", container_id, hImeJpHandle, addDicPath);
|
||||
|
||||
@@ -156,7 +253,7 @@ error_code cellImeJpOpen(sys_memory_container_t container_id, vm::ptr<CellImeJpH
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpOpen2(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cptr<CellImeJpAddDic> addDicPath)
|
||||
static error_code cellImeJpOpen2(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cptr<CellImeJpAddDic> addDicPath)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpOpen2(container_id=*0x%x, hImeJpHandle=*0x%x, addDicPath=*0x%x)", container_id, hImeJpHandle, addDicPath);
|
||||
|
||||
@@ -187,7 +284,7 @@ error_code cellImeJpOpen2(sys_memory_container_t container_id, vm::ptr<CellImeJp
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpOpen3(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cpptr<CellImeJpAddDic> addDicPath)
|
||||
static error_code cellImeJpOpen3(sys_memory_container_t container_id, vm::ptr<CellImeJpHandle> hImeJpHandle, vm::cpptr<CellImeJpAddDic> addDicPath)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpOpen3(container_id=*0x%x, hImeJpHandle=*0x%x, addDicPath=*0x%x)", container_id, hImeJpHandle, addDicPath);
|
||||
|
||||
@@ -224,13 +321,13 @@ error_code cellImeJpOpen3(sys_memory_container_t container_id, vm::ptr<CellImeJp
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpOpenExt()
|
||||
static error_code cellImeJpOpenExt()
|
||||
{
|
||||
cellImeJp.todo("cellImeJpOpenExt()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpClose(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpClose(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpClose(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -243,17 +340,14 @@ error_code cellImeJpClose(CellImeJpHandle hImeJpHandle)
|
||||
}
|
||||
|
||||
manager.input_state = CELL_IMEJP_BEFORE_INPUT;
|
||||
manager.input_string.clear();
|
||||
manager.converted_string.clear();
|
||||
manager.clear_input();
|
||||
manager.confirmed_string.clear();
|
||||
manager.cursor = 0;
|
||||
manager.cursor_end = 0;
|
||||
manager.is_initialized = false;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpSetKanaInputMode(CellImeJpHandle hImeJpHandle, s16 inputOption)
|
||||
static error_code cellImeJpSetKanaInputMode(CellImeJpHandle hImeJpHandle, s16 inputOption)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpSetKanaInputMode(hImeJpHandle=*0x%x, inputOption=%d)", hImeJpHandle, inputOption);
|
||||
|
||||
@@ -275,7 +369,7 @@ error_code cellImeJpSetKanaInputMode(CellImeJpHandle hImeJpHandle, s16 inputOpti
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpSetInputCharType(CellImeJpHandle hImeJpHandle, s16 charTypeOption)
|
||||
static error_code cellImeJpSetInputCharType(CellImeJpHandle hImeJpHandle, s16 charTypeOption)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpSetInputCharType(hImeJpHandle=*0x%x, charTypeOption=%d)", hImeJpHandle, charTypeOption);
|
||||
|
||||
@@ -292,7 +386,7 @@ error_code cellImeJpSetInputCharType(CellImeJpHandle hImeJpHandle, s16 charTypeO
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpSetFixInputMode(CellImeJpHandle hImeJpHandle, s16 fixInputMode)
|
||||
static error_code cellImeJpSetFixInputMode(CellImeJpHandle hImeJpHandle, s16 fixInputMode)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpSetFixInputMode(hImeJpHandle=*0x%x, fixInputMode=%d)", hImeJpHandle, fixInputMode);
|
||||
|
||||
@@ -309,7 +403,7 @@ error_code cellImeJpSetFixInputMode(CellImeJpHandle hImeJpHandle, s16 fixInputMo
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpAllowExtensionCharacters(CellImeJpHandle hImeJpHandle, s16 extensionCharacters)
|
||||
static error_code cellImeJpAllowExtensionCharacters(CellImeJpHandle hImeJpHandle, s16 extensionCharacters)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpSetFixInputMode(hImeJpHandle=*0x%x, extensionCharacters=%d)", hImeJpHandle, extensionCharacters);
|
||||
|
||||
@@ -331,7 +425,7 @@ error_code cellImeJpAllowExtensionCharacters(CellImeJpHandle hImeJpHandle, s16 e
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpReset(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpReset(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpReset(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -344,16 +438,13 @@ error_code cellImeJpReset(CellImeJpHandle hImeJpHandle)
|
||||
}
|
||||
|
||||
manager.input_state = CELL_IMEJP_BEFORE_INPUT;
|
||||
manager.input_string.clear();
|
||||
manager.converted_string.clear();
|
||||
manager.clear_input();
|
||||
manager.confirmed_string.clear();
|
||||
manager.cursor = 0;
|
||||
manager.cursor_end = 0;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetStatus(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pInputStatus)
|
||||
static error_code cellImeJpGetStatus(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pInputStatus)
|
||||
{
|
||||
cellImeJp.warning("cellImeJpGetStatus(hImeJpHandle=*0x%x, pInputStatus=%d)", hImeJpHandle, pInputStatus);
|
||||
|
||||
@@ -375,7 +466,7 @@ error_code cellImeJpGetStatus(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pInputS
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpEnterChar(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::ptr<s16> pOutputStatus)
|
||||
static error_code cellImeJpEnterChar(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::ptr<s16> pOutputStatus)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpEnterChar(hImeJpHandle=*0x%x, inputChar=%d, pOutputStatus=%d)", hImeJpHandle, inputChar, pOutputStatus);
|
||||
|
||||
@@ -404,13 +495,13 @@ error_code cellImeJpEnterChar(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::p
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpEnterCharExt(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::ptr<s16> pOutputStatus)
|
||||
static error_code cellImeJpEnterCharExt(CellImeJpHandle hImeJpHandle, u16 inputChar, vm::ptr<s16> pOutputStatus)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpEnterCharExt(hImeJpHandle=*0x%x, inputChar=%d, pOutputStatus=%d", hImeJpHandle, inputChar, pOutputStatus);
|
||||
return cellImeJpEnterChar(hImeJpHandle, inputChar, pOutputStatus);
|
||||
}
|
||||
|
||||
error_code cellImeJpEnterString(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInputString, vm::ptr<s16> pOutputStatus)
|
||||
static error_code cellImeJpEnterString(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInputString, vm::ptr<s16> pOutputStatus)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpEnterString(hImeJpHandle=*0x%x, pInputString=*0x%x, pOutputStatus=%d", hImeJpHandle, pInputString, pOutputStatus);
|
||||
|
||||
@@ -439,13 +530,13 @@ error_code cellImeJpEnterString(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInp
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpEnterStringExt(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInputString, vm::ptr<s16> pOutputStatus)
|
||||
static error_code cellImeJpEnterStringExt(CellImeJpHandle hImeJpHandle, vm::cptr<u16> pInputString, vm::ptr<s16> pOutputStatus)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpEnterStringExt(hImeJpHandle=*0x%x, pInputString=*0x%x, pOutputStatus=%d", hImeJpHandle, pInputString, pOutputStatus);
|
||||
return cellImeJpEnterString(hImeJpHandle, pInputString, pOutputStatus);
|
||||
}
|
||||
|
||||
error_code cellImeJpModeCaretRight(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpModeCaretRight(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpModeCaretRight(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -462,12 +553,12 @@ error_code cellImeJpModeCaretRight(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_IMEJP_ERROR_ERR;
|
||||
}
|
||||
|
||||
manager.moveCursor(1);
|
||||
manager.move_cursor(1);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpModeCaretLeft(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpModeCaretLeft(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpModeCaretLeft(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -484,12 +575,12 @@ error_code cellImeJpModeCaretLeft(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_IMEJP_ERROR_ERR;
|
||||
}
|
||||
|
||||
manager.moveCursor(-1);
|
||||
manager.move_cursor(-1);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpBackspaceWord(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpBackspaceWord(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpBackspaceWord(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -511,7 +602,7 @@ error_code cellImeJpBackspaceWord(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpDeleteWord(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpDeleteWord(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpDeleteWord(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -533,7 +624,7 @@ error_code cellImeJpDeleteWord(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpAllDeleteConvertString(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpAllDeleteConvertString(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpAllDeleteConvertString(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -550,16 +641,13 @@ error_code cellImeJpAllDeleteConvertString(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_IMEJP_ERROR_ERR;
|
||||
}
|
||||
|
||||
manager.cursor = 0;
|
||||
manager.cursor_end = 0;
|
||||
manager.input_string.clear();
|
||||
manager.converted_string.clear();
|
||||
manager.clear_input();
|
||||
manager.input_state = CELL_IMEJP_BEFORE_INPUT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpConvertForward(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpConvertForward(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpConvertForward(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -581,7 +669,7 @@ error_code cellImeJpConvertForward(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpConvertBackward(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpConvertBackward(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpConvertBackward(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -603,7 +691,7 @@ error_code cellImeJpConvertBackward(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpCurrentPartConfirm(CellImeJpHandle hImeJpHandle, s16 listItem)
|
||||
static error_code cellImeJpCurrentPartConfirm(CellImeJpHandle hImeJpHandle, s16 listItem)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpCurrentPartConfirm(hImeJpHandle=*0x%x, listItem=%d)", hImeJpHandle, listItem);
|
||||
|
||||
@@ -623,7 +711,7 @@ error_code cellImeJpCurrentPartConfirm(CellImeJpHandle hImeJpHandle, s16 listIte
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpAllConfirm(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpAllConfirm(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpAllConfirm(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -642,16 +730,13 @@ error_code cellImeJpAllConfirm(CellImeJpHandle hImeJpHandle)
|
||||
|
||||
// Use input_string for now
|
||||
manager.confirmed_string = manager.input_string;
|
||||
manager.cursor = 0;
|
||||
manager.cursor_end = 0;
|
||||
manager.input_string.clear();
|
||||
manager.converted_string.clear();
|
||||
manager.clear_input();
|
||||
manager.input_state = CELL_IMEJP_BEFORE_INPUT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpAllConvertCancel(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpAllConvertCancel(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpAllConvertCancel(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -674,7 +759,7 @@ error_code cellImeJpAllConvertCancel(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpConvertCancel(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpConvertCancel(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpConvertCancel(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -691,11 +776,13 @@ error_code cellImeJpConvertCancel(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_IMEJP_ERROR_ERR;
|
||||
}
|
||||
|
||||
// TODO: only cancel all if cursor is at 0
|
||||
return cellImeJpAllConvertCancel(hImeJpHandle);
|
||||
manager.converted_string.clear();
|
||||
manager.input_state = CELL_IMEJP_BEFORE_CONVERT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpExtendConvertArea(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpExtendConvertArea(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpExtendConvertArea(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -712,12 +799,13 @@ error_code cellImeJpExtendConvertArea(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_IMEJP_ERROR_ERR;
|
||||
}
|
||||
|
||||
manager.moveCursorEnd(1);
|
||||
// Move end of the focus by one. Wrap around if the focus end is already at the end of the input string.
|
||||
manager.move_focus_end(1, true);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpShortenConvertArea(CellImeJpHandle hImeJpHandle)
|
||||
static error_code cellImeJpShortenConvertArea(CellImeJpHandle hImeJpHandle)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpShortenConvertArea(hImeJpHandle=*0x%x)", hImeJpHandle);
|
||||
|
||||
@@ -734,12 +822,13 @@ error_code cellImeJpShortenConvertArea(CellImeJpHandle hImeJpHandle)
|
||||
return CELL_IMEJP_ERROR_ERR;
|
||||
}
|
||||
|
||||
manager.moveCursorEnd(-1);
|
||||
// Move end of focus by one. Wrap around if the focus end is already at the beginning of the input string.
|
||||
manager.move_focus_end(-1, true);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpTemporalConfirm(CellImeJpHandle hImeJpHandle, s16 selectIndex)
|
||||
static error_code cellImeJpTemporalConfirm(CellImeJpHandle hImeJpHandle, s16 selectIndex)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpTemporalConfirm(hImeJpHandle=*0x%x, selectIndex=%d)", hImeJpHandle, selectIndex);
|
||||
|
||||
@@ -759,7 +848,7 @@ error_code cellImeJpTemporalConfirm(CellImeJpHandle hImeJpHandle, s16 selectInde
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpPostConvert(CellImeJpHandle hImeJpHandle, s16 postType)
|
||||
static error_code cellImeJpPostConvert(CellImeJpHandle hImeJpHandle, s16 postType)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpPostConvert(hImeJpHandle=*0x%x, postType=%d)", hImeJpHandle, postType);
|
||||
|
||||
@@ -779,7 +868,7 @@ error_code cellImeJpPostConvert(CellImeJpHandle hImeJpHandle, s16 postType)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpMoveFocusClause(CellImeJpHandle hImeJpHandle, s16 moveType)
|
||||
static error_code cellImeJpMoveFocusClause(CellImeJpHandle hImeJpHandle, s16 moveType)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpMoveFocusClause(hImeJpHandle=*0x%x, moveType=%d)", hImeJpHandle, moveType);
|
||||
|
||||
@@ -799,17 +888,17 @@ error_code cellImeJpMoveFocusClause(CellImeJpHandle hImeJpHandle, s16 moveType)
|
||||
switch (moveType)
|
||||
{
|
||||
case CELL_IMEJP_FOCUS_NEXT:
|
||||
manager.moveCursor(1);
|
||||
manager.move_focus(1);
|
||||
break;
|
||||
case CELL_IMEJP_FOCUS_BEFORE:
|
||||
manager.moveCursor(-1);
|
||||
manager.move_focus(-1);
|
||||
break;
|
||||
case CELL_IMEJP_FOCUS_TOP:
|
||||
manager.moveCursor(-1 * ::narrow<s8>(manager.input_string.length()));
|
||||
manager.move_focus(-1 * ::narrow<s8>(manager.input_string.length()));
|
||||
break;
|
||||
case CELL_IMEJP_FOCUS_END:
|
||||
manager.moveCursor(::narrow<s8>(manager.input_string.length()));
|
||||
manager.moveCursor(-1);
|
||||
manager.move_focus(::narrow<s8>(manager.input_string.length()));
|
||||
manager.move_focus(-1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -820,7 +909,7 @@ error_code cellImeJpMoveFocusClause(CellImeJpHandle hImeJpHandle, s16 moveType)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetFocusTop(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocusTop)
|
||||
static error_code cellImeJpGetFocusTop(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocusTop)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpGetFocusTop(hImeJpHandle=*0x%x, pFocusTop=*0x%x)", hImeJpHandle, pFocusTop);
|
||||
|
||||
@@ -837,12 +926,12 @@ error_code cellImeJpGetFocusTop(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocu
|
||||
return CELL_IMEJP_ERROR_CONTEXT;
|
||||
}
|
||||
|
||||
*pFocusTop = static_cast<u16>(manager.cursor * 2); // offset in bytes
|
||||
*pFocusTop = static_cast<u16>(manager.focus_begin * 2); // offset in bytes
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetFocusLength(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocusLength)
|
||||
static error_code cellImeJpGetFocusLength(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pFocusLength)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpGetFocusLength(hImeJpHandle=*0x%x, pFocusLength=*0x%x)", hImeJpHandle, pFocusLength);
|
||||
|
||||
@@ -859,19 +948,12 @@ error_code cellImeJpGetFocusLength(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pF
|
||||
return CELL_IMEJP_ERROR_CONTEXT;
|
||||
}
|
||||
|
||||
if (manager.cursor >= (CELL_IMEJP_STRING_MAXLENGTH - 1))
|
||||
{
|
||||
*pFocusLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pFocusLength = static_cast<u16>((manager.cursor_end - manager.cursor + 1) * 2); // offset in bytes
|
||||
}
|
||||
*pFocusLength = ::narrow<s16>(manager.focus_length * 2); // offset in bytes
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetConfirmYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pYomiString)
|
||||
static error_code cellImeJpGetConfirmYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pYomiString)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpGetConfirmYomiString(hImeJpHandle=*0x%x, pYomiString=*0x%x)", hImeJpHandle, pYomiString);
|
||||
|
||||
@@ -888,22 +970,22 @@ error_code cellImeJpGetConfirmYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u
|
||||
return CELL_IMEJP_ERROR_CONTEXT;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < CELL_IMEJP_STRING_MAXLENGTH; i++)
|
||||
{
|
||||
pYomiString[i] = 0;
|
||||
}
|
||||
|
||||
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1, manager.confirmed_string.length());
|
||||
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1ULL, manager.confirmed_string.length());
|
||||
|
||||
for (u32 i = 0; i < max_len; i++)
|
||||
{
|
||||
pYomiString[i] = manager.confirmed_string[i];
|
||||
}
|
||||
|
||||
for (u32 i = static_cast<u32>(max_len); i < CELL_IMEJP_STRING_MAXLENGTH; i++)
|
||||
{
|
||||
pYomiString[i] = 0;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetConfirmString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pConfirmString)
|
||||
static error_code cellImeJpGetConfirmString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pConfirmString)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpGetConfirmString(hImeJpHandle=*0x%x, pConfirmString=*0x%x)", hImeJpHandle, pConfirmString);
|
||||
|
||||
@@ -920,22 +1002,22 @@ error_code cellImeJpGetConfirmString(CellImeJpHandle hImeJpHandle, vm::ptr<u16>
|
||||
return CELL_IMEJP_ERROR_CONTEXT;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < CELL_IMEJP_STRING_MAXLENGTH; i++)
|
||||
{
|
||||
pConfirmString[i] = 0;
|
||||
}
|
||||
|
||||
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1, manager.confirmed_string.length());
|
||||
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1ULL, manager.confirmed_string.length());
|
||||
|
||||
for (u32 i = 0; i < max_len; i++)
|
||||
{
|
||||
pConfirmString[i] = manager.confirmed_string[i];
|
||||
}
|
||||
|
||||
for (u32 i = static_cast<u32>(max_len); i < CELL_IMEJP_STRING_MAXLENGTH; i++)
|
||||
{
|
||||
pConfirmString[i] = 0;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetConvertYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pYomiString)
|
||||
static error_code cellImeJpGetConvertYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pYomiString)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpGetConvertYomiString(hImeJpHandle=*0x%x, pYomiString=*0x%x)", hImeJpHandle, pYomiString);
|
||||
|
||||
@@ -952,22 +1034,22 @@ error_code cellImeJpGetConvertYomiString(CellImeJpHandle hImeJpHandle, vm::ptr<u
|
||||
return CELL_IMEJP_ERROR_CONTEXT;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < CELL_IMEJP_STRING_MAXLENGTH; i++)
|
||||
{
|
||||
pYomiString[i] = 0;
|
||||
}
|
||||
|
||||
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1, manager.input_string.length());
|
||||
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1ULL, manager.input_string.length());
|
||||
|
||||
for (u32 i = 0; i < max_len; i++)
|
||||
{
|
||||
pYomiString[i] = manager.input_string[i];
|
||||
}
|
||||
|
||||
for (u32 i = static_cast<u32>(max_len); i < CELL_IMEJP_STRING_MAXLENGTH; i++)
|
||||
{
|
||||
pYomiString[i] = 0;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetConvertString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pConvertString)
|
||||
static error_code cellImeJpGetConvertString(CellImeJpHandle hImeJpHandle, vm::ptr<u16> pConvertString)
|
||||
{
|
||||
cellImeJp.warning("cellImeJpGetConvertString(hImeJpHandle=*0x%x, pConvertString=*0x%x)", hImeJpHandle, pConvertString);
|
||||
|
||||
@@ -984,22 +1066,22 @@ error_code cellImeJpGetConvertString(CellImeJpHandle hImeJpHandle, vm::ptr<u16>
|
||||
return CELL_IMEJP_ERROR_CONTEXT;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < CELL_IMEJP_STRING_MAXLENGTH; i++)
|
||||
{
|
||||
pConvertString[i] = 0;
|
||||
}
|
||||
|
||||
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1, manager.input_string.length());
|
||||
const usz max_len = std::min<usz>(CELL_IMEJP_STRING_MAXLENGTH - 1ULL, manager.input_string.length());
|
||||
|
||||
for (u32 i = 0; i < max_len; i++)
|
||||
{
|
||||
pConvertString[i] = manager.input_string[i];
|
||||
}
|
||||
|
||||
for (u32 i = static_cast<u32>(max_len); i < CELL_IMEJP_STRING_MAXLENGTH; i++)
|
||||
{
|
||||
pConvertString[i] = 0;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetCandidateListSize(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pListSize)
|
||||
static error_code cellImeJpGetCandidateListSize(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pListSize)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpGetCandidateListSize(hImeJpHandle=*0x%x, pListSize=*0x%x)", hImeJpHandle, pListSize);
|
||||
|
||||
@@ -1021,12 +1103,23 @@ error_code cellImeJpGetCandidateListSize(CellImeJpHandle hImeJpHandle, vm::ptr<s
|
||||
return CELL_IMEJP_ERROR_ERR;
|
||||
}
|
||||
|
||||
*pListSize = 0;
|
||||
// Add focus string size, including null terminator
|
||||
const std::u16string focus_string = manager.get_focus_string();
|
||||
usz size = sizeof(u16) * (focus_string.length() + 1);
|
||||
|
||||
// Add candidates, including null terminators and offsets
|
||||
for (const ime_jp_manager::candidate& can : manager.get_candidate_list())
|
||||
{
|
||||
constexpr usz offset_size = sizeof(u16);
|
||||
size += offset_size + (can.text.size() + 1) * sizeof(u16);
|
||||
}
|
||||
|
||||
*pListSize = ::narrow<s16>(size);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetCandidateList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> plistNum, vm::ptr<u16> pCandidateString)
|
||||
static error_code cellImeJpGetCandidateList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> plistNum, vm::ptr<u16> pCandidateString)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpGetCandidateList(hImeJpHandle=*0x%x, plistNum=*0x%x, pCandidateString=*0x%x)", hImeJpHandle, plistNum, pCandidateString);
|
||||
|
||||
@@ -1048,12 +1141,42 @@ error_code cellImeJpGetCandidateList(CellImeJpHandle hImeJpHandle, vm::ptr<s16>
|
||||
return CELL_IMEJP_ERROR_ERR;
|
||||
}
|
||||
|
||||
*plistNum = 0;
|
||||
// First, copy the focus string
|
||||
u32 pos = 0;
|
||||
const std::u16string focus_string = manager.get_focus_string();
|
||||
for (u32 i = pos; i < focus_string.length(); i++)
|
||||
{
|
||||
pCandidateString[i] = focus_string[i];
|
||||
}
|
||||
pos += ::narrow<u32>(focus_string.length());
|
||||
|
||||
// Add null terminator
|
||||
pCandidateString[pos++] = 0;
|
||||
|
||||
// Add list of candidates
|
||||
const std::vector<ime_jp_manager::candidate> list = manager.get_candidate_list();
|
||||
for (const ime_jp_manager::candidate& can : list)
|
||||
{
|
||||
// Copy the candidate
|
||||
for (u32 i = pos; i < can.text.length(); i++)
|
||||
{
|
||||
pCandidateString[i] = can.text[i];
|
||||
}
|
||||
pos += ::narrow<u32>(can.text.length());
|
||||
|
||||
// Add null terminator
|
||||
pCandidateString[pos++] = 0;
|
||||
|
||||
// Add offset
|
||||
pCandidateString[pos++] = can.offset;
|
||||
}
|
||||
|
||||
*plistNum = ::narrow<s16>(list.size());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetCandidateSelect(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pIndex)
|
||||
static error_code cellImeJpGetCandidateSelect(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pIndex)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpGetCandidateSelect(hImeJpHandle=*0x%x, pIndex=*0x%x)", hImeJpHandle, pIndex);
|
||||
|
||||
@@ -1080,7 +1203,7 @@ error_code cellImeJpGetCandidateSelect(CellImeJpHandle hImeJpHandle, vm::ptr<s16
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpGetPredictList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pYomiString, s32 itemNum, vm::ptr<s32> plistCount, vm::ptr<CellImeJpPredictItem> pPredictItem)
|
||||
static error_code cellImeJpGetPredictList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pYomiString, s32 itemNum, vm::ptr<s32> plistCount, vm::ptr<CellImeJpPredictItem> pPredictItem)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpGetPredictList(hImeJpHandle=*0x%x, pYomiString=*0x%x, itemNum=%d, plistCount=*0x%x, pPredictItem=*0x%x)", hImeJpHandle, pYomiString, itemNum, plistCount, pPredictItem);
|
||||
|
||||
@@ -1102,7 +1225,7 @@ error_code cellImeJpGetPredictList(CellImeJpHandle hImeJpHandle, vm::ptr<s16> pY
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellImeJpConfirmPrediction(CellImeJpHandle hImeJpHandle, vm::ptr<CellImeJpPredictItem> pPredictItem)
|
||||
static error_code cellImeJpConfirmPrediction(CellImeJpHandle hImeJpHandle, vm::ptr<CellImeJpPredictItem> pPredictItem)
|
||||
{
|
||||
cellImeJp.todo("cellImeJpConfirmPrediction(hImeJpHandle=*0x%x, pPredictItem=*0x%x)", hImeJpHandle, pPredictItem);
|
||||
|
||||
|
||||
@@ -115,11 +115,12 @@ struct ime_jp_manager
|
||||
|
||||
u32 input_state = CELL_IMEJP_BEFORE_INPUT;
|
||||
std::vector<std::string> dictionary_paths;
|
||||
std::u16string confirmed_string;
|
||||
std::u16string converted_string;
|
||||
std::u16string input_string;
|
||||
usz cursor = 0;
|
||||
usz cursor_end = 0;
|
||||
std::u16string confirmed_string; // Confirmed part of the string (first part of the entire string)
|
||||
std::u16string converted_string; // Converted part of the unconfirmed input string
|
||||
std::u16string input_string; // Unconfirmed part of the string (second part of the entire string)
|
||||
usz cursor = 0; // The cursor. Can move across the entire input string.
|
||||
usz focus_begin = 0; // Begin of the focus string
|
||||
usz focus_length = 0; // Length of the focus string
|
||||
s16 fix_input_mode = CELL_IMEJP_FIXINMODE_OFF;
|
||||
s16 input_char_type = CELL_IMEJP_DSPCHAR_HIRA;
|
||||
s16 kana_input_mode = CELL_IMEJP_ROMAN_INPUT;
|
||||
@@ -131,6 +132,17 @@ struct ime_jp_manager
|
||||
bool addString(vm::cptr<u16> str);
|
||||
bool backspaceWord();
|
||||
bool deleteWord();
|
||||
void moveCursor(s8 amount);
|
||||
void moveCursorEnd(s8 amount);
|
||||
bool remove_character(bool forward);
|
||||
void clear_input();
|
||||
void move_cursor(s8 amount); // s8 because CELL_IMEJP_STRING_MAXLENGTH is 128
|
||||
void move_focus(s8 amount); // s8 because CELL_IMEJP_STRING_MAXLENGTH is 128
|
||||
void move_focus_end(s8 amount, bool wrap_around); // s8 because CELL_IMEJP_STRING_MAXLENGTH is 128
|
||||
|
||||
struct candidate
|
||||
{
|
||||
std::u16string text; // Actual text of the candidate
|
||||
u16 offset = 0; // The offset of the next character after the candidate replaced part of the current focus.
|
||||
};
|
||||
std::vector<candidate> get_candidate_list() const;
|
||||
std::u16string get_focus_string() const;
|
||||
};
|
||||
|
||||
@@ -42,13 +42,16 @@ KeyboardHandlerBase::KeyboardHandlerBase(utils::serial* ar)
|
||||
return;
|
||||
}
|
||||
|
||||
(*ar)(m_info.max_connect);
|
||||
u32 max_connect = 0;
|
||||
|
||||
if (m_info.max_connect)
|
||||
(*ar)(max_connect);
|
||||
|
||||
if (max_connect)
|
||||
{
|
||||
Emu.PostponeInitCode([this]()
|
||||
Emu.PostponeInitCode([this, max_connect]()
|
||||
{
|
||||
Init(m_info.max_connect);
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
AddConsumer(keyboard_consumer::identifier::cellKb, max_connect);
|
||||
auto lk = init.init();
|
||||
});
|
||||
}
|
||||
@@ -56,9 +59,20 @@ KeyboardHandlerBase::KeyboardHandlerBase(utils::serial* ar)
|
||||
|
||||
void KeyboardHandlerBase::save(utils::serial& ar)
|
||||
{
|
||||
u32 max_connect = 0;
|
||||
const auto inited = init.access();
|
||||
|
||||
ar(inited ? m_info.max_connect : 0);
|
||||
if (inited)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (auto it = m_consumers.find(keyboard_consumer::identifier::cellKb); it != m_consumers.end())
|
||||
{
|
||||
max_connect = it->second.GetInfo().max_connect;
|
||||
}
|
||||
}
|
||||
|
||||
ar(max_connect);
|
||||
}
|
||||
|
||||
error_code cellKbInit(ppu_thread& ppu, u32 max_connect)
|
||||
@@ -79,7 +93,9 @@ error_code cellKbInit(ppu_thread& ppu, u32 max_connect)
|
||||
}
|
||||
|
||||
sys_config_start(ppu);
|
||||
handler.Init(std::min(max_connect, 7u));
|
||||
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
handler.AddConsumer(keyboard_consumer::identifier::cellKb, std::min(max_connect, 7u));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -95,6 +111,11 @@ error_code cellKbEnd(ppu_thread& ppu)
|
||||
if (!init)
|
||||
return CELL_KB_ERROR_UNINITIALIZED;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
handler.RemoveConsumer(keyboard_consumer::identifier::cellKb);
|
||||
}
|
||||
|
||||
// TODO
|
||||
sys_config_stop(ppu);
|
||||
return CELL_OK;
|
||||
@@ -116,12 +137,13 @@ error_code cellKbClearBuf(u32 port_no)
|
||||
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
|
||||
const KbInfo& current_info = handler.GetInfo();
|
||||
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
|
||||
const KbInfo& current_info = consumer.GetInfo();
|
||||
|
||||
if (port_no >= handler.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
|
||||
if (port_no >= consumer.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
|
||||
return not_an_error(CELL_KB_ERROR_NO_DEVICE);
|
||||
|
||||
KbData& current_data = handler.GetData(port_no);
|
||||
KbData& current_data = consumer.GetData(port_no);
|
||||
current_data.len = 0;
|
||||
current_data.led = 0;
|
||||
current_data.mkey = 0;
|
||||
@@ -298,8 +320,9 @@ error_code cellKbGetInfo(vm::ptr<CellKbInfo> info)
|
||||
std::memset(info.get_ptr(), 0, info.size());
|
||||
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
|
||||
|
||||
const KbInfo& current_info = handler.GetInfo();
|
||||
const KbInfo& current_info = consumer.GetInfo();
|
||||
info->max_connect = current_info.max_connect;
|
||||
info->now_connect = current_info.now_connect;
|
||||
info->info = current_info.info;
|
||||
@@ -327,13 +350,13 @@ error_code cellKbRead(u32 port_no, vm::ptr<CellKbData> data)
|
||||
return CELL_KB_ERROR_INVALID_PARAMETER;
|
||||
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
|
||||
const KbInfo& current_info = consumer.GetInfo();
|
||||
|
||||
const KbInfo& current_info = handler.GetInfo();
|
||||
|
||||
if (port_no >= handler.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
|
||||
if (port_no >= consumer.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
|
||||
return not_an_error(CELL_KB_ERROR_NO_DEVICE);
|
||||
|
||||
KbData& current_data = handler.GetData(port_no);
|
||||
KbData& current_data = consumer.GetData(port_no);
|
||||
|
||||
if (current_info.is_null_handler || (current_info.info & CELL_KB_INFO_INTERCEPTED) || !is_input_allowed())
|
||||
{
|
||||
@@ -355,7 +378,7 @@ error_code cellKbRead(u32 port_no, vm::ptr<CellKbData> data)
|
||||
data->keycode[i] = current_data.buttons[i].m_keyCode;
|
||||
}
|
||||
|
||||
KbConfig& current_config = handler.GetConfig(port_no);
|
||||
KbConfig& current_config = consumer.GetConfig(port_no);
|
||||
|
||||
// For single character mode to work properly we need to "flush" the buffer after reading or else we'll constantly get the same key presses with each call.
|
||||
// Actual key repeats are handled by adding a new key code to the buffer periodically. Key releases are handled in a similar fashion.
|
||||
@@ -383,12 +406,13 @@ error_code cellKbSetCodeType(u32 port_no, u32 type)
|
||||
if (port_no >= CELL_KB_MAX_KEYBOARDS || type > CELL_KB_CODETYPE_ASCII)
|
||||
return CELL_KB_ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (port_no >= handler.GetKeyboards().size())
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
|
||||
|
||||
if (port_no >= consumer.GetKeyboards().size())
|
||||
return CELL_OK;
|
||||
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
|
||||
KbConfig& current_config = handler.GetConfig(port_no);
|
||||
KbConfig& current_config = consumer.GetConfig(port_no);
|
||||
current_config.code_type = type;
|
||||
|
||||
// can also return CELL_KB_ERROR_SYS_SETTING_FAILED
|
||||
@@ -413,12 +437,13 @@ error_code cellKbSetLEDStatus(u32 port_no, u8 led)
|
||||
if (led > 7)
|
||||
return CELL_KB_ERROR_SYS_SETTING_FAILED;
|
||||
|
||||
if (port_no >= handler.GetKeyboards().size() || handler.GetInfo().status[port_no] != CELL_KB_STATUS_CONNECTED)
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
|
||||
|
||||
if (port_no >= consumer.GetKeyboards().size() || consumer.GetInfo().status[port_no] != CELL_KB_STATUS_CONNECTED)
|
||||
return CELL_KB_ERROR_FATAL;
|
||||
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
|
||||
KbData& current_data = handler.GetData(port_no);
|
||||
KbData& current_data = consumer.GetData(port_no);
|
||||
current_data.led = static_cast<u32>(led);
|
||||
|
||||
return CELL_OK;
|
||||
@@ -438,16 +463,17 @@ error_code cellKbSetReadMode(u32 port_no, u32 rmode)
|
||||
if (port_no >= CELL_KB_MAX_KEYBOARDS || rmode > CELL_KB_RMODE_PACKET)
|
||||
return CELL_KB_ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (port_no >= handler.GetKeyboards().size())
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
|
||||
|
||||
if (port_no >= consumer.GetKeyboards().size())
|
||||
return CELL_OK;
|
||||
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
|
||||
KbConfig& current_config = handler.GetConfig(port_no);
|
||||
KbConfig& current_config = consumer.GetConfig(port_no);
|
||||
current_config.read_mode = rmode;
|
||||
|
||||
// Key repeat must be disabled in packet mode. But let's just always enable it otherwise.
|
||||
Keyboard& keyboard = handler.GetKeyboards()[port_no];
|
||||
Keyboard& keyboard = consumer.GetKeyboards()[port_no];
|
||||
keyboard.m_key_repeat = rmode != CELL_KB_RMODE_PACKET;
|
||||
|
||||
// can also return CELL_KB_ERROR_SYS_SETTING_FAILED
|
||||
@@ -471,16 +497,18 @@ error_code cellKbGetConfiguration(u32 port_no, vm::ptr<CellKbConfig> config)
|
||||
|
||||
std::lock_guard<std::mutex> lock(handler.m_mutex);
|
||||
|
||||
const KbInfo& current_info = handler.GetInfo();
|
||||
keyboard_consumer& consumer = handler.GetConsumer(keyboard_consumer::identifier::cellKb);
|
||||
|
||||
if (port_no >= handler.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
|
||||
const KbInfo& current_info = consumer.GetInfo();
|
||||
|
||||
if (port_no >= consumer.GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED)
|
||||
return not_an_error(CELL_KB_ERROR_NO_DEVICE);
|
||||
|
||||
// tests show that config is checked only after the device's status
|
||||
if (!config)
|
||||
return CELL_KB_ERROR_INVALID_PARAMETER;
|
||||
|
||||
const KbConfig& current_config = handler.GetConfig(port_no);
|
||||
const KbConfig& current_config = consumer.GetConfig(port_no);
|
||||
config->arrange = current_config.arrange;
|
||||
config->read_mode = current_config.read_mode;
|
||||
config->code_type = current_config.code_type;
|
||||
|
||||
@@ -1144,8 +1144,6 @@ error_code cellMicRemoveNotifyEventQueue(u64 key)
|
||||
|
||||
error_code cell_mic_read(s32 dev_num, vm::ptr<void> data, s32 max_bytes, /*CellMicSignalType*/u32 type)
|
||||
{
|
||||
// TODO: CELL_MICIN_ERROR_PARAM
|
||||
|
||||
auto& mic_thr = g_fxo->get<mic_thread>();
|
||||
const std::lock_guard lock(mic_thr.mutex);
|
||||
if (!mic_thr.init)
|
||||
@@ -1159,16 +1157,19 @@ error_code cell_mic_read(s32 dev_num, vm::ptr<void> data, s32 max_bytes, /*CellM
|
||||
if (!device.is_opened() || !(device.get_signal_types() & type))
|
||||
return CELL_MICIN_ERROR_NOT_OPEN;
|
||||
|
||||
if (!data)
|
||||
return not_an_error(0);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CELLMIC_SIGTYPE_DSP: return not_an_error(device.read_dsp(vm::_ptr<u8>(data.addr()), max_bytes));
|
||||
case CELLMIC_SIGTYPE_AUX: return CELL_OK; // TODO
|
||||
case CELLMIC_SIGTYPE_AUX: return not_an_error(0); // TODO
|
||||
case CELLMIC_SIGTYPE_RAW: return not_an_error(device.read_raw(vm::_ptr<u8>(data.addr()), max_bytes));
|
||||
default:
|
||||
fmt::throw_exception("Invalid CELLMIC_SIGTYPE %d", type);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
return not_an_error(0);
|
||||
}
|
||||
|
||||
error_code cellMicReadRaw(s32 dev_num, vm::ptr<void> data, s32 max_bytes)
|
||||
|
||||
@@ -157,9 +157,8 @@ struct CellMicInputStream
|
||||
|
||||
struct CellMicInputDefinition
|
||||
{
|
||||
// TODO: Data types
|
||||
volatile u32 uiDevId;
|
||||
CellMicInputStream data;
|
||||
be_t<u32> uiDevId;
|
||||
CellMicInputStream data;
|
||||
CellMicInputFormatI aux_format;
|
||||
CellMicInputFormatI raw_format;
|
||||
CellMicInputFormatI sig_format;
|
||||
@@ -182,13 +181,13 @@ struct CellMicStatus
|
||||
// --- End of cell definitions ---
|
||||
|
||||
|
||||
template <usz S>
|
||||
template <usz Size>
|
||||
class simple_ringbuf
|
||||
{
|
||||
public:
|
||||
simple_ringbuf()
|
||||
{
|
||||
m_container.resize(S);
|
||||
m_container.resize(Size);
|
||||
}
|
||||
|
||||
bool has_data() const
|
||||
@@ -200,19 +199,19 @@ public:
|
||||
{
|
||||
ensure(buf);
|
||||
|
||||
u32 to_read = size > m_used ? m_used : size;
|
||||
const u32 to_read = size > m_used ? m_used : size;
|
||||
if (!to_read)
|
||||
return 0;
|
||||
|
||||
u8* data = m_container.data();
|
||||
u32 new_tail = m_tail + to_read;
|
||||
u8* data = m_container.data();
|
||||
const u32 new_tail = m_tail + to_read;
|
||||
|
||||
if (new_tail >= S)
|
||||
if (new_tail >= Size)
|
||||
{
|
||||
u32 first_chunk_size = S - m_tail;
|
||||
const u32 first_chunk_size = Size - m_tail;
|
||||
std::memcpy(buf, data + m_tail, first_chunk_size);
|
||||
std::memcpy(buf + first_chunk_size, data, to_read - first_chunk_size);
|
||||
m_tail = (new_tail - S);
|
||||
m_tail = (new_tail - Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -227,30 +226,32 @@ public:
|
||||
|
||||
void write_bytes(const u8* buf, const u32 size)
|
||||
{
|
||||
ensure(size <= S);
|
||||
ensure(size <= Size);
|
||||
|
||||
if (u32 over_size = m_used + size; over_size > S)
|
||||
const u32 over_size = m_used + size;
|
||||
|
||||
if (over_size > Size)
|
||||
{
|
||||
m_tail += (over_size - S);
|
||||
if (m_tail > S)
|
||||
m_tail -= S;
|
||||
m_tail += (over_size - Size);
|
||||
if (m_tail > Size)
|
||||
m_tail -= Size;
|
||||
|
||||
m_used = S;
|
||||
m_used = Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_used = over_size;
|
||||
}
|
||||
|
||||
u8* data = m_container.data();
|
||||
u32 new_head = m_head + size;
|
||||
u8* data = m_container.data();
|
||||
const u32 new_head = m_head + size;
|
||||
|
||||
if (new_head >= S)
|
||||
if (new_head >= Size)
|
||||
{
|
||||
u32 first_chunk_size = S - m_head;
|
||||
const u32 first_chunk_size = Size - m_head;
|
||||
std::memcpy(data + m_head, buf, first_chunk_size);
|
||||
std::memcpy(data, buf + first_chunk_size, size - first_chunk_size);
|
||||
m_head = (new_head - S);
|
||||
m_head = (new_head - Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -259,7 +259,7 @@ error_code cellMouseGetData(u32 port_no, vm::ptr<CellMouseData> data)
|
||||
|
||||
error_code cellMouseGetDataList(u32 port_no, vm::ptr<CellMouseDataList> data)
|
||||
{
|
||||
sys_io.notice("cellMouseGetDataList(port_no=%d, data=0x%x)", port_no, data);
|
||||
sys_io.trace("cellMouseGetDataList(port_no=%d, data=0x%x)", port_no, data);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
@@ -406,7 +406,7 @@ error_code cellMouseGetTabletDataList(u32 port_no, vm::ptr<CellMouseTabletDataLi
|
||||
|
||||
error_code cellMouseGetRawData(u32 port_no, vm::ptr<CellMouseRawData> data)
|
||||
{
|
||||
sys_io.notice("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
sys_io.trace("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data);
|
||||
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ error_code cellMusicGetSelectionContext(vm::ptr<CellMusicSelectionContext> conte
|
||||
|
||||
if (!music.current_selection_context)
|
||||
{
|
||||
return CELL_MUSIC2_ERROR_NO_ACTIVE_CONTENT;
|
||||
return CELL_MUSIC_ERROR_NO_ACTIVE_CONTENT;
|
||||
}
|
||||
|
||||
*context = music.current_selection_context.get();
|
||||
@@ -325,7 +325,7 @@ error_code cellMusicGetContentsId(vm::ptr<CellSearchContentId> contents_id)
|
||||
|
||||
if (!music.current_selection_context)
|
||||
{
|
||||
return CELL_MUSIC2_ERROR_NO_ACTIVE_CONTENT;
|
||||
return CELL_MUSIC_ERROR_NO_ACTIVE_CONTENT;
|
||||
}
|
||||
|
||||
return music.current_selection_context.find_content_id(contents_id);
|
||||
@@ -408,6 +408,12 @@ error_code cellMusicGetContentsId2(vm::ptr<CellSearchContentId> contents_id)
|
||||
// HACKY
|
||||
auto& music = g_fxo->get<music_state>();
|
||||
std::lock_guard lock(music.mtx);
|
||||
|
||||
if (!music.current_selection_context)
|
||||
{
|
||||
return CELL_MUSIC2_ERROR_NO_ACTIVE_CONTENT;
|
||||
}
|
||||
|
||||
return music.current_selection_context.find_content_id(contents_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -227,6 +227,12 @@ error_code cell_music_decode_read(vm::ptr<void> buf, vm::ptr<u32> startTime, u64
|
||||
|
||||
std::memcpy(buf.get_ptr(), &dec.decoder.data[dec.read_pos], size_to_read);
|
||||
|
||||
if (size_to_read < reqSize)
|
||||
{
|
||||
// Set the rest of the buffer to zero to prevent loud pops at the end of the stream if the game ignores the readSize.
|
||||
std::memset(vm::static_ptr_cast<u8>(buf).get_ptr() + size_to_read, 0, reqSize - size_to_read);
|
||||
}
|
||||
|
||||
dec.read_pos += size_to_read;
|
||||
|
||||
s64 start_time_ms = 0;
|
||||
|
||||
@@ -425,14 +425,14 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_kook_key = false;
|
||||
bool is_hook_key = false;
|
||||
|
||||
switch (key_message.keycode)
|
||||
{
|
||||
case CELL_KEYC_NO_EVENT:
|
||||
{
|
||||
// Any shift/alt/ctrl key
|
||||
is_kook_key = key_message.mkey > 0 && (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ONLY_MODIFIER);
|
||||
is_hook_key = key_message.mkey > 0 && (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ONLY_MODIFIER);
|
||||
break;
|
||||
}
|
||||
case CELL_KEYC_E_ROLLOVER:
|
||||
@@ -473,18 +473,18 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
|
||||
case CELL_KEYC_MUHENKAN:
|
||||
{
|
||||
// Any function key or other special key like Delete
|
||||
is_kook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_FUNCTION_KEY);
|
||||
is_hook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_FUNCTION_KEY);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Any regular ascii key
|
||||
is_kook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ASCII_KEY);
|
||||
is_hook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ASCII_KEY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_kook_key)
|
||||
if (!is_hook_key)
|
||||
{
|
||||
cellOskDialog.notice("on_osk_key_input_entered: not a hook key: led=%d, mkey=%d, keycode=%d, hook_event_mode=%d", key_message.led, key_message.mkey, key_message.keycode, info.hook_event_mode.load());
|
||||
return;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user