Compare commits
355 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a8e62e1bc1 | |||
| 42aa8f263a | |||
| af95ff5f8b | |||
| f0093375b8 | |||
| 7d26e61d82 | |||
| e035000864 | |||
| 6db5d83615 | |||
| 86a04a867b | |||
| f3823232e0 | |||
| 6b8b23c401 | |||
| 6fd2a9b677 | |||
| da559b5568 | |||
| 24587ab459 | |||
| c7e49b58a8 | |||
| c5680c29bd | |||
| 1144121d08 | |||
| fa6736e69d | |||
| 10e6b43a2f | |||
| 0809e7cf9f | |||
| 12fd43e1c6 | |||
| 397a795e75 | |||
| 1f9ade0ab6 | |||
| 83407c386c | |||
| b791d90b35 | |||
| 574e934bf3 | |||
| b57ea3a229 | |||
| 771f3c49e5 | |||
| 13e1305a76 | |||
| 9214df482e | |||
| b1a9e87ecf | |||
| 0a34403ef8 | |||
| e5bb0ba004 | |||
| 2147fe479c | |||
| 93e7988df7 | |||
| 7801e8368b | |||
| 91d7f28c67 | |||
| 8171c7766c | |||
| 3f69ceac40 | |||
| 4be9e0d396 | |||
| 6bd8a93ff4 | |||
| e39797d860 | |||
| 254ddcad51 | |||
| abd8bd6f36 | |||
| fd6c33980b | |||
| 2d5d5746d1 | |||
| 314b63eebf | |||
| f382d54e9a | |||
| 9581e4ff98 | |||
| b7a57ac4b0 | |||
| df5295ae85 | |||
| c8ad8b18bb | |||
| 44cc254620 | |||
| cef512a123 | |||
| 7895d43a98 | |||
| 4f4a80cc04 | |||
| d6597038ee | |||
| ec3e8de780 | |||
| f667b52cca | |||
| 48b54131f6 | |||
| d172b9add6 | |||
| 2d9f21a2ea | |||
| 247759b75b | |||
| 987166f4da | |||
| 90d368ae30 | |||
| a2d33a7d76 | |||
| 51f9310b9f | |||
| dca3d477c9 | |||
| 02cdf8ac63 | |||
| 6b370e85d5 | |||
| 05e80aad90 | |||
| 4ad255b8e0 | |||
| 09a60cdefa | |||
| eacf5a3813 | |||
| e951c619c5 | |||
| 6c5b8dc31c | |||
| fd0e7a4efa | |||
| a4c4548c3a | |||
| 8efc29972d | |||
| 7977fbb9c5 | |||
| 681bab558b | |||
| 107107107c | |||
| 3a804674c9 | |||
| 91673f8fdc | |||
| 86919ec0e1 | |||
| 0e320d17c1 | |||
| d063f0b335 | |||
| 781b2b4548 | |||
| bb65e6797f | |||
| b0f0641564 | |||
| 16aae4eb77 | |||
| 3a1082fe0d | |||
| dba2baba9c | |||
| ffe00e8619 | |||
| 3fa45ff994 | |||
| 73ff506b88 | |||
| 3a1676e558 | |||
| 0db9850a73 | |||
| 11ee1f3eb2 | |||
| 14951d8713 | |||
| 065ee621b8 | |||
| 12c83b340d | |||
| d2897bc6a0 | |||
| 5920372929 | |||
| 1fa82eec89 | |||
| 8c2fd50957 | |||
| 2f7d38bb81 | |||
| 4f8b5849b7 | |||
| 7f216f2581 | |||
| 6ffd38c393 | |||
| 801e7f3c2f | |||
| c7140df5f8 | |||
| 6b5f0957ce | |||
| f2ed50e6b0 | |||
| 511ca82e30 | |||
| 00274bb4da | |||
| a4d94a83b9 | |||
| 0de9960772 | |||
| aa7c9dd15d | |||
| 628354ba92 | |||
| 17b1a34ebf | |||
| 349f251d14 | |||
| 3942a464fe | |||
| 2331dc3256 | |||
| 8c3fb3998c | |||
| 327c577024 | |||
| d572d90bb7 | |||
| b42fae0989 | |||
| d92008abe4 | |||
| 484a3e6824 | |||
| 08b02efc6c | |||
| 4728478247 | |||
| 4704367382 | |||
| 14cca55b50 | |||
| 248f9424ac | |||
| b404d37eb0 | |||
| 14170afe8a | |||
| 58fdf58150 | |||
| 000ec71629 | |||
| 3e794e7fdb | |||
| c38ca21a81 | |||
| f923eaf09a | |||
| 5b980b99a0 | |||
| 22240777aa | |||
| f95395b351 | |||
| df24cff0b1 | |||
| 6dda047128 | |||
| e9efa73eed | |||
| 1c0b3fc7e0 | |||
| 580bd2b25e | |||
| d6aa834b5f | |||
| f526027778 | |||
| 949e93bec7 | |||
| cd016be86e | |||
| 84753db574 | |||
| ef0bee9228 | |||
| a60cee6536 | |||
| 108846055b | |||
| b9179de288 | |||
| 0c4b2ff06b | |||
| 8c9090fd03 | |||
| ef66b002e0 | |||
| 0d1c0e72a6 | |||
| 37f24d8c1c | |||
| 3571e6ef85 | |||
| ed542b2cb4 | |||
| b950651487 | |||
| 09700360f7 | |||
| 29a6db8960 | |||
| 6d737e61fd | |||
| d874ca5d8c | |||
| 1adc408ad7 | |||
| 83026fd263 | |||
| 92824b6729 | |||
| 7563655221 | |||
| 6889b48973 | |||
| 9766d87126 | |||
| bba528e2ae | |||
| 7c39c1de9b | |||
| 81c2fb508b | |||
| 350257e1a4 | |||
| 0e07d3c58f | |||
| 0d4543ca2a | |||
| 20cc2d7267 | |||
| 39a832d07f | |||
| 13136ec083 | |||
| 31a5a77ae5 | |||
| 1c014299eb | |||
| 7c47b0029c | |||
| 61d9852632 | |||
| cb2748ae08 | |||
| 900d7df40f | |||
| 6837370a62 | |||
| 9cfdd8afea | |||
| 7b24df0957 | |||
| 122555fb66 | |||
| d836033212 | |||
| 510041a873 | |||
| 8b4b6ba946 | |||
| d36a715b24 | |||
| 599e00d6da | |||
| 3cd8891ab8 | |||
| e3e6fb5489 | |||
| a9303acfdf | |||
| b4ec4f46b8 | |||
| 6ee9d0f35f | |||
| a0040e6fb1 | |||
| 28d7af313b | |||
| 39ef39aa4e | |||
| d9a1308624 | |||
| 56dd09f4fe | |||
| de495952fd | |||
| 1ce5349199 | |||
| dcd011048d | |||
| 12e3c9e08b | |||
| 262ff01619 | |||
| 76ccaf5e6f | |||
| 47e4a95d8f | |||
| c0bafbc804 | |||
| 61c64d1060 | |||
| 3e1e1a683c | |||
| 18f59d3be8 | |||
| bf739aa156 | |||
| 43b7d1fe98 | |||
| cc21d1b3cf | |||
| 08333e0876 | |||
| 2f93df480b | |||
| 56fe450959 | |||
| 6f9adbd162 | |||
| f48c535802 | |||
| 5f7e5a9844 | |||
| 3f3b4bc363 | |||
| 68466f05b6 | |||
| e6b4655142 | |||
| f690d55045 | |||
| d523f9cc6b | |||
| 7ca15c60bb | |||
| 8abd3e8bb4 | |||
| 6730dc1dc4 | |||
| 6b40d69a8f | |||
| d6420b8803 | |||
| a4ad0a9468 | |||
| a09fd80905 | |||
| 0617e9e14b | |||
| cb4711203b | |||
| e3e39e8de3 | |||
| 209b14fbac | |||
| 04c9d01390 | |||
| c9d8e59dbf | |||
| 86b194014b | |||
| e7c827f73b | |||
| abe498f35c | |||
| 49c02854f5 | |||
| cccfb89aa0 | |||
| 2981867375 | |||
| 56d922999f | |||
| 813c3298ad | |||
| 02832d9623 | |||
| 0ab36ef44d | |||
| 9bb46aa944 | |||
| 474baca6d8 | |||
| 88d0b7d135 | |||
| aea1ec2594 | |||
| 22a7b026e7 | |||
| c8d4a0dcdc | |||
| f16949c292 | |||
| f910a152f1 | |||
| 270c2e58a0 | |||
| a586d1c529 | |||
| 09b047611b | |||
| e5005597fe | |||
| 38bfefcdfa | |||
| 44fe6f6d39 | |||
| 4fe17fcecf | |||
| 276ee81da8 | |||
| 5e158bd3f2 | |||
| 2b924175aa | |||
| 37a722cc1d | |||
| a84223bdc6 | |||
| 4df1a938b1 | |||
| 94a3b1cfe8 | |||
| a21c6c4628 | |||
| 58f0fa3ca5 | |||
| 97bd8f7bc1 | |||
| 4c0ef37a5c | |||
| 1df8f52a9f | |||
| f9434091c3 | |||
| 59f253ba24 | |||
| c52d447381 | |||
| 524b065bc8 | |||
| f7b55ec8d4 | |||
| e7fc2bfa3b | |||
| 22e3075c64 | |||
| 09ead539a5 | |||
| 5272dd951b | |||
| 7eee9e7b05 | |||
| e5eb727110 | |||
| 7352a5a495 | |||
| 3d859a7493 | |||
| 3587cfd2df | |||
| de2be90636 | |||
| 9f35c3f52d | |||
| 22910c02a9 | |||
| fef8905dc2 | |||
| 0f7534c755 | |||
| 4d0330bf82 | |||
| 026efd96b2 | |||
| f6af5ff13a | |||
| 0d7b7585a8 | |||
| 6283600b84 | |||
| f6e04ffdd2 | |||
| 44b42f68fd | |||
| 56241838c0 | |||
| 26475f8f40 | |||
| ff5e31f396 | |||
| 59b1c324a9 | |||
| 1f627caa81 | |||
| 7dc3a50ddf | |||
| cfe08de951 | |||
| 48ad959697 | |||
| 05881ffa62 | |||
| 8b3ed7b599 | |||
| 48ad7ca3a0 | |||
| cbec04cd0f | |||
| 3fde455932 | |||
| ba727e13ae | |||
| 2248007c9a | |||
| 2359ba9aed | |||
| b736691bde | |||
| 50bf528f3f | |||
| 7e3eab9915 | |||
| dc0793b731 | |||
| c194804fec | |||
| d41e405420 | |||
| 516cb959cb | |||
| 704e74b904 | |||
| b70f08d850 | |||
| 53f2594983 | |||
| 7573d7289b | |||
| f9abe40494 | |||
| 88bb26afb4 | |||
| dac0baac0d | |||
| f7eacf70ec | |||
| 067b35217a | |||
| c3888f5bbb | |||
| af3ef02ca0 | |||
| c49ebba648 | |||
| 933d96af5f | |||
| bf6044fced | |||
| 1a0392bf15 | |||
| ad00c44231 | |||
| 69f321a471 | |||
| 37383f4217 | |||
| b84e95d768 | |||
| 4369fb234e | |||
| 58040d478a |
+10
-4
@@ -7,10 +7,16 @@ git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ { print $3 }'
|
||||
|
||||
# Prefer newer Clang than in base system (see also .ci/install-freebsd.sh)
|
||||
# libc++ isn't in llvm* packages, so download manually
|
||||
fetch https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.0/libcxx-12.0.0.src.tar.xz
|
||||
tar xf libcxx-12.0.0.src.tar.xz
|
||||
export CC=clang12 CXX=clang++12
|
||||
export CXXFLAGS="$CXXFLAGS -nostdinc++ -D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS -isystem $PWD/libcxx-12.0.0.src/include"
|
||||
fetch https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-13.0.1-rc1.tar.gz
|
||||
tar xf llvm*.tar.gz
|
||||
export CC=clang13 CXX=clang++13
|
||||
cmake -B libcxx_build -G Ninja -S llvm*/libcxx \
|
||||
-DLLVM_CCACHE_BUILD=ON \
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=libcxx_prefix
|
||||
cmake --build libcxx_build
|
||||
cmake --install libcxx_build
|
||||
export CXXFLAGS="$CXXFLAGS -nostdinc++ -isystem$PWD/libcxx_prefix/include/c++/v1"
|
||||
export LDFLAGS="$LDFLAGS -nostdlib++ -L$PWD/libcxx_prefix/lib -l:libc++.a -lcxxrt"
|
||||
|
||||
CONFIGURE_ARGS="
|
||||
-DWITH_LLVM=OFF
|
||||
|
||||
+61
-20
@@ -1,27 +1,68 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
export CCACHE_SLOPPINESS=pch_defines,time_macros
|
||||
export CMAKE_PREFIX_PATH=/usr/local/opt/qt5/
|
||||
export PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||
brew update
|
||||
brew install llvm@13 molten-vk vulkan-headers sdl2 nasm qt@5 ninja cmake glew git p7zip create-dmg ccache
|
||||
|
||||
# Setup vulkan and gfx-rs/portability
|
||||
curl -sLO https://github.com/gfx-rs/portability/releases/download/latest/gfx-portability-macos-latest.zip
|
||||
unzip -: gfx-portability-macos-latest.zip
|
||||
curl -sLO https://github.com/KhronosGroup/Vulkan-Headers/archive/sdk-1.1.106.0.zip
|
||||
unzip -: sdk-*.zip
|
||||
mkdir vulkan-sdk
|
||||
ln -s "${PWD}"/Vulkan-Headers*/include vulkan-sdk/include
|
||||
mkdir vulkan-sdk/lib
|
||||
cp target/release/libportability.dylib vulkan-sdk/lib/libVulkan.dylib
|
||||
# Let macdeployqt locate and install Vulkan library
|
||||
install_name_tool -id "${PWD}"/vulkan-sdk/lib/libVulkan.dylib vulkan-sdk/lib/libVulkan.dylib
|
||||
export VULKAN_SDK="${PWD}/vulkan-sdk"
|
||||
export CXX=clang++
|
||||
export CC=clang
|
||||
export Qt5_DIR="/usr/local/Cellar/qt@5/5.15.2_1/lib/cmake/Qt5"
|
||||
export PATH="/usr/local/opt/llvm/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin"
|
||||
export LDFLAGS="-L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib"
|
||||
export CPPFLAGS="-I/usr/local/opt/llvm/include -msse -msse2 -mcx16 -no-pie"
|
||||
export CPLUS_INCLUDE_PATH="/usr/local/opt/molten-vk/include"
|
||||
export VULKAN_SDK="/usr/local/opt/molten-vk"
|
||||
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
|
||||
|
||||
# Pull all the submodules except llvm
|
||||
# Note: Tried to use git submodule status, but it takes over 20 seconds
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
|
||||
git submodule update --init --recursive --depth 1
|
||||
|
||||
# 3rdparty fixes
|
||||
ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib"
|
||||
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
|
||||
|
||||
cd ..
|
||||
mkdir build && cd build || exit 1
|
||||
cmake .. -DWITH_LLVM=OFF -DUSE_NATIVE_INSTRUCTIONS=OFF -G Ninja
|
||||
cmake -DUSE_DISCORD_RPC=OFF -DUSE_VULKAN=ON -DUSE_ALSA=OFF -DUSE_PULSE=OFF -DUSE_AUDIOUNIT=ON \
|
||||
-G Ninja -DLLVM_CCACHE_BUILD=OFF -DLLVM_TARGETS_TO_BUILD="X86" -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF \
|
||||
-DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF \
|
||||
-DLLVM_INCLUDE_UTILS=OFF -DLLVM_USE_PERF=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF \
|
||||
-DCMAKE_CXX_STANDARD=20 -DUSE_NATIVE_INSTRUCTIONS=OFF \
|
||||
../cirrus-ci-build/
|
||||
ninja
|
||||
|
||||
cd ../cirrus-ci-build/
|
||||
COMM_TAG="$(grep 'version{.*}' rpcs3/rpcs3_version.cpp | awk -F[\{,] '{printf "%d.%d.%d", $2, $3, $4}')"
|
||||
COMM_COUNT="$(git rev-list --count HEAD)"
|
||||
COMM_HASH="$(git rev-parse --short=8 HEAD)"
|
||||
cd ../build/bin
|
||||
|
||||
mkdir "rpcs3.app/Contents/lib/"
|
||||
cp "/usr/local/opt/llvm/lib/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
|
||||
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
|
||||
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
|
||||
"rpcs3.app/Contents/Frameworks/QtQmlModels.framework" \
|
||||
"rpcs3.app/Contents/Frameworks/QtQuick.framework" \
|
||||
"rpcs3.app/Contents/Frameworks/QtVirtualKeyboard.framework" \
|
||||
"rpcs3.app/Contents/Plugins/platforminputcontexts" \
|
||||
"rpcs3.app/Contents/Plugins/virtualkeyboard"
|
||||
|
||||
mv rpcs3.app RPCS3_.app
|
||||
mv RPCS3_.app RPCS3.app
|
||||
|
||||
echo "[InternetShortcut]" > Quickstart.url
|
||||
echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url
|
||||
echo "IconIndex=0" >> Quickstart.url
|
||||
|
||||
create-dmg --volname RPCS3 \
|
||||
--window-size 800 400 \
|
||||
--icon-size 100 \
|
||||
--icon rpcs3.app 200 190 \
|
||||
--add-file Quickstart.url Quickstart.url 400 20 \
|
||||
--hide-extension rpcs3.app \
|
||||
--hide-extension Quickstart.url \
|
||||
--app-drop-link 600 185 \
|
||||
--skip-jenkins \
|
||||
"$ARTDIR/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos.dmg" \
|
||||
RPCS3.app
|
||||
|
||||
7z a -mx9 rpcs3-v"${COMM_TAG}"-"${COMM_COUNT}"-"${COMM_HASH}"_macos.7z RPCS3.app
|
||||
mv rpcs3-v"${COMM_TAG}"-"${COMM_COUNT}"-"${COMM_HASH}"_macos.7z "$ARTDIR"
|
||||
|
||||
@@ -18,6 +18,11 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
||||
# Embed newer libstdc++ for distros that don't come with it (ubuntu 16.04)
|
||||
mkdir -p appdir/usr/optional/ ; mkdir -p appdir/usr/optional/libstdc++/
|
||||
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./appdir/usr/optional/libstdc++/
|
||||
|
||||
# Remove libwayland-client because it has platform-dependent exports and breaks other OSes
|
||||
rm -f ./appdir/usr/lib/libwayland-client.so*
|
||||
|
||||
# Install latest appimage runner
|
||||
rm ./appdir/AppRun
|
||||
curl -sL https://github.com/RPCS3/AppImageKit-checkrt/releases/download/continuous2/AppRun-patched-x86_64 -o ./appdir/AppRun
|
||||
chmod a+x ./appdir/AppRun
|
||||
|
||||
@@ -9,7 +9,7 @@ export ASSUME_ALWAYS_YES=true
|
||||
pkg info # debug
|
||||
|
||||
# Prefer newer Clang than in base system (see also .ci/build-freebsd.sh)
|
||||
pkg install llvm12
|
||||
pkg install llvm13
|
||||
|
||||
# Mandatory dependencies (qt5-dbus and qt5-gui are pulled via qt5-widgets)
|
||||
pkg install git ccache cmake ninja qt5-qmake qt5-buildtools qt5-widgets qt5-concurrent qt5-multimedia qt5-svg glew openal-soft ffmpeg
|
||||
|
||||
+20
@@ -111,3 +111,23 @@ freebsd_task:
|
||||
folder: /tmp/ccache_dir
|
||||
install_script: "sh -ex ./.ci/install-freebsd.sh"
|
||||
script: "./.ci/build-freebsd.sh"
|
||||
|
||||
macos_task:
|
||||
timeout_in: 120m
|
||||
ccache_cache:
|
||||
folder: /tmp/ccache_dir
|
||||
matrix:
|
||||
- name: Cirrus macOS
|
||||
osx_instance:
|
||||
image: big-sur-base
|
||||
mac_script:
|
||||
- mkdir artifacts
|
||||
- ".ci/build-mac.sh"
|
||||
env:
|
||||
ARTDIR: ${CIRRUS_WORKING_DIR}/artifacts/
|
||||
CCACHE_DIR: "/tmp/ccache_dir"
|
||||
CCACHE_MAXSIZE: 300M
|
||||
CI_HAS_ARTIFACTS: true
|
||||
artifacts:
|
||||
name: Artifact
|
||||
path: "artifacts/rpcs3-*_macos.*"
|
||||
|
||||
+10
-2
@@ -4,8 +4,8 @@
|
||||
ignore = dirty
|
||||
[submodule "asmjit"]
|
||||
path = 3rdparty/asmjit/asmjit
|
||||
url = ../../asmjit/asmjit.git
|
||||
branch = oldstable
|
||||
url = ../../RPCS3/asmjit.git
|
||||
branch = aarch64
|
||||
ignore = dirty
|
||||
[submodule "llvm"]
|
||||
path = llvm
|
||||
@@ -68,3 +68,11 @@
|
||||
path = 3rdparty/flatbuffers
|
||||
url = ../../google/flatbuffers.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/cubeb/cubeb"]
|
||||
path = 3rdparty/cubeb/cubeb
|
||||
url = ../../mozilla/cubeb.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/SoundTouch/soundtouch"]
|
||||
path = 3rdparty/SoundTouch/soundtouch
|
||||
url = ../../RPCS3/soundtouch.git
|
||||
ignore = dirty
|
||||
|
||||
Vendored
+5
-33
@@ -128,38 +128,11 @@ target_include_directories(3rdparty_stblib INTERFACE stblib/include)
|
||||
# DiscordRPC
|
||||
add_subdirectory(discord-rpc)
|
||||
|
||||
# Cubeb
|
||||
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
|
||||
|
||||
# ALSA
|
||||
set(ALSA_TARGET 3rdparty_dummy_lib)
|
||||
|
||||
if(USE_ALSA)
|
||||
find_package(ALSA)
|
||||
if(ALSA_FOUND)
|
||||
add_library(3rdparty_alsa INTERFACE)
|
||||
target_compile_definitions(3rdparty_alsa INTERFACE -DHAVE_ALSA)
|
||||
target_include_directories(3rdparty_alsa SYSTEM INTERFACE ${ALSA_INCLUDE_DIRS})
|
||||
target_link_libraries(3rdparty_alsa INTERFACE ${ALSA_LIBRARIES})
|
||||
|
||||
set(ALSA_TARGET 3rdparty_alsa)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# Pulse
|
||||
set(PULSE_TARGET 3rdparty_dummy_lib)
|
||||
if(USE_PULSE)
|
||||
pkg_check_modules(PULSE libpulse-simple)
|
||||
|
||||
if(PULSE_FOUND)
|
||||
add_library(3rdparty_pulse INTERFACE)
|
||||
target_compile_definitions(3rdparty_pulse INTERFACE -DHAVE_PULSE)
|
||||
target_include_directories(3rdparty_pulse SYSTEM
|
||||
INTERFACE ${PULSE_INCLUDE_DIRS})
|
||||
target_link_libraries(3rdparty_pulse INTERFACE ${PULSE_LDFLAGS})
|
||||
|
||||
set(PULSE_TARGET 3rdparty_pulse)
|
||||
endif()
|
||||
endif()
|
||||
# SoundTouch
|
||||
add_subdirectory(SoundTouch EXCLUDE_FROM_ALL)
|
||||
|
||||
# libevdev
|
||||
set(LIBEVDEV_TARGET 3rdparty_dummy_lib)
|
||||
@@ -334,8 +307,6 @@ add_library(3rdparty::libpng ALIAS ${LIBPNG_TARGET})
|
||||
add_library(3rdparty::opengl ALIAS 3rdparty_opengl)
|
||||
add_library(3rdparty::stblib ALIAS 3rdparty_stblib)
|
||||
add_library(3rdparty::discordRPC ALIAS 3rdparty_discordRPC)
|
||||
add_library(3rdparty::alsa ALIAS ${ALSA_TARGET})
|
||||
add_library(3rdparty::pulse ALIAS ${PULSE_TARGET})
|
||||
add_library(3rdparty::faudio ALIAS ${FAUDIO_TARGET})
|
||||
add_library(3rdparty::libevdev ALIAS ${LIBEVDEV_TARGET})
|
||||
add_library(3rdparty::vulkan ALIAS ${VULKAN_TARGET})
|
||||
@@ -344,3 +315,4 @@ add_library(3rdparty::ffmpeg ALIAS 3rdparty_ffmpeg)
|
||||
add_library(3rdparty::glew ALIAS 3rdparty_glew)
|
||||
add_library(3rdparty::wolfssl ALIAS wolfssl)
|
||||
add_library(3rdparty::libcurl ALIAS libcurl)
|
||||
add_library(3rdparty::soundtouch ALIAS soundtouch)
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/FAudio updated: 28528bc885...caf9754455
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
add_library(soundtouch STATIC EXCLUDE_FROM_ALL
|
||||
soundtouch/source/SoundTouch/AAFilter.cpp
|
||||
soundtouch/source/SoundTouch/FIFOSampleBuffer.cpp
|
||||
soundtouch/source/SoundTouch/FIRFilter.cpp
|
||||
soundtouch/source/SoundTouch/InterpolateCubic.cpp
|
||||
soundtouch/source/SoundTouch/InterpolateLinear.cpp
|
||||
soundtouch/source/SoundTouch/InterpolateShannon.cpp
|
||||
soundtouch/source/SoundTouch/RateTransposer.cpp
|
||||
soundtouch/source/SoundTouch/SoundTouch.cpp
|
||||
soundtouch/source/SoundTouch/sse_optimized.cpp
|
||||
soundtouch/source/SoundTouch/TDStretch.cpp
|
||||
)
|
||||
|
||||
target_include_directories(soundtouch PRIVATE
|
||||
soundtouch/source/SoundTouch
|
||||
soundtouch/include)
|
||||
|
||||
target_include_directories(soundtouch INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/soundtouch/include>
|
||||
$<INSTALL_INTERFACE:/soundtouch/include>)
|
||||
|
||||
set_property(TARGET soundtouch PROPERTY FOLDER "3rdparty/")
|
||||
|
||||
target_compile_definitions(soundtouch PUBLIC
|
||||
ST_NO_EXCEPTION_HANDLING
|
||||
USE_MULTICH_ALWAYS
|
||||
SOUNDTOUCH_FLOAT_SAMPLES;
|
||||
)
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|X86|amd64|AMD64|em64t|EM64T)")
|
||||
target_compile_definitions(soundtouch PUBLIC
|
||||
SOUNDTOUCH_ALLOW_SSE
|
||||
)
|
||||
endif ()
|
||||
+1
Submodule 3rdparty/SoundTouch/soundtouch added at 83cfba67b6
+77
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="soundtouch\include\FIFOSampleBuffer.h" />
|
||||
<ClInclude Include="soundtouch\include\FIFOSamplePipe.h" />
|
||||
<ClInclude Include="soundtouch\include\SoundTouch.h" />
|
||||
<ClInclude Include="soundtouch\include\STTypes.h" />
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\AAFilter.h" />
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\FIRFilter.h" />
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\InterpolateCubic.h" />
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\InterpolateLinear.h" />
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\InterpolateShannon.h" />
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\RateTransposer.h" />
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\TDStretch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\AAFilter.cpp" />
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\FIFOSampleBuffer.cpp" />
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\FIRFilter.cpp" />
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\InterpolateCubic.cpp" />
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\InterpolateLinear.cpp" />
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\InterpolateShannon.cpp" />
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\RateTransposer.cpp" />
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\SoundTouch.cpp" />
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\sse_optimized.cpp" />
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\TDStretch.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{508c291a-3d18-49f5-b25d-f7c8db92cb21}</ProjectGuid>
|
||||
<RootNamespace>soundtouch</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<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 Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_default.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_release.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>SOUNDTOUCH_ALLOW_SSE;ST_NO_EXCEPTION_HANDLING;USE_MULTICH_ALWAYS;SOUNDTOUCH_FLOAT_SAMPLES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>./soundtouch/source/SoundTouch;./soundtouch/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="soundtouch\include\FIFOSampleBuffer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\include\FIFOSamplePipe.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\include\SoundTouch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\include\STTypes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\FIRFilter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\InterpolateCubic.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\InterpolateLinear.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\InterpolateShannon.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\RateTransposer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\TDStretch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="soundtouch\source\SoundTouch\AAFilter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\InterpolateLinear.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\InterpolateShannon.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\RateTransposer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\SoundTouch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\sse_optimized.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\TDStretch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\AAFilter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\FIFOSampleBuffer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\FIRFilter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="soundtouch\source\SoundTouch\InterpolateCubic.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Vendored
+1
-1
Submodule 3rdparty/asmjit/asmjit updated: 723f58581a...fc2a5d82f7
Vendored
+132
-52
@@ -11,66 +11,146 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="asmjit\src\asmjit\base\arch.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\assembler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\codebuilder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\codecompiler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\codeemitter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\codeholder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\constpool.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\cpuinfo.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\func.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\globals.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\inst.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\logging.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\osutils.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\operand.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\regalloc.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\runtime.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\string.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\vmem.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\zone.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\archtraits.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\assembler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\builder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\codeholder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\codewriter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\compiler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\constpool.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\cpuinfo.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\emithelper.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\emitter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\emitterutils.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\environment.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\errorhandler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\formatter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\funcargscontext.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\func.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\globals.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\inst.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\jitallocator.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\jitruntime.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\logger.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\operand.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\osutils.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\ralocal.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\rapass.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\rastack.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\string.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\support.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\target.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\type.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\virtmem.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zone.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonehash.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonelist.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonestack.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonetree.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonevector.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86assembler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86builder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86compiler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86inst.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86instimpl.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86internal.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86logging.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86emithelper.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86formatter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86func.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86instapi.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86instdb.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86operand.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86operand_regs.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86regalloc.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86rapass.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64assembler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64builder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64compiler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64emithelper.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64instapi.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64instdb.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64operand.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64rapass.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\armformatter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\armfunc.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="asmjit\src\asmjit\base\arch.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\assembler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\codebuilder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\codecompiler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\codeemitter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\codeholder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\constpool.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\context_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\cpuinfo.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\func.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\logging.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\globals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\inst.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\lock.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\operand.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\osutils.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\regalloc_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\runtime.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\string.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\vectypes.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\vmem.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\zone.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\api-build_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\api-config.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\archcommons.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\archtraits.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\assembler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\builder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\codebuffer.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\codeholder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\codewriter_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\compilerdefs.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\compiler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\constpool.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\cpuinfo.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\emithelper_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\emitter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\emitterutils_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\environment.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\errorhandler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\formatter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\formatter_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\funcargscontext_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\func.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\globals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\inst.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\jitallocator.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\jitruntime.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\logger.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\misc_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\operand.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\osutils.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\osutils_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\raassignment_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\rabuilders_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\radefs_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\ralocal_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\rapass_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\rastack_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\string.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\support.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\target.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\type.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\virtmem.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zone.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonehash.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonelist.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonestack.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonestring.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonetree.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonevector.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86archtraits_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86assembler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86builder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86compiler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86inst.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86instimpl_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86internal_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86logging_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86emithelper_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86emitter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86formatter_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86func_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86globals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86instapi_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86instdb.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86instdb_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86opcode_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86operand.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86regalloc_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86rapass_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64assembler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64builder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64compiler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64emithelper_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64emitter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64globals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64instapi_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64operand.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64rapass_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64utils.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armarchtraits_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armformatter_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armfunc_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armglobals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armoperand.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{AC40FF01-426E-4838-A317-66354CEFAE88}</ProjectGuid>
|
||||
|
||||
+132
-52
@@ -1,65 +1,145 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="asmjit\src\asmjit\base\arch.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\assembler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\codebuilder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\codecompiler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\codeemitter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\codeholder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\constpool.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\cpuinfo.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\func.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\globals.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\inst.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\logging.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\osutils.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\operand.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\regalloc.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\runtime.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\string.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\vmem.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\base\zone.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\archtraits.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\assembler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\builder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\codeholder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\codewriter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\compiler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\constpool.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\cpuinfo.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\emithelper.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\emitter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\emitterutils.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\environment.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\errorhandler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\formatter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\funcargscontext.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\func.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\globals.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\inst.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\jitallocator.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\jitruntime.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\logger.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\operand.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\osutils.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\ralocal.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\rapass.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\rastack.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\string.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\support.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\target.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\type.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\virtmem.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zone.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonehash.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonelist.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonestack.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonetree.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\core\zonevector.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86assembler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86builder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86compiler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86inst.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86instimpl.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86internal.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86logging.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86emithelper.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86formatter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86func.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86instapi.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86instdb.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86operand.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86operand_regs.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86regalloc.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\x86\x86rapass.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64assembler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64builder.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64compiler.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64emithelper.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64instapi.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64instdb.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64operand.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\a64rapass.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\armformatter.cpp" />
|
||||
<ClCompile Include="asmjit\src\asmjit\arm\armfunc.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="asmjit\src\asmjit\base\arch.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\assembler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\codebuilder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\codecompiler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\codeemitter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\codeholder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\constpool.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\context_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\cpuinfo.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\func.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\logging.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\globals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\inst.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\lock.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\operand.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\osutils.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\regalloc_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\runtime.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\string.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\vectypes.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\vmem.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\base\zone.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\api-build_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\api-config.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\archcommons.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\archtraits.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\assembler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\builder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\codebuffer.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\codeholder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\codewriter_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\compilerdefs.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\compiler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\constpool.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\cpuinfo.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\emithelper_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\emitter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\emitterutils_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\environment.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\errorhandler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\formatter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\formatter_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\funcargscontext_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\func.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\globals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\inst.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\jitallocator.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\jitruntime.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\logger.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\misc_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\operand.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\osutils.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\osutils_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\raassignment_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\rabuilders_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\radefs_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\ralocal_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\rapass_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\rastack_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\string.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\support.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\target.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\type.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\virtmem.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zone.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonehash.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonelist.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonestack.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonestring.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonetree.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\core\zonevector.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86archtraits_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86assembler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86builder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86compiler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86inst.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86instimpl_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86internal_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86logging_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86emithelper_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86emitter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86formatter_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86func_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86globals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86instapi_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86instdb.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86instdb_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86opcode_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86operand.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86regalloc_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\x86\x86rapass_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64assembler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64builder.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64compiler.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64emithelper_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64emitter.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64globals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64instapi_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64instdb_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64operand.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64rapass_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\a64utils.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armarchtraits_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armformatter_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armfunc_p.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armglobals.h" />
|
||||
<ClInclude Include="asmjit\src\asmjit\arm\armoperand.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
# Cubeb
|
||||
|
||||
function(add_sanitizers ...)
|
||||
endfunction(add_sanitizers)
|
||||
|
||||
set(BUILD_SHARED_LIBS FALSE CACHE BOOL "Don't build shared libs")
|
||||
set(BUILD_TESTS FALSE CACHE BOOL "Don't build tests")
|
||||
set(BUILD_RUST_LIBS FALSE CACHE BOOL "Don't build rust libs")
|
||||
set(BUILD_TOOLS FALSE CACHE BOOL "Don't build tools")
|
||||
|
||||
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
|
||||
add_library(3rdparty::cubeb ALIAS cubeb)
|
||||
+1
Submodule 3rdparty/cubeb/cubeb added at d512bfa07a
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define CUBEB_EXPORT
|
||||
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="cubeb\src\cubeb.c" />
|
||||
<ClCompile Include="cubeb\src\cubeb_log.cpp" />
|
||||
<ClCompile Include="cubeb\src\cubeb_mixer.cpp" />
|
||||
<ClCompile Include="cubeb\src\cubeb_resampler.cpp" />
|
||||
<ClCompile Include="cubeb\src\cubeb_strings.c" />
|
||||
<ClCompile Include="cubeb\src\cubeb_utils.cpp" />
|
||||
<ClCompile Include="cubeb\src\cubeb_wasapi.cpp" />
|
||||
<ClCompile Include="cubeb\src\cubeb_winmm.c" />
|
||||
<ClCompile Include="cubeb\src\speex\resample.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="cubeb\include\cubeb\cubeb.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb-internal.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb-speex-resampler.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_array_queue.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_assert.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_log.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_mixer.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_resampler.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_resampler_internal.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_ringbuffer.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_ring_array.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_strings.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_utils.h" />
|
||||
<ClInclude Include="cubeb\src\cubeb_utils_win.h" />
|
||||
<ClInclude Include="cubeb\src\speex\arch.h" />
|
||||
<ClInclude Include="cubeb\src\speex\fixed_generic.h" />
|
||||
<ClInclude Include="cubeb\src\speex\resample_neon.h" />
|
||||
<ClInclude Include="cubeb\src\speex\resample_sse.h" />
|
||||
<ClInclude Include="cubeb\src\speex\speex_config_types.h" />
|
||||
<ClInclude Include="cubeb\src\speex\speex_resampler.h" />
|
||||
<ClInclude Include="cubeb\src\speex\stack_alloc.h" />
|
||||
<ClInclude Include="extra\cubeb_export.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{fda7b080-03b0-48c8-b24f-88118981422a}</ProjectGuid>
|
||||
<RootNamespace>libcubeb</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<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 Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_default.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_release.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>OUTSIDE_SPEEX;RANDOM_PREFIX=speex;FLOATING_POINT;EXPORT=;USE_WASAPI;USE_WINMM;CUBEB_WASAPI_USE_IAUDIOSTREAMVOLUME;_HAS_DEPRECATED_RESULT_OF;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>./cubeb/src/speex/;./extra/;./cubeb/src/;./cubeb/include/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="cubeb\src\speex\resample.c">
|
||||
<Filter>Source files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cubeb\src\cubeb_winmm.c">
|
||||
<Filter>Source files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cubeb\src\cubeb_utils.cpp">
|
||||
<Filter>Source files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cubeb\src\cubeb_wasapi.cpp">
|
||||
<Filter>Source files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cubeb\src\cubeb_strings.c">
|
||||
<Filter>Source files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cubeb\src\cubeb_resampler.cpp">
|
||||
<Filter>Source files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cubeb\src\cubeb_mixer.cpp">
|
||||
<Filter>Source files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cubeb\src\cubeb_log.cpp">
|
||||
<Filter>Source files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cubeb\src\cubeb.c">
|
||||
<Filter>Source files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="cubeb\include\cubeb\cubeb.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\speex\arch.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_array_queue.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_assert.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="extra\cubeb_export.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_log.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_mixer.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_resampler.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_resampler_internal.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_ring_array.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_ringbuffer.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_strings.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_utils.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb_utils_win.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb-internal.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\cubeb-speex-resampler.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\speex\fixed_generic.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\speex\resample_neon.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\speex\resample_sse.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\speex\speex_config_types.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\speex\speex_resampler.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cubeb\src\speex\stack_alloc.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Source files">
|
||||
<UniqueIdentifier>{cd86de6d-e811-4c48-9653-af00c7098a45}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header files">
|
||||
<UniqueIdentifier>{566bbf3e-ca28-4390-b054-58c92a66f24e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Vendored
+1
@@ -7,6 +7,7 @@ if(USE_SYSTEM_CURL)
|
||||
target_link_libraries(libcurl INTERFACE CURL::libcurl)
|
||||
else()
|
||||
message("-- RPCS3: building libcurl + wolfssl submodules")
|
||||
add_compile_definitions(HAVE_SNI)
|
||||
option(BUILD_CURL_EXE "Set to ON to build curl executable." OFF)
|
||||
option(CMAKE_USE_WOLFSSL "enable wolfSSL for SSL/TLS" ON)
|
||||
option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" ON)
|
||||
|
||||
Vendored
+1
-1
@@ -2,7 +2,7 @@
|
||||
add_library(3rdparty_discordRPC INTERFACE)
|
||||
|
||||
# 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))
|
||||
if (USE_DISCORD_RPC AND (WIN32 OR CMAKE_SYSTEM MATCHES "Linux" OR APPLE) AND COMPILER_X86)
|
||||
if (WIN32 AND NOT MSVC)
|
||||
ExternalProject_Add(discordRPC
|
||||
GIT_REPOSITORY https://github.com/discordapp/discord-rpc
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/ffmpeg updated: e5fb13bbb0...bf019f8c88
Vendored
+1
-1
Submodule 3rdparty/glslang/glslang updated: 2fb89a0072...c9706bdda0
Vendored
+9
-14
@@ -1,25 +1,20 @@
|
||||
# hidapi
|
||||
set(BUILD_SHARED_LIBS FALSE CACHE BOOL "Don't build shared libs")
|
||||
set(HIDAPI_INSTALL_TARGETS FALSE CACHE BOOL "Don't install anything")
|
||||
|
||||
if(CMAKE_SYSTEM MATCHES "Linux")
|
||||
set(HIDAPI_WITH_LIBUSB FALSE CACHE BOOL "Don't build with libusb for linux")
|
||||
endif()
|
||||
|
||||
add_library(3rdparty_hidapi INTERFACE)
|
||||
target_include_directories(3rdparty_hidapi INTERFACE hidapi/hidapi)
|
||||
add_subdirectory(hidapi EXCLUDE_FROM_ALL)
|
||||
|
||||
if(APPLE)
|
||||
add_subdirectory(hidapi/mac EXCLUDE_FROM_ALL)
|
||||
target_include_directories(hidapi-mac PUBLIC hidapi/hidapi)
|
||||
|
||||
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-mac "-framework CoreFoundation" "-framework IOKit")
|
||||
target_link_libraries(3rdparty_hidapi INTERFACE hidapi_darwin "-framework CoreFoundation" "-framework IOKit")
|
||||
elseif(CMAKE_SYSTEM MATCHES "Linux")
|
||||
add_subdirectory(hidapi/linux EXCLUDE_FROM_ALL)
|
||||
target_include_directories(hidapi-hidraw PUBLIC hidapi/hidapi)
|
||||
|
||||
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-hidraw udev)
|
||||
elseif(WIN32)
|
||||
add_subdirectory(hidapi/windows EXCLUDE_FROM_ALL)
|
||||
target_include_directories(hidapi-hid PUBLIC hidapi/hidapi)
|
||||
|
||||
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-hid Shlwapi.lib)
|
||||
else()
|
||||
add_subdirectory(hidapi/libusb EXCLUDE_FROM_ALL)
|
||||
target_include_directories(hidapi-libusb PUBLIC hidapi/hidapi)
|
||||
|
||||
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-libusb usb)
|
||||
endif()
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/hidapi/hidapi updated: 01f601a150...6cf133697c
Vendored
+31
-4
@@ -1,8 +1,10 @@
|
||||
if(WITH_LLVM)
|
||||
CHECK_CXX_COMPILER_FLAG("-msse -msse2 -mcx16" COMPILER_X86)
|
||||
CHECK_CXX_COMPILER_FLAG("-march=armv8-a+lse" COMPILER_ARM)
|
||||
|
||||
if(BUILD_LLVM_SUBMODULE)
|
||||
message(STATUS "LLVM will be built from the submodule.")
|
||||
|
||||
set(LLVM_TARGETS_TO_BUILD "X86" CACHE INTERNAL "")
|
||||
option(LLVM_BUILD_RUNTIME OFF)
|
||||
option(LLVM_BUILD_TOOLS OFF)
|
||||
option(LLVM_INCLUDE_BENCHMARKS OFF)
|
||||
@@ -13,6 +15,15 @@ if(WITH_LLVM)
|
||||
option(LLVM_INCLUDE_UTILS OFF)
|
||||
option(LLVM_CCACHE_BUILD ON)
|
||||
|
||||
if(WIN32)
|
||||
set(LLVM_USE_INTEL_JITEVENTS ON)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM MATCHES "Linux")
|
||||
set(LLVM_USE_INTEL_JITEVENTS ON)
|
||||
set(LLVM_USE_PERF ON)
|
||||
endif()
|
||||
|
||||
set(CXX_FLAGS_OLD ${CMAKE_CXX_FLAGS})
|
||||
|
||||
if (MSVC)
|
||||
@@ -26,7 +37,7 @@ if(WITH_LLVM)
|
||||
set(CMAKE_CXX_FLAGS ${CXX_FLAGS_OLD})
|
||||
|
||||
# now tries to find LLVM again
|
||||
find_package(LLVM 11.0 CONFIG)
|
||||
find_package(LLVM 13.0 CONFIG)
|
||||
if(NOT LLVM_FOUND)
|
||||
message(FATAL_ERROR "Couldn't build LLVM from the submodule. You might need to run `git submodule update --init`")
|
||||
endif()
|
||||
@@ -39,7 +50,7 @@ if(WITH_LLVM)
|
||||
set(LLVM_DIR ${CMAKE_SOURCE_DIR}/${LLVM_DIR})
|
||||
endif()
|
||||
|
||||
find_package(LLVM 11.0 CONFIG)
|
||||
find_package(LLVM 13.0 CONFIG)
|
||||
|
||||
if (NOT LLVM_FOUND)
|
||||
if (LLVM_VERSION AND LLVM_VERSION_MAJOR LESS 11)
|
||||
@@ -52,7 +63,23 @@ if(WITH_LLVM)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LLVM_LIBS LLVMMCJIT LLVMX86CodeGen LLVMX86AsmParser)
|
||||
set(LLVM_LIBS LLVMMCJIT)
|
||||
|
||||
if(COMPILER_X86)
|
||||
set(LLVM_LIBS ${LLVM_LIBS} LLVMX86CodeGen LLVMX86AsmParser)
|
||||
endif()
|
||||
|
||||
if(COMPILER_ARM)
|
||||
set(LLVM_LIBS ${LLVM_LIBS} LLVMX86CodeGen LLVMX86AsmParser LLVMARMCodeGen LLVMARMAsmParser)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR CMAKE_SYSTEM MATCHES "Linux")
|
||||
set(LLVM_LIBS ${LLVM_LIBS} LLVMIntelJITEvents)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM MATCHES "Linux")
|
||||
set(LLVM_LIBS ${LLVM_LIBS} LLVMPerfJITEvents)
|
||||
endif()
|
||||
|
||||
add_library(3rdparty_llvm INTERFACE)
|
||||
target_link_libraries(3rdparty_llvm INTERFACE ${LLVM_LIBS})
|
||||
|
||||
Vendored
+1
-12
@@ -27,18 +27,7 @@ else()
|
||||
|
||||
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
|
||||
|
||||
# TODO(cjj19970505@live.cn)
|
||||
# This only works in single-config generator
|
||||
# For a multi-config generator, we need to provide different wolfssl binaries for different config
|
||||
if (GENERATOR_IS_MULTI_CONFIG)
|
||||
message( FATAL_ERROR "RPCS3 can only be configured using single-config generator." )
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set(WolfSSL_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/${CMAKE_BUILD_TYPE}/wolfssl.lib" CACHE INTERNAL "")
|
||||
else()
|
||||
set(WolfSSL_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/libwolfssl.a" CACHE INTERNAL "")
|
||||
endif()
|
||||
set(WolfSSL_LIBRARY "$<TARGET_FILE:wolfssl>" CACHE INTERNAL "")
|
||||
|
||||
# "${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfssl/" provides openssl headers
|
||||
# So that curl can be built on an environment where openssl headers are not provided
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
#ifndef _WIN_USER_SETTINGS_H_
|
||||
#define _WIN_USER_SETTINGS_H_
|
||||
|
||||
/* Verify this is Windows */
|
||||
#ifndef _WIN32
|
||||
#error This user_settings.h header is only designed for Windows
|
||||
#endif
|
||||
|
||||
/* Configurations */
|
||||
#define WOLFSSL_DES_ECB
|
||||
#define HAVE_FFDHE_2048
|
||||
#define TFM_TIMING_RESISTANT
|
||||
#define NO_DSA
|
||||
#define TFM_ECC256
|
||||
#define NO_RC4
|
||||
#define NO_HC128
|
||||
#define NO_RABBIT
|
||||
#define WOLFSSL_SHA224
|
||||
#define WOLFSSL_SHA384
|
||||
#define WOLFSSL_SHA3
|
||||
#define WOLFSSL_SHA512
|
||||
#define WOLFSSL_SHAKE256
|
||||
#define HAVE_POLY1305
|
||||
#define HAVE_ONE_TIME_AUTH
|
||||
#define HAVE_CHACHA
|
||||
#define HAVE_HASHDRBG
|
||||
#define HAVE_SNI
|
||||
#define HAVE_ENCRYPT_THEN_MAC
|
||||
#define NO_MD4
|
||||
#define WC_NO_ASYNC_THREADING
|
||||
#define WC_NO_HARDEN
|
||||
#define HAVE_WRITE_DUP
|
||||
#define WC_RSA_BLINDING
|
||||
#define NO_MULTIBYTE_PRINT
|
||||
#define OPENSSL_EXTRA
|
||||
#define WOLFSSL_RIPEMD
|
||||
#define NO_PSK
|
||||
#define HAVE_EXTENDED_MASTER
|
||||
#define WOLFSSL_SNIFFER
|
||||
#define HAVE_AESGCM
|
||||
#define HAVE_SUPPORTED_CURVES
|
||||
#define HAVE_TLS_EXTENSIONS
|
||||
#define HAVE_ECC
|
||||
#define ECC_SHAMIR
|
||||
#define ECC_TIMING_RESISTANT
|
||||
|
||||
/* UTF-8 aware filesystem functions for Windows */
|
||||
#define WOLFSSL_USER_FILESYSTEM
|
||||
|
||||
#include <stdio.h>
|
||||
#define XFILE FILE*
|
||||
|
||||
extern FILE* wolfSSL_fopen_utf8(const char* name, const char* mode);
|
||||
#define XFOPEN wolfSSL_fopen_utf8
|
||||
|
||||
#define XFDOPEN fdopen
|
||||
#define XFSEEK fseek
|
||||
#define XFTELL ftell
|
||||
#define XREWIND rewind
|
||||
#define XFREAD fread
|
||||
#define XFWRITE fwrite
|
||||
#define XFCLOSE fclose
|
||||
#define XSEEK_END SEEK_END
|
||||
#define XBADFILE NULL
|
||||
#define XFGETS fgets
|
||||
#define XFPRINTF fprintf
|
||||
#define XFFLUSH fflush
|
||||
|
||||
#include <sys/stat.h>
|
||||
#define XSTAT _stat
|
||||
#define XS_ISREG(s) (s & _S_IFREG)
|
||||
#define SEPARATOR_CHAR ';'
|
||||
|
||||
#endif /* _WIN_USER_SETTINGS_H_ */
|
||||
Vendored
+1
-1
Submodule 3rdparty/wolfssl/wolfssl updated: 723ed009ae...4bbf90d604
Vendored
+7
-6
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
@@ -47,8 +47,8 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>./wolfssl;./wolfssl/IDE/WIN;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_DES_ECB;HAVE_FFDHE_2048;TFM_TIMING_RESISTANT;NO_DSA;TFM_ECC256;NO_RC4;NO_HC128;NO_RABBIT;WOLFSSL_SHA224;WOLFSSL_SHA3;WOLFSSL_SHAKE256;HAVE_POLY1305;HAVE_ONE_TIME_AUTH;HAVE_CHACHA;HAVE_HASHDRBG;HAVE_SNI;HAVE_ENCRYPT_THEN_MAC;NO_MD4;WC_NO_ASYNC_THREADING;CYASSL_USER_SETTINGS;WC_NO_HARDEN;HAVE_WRITE_DUP;WC_RSA_BLINDING;NO_MULTIBYTE_PRINT;OPENSSL_EXTRA;WOLFSSL_RIPEMD;NO_PSK;HAVE_EXTENDED_MASTER;WOLFSSL_SNIFFER;HAVE_AESGCM;WOLFSSL_SHA384;WOLFSSL_SHA512;HAVE_SUPPORTED_CURVES;HAVE_TLS_EXTENSIONS;HAVE_ECC;ECC_SHAMIR;ECC_TIMING_RESISTANT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>./wolfssl;./extra/win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
@@ -61,8 +61,8 @@
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>./wolfssl;./wolfssl/IDE/WIN;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_DES_ECB;HAVE_FFDHE_2048;TFM_TIMING_RESISTANT;NO_DSA;TFM_ECC256;NO_RC4;NO_HC128;NO_RABBIT;WOLFSSL_SHA224;WOLFSSL_SHA3;WOLFSSL_SHAKE256;HAVE_POLY1305;HAVE_ONE_TIME_AUTH;HAVE_CHACHA;HAVE_HASHDRBG;HAVE_SNI;HAVE_ENCRYPT_THEN_MAC;NO_MD4;WC_NO_ASYNC_THREADING;CYASSL_USER_SETTINGS;WC_NO_HARDEN;HAVE_WRITE_DUP;WC_RSA_BLINDING;NO_MULTIBYTE_PRINT;OPENSSL_EXTRA;WOLFSSL_RIPEMD;NO_PSK;HAVE_EXTENDED_MASTER;WOLFSSL_SNIFFER;HAVE_AESGCM;WOLFSSL_SHA384;WOLFSSL_SHA512;HAVE_SUPPORTED_CURVES;HAVE_TLS_EXTENSIONS;HAVE_ECC;ECC_SHAMIR;ECC_TIMING_RESISTANT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>./wolfssl;./extra/win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
@@ -105,6 +105,7 @@
|
||||
<ClCompile Include="wolfssl\wolfcrypt\src\hmac.c" />
|
||||
<ClCompile Include="wolfssl\wolfcrypt\src\idea.c" />
|
||||
<ClCompile Include="wolfssl\wolfcrypt\src\integer.c" />
|
||||
<ClCompile Include="wolfssl\wolfcrypt\src\kdf.c" />
|
||||
<ClCompile Include="wolfssl\wolfcrypt\src\logging.c" />
|
||||
<ClCompile Include="wolfssl\wolfcrypt\src\md2.c" />
|
||||
<ClCompile Include="wolfssl\wolfcrypt\src\md4.c" />
|
||||
@@ -136,6 +137,7 @@
|
||||
<ClCompile Include="wolfssl\wolfcrypt\src\wolfevent.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="extra\win32\user_settings.h" />
|
||||
<ClInclude Include="wolfssl\resource.h" />
|
||||
<CustomBuild Include="wolfssl\wolfcrypt\src\aes_asm.asm">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
@@ -151,7 +153,6 @@
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)%(Filename).obj</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='DLL Release|x64'">$(IntDir)%(Filename).obj</Outputs>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="wolfssl\IDE\WIN\user_settings.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="wolfssl\wolfssl.rc">
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/xxHash updated: 94e5f23e73...35b0373c69
+7
-7
@@ -11,7 +11,7 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
|
||||
* [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
|
||||
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
|
||||
* [Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
|
||||
* [Vulkan SDK 1.2.154+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html))
|
||||
* [Vulkan SDK 1.2.198+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html))
|
||||
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.15.2\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
|
||||
|
||||
@@ -22,18 +22,18 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
|
||||
* Clang 12+ or GCC 11+
|
||||
* [CMake 3.16.9+](https://www.cmake.org/download/)
|
||||
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
|
||||
* [Vulkan SDK 1.2.154+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html))
|
||||
* [Vulkan SDK 1.2.198+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html))
|
||||
* [SDL2](https://www.libsdl.org/download-2.0.php) (for the FAudio backend)
|
||||
|
||||
**If you have an NVIDIA GPU, you may need to install the libglvnd package.**
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
sudo pacman -S glew openal cmake vulkan-validation-layers qt5-base qt5-declarative sdl2
|
||||
sudo pacman -S glew openal cmake vulkan-validation-layers qt5-base qt5-declarative sdl2 sndio jack2
|
||||
|
||||
#### Debian & Ubuntu
|
||||
|
||||
sudo apt-get install build-essential libasound2-dev libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git libevdev-dev libsdl2-2.0 libsdl2-dev
|
||||
sudo apt-get install build-essential libasound2-dev libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git libevdev-dev libsdl2-2.0 libsdl2-dev libjack-dev libsndio-dev
|
||||
|
||||
Ubuntu is usually horrendously out of date, and some packages need to be downloaded by hand. This part is for Qt, GCC, Vulkan, and CMake
|
||||
##### Qt PPA
|
||||
@@ -64,7 +64,7 @@ For Ubuntu systems, it is strongly recommended to use the PPA from [LunarG](http
|
||||
```
|
||||
. /etc/os-release
|
||||
wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.2.154-$UBUNTU_CODENAME.list https://packages.lunarg.com/vulkan/1.2.154/lunarg-vulkan-1.2.154-$UBUNTU_CODENAME.list
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.2.198-$UBUNTU_CODENAME.list https://packages.lunarg.com/vulkan/1.2.198/lunarg-vulkan-1.2.198-$UBUNTU_CODENAME.list
|
||||
sudo apt update
|
||||
sudo apt install vulkan-sdk
|
||||
```
|
||||
@@ -82,11 +82,11 @@ sudo apt-get install cmake
|
||||
|
||||
#### Fedora
|
||||
|
||||
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-qtbase-devel qt5-qtbase-private-devel vulkan-devel
|
||||
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-qtbase-devel qt5-qtbase-private-devel vulkan-devel pipewire-jack-audio-connection-kit-devel qt5-qtmultimedia-devel qt5-qtsvg-devel
|
||||
|
||||
#### OpenSUSE
|
||||
|
||||
sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel glew-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt5-qtbase-devel libqt5gui-private-headers-devel libevdev-devel
|
||||
sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel glew-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt5-qtbase-devel libqt5-qtmultimedia-devel libqt5-qtsvg-devel libQt5Gui-private-headers-devel libevdev-devel libsndio7_1 libjack-devel
|
||||
|
||||
## Setup the project
|
||||
|
||||
|
||||
+25
-22
@@ -15,11 +15,9 @@ endif()
|
||||
option(USE_NATIVE_INSTRUCTIONS "USE_NATIVE_INSTRUCTIONS makes rpcs3 compile with -march=native, which is useful for local builds, but not good for packages." ON)
|
||||
option(WITH_LLVM "Enable usage of LLVM library" ON)
|
||||
option(BUILD_LLVM_SUBMODULE "Build LLVM from git submodule" ON)
|
||||
option(USE_ALSA "ALSA audio backend" ON)
|
||||
option(USE_PULSE "PulseAudio audio backend" ON)
|
||||
option(USE_FAUDIO "FAudio audio backend" ON)
|
||||
option(USE_LIBEVDEV "libevdev-based joystick support" ON)
|
||||
option(USE_DISCORD_RPC "Discord rich presence integration" ON)
|
||||
option(USE_DISCORD_RPC "Discord rich presence integration" OFF)
|
||||
option(USE_SYSTEM_ZLIB "Prefer system ZLIB instead of the builtin one" ON)
|
||||
option(USE_VULKAN "Vulkan render backend" ON)
|
||||
option(USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
|
||||
@@ -28,16 +26,17 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/buildfiles/cmake")
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
# TODO(cjj19970505@live.cn)
|
||||
# Currently cmake config scripts are single-config generator only.
|
||||
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(IS_MULTI_CONFIG)
|
||||
message(FATAL_ERROR "Multi-config generators are not supported.")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
# TODO(cjj19970505@live.cn)
|
||||
# Currently DicordRPC is included as a binary compiled with /MT flag.
|
||||
# We need all 4 binaries(/MT /MTd /MD /MDd) or including the source instead of binary.
|
||||
set(USE_DISCORD_RPC OFF CACHE BOOL "Discord RPC is only avaliable with single-config generator" FORCE)
|
||||
else()
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Debug" AND NOT MSVC)
|
||||
@@ -47,21 +46,23 @@ endif()
|
||||
if(MSVC)
|
||||
option(USE_MSVC_STATIC_CRT "Use static MSVC C runtime" OFF)
|
||||
|
||||
# TODO(cjj19970505@live.cno)
|
||||
# TODO(cjj19970505@live.cn)
|
||||
# DiscordRPC binary in 3rdparty is compiled /MT
|
||||
# So theoretically we should enable DiscordRPC in Release and static CRT build
|
||||
# since we might encounter some rumtime issues when more than one CRT version are presented.
|
||||
# https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-160#what-problems-exist-if-an-application-uses-more-than-one-crt-version
|
||||
# Add other DiscordRPC binaries(compiled with /MTd, /MD, /MDd) or compile it from source may address this issue.
|
||||
if(NOT(CMAKE_BUILD_TYPE MATCHES "Release" AND USE_MSVC_STATIC_CRT))
|
||||
set(USE_DISCORD_RPC OFF CACHE BOOL "Discord RPC is only available in Release and static CRT build." FORCE)
|
||||
if(NOT IS_MULTI_CONFIG)
|
||||
if(NOT(CMAKE_BUILD_TYPE MATCHES "Release" AND USE_MSVC_STATIC_CRT))
|
||||
set(USE_DISCORD_RPC OFF CACHE BOOL "Discord RPC is only available in Release and static CRT build." FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(USE_MSVC_STATIC_CRT)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
else()
|
||||
# though doc ( https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html )
|
||||
# says if that property is not set then CMake uses the default value MultiThreaded$<$<CONFIG:Debug>:Debug>DLL
|
||||
# says if that property is not set then CMake uses the default value MultiThreaded$<$<CONFIG:Debug>:Debug>DLL
|
||||
# to select a MSVC runtime library.
|
||||
# But yaml-cpp set /MT(d) if CMAKE_MSVC_RUNTIME_LIBRARY is undefined
|
||||
# So we have to define it explicitly
|
||||
@@ -71,18 +72,20 @@ if(MSVC)
|
||||
# TODO(cjj19970505@live.cn)
|
||||
# offical QT uses dynamic CRT.
|
||||
# When building our lib with static CRT and debug build type
|
||||
# and linking with Qt with dynmaic CRT and debug build,
|
||||
# error is encountered in runtime (which is expected).
|
||||
# But building our lib with static CRT and release build type,
|
||||
# and linking with Qt with dynamic CRT and release build seems to be working,
|
||||
# and linking with Qt with dynmaic CRT and debug build,
|
||||
# error is encountered in runtime (which is expected).
|
||||
# But building our lib with static CRT and release build type,
|
||||
# and linking with Qt with dynamic CRT and release build seems to be working,
|
||||
# which is the same config with VS solution.
|
||||
# (though technically it might still have some hidden errors).
|
||||
# So we allow static CRT in both relase and debug build, but prompt warning in debug build.
|
||||
# For more info:
|
||||
# https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-160#what-problems-exist-if-an-application-uses-more-than-one-crt-version
|
||||
# https://wiki.qt.io/Technical_FAQ#Why_does_a_statically_built_Qt_use_the_dynamic_Visual_Studio_runtime_libraries_.3F_Do_I_need_to_deploy_those_with_my_application_.3F
|
||||
if(USE_MSVC_STATIC_CRT AND CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
message(AUTHOR_WARNING "Debug build currently can not work with static CRT.")
|
||||
if(USE_MSVC_STATIC_CRT)
|
||||
if(IS_MULTI_CONFIG OR CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
message(AUTHOR_WARNING "Debug build currently can not work with static CRT.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ RPCS3
|
||||
|
||||
[](https://dev.azure.com/nekotekina/nekotekina/_build?definitionId=4&branchName=master)
|
||||
[&logo=cirrus-ci)](https://cirrus-ci.com/github/RPCS3/rpcs3)
|
||||
[](https://discord.me/rpcs3)
|
||||
[](https://discord.me/rpcs3)
|
||||
|
||||
The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows and Linux.
|
||||
|
||||
|
||||
+24
-19
@@ -19,8 +19,8 @@ namespace cfg
|
||||
}
|
||||
}
|
||||
|
||||
_base::_base(type _type, node* owner, const std::string& name, bool dynamic)
|
||||
: m_type(_type), m_dynamic(dynamic), m_name(name)
|
||||
_base::_base(type _type, node* owner, std::string name, bool dynamic)
|
||||
: m_type(_type), m_dynamic(dynamic), m_name(std::move(name))
|
||||
{
|
||||
for (const auto& node : owner->m_nodes)
|
||||
{
|
||||
@@ -33,7 +33,7 @@ namespace cfg
|
||||
owner->m_nodes.emplace_back(this);
|
||||
}
|
||||
|
||||
bool _base::from_string(const std::string&, bool)
|
||||
bool _base::from_string(std::string_view, bool)
|
||||
{
|
||||
cfg_log.fatal("cfg::_base::from_string() purecall");
|
||||
return false;
|
||||
@@ -58,7 +58,7 @@ std::vector<std::string> cfg::make_int_range(s64 min, s64 max)
|
||||
return {std::to_string(min), std::to_string(max)};
|
||||
}
|
||||
|
||||
bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
|
||||
bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max)
|
||||
{
|
||||
s64 result;
|
||||
const char* start = &value.front();
|
||||
@@ -104,7 +104,7 @@ std::vector<std::string> cfg::make_uint_range(u64 min, u64 max)
|
||||
return {std::to_string(min), std::to_string(max)};
|
||||
}
|
||||
|
||||
bool try_to_uint64(u64* out, const std::string& value, u64 min, u64 max)
|
||||
bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max)
|
||||
{
|
||||
u64 result;
|
||||
const char* start = &value.front();
|
||||
@@ -136,7 +136,7 @@ bool try_to_uint64(u64* out, const std::string& value, u64 min, u64 max)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, const std::string& value)
|
||||
bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, std::string_view value)
|
||||
{
|
||||
u64 max = umax;
|
||||
|
||||
@@ -320,7 +320,7 @@ void cfg::decode(const YAML::Node& data, cfg::_base& rhs, bool dynamic)
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> values;
|
||||
map_of_type<std::string> values;
|
||||
|
||||
for (const auto& pair : data)
|
||||
{
|
||||
@@ -339,7 +339,7 @@ void cfg::decode(const YAML::Node& data, cfg::_base& rhs, bool dynamic)
|
||||
return; // ???
|
||||
}
|
||||
|
||||
std::map<std::string, logs::level> values;
|
||||
map_of_type<logs::level> values;
|
||||
|
||||
for (const auto& pair : data)
|
||||
{
|
||||
@@ -377,9 +377,9 @@ std::string cfg::node::to_string() const
|
||||
return {out.c_str(), out.size()};
|
||||
}
|
||||
|
||||
bool cfg::node::from_string(const std::string& value, bool dynamic)
|
||||
bool cfg::node::from_string(std::string_view value, bool dynamic)
|
||||
{
|
||||
auto [result, error] = yaml_load(value);
|
||||
auto [result, error] = yaml_load(std::string(value));
|
||||
|
||||
if (error.empty())
|
||||
{
|
||||
@@ -414,26 +414,31 @@ void cfg::set_entry::from_default()
|
||||
m_set = {};
|
||||
}
|
||||
|
||||
std::string cfg::map_entry::get_value(const std::string& key)
|
||||
std::string cfg::map_entry::get_value(std::string_view key)
|
||||
{
|
||||
return m_map.contains(key) ? m_map.at(key) : "";
|
||||
if (auto it = m_map.find(key); it != m_map.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void cfg::map_entry::set_value(const std::string& key, const std::string& value)
|
||||
void cfg::map_entry::set_value(std::string key, std::string value)
|
||||
{
|
||||
m_map[key] = value;
|
||||
m_map[std::move(key)] = std::move(value);
|
||||
}
|
||||
|
||||
void cfg::map_entry::set_map(std::map<std::string, std::string>&& map)
|
||||
void cfg::map_entry::set_map(map_of_type<std::string>&& map)
|
||||
{
|
||||
m_map = std::move(map);
|
||||
}
|
||||
|
||||
void cfg::map_entry::erase(const std::string& key)
|
||||
void cfg::map_entry::erase(std::string_view key)
|
||||
{
|
||||
if (m_map.contains(key))
|
||||
if (auto it = m_map.find(key); it != m_map.end())
|
||||
{
|
||||
m_map.erase(key);
|
||||
m_map.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,7 +447,7 @@ void cfg::map_entry::from_default()
|
||||
set_map({});
|
||||
}
|
||||
|
||||
void cfg::log_entry::set_map(std::map<std::string, logs::level>&& map)
|
||||
void cfg::log_entry::set_map(map_of_type<logs::level>&& map)
|
||||
{
|
||||
m_map = std::move(map);
|
||||
}
|
||||
|
||||
+26
-23
@@ -21,7 +21,7 @@ namespace cfg
|
||||
std::vector<std::string> make_uint_range(u64 min, u64 max);
|
||||
|
||||
// Internal hack
|
||||
bool try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, const std::string&);
|
||||
bool try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, std::string_view);
|
||||
|
||||
// Internal hack
|
||||
std::vector<std::string> try_to_enum_list(decltype(&fmt_class_string<int>::format) func);
|
||||
@@ -53,7 +53,7 @@ namespace cfg
|
||||
_base(type _type);
|
||||
|
||||
// Owned entry constructor
|
||||
_base(type _type, class node* owner, const std::string& name, bool dynamic);
|
||||
_base(type _type, class node* owner, std::string name, bool dynamic);
|
||||
|
||||
public:
|
||||
_base(const _base&) = delete;
|
||||
@@ -80,7 +80,7 @@ namespace cfg
|
||||
}
|
||||
|
||||
// Try to convert from string (optional)
|
||||
virtual bool from_string(const std::string&, bool /*dynamic*/ = false);
|
||||
virtual bool from_string(std::string_view, bool /*dynamic*/ = false);
|
||||
|
||||
// Get string list (optional)
|
||||
virtual std::vector<std::string> to_list() const
|
||||
@@ -107,8 +107,8 @@ namespace cfg
|
||||
}
|
||||
|
||||
// Registered node constructor
|
||||
node(node* owner, const std::string& name, bool dynamic = true)
|
||||
: _base(type::node, owner, name, dynamic)
|
||||
node(node* owner, std::string name, bool dynamic = true)
|
||||
: _base(type::node, owner, std::move(name), dynamic)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace cfg
|
||||
std::string to_string() const override;
|
||||
|
||||
// Deserialize node
|
||||
bool from_string(const std::string& value, bool dynamic = false) override;
|
||||
bool from_string(std::string_view value, bool dynamic = false) override;
|
||||
|
||||
// Set default values
|
||||
void from_default() override;
|
||||
@@ -135,8 +135,8 @@ namespace cfg
|
||||
public:
|
||||
bool def;
|
||||
|
||||
_bool(node* owner, const std::string& name, bool def = false, bool dynamic = false)
|
||||
: _base(type::_bool, owner, name, dynamic)
|
||||
_bool(node* owner, std::string name, bool def = false, bool dynamic = false)
|
||||
: _base(type::_bool, owner, std::move(name), dynamic)
|
||||
, m_value(def)
|
||||
, def(def)
|
||||
{
|
||||
@@ -159,7 +159,7 @@ namespace cfg
|
||||
return m_value ? "true" : "false";
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
|
||||
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
||||
{
|
||||
if (value == "false")
|
||||
m_value = false;
|
||||
@@ -220,7 +220,7 @@ namespace cfg
|
||||
return result; // TODO: ???
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
|
||||
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
||||
{
|
||||
u64 result;
|
||||
|
||||
@@ -285,7 +285,7 @@ namespace cfg
|
||||
return std::to_string(m_value);
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
|
||||
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
||||
{
|
||||
s64 result;
|
||||
if (try_to_int64(&result, value, Min, Max))
|
||||
@@ -359,7 +359,7 @@ namespace cfg
|
||||
return std::to_string(m_value);
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
|
||||
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
||||
{
|
||||
u64 result;
|
||||
if (try_to_uint64(&result, value, Min, Max))
|
||||
@@ -430,9 +430,9 @@ namespace cfg
|
||||
return *m_value.load().get();
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
|
||||
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
||||
{
|
||||
m_value = value;
|
||||
m_value = std::string(value);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -474,9 +474,12 @@ namespace cfg
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using map_of_type = std::map<std::string, T, std::less<>>;
|
||||
|
||||
class map_entry final : public _base
|
||||
{
|
||||
std::map<std::string, std::string> m_map{};
|
||||
map_of_type<std::string> m_map{};
|
||||
|
||||
public:
|
||||
map_entry(node* owner, const std::string& name)
|
||||
@@ -484,24 +487,24 @@ namespace cfg
|
||||
{
|
||||
}
|
||||
|
||||
const std::map<std::string, std::string>& get_map() const
|
||||
const map_of_type<std::string>& get_map() const
|
||||
{
|
||||
return m_map;
|
||||
}
|
||||
|
||||
std::string get_value(const std::string& key);
|
||||
std::string get_value(std::string_view key);
|
||||
|
||||
void set_value(const std::string& key, const std::string& value);
|
||||
void set_map(std::map<std::string, std::string>&& map);
|
||||
void set_value(std::string key, std::string value);
|
||||
void set_map(map_of_type<std::string>&& map);
|
||||
|
||||
void erase(const std::string& key);
|
||||
void erase(std::string_view key);
|
||||
|
||||
void from_default() override;
|
||||
};
|
||||
|
||||
class log_entry final : public _base
|
||||
{
|
||||
std::map<std::string, logs::level> m_map{};
|
||||
map_of_type<logs::level> m_map{};
|
||||
|
||||
public:
|
||||
log_entry(node* owner, const std::string& name)
|
||||
@@ -509,12 +512,12 @@ namespace cfg
|
||||
{
|
||||
}
|
||||
|
||||
const std::map<std::string, logs::level>& get_map() const
|
||||
const map_of_type<logs::level>& get_map() const
|
||||
{
|
||||
return m_map;
|
||||
}
|
||||
|
||||
void set_map(std::map<std::string, logs::level>&& map);
|
||||
void set_map(map_of_type<logs::level>&& map);
|
||||
|
||||
void from_default() override;
|
||||
};
|
||||
|
||||
+33
-2
@@ -9,6 +9,7 @@
|
||||
#include <map>
|
||||
|
||||
#include "util/asm.hpp"
|
||||
#include "util/coro.hpp"
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
@@ -1182,7 +1183,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
|
||||
for (const char* data = static_cast<const char*>(buffer); count;)
|
||||
{
|
||||
const DWORD size = static_cast<DWORD>(std::min<u64>(count, DWORD{umax} & -4096));
|
||||
const DWORD size = static_cast<DWORD>(std::min<u64>(count, DWORD{umax} & -4096));
|
||||
|
||||
DWORD nwritten = 0;
|
||||
ensure(WriteFile(m_handle, data, size, &nwritten, nullptr)); // "file::write"
|
||||
@@ -1412,6 +1413,12 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
};
|
||||
|
||||
m_file = std::make_unique<unix_file>(fd);
|
||||
|
||||
if (mode & fs::isfile && !(mode & fs::write) && stat().is_directory)
|
||||
{
|
||||
m_file.reset();
|
||||
g_tls_error = error::isdir;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1658,7 +1665,7 @@ bool fs::dir::open(const std::string& path)
|
||||
|
||||
bool fs::file::strict_read_check(u64 _size, u64 type_size) const
|
||||
{
|
||||
if (usz pos0 = pos(), size0 = size(); pos0 >= size0 || (size0 - pos0) / type_size < _size)
|
||||
if (usz pos0 = pos(), size0 = size(); (pos0 >= size0 ? 0 : (size0 - pos0)) / type_size < _size)
|
||||
{
|
||||
fs::g_tls_error = fs::error::inval;
|
||||
return false;
|
||||
@@ -2039,6 +2046,30 @@ bool fs::pending_file::commit(bool overwrite)
|
||||
return false;
|
||||
}
|
||||
|
||||
stx::generator<fs::dir_entry&> fs::list_dir_recursively(std::string path)
|
||||
{
|
||||
for (auto& entry : fs::dir(path))
|
||||
{
|
||||
if (entry.name == "." || entry.name == "..")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string new_path = path_append(path, entry.name);
|
||||
|
||||
if (entry.is_directory)
|
||||
{
|
||||
for (auto& nested : fs::list_dir_recursively(new_path))
|
||||
{
|
||||
co_yield nested;
|
||||
}
|
||||
}
|
||||
|
||||
entry.name = std::move(new_path);
|
||||
co_yield entry;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<fs::seek_mode>::format(std::string& out, u64 arg)
|
||||
{
|
||||
|
||||
+44
-54
@@ -32,6 +32,7 @@ namespace fs
|
||||
excl,
|
||||
lock,
|
||||
unread,
|
||||
isfile,
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
@@ -44,6 +45,7 @@ namespace fs
|
||||
constexpr auto excl = +open_mode::excl; // Failure if the file already exists (used with `create`)
|
||||
constexpr auto lock = +open_mode::lock; // Prevent opening the file more than once
|
||||
constexpr auto unread = +open_mode::unread; // Aggressively prevent reading the opened file (do not use)
|
||||
constexpr auto isfile = +open_mode::isfile; // Ensure valid fs::file handle is not of directory
|
||||
|
||||
constexpr auto write_new = write + create + excl;
|
||||
constexpr auto rewrite = write + create + trunc;
|
||||
@@ -205,8 +207,6 @@ namespace fs
|
||||
{
|
||||
std::unique_ptr<file_base> m_file{};
|
||||
|
||||
bool strict_read_check(u64 size, u64 type_size) const;
|
||||
|
||||
public:
|
||||
// Default constructor
|
||||
file() = default;
|
||||
@@ -281,6 +281,9 @@ namespace fs
|
||||
return m_file->sync();
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Read the data from the file and return the amount of data written in buffer
|
||||
u64 read(void* buffer, u64 count,
|
||||
u32 line = __builtin_LINE(),
|
||||
@@ -337,8 +340,8 @@ namespace fs
|
||||
}
|
||||
|
||||
// Write std::basic_string unconditionally
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::basic_string<T>& str,
|
||||
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
|
||||
const file& write(const std::basic_string<T>& str,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
@@ -349,8 +352,8 @@ namespace fs
|
||||
}
|
||||
|
||||
// Write POD unconditionally
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const T& data,
|
||||
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
|
||||
const file& write(const T& data,
|
||||
pod_tag_t = pod_tag,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
@@ -362,8 +365,8 @@ namespace fs
|
||||
}
|
||||
|
||||
// Write POD std::vector unconditionally
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::vector<T>& vec,
|
||||
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
|
||||
const file& write(const std::vector<T>& vec,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
@@ -373,84 +376,69 @@ namespace fs
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Read std::basic_string, size must be set by resize() method
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
return read(&str[0], str.size() * sizeof(T), line, col, file, func) == str.size() * sizeof(T);
|
||||
}
|
||||
|
||||
// Read std::basic_string
|
||||
template <bool IsStrict = false, typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str, usz _size,
|
||||
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
|
||||
bool read(std::basic_string<T>& str, usz _size = umax,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
if (!_size) return true;
|
||||
|
||||
if constexpr (IsStrict)
|
||||
if (_size != umax)
|
||||
{
|
||||
// If _size arg is too high std::bad_alloc may happen in resize and then we cannot error check
|
||||
if (!strict_read_check(_size, sizeof(T))) return false;
|
||||
// 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)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
str.resize(_size);
|
||||
}
|
||||
|
||||
str.resize(_size);
|
||||
return read(str.data(), sizeof(T) * _size, line, col, file, func) == sizeof(T) * _size;
|
||||
return read(str.data(), sizeof(T) * str.size(), line, col, file, func) == sizeof(T) * str.size();
|
||||
}
|
||||
|
||||
// Read POD, sizeof(T) is used
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(T& data,
|
||||
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
|
||||
bool read(T& data,
|
||||
pod_tag_t = pod_tag,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
return read(&data, sizeof(T), line, col, file, func) == sizeof(T);
|
||||
}
|
||||
|
||||
// Read POD std::vector, size must be set by resize() method
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
|
||||
return read(std::addressof(data), sizeof(T), line, col, file, func) == sizeof(T);
|
||||
}
|
||||
|
||||
// Read POD std::vector
|
||||
template <bool IsStrict = false, typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec, usz _size,
|
||||
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
|
||||
bool read(std::vector<T>& vec, usz _size = umax,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
if (!_size) return true;
|
||||
|
||||
if constexpr (IsStrict)
|
||||
if (_size != umax)
|
||||
{
|
||||
if (!strict_read_check(_size, sizeof(T))) return false;
|
||||
// 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)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vec.resize(_size);
|
||||
}
|
||||
|
||||
vec.resize(_size);
|
||||
return read(vec.data(), sizeof(T) * _size, line, col, file, func) == sizeof(T) * _size;
|
||||
return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
|
||||
}
|
||||
|
||||
// Read POD (experimental)
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T> read(
|
||||
template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
|
||||
T read(
|
||||
pod_tag_t = pod_tag,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
@@ -472,13 +460,13 @@ namespace fs
|
||||
{
|
||||
std::basic_string<T> result;
|
||||
result.resize(size() / sizeof(T));
|
||||
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func});
|
||||
if (seek(0), !read(result, result.size(), file, func, line, col)) xfail({line, col, file, func});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read full file to std::vector
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, std::vector<T>> to_vector(
|
||||
template<typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
|
||||
std::vector<T> to_vector(
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
@@ -486,7 +474,7 @@ namespace fs
|
||||
{
|
||||
std::vector<T> result;
|
||||
result.resize(size() / sizeof(T));
|
||||
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func});
|
||||
if (seek(0), !read(result, result.size(), file, func, line, col)) xfail({line, col, file, func});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -818,4 +806,6 @@ namespace fs
|
||||
}
|
||||
|
||||
file make_gather(std::vector<file>);
|
||||
|
||||
stx::generator<dir_entry&> list_dir_recursively(std::string path);
|
||||
}
|
||||
|
||||
+194
-78
@@ -16,6 +16,79 @@
|
||||
|
||||
LOG_CHANNEL(jit_log, "JIT");
|
||||
|
||||
void jit_announce(uptr func, usz size, std::string_view name)
|
||||
{
|
||||
if (!size)
|
||||
{
|
||||
jit_log.error("Empty function announced: %s (%p)", name, func);
|
||||
return;
|
||||
}
|
||||
|
||||
// If directory ASMJIT doesn't exist, nothing will be written
|
||||
static constexpr u64 c_dump_size = 0x1'0000'0000;
|
||||
static constexpr u64 c_index_size = c_dump_size / 16;
|
||||
static atomic_t<u64> g_index_off = 0;
|
||||
static atomic_t<u64> g_data_off = c_index_size;
|
||||
|
||||
static void* g_asm = []() -> void*
|
||||
{
|
||||
fs::remove_all(fs::get_cache_dir() + "/ASMJIT/", false);
|
||||
|
||||
fs::file objs(fmt::format("%s/ASMJIT/.objects", fs::get_cache_dir()), fs::read + fs::rewrite);
|
||||
|
||||
if (!objs || !objs.trunc(c_dump_size))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return utils::memory_map_fd(objs.get_handle(), c_dump_size, utils::protection::rw);
|
||||
}();
|
||||
|
||||
if (g_asm && size < c_index_size)
|
||||
{
|
||||
struct entry
|
||||
{
|
||||
u64 addr; // RPCS3 process address
|
||||
u32 size; // Function size
|
||||
u32 off; // Function offset
|
||||
};
|
||||
|
||||
// Write index entry at the beginning of file, and data + NTS name at fixed offset
|
||||
const u64 index_off = g_index_off.fetch_add(1);
|
||||
const u64 size_all = size + name.size() + 1;
|
||||
const u64 data_off = g_data_off.fetch_add(size_all);
|
||||
|
||||
// If either index or data area is exhausted, nothing will be written
|
||||
if (index_off < c_index_size / sizeof(entry) && data_off + size_all < c_dump_size)
|
||||
{
|
||||
entry& index = static_cast<entry*>(g_asm)[index_off];
|
||||
|
||||
std::memcpy(static_cast<char*>(g_asm) + data_off, reinterpret_cast<char*>(func), size);
|
||||
std::memcpy(static_cast<char*>(g_asm) + data_off + size, name.data(), name.size());
|
||||
index.size = static_cast<u32>(size);
|
||||
index.off = static_cast<u32>(data_off);
|
||||
atomic_storage<u64>::store(index.addr, func);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_asm && !name.empty() && name[0] != '_')
|
||||
{
|
||||
// Save some objects separately
|
||||
fs::file dump(fmt::format("%s/ASMJIT/%s", fs::get_cache_dir(), name), fs::rewrite);
|
||||
|
||||
if (dump)
|
||||
{
|
||||
dump.write(reinterpret_cast<uchar*>(func), size);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static const fs::file s_map(fmt::format("/tmp/perf-%d.map", getpid()), fs::rewrite + fs::append);
|
||||
|
||||
s_map.write(fmt::format("%x %x %s\n", func, size, name));
|
||||
#endif
|
||||
}
|
||||
|
||||
static u8* get_jit_memory()
|
||||
{
|
||||
// Reserve 2G memory (magic static)
|
||||
@@ -104,8 +177,37 @@ static u8* add_jit_memory(usz size, uint align)
|
||||
return pointer + pos;
|
||||
}
|
||||
|
||||
const asmjit::Environment& jit_runtime_base::environment() const noexcept
|
||||
{
|
||||
static const asmjit::Environment g_env = asmjit::Environment::host();
|
||||
|
||||
return g_env;
|
||||
}
|
||||
|
||||
void* jit_runtime_base::_add(asmjit::CodeHolder* code) noexcept
|
||||
{
|
||||
ensure(!code->flatten());
|
||||
ensure(!code->resolveUnresolvedLinks());
|
||||
usz codeSize = code->codeSize();
|
||||
if (!codeSize)
|
||||
return nullptr;
|
||||
|
||||
auto p = ensure(this->_alloc(codeSize, 64));
|
||||
ensure(!code->relocateToBase(uptr(p)));
|
||||
|
||||
{
|
||||
asmjit::VirtMem::ProtectJitReadWriteScope rwScope(p, codeSize);
|
||||
|
||||
for (asmjit::Section* section : code->_sections)
|
||||
{
|
||||
std::memcpy(p + section->offset(), section->data(), section->bufferSize());
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
jit_runtime::jit_runtime()
|
||||
: HostRuntime()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -113,38 +215,9 @@ jit_runtime::~jit_runtime()
|
||||
{
|
||||
}
|
||||
|
||||
asmjit::Error jit_runtime::_add(void** dst, asmjit::CodeHolder* code) noexcept
|
||||
uchar* jit_runtime::_alloc(usz size, usz align) noexcept
|
||||
{
|
||||
usz codeSize = code->getCodeSize();
|
||||
if (!codeSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorNoCodeGenerated;
|
||||
}
|
||||
|
||||
void* p = jit_runtime::alloc(codeSize, 16);
|
||||
if (!p) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorNoVirtualMemory;
|
||||
}
|
||||
|
||||
usz relocSize = code->relocate(p);
|
||||
if (!relocSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorInvalidState;
|
||||
}
|
||||
|
||||
flush(p, relocSize);
|
||||
*dst = p;
|
||||
|
||||
return asmjit::kErrorOk;
|
||||
}
|
||||
|
||||
asmjit::Error jit_runtime::_release(void*) noexcept
|
||||
{
|
||||
return asmjit::kErrorOk;
|
||||
return jit_runtime::alloc(size, align, true);
|
||||
}
|
||||
|
||||
u8* jit_runtime::alloc(usz size, uint align, bool exec) noexcept
|
||||
@@ -191,12 +264,12 @@ void jit_runtime::finalize() noexcept
|
||||
std::memcpy(alloc(s_data_init.size(), 1, false), s_data_init.data(), s_data_init.size());
|
||||
}
|
||||
|
||||
asmjit::Runtime& asmjit::get_global_runtime()
|
||||
jit_runtime_base& asmjit::get_global_runtime()
|
||||
{
|
||||
// 16 MiB for internal needs
|
||||
static constexpr u64 size = 1024 * 1024 * 16;
|
||||
|
||||
struct custom_runtime final : asmjit::HostRuntime
|
||||
struct custom_runtime final : jit_runtime_base
|
||||
{
|
||||
custom_runtime() noexcept
|
||||
{
|
||||
@@ -205,7 +278,7 @@ asmjit::Runtime& asmjit::get_global_runtime()
|
||||
{
|
||||
if (auto ptr = utils::memory_reserve(size, reinterpret_cast<void*>(addr)))
|
||||
{
|
||||
m_pos.raw() = static_cast<std::byte*>(ptr);
|
||||
m_pos.raw() = static_cast<uchar*>(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -217,50 +290,26 @@ asmjit::Runtime& asmjit::get_global_runtime()
|
||||
utils::memory_commit(m_pos, size, utils::protection::wx);
|
||||
}
|
||||
|
||||
custom_runtime(const custom_runtime&) = delete;
|
||||
|
||||
custom_runtime& operator=(const custom_runtime&) = delete;
|
||||
|
||||
asmjit::Error _add(void** dst, asmjit::CodeHolder* code) noexcept override
|
||||
uchar* _alloc(usz size, usz align) noexcept override
|
||||
{
|
||||
usz codeSize = code->getCodeSize();
|
||||
if (!codeSize) [[unlikely]]
|
||||
return m_pos.atomic_op([&](uchar*& pos) -> uchar*
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorNoCodeGenerated;
|
||||
}
|
||||
const auto r = reinterpret_cast<uchar*>(utils::align(uptr(pos), align));
|
||||
|
||||
void* p = m_pos.fetch_add(utils::align(codeSize, 4096));
|
||||
if (!p || m_pos > m_max) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
jit_log.fatal("Out of memory (static asmjit)");
|
||||
return asmjit::kErrorNoVirtualMemory;
|
||||
}
|
||||
if (r >= pos && r + size > pos && r + size <= m_max)
|
||||
{
|
||||
pos = r + size;
|
||||
return r;
|
||||
}
|
||||
|
||||
usz relocSize = code->relocate(p);
|
||||
if (!relocSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorInvalidState;
|
||||
}
|
||||
|
||||
utils::memory_protect(p, utils::align(codeSize, 4096), utils::protection::rx);
|
||||
flush(p, relocSize);
|
||||
*dst = p;
|
||||
|
||||
return asmjit::kErrorOk;
|
||||
}
|
||||
|
||||
asmjit::Error _release(void*) noexcept override
|
||||
{
|
||||
return asmjit::kErrorOk;
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
atomic_t<std::byte*> m_pos{};
|
||||
atomic_t<uchar*> m_pos{};
|
||||
|
||||
std::byte* m_max{};
|
||||
uchar* m_max{};
|
||||
};
|
||||
|
||||
// Magic static
|
||||
@@ -268,6 +317,24 @@ asmjit::Runtime& asmjit::get_global_runtime()
|
||||
return g_rt;
|
||||
}
|
||||
|
||||
asmjit::inline_runtime::inline_runtime(uchar* data, usz size)
|
||||
: m_data(data)
|
||||
, m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
uchar* asmjit::inline_runtime::_alloc(usz size, usz align) noexcept
|
||||
{
|
||||
ensure(align <= 4096);
|
||||
|
||||
return size <= m_size ? m_data : nullptr;
|
||||
}
|
||||
|
||||
asmjit::inline_runtime::~inline_runtime()
|
||||
{
|
||||
utils::memory_protect(m_data, m_size, utils::protection::rx);
|
||||
}
|
||||
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
#include <unordered_map>
|
||||
@@ -293,6 +360,9 @@ asmjit::Runtime& asmjit::get_global_runtime()
|
||||
#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
|
||||
@@ -348,19 +418,21 @@ static u64 make_null_function(const std::string& name)
|
||||
using namespace asmjit;
|
||||
|
||||
// Build a "null" function that contains its name
|
||||
const auto func = build_function_asm<void (*)()>([&](X86Assembler& c, auto& args)
|
||||
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_ptr(&null));
|
||||
c.align(kAlignCode, 16);
|
||||
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(kAlignData, 16);
|
||||
c.align(AlignMode::kData, 16);
|
||||
#endif
|
||||
});
|
||||
|
||||
func_ptr = reinterpret_cast<u64>(func);
|
||||
@@ -368,6 +440,42 @@ static u64 make_null_function(const std::string& name)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
@@ -391,7 +499,8 @@ struct MemoryManager1 : llvm::RTDyldMemoryManager
|
||||
|
||||
~MemoryManager1() override
|
||||
{
|
||||
utils::memory_release(ptr, c_max_size * 2);
|
||||
// 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
|
||||
@@ -725,11 +834,12 @@ std::string jit_compiler::cpu(const std::string& _cpu)
|
||||
}
|
||||
|
||||
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, const std::string& _cpu, u32 flags)
|
||||
: m_cpu(cpu(_cpu))
|
||||
: m_context(new llvm::LLVMContext)
|
||||
, m_cpu(cpu(_cpu))
|
||||
{
|
||||
std::string result;
|
||||
|
||||
auto null_mod = std::make_unique<llvm::Module> ("null_", m_context);
|
||||
auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context);
|
||||
|
||||
if (_link.empty())
|
||||
{
|
||||
@@ -773,6 +883,12 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
+180
-59
@@ -1,8 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
|
||||
// Include asmjit with warnings ignored
|
||||
#define ASMJIT_EMBED
|
||||
#define ASMJIT_DEBUG
|
||||
#define ASMJIT_STATIC
|
||||
#define ASMJIT_BUILD_DEBUG
|
||||
#undef Bool
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
@@ -18,15 +22,41 @@
|
||||
#pragma GCC diagnostic ignored "-Wredundant-decls"
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#ifndef __clang__
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-anon-enum-enum-conversion"
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#else
|
||||
#pragma GCC diagnostic ignored "-Wduplicated-branches"
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion"
|
||||
#endif
|
||||
#include <asmjit/asmjit.h>
|
||||
#if defined(ARCH_ARM64)
|
||||
#include <asmjit/a64.h>
|
||||
#endif
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
using native_asm = asmjit::x86::Assembler;
|
||||
using native_args = std::array<asmjit::x86::Gp, 4>;
|
||||
#elif defined(ARCH_ARM64)
|
||||
using native_asm = asmjit::a64::Assembler;
|
||||
using native_args = std::array<asmjit::a64::Gp, 4>;
|
||||
#endif
|
||||
|
||||
void jit_announce(uptr func, usz size, std::string_view name);
|
||||
|
||||
void jit_announce(auto* func, usz size, std::string_view name)
|
||||
{
|
||||
jit_announce(uptr(func), size, name);
|
||||
}
|
||||
|
||||
enum class jit_class
|
||||
{
|
||||
@@ -36,17 +66,27 @@ enum class jit_class
|
||||
spu_data,
|
||||
};
|
||||
|
||||
struct jit_runtime_base
|
||||
{
|
||||
jit_runtime_base() noexcept = default;
|
||||
virtual ~jit_runtime_base() = default;
|
||||
|
||||
jit_runtime_base(const jit_runtime_base&) = delete;
|
||||
jit_runtime_base& operator=(const jit_runtime_base&) = delete;
|
||||
|
||||
const asmjit::Environment& environment() const noexcept;
|
||||
void* _add(asmjit::CodeHolder* code) noexcept;
|
||||
virtual uchar* _alloc(usz size, usz align) noexcept = 0;
|
||||
};
|
||||
|
||||
// ASMJIT runtime for emitting code in a single 2G region
|
||||
struct jit_runtime final : asmjit::HostRuntime
|
||||
struct jit_runtime final : jit_runtime_base
|
||||
{
|
||||
jit_runtime();
|
||||
~jit_runtime() override;
|
||||
|
||||
// Allocate executable memory
|
||||
asmjit::Error _add(void** dst, asmjit::CodeHolder* code) noexcept override;
|
||||
|
||||
// Do nothing (deallocation is delayed)
|
||||
asmjit::Error _release(void* p) noexcept override;
|
||||
uchar* _alloc(usz size, usz align) noexcept override;
|
||||
|
||||
// Allocate memory
|
||||
static u8* alloc(usz size, uint align, bool exec = true) noexcept;
|
||||
@@ -61,11 +101,25 @@ struct jit_runtime final : asmjit::HostRuntime
|
||||
namespace asmjit
|
||||
{
|
||||
// Should only be used to build global functions
|
||||
asmjit::Runtime& get_global_runtime();
|
||||
jit_runtime_base& get_global_runtime();
|
||||
|
||||
// Don't use directly
|
||||
class inline_runtime : public jit_runtime_base
|
||||
{
|
||||
uchar* m_data;
|
||||
usz m_size;
|
||||
|
||||
public:
|
||||
inline_runtime(uchar* data, usz size);
|
||||
|
||||
~inline_runtime();
|
||||
|
||||
uchar* _alloc(usz size, usz align) noexcept override;
|
||||
};
|
||||
|
||||
// Emit xbegin and adjacent loop, return label at xbegin (don't use xabort please)
|
||||
template <typename F>
|
||||
[[nodiscard]] inline asmjit::Label build_transaction_enter(asmjit::X86Assembler& c, asmjit::Label fallback, F func)
|
||||
[[nodiscard]] inline asmjit::Label build_transaction_enter(asmjit::x86::Assembler& c, asmjit::Label fallback, F func)
|
||||
{
|
||||
Label fall = c.newLabel();
|
||||
Label begin = c.newLabel();
|
||||
@@ -80,7 +134,7 @@ namespace asmjit
|
||||
func();
|
||||
|
||||
// Other bad statuses are ignored regardless of repeat flag (TODO)
|
||||
c.align(kAlignCode, 16);
|
||||
c.align(AlignMode::kCode, 16);
|
||||
c.bind(begin);
|
||||
return fall;
|
||||
|
||||
@@ -88,7 +142,7 @@ namespace asmjit
|
||||
}
|
||||
|
||||
// Helper to spill RDX (EDX) register for RDTSC
|
||||
inline void build_swap_rdx_with(asmjit::X86Assembler& c, std::array<X86Gp, 4>& args, const asmjit::X86Gp& with)
|
||||
inline void build_swap_rdx_with(asmjit::x86::Assembler& c, std::array<x86::Gp, 4>& args, const asmjit::x86::Gp& with)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
c.xchg(args[1], with);
|
||||
@@ -100,7 +154,7 @@ namespace asmjit
|
||||
}
|
||||
|
||||
// Get full RDTSC value into chosen register (clobbers rax/rdx or saves only rax with other target)
|
||||
inline void build_get_tsc(asmjit::X86Assembler& c, const asmjit::X86Gp& to = asmjit::x86::rax)
|
||||
inline void build_get_tsc(asmjit::x86::Assembler& c, const asmjit::x86::Gp& to = asmjit::x86::rax)
|
||||
{
|
||||
if (&to != &x86::rax && &to != &x86::rdx)
|
||||
{
|
||||
@@ -127,21 +181,103 @@ namespace asmjit
|
||||
c.or_(to.r64(), x86::rdx);
|
||||
}
|
||||
}
|
||||
|
||||
inline void build_init_args_from_ghc(native_asm& c, native_args& args)
|
||||
{
|
||||
#if defined(ARCH_X64)
|
||||
// TODO: handle case when args don't overlap with r13/rbp/r12/rbx
|
||||
c.mov(args[0], x86::r13);
|
||||
c.mov(args[1], x86::rbp);
|
||||
c.mov(args[2], x86::r12);
|
||||
c.mov(args[3], x86::rbx);
|
||||
#else
|
||||
static_cast<void>(c);
|
||||
static_cast<void>(args);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void build_init_ghc_args(native_asm& c, native_args& args)
|
||||
{
|
||||
#if defined(ARCH_X64)
|
||||
// TODO: handle case when args don't overlap with r13/rbp/r12/rbx
|
||||
c.mov(x86::r13, args[0]);
|
||||
c.mov(x86::rbp, args[1]);
|
||||
c.mov(x86::r12, args[2]);
|
||||
c.mov(x86::rbx, args[3]);
|
||||
#else
|
||||
static_cast<void>(c);
|
||||
static_cast<void>(args);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
template <uint Size>
|
||||
struct native_vec;
|
||||
|
||||
template <>
|
||||
struct native_vec<16> { using type = x86::Xmm; };
|
||||
|
||||
template <>
|
||||
struct native_vec<32> { using type = x86::Ymm; };
|
||||
|
||||
template <>
|
||||
struct native_vec<64> { using type = x86::Zmm; };
|
||||
|
||||
template <uint Size>
|
||||
using native_vec_t = typename native_vec<Size>::type;
|
||||
|
||||
// if (count > step) { for (; ctr < (count - step); ctr += step) {...} count -= ctr; }
|
||||
inline void build_incomplete_loop(native_asm& c, auto ctr, auto count, u32 step, auto&& build)
|
||||
{
|
||||
asmjit::Label body = c.newLabel();
|
||||
asmjit::Label exit = c.newLabel();
|
||||
|
||||
ensure((step & (step - 1)) == 0);
|
||||
c.cmp(count, step);
|
||||
c.jbe(exit);
|
||||
c.sub(count, step);
|
||||
c.align(asmjit::AlignMode::kCode, 16);
|
||||
c.bind(body);
|
||||
build();
|
||||
c.add(ctr, step);
|
||||
c.sub(count, step);
|
||||
c.ja(body);
|
||||
c.add(count, step);
|
||||
c.bind(exit);
|
||||
}
|
||||
|
||||
// for (; count > 0; ctr++, count--)
|
||||
inline void build_loop(native_asm& c, auto ctr, auto count, auto&& build)
|
||||
{
|
||||
asmjit::Label body = c.newLabel();
|
||||
asmjit::Label exit = c.newLabel();
|
||||
|
||||
c.test(count, count);
|
||||
c.jz(exit);
|
||||
c.align(asmjit::AlignMode::kCode, 16);
|
||||
c.bind(body);
|
||||
build();
|
||||
c.inc(ctr);
|
||||
c.sub(count, 1);
|
||||
c.ja(body);
|
||||
c.bind(exit);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Build runtime function with asmjit::X86Assembler
|
||||
template <typename FT, typename F>
|
||||
inline FT build_function_asm(F&& builder)
|
||||
template <typename FT, typename Asm = native_asm, typename F>
|
||||
inline FT build_function_asm(std::string_view name, F&& builder)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
auto& rt = get_global_runtime();
|
||||
|
||||
CodeHolder code;
|
||||
code.init(rt.getCodeInfo());
|
||||
code._globalHints = asmjit::CodeEmitter::kHintOptimizedAlign;
|
||||
code.init(rt.environment());
|
||||
|
||||
std::array<X86Gp, 4> args;
|
||||
#if defined(ARCH_X64)
|
||||
native_args args;
|
||||
#ifdef _WIN32
|
||||
args[0] = x86::rcx;
|
||||
args[1] = x86::rdx;
|
||||
@@ -153,60 +289,45 @@ inline FT build_function_asm(F&& builder)
|
||||
args[2] = x86::rdx;
|
||||
args[3] = x86::rcx;
|
||||
#endif
|
||||
#elif defined(ARCH_ARM64)
|
||||
native_args args;
|
||||
args[0] = a64::x0;
|
||||
args[1] = a64::x1;
|
||||
args[2] = a64::x2;
|
||||
args[3] = a64::x3;
|
||||
#endif
|
||||
|
||||
X86Assembler compiler(&code);
|
||||
builder(std::ref(compiler), args);
|
||||
ensure(compiler.getLastError() == 0);
|
||||
|
||||
FT result;
|
||||
|
||||
if (rt.add(&result, &code))
|
||||
Asm compiler(&code);
|
||||
compiler.addEncodingOptions(EncodingOptions::kOptimizedAlign);
|
||||
if constexpr (std::is_invocable_r_v<bool, F, Asm&, native_args&>)
|
||||
{
|
||||
return nullptr;
|
||||
if (!builder(compiler, args))
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
builder(compiler, args);
|
||||
}
|
||||
|
||||
return result;
|
||||
const auto result = rt._add(&code);
|
||||
jit_announce(result, code.codeSize(), name);
|
||||
return reinterpret_cast<FT>(uptr(result));
|
||||
}
|
||||
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "util/types.hpp"
|
||||
|
||||
#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 "-Wsuggest-override"
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Winconsistent-missing-override"
|
||||
#endif
|
||||
#endif
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
namespace llvm
|
||||
{
|
||||
class LLVMContext;
|
||||
class ExecutionEngine;
|
||||
class Module;
|
||||
}
|
||||
|
||||
// Temporary compiler interface
|
||||
class jit_compiler final
|
||||
{
|
||||
// Local LLVM context
|
||||
llvm::LLVMContext m_context{};
|
||||
std::unique_ptr<llvm::LLVMContext> m_context{};
|
||||
|
||||
// Execution instance
|
||||
std::unique_ptr<llvm::ExecutionEngine> m_engine{};
|
||||
@@ -221,7 +342,7 @@ public:
|
||||
// Get LLVM context
|
||||
auto& get_context()
|
||||
{
|
||||
return m_context;
|
||||
return *m_context;
|
||||
}
|
||||
|
||||
auto& get_engine() const
|
||||
|
||||
+9
-30
@@ -16,43 +16,22 @@
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string wchar_to_utf8(const wchar_t *src)
|
||||
std::string wchar_to_utf8(std::wstring_view src)
|
||||
{
|
||||
std::string utf8_string;
|
||||
const auto tmp_size = WideCharToMultiByte(CP_UTF8, 0, src, -1, nullptr, 0, nullptr, nullptr);
|
||||
const auto tmp_size = WideCharToMultiByte(CP_UTF8, 0, src.data(), src.size(), nullptr, 0, nullptr, nullptr);
|
||||
utf8_string.resize(tmp_size);
|
||||
WideCharToMultiByte(CP_UTF8, 0, src, -1, utf8_string.data(), tmp_size, nullptr, nullptr);
|
||||
WideCharToMultiByte(CP_UTF8, 0, src.data(), src.size(), utf8_string.data(), tmp_size, nullptr, nullptr);
|
||||
return utf8_string;
|
||||
}
|
||||
|
||||
std::string wchar_path_to_ansi_path(const std::wstring& src)
|
||||
std::wstring utf8_to_wchar(std::string_view src)
|
||||
{
|
||||
std::wstring buf_short;
|
||||
std::string buf_final;
|
||||
|
||||
// Get the short path from the wide char path(short path should only contain ansi characters)
|
||||
auto tmp_size = GetShortPathNameW(src.data(), nullptr, 0);
|
||||
buf_short.resize(tmp_size);
|
||||
GetShortPathNameW(src.data(), buf_short.data(), tmp_size);
|
||||
|
||||
// Convert wide char to ansi
|
||||
tmp_size = WideCharToMultiByte(CP_ACP, 0, buf_short.data(), -1, nullptr, 0, nullptr, nullptr);
|
||||
buf_final.resize(tmp_size);
|
||||
WideCharToMultiByte(CP_ACP, 0, buf_short.data(), -1, buf_final.data(), tmp_size, nullptr, nullptr);
|
||||
|
||||
return buf_final;
|
||||
}
|
||||
|
||||
std::string utf8_path_to_ansi_path(const std::string& src)
|
||||
{
|
||||
std::wstring buf_wide;
|
||||
|
||||
// Converts the utf-8 path to wide char
|
||||
const auto tmp_size = MultiByteToWideChar(CP_UTF8, 0, src.c_str(), -1, nullptr, 0);
|
||||
buf_wide.resize(tmp_size);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src.c_str(), -1, buf_wide.data(), tmp_size);
|
||||
|
||||
return wchar_path_to_ansi_path(buf_wide);
|
||||
std::wstring wchar_string;
|
||||
const auto tmp_size = MultiByteToWideChar(CP_UTF8, 0, src.data(), src.size(), nullptr, 0);
|
||||
wchar_string.resize(tmp_size);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src.data(), src.size(), wchar_string.data(), tmp_size);
|
||||
return wchar_string;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
@@ -239,7 +239,7 @@ struct fmt_class_string<T, void>
|
||||
static void format(std::string& out, u64 arg)
|
||||
{
|
||||
const auto& obj = get_object(arg);
|
||||
|
||||
|
||||
void format_byte_array(std::string&, const uchar*, usz);
|
||||
format_byte_array(out, reinterpret_cast<const uchar*>(std::data(obj)), std::size(obj));
|
||||
}
|
||||
|
||||
+18
-10
@@ -6,10 +6,11 @@
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
|
||||
#include "util/types.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string wchar_to_utf8(const wchar_t *src);
|
||||
std::string wchar_path_to_ansi_path(const std::wstring& src);
|
||||
std::string utf8_path_to_ansi_path(const std::string& src);
|
||||
std::wstring utf8_to_wchar(std::string_view src);
|
||||
std::string wchar_to_utf8(std::wstring_view src);
|
||||
#endif
|
||||
|
||||
// Copy null-terminated string from a std::string or a char array to a char array with truncation
|
||||
@@ -22,17 +23,17 @@ inline void strcpy_trunc(D& dst, const T& src)
|
||||
}
|
||||
|
||||
// Convert string to signed integer
|
||||
bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max);
|
||||
bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max);
|
||||
|
||||
// Convert string to unsigned integer
|
||||
bool try_to_uint64(u64* out, const std::string& value, u64 min, u64 max);
|
||||
bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max);
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
std::string replace_all(std::string_view src, std::string_view from, std::string_view to, usz count = -1);
|
||||
|
||||
template <usz list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::string> (&list)[list_size])
|
||||
std::string replace_all(std::string src, const std::pair<std::string_view, std::string> (&list)[list_size])
|
||||
{
|
||||
for (usz pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
@@ -41,11 +42,14 @@ namespace fmt
|
||||
const usz comp_length = list[i].first.length();
|
||||
|
||||
if (src.length() - pos < comp_length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (src.substr(pos, comp_length) == list[i].first)
|
||||
{
|
||||
src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + src.substr(pos + comp_length);
|
||||
src.erase(pos, comp_length);
|
||||
src.insert(pos, list[i].second.data(), list[i].second.length());
|
||||
pos += list[i].second.length() - 1;
|
||||
break;
|
||||
}
|
||||
@@ -56,7 +60,7 @@ namespace fmt
|
||||
}
|
||||
|
||||
template <usz list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>> (&list)[list_size])
|
||||
std::string replace_all(std::string src, const std::pair<std::string_view, std::function<std::string()>> (&list)[list_size])
|
||||
{
|
||||
for (usz pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
@@ -65,12 +69,16 @@ namespace fmt
|
||||
const usz comp_length = list[i].first.length();
|
||||
|
||||
if (src.length() - pos < comp_length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (src.substr(pos, comp_length) == list[i].first)
|
||||
{
|
||||
src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + src.substr(pos + comp_length);
|
||||
pos += list[i].second().length() - 1;
|
||||
src.erase(pos, comp_length);
|
||||
auto replacement = list[i].second();
|
||||
src.insert(pos, replacement);
|
||||
pos += replacement.length() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+89
-28
@@ -77,7 +77,7 @@
|
||||
#include "util/logs.hpp"
|
||||
#include "util/asm.hpp"
|
||||
#include "util/v128.hpp"
|
||||
#include "util/v128sse.hpp"
|
||||
#include "util/simd.hpp"
|
||||
#include "util/sysinfo.hpp"
|
||||
#include "Emu/Memory/vm_locking.h"
|
||||
|
||||
@@ -189,6 +189,7 @@ bool IsDebuggerPresent()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
enum x64_reg_t : u32
|
||||
{
|
||||
X64R_RAX = 0,
|
||||
@@ -839,6 +840,7 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, usz
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef CONTEXT x64_context;
|
||||
typedef CONTEXT ucontext_t;
|
||||
|
||||
#define X64REG(context, reg) (&(&(context)->Rax)[reg])
|
||||
#define XMMREG(context, reg) (reinterpret_cast<v128*>(&(&(context)->Xmm0)[reg]))
|
||||
@@ -1211,12 +1213,18 @@ usz get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, usz d_
|
||||
return d_size;
|
||||
}
|
||||
|
||||
#elif defined(ARCH_ARM64)
|
||||
|
||||
#define RIP(context) ((context)->uc_mcontext.pc)
|
||||
|
||||
#endif /* ARCH_ */
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
extern std::function<bool(u32 addr, bool is_writing)> g_access_violation_handler;
|
||||
}
|
||||
|
||||
bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) noexcept
|
||||
bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noexcept
|
||||
{
|
||||
g_tls_fault_all++;
|
||||
|
||||
@@ -1243,6 +1251,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
const u8* const code = reinterpret_cast<u8*>(RIP(context));
|
||||
|
||||
x64_op_t op;
|
||||
@@ -1382,6 +1391,9 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
g_tls_fault_spu++;
|
||||
return true;
|
||||
} while (0);
|
||||
#else
|
||||
static_cast<void>(context);
|
||||
#endif /* ARCH_ */
|
||||
|
||||
if (vm::check_addr(addr, is_writing ? vm::page_writable : vm::page_readable))
|
||||
{
|
||||
@@ -1545,7 +1557,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
if (!g_tls_access_violation_recovered)
|
||||
{
|
||||
vm_log.notice("\n%s", dump_useful_thread_info());
|
||||
vm_log.error("Access violation %s location 0x%x (%s) [type=u%u]", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory", d_size * 8);
|
||||
vm_log.error("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
}
|
||||
|
||||
// TODO:
|
||||
@@ -1582,7 +1594,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
// Do not log any further access violations in this case.
|
||||
if (!g_tls_access_violation_recovered)
|
||||
{
|
||||
vm_log.fatal("Access violation %s location 0x%x (%s) [type=u%u]", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory", d_size * 8);
|
||||
vm_log.fatal("Access violation %s location 0x%x (%s)", is_writing ? "writing" : (cpu && cpu->id_type() == 1 && cpu->get_pc() == addr ? "executing" : "reading"), addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
}
|
||||
|
||||
while (Emu.IsPaused())
|
||||
@@ -1754,8 +1766,9 @@ const bool s_exception_handler_set = []() -> bool
|
||||
|
||||
static void signal_handler(int /*sig*/, siginfo_t* info, void* uct) noexcept
|
||||
{
|
||||
x64_context* context = static_cast<ucontext_t*>(uct);
|
||||
ucontext_t* context = static_cast<ucontext_t*>(uct);
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
#ifdef __APPLE__
|
||||
const u64 err = context->uc_mcontext->__es.__err;
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
@@ -1770,6 +1783,23 @@ static void signal_handler(int /*sig*/, siginfo_t* info, void* uct) noexcept
|
||||
|
||||
const bool is_executing = err & 0x10;
|
||||
const bool is_writing = err & 0x2;
|
||||
#elif defined(ARCH_ARM64)
|
||||
const bool is_executing = uptr(info->si_addr) == RIP(context);
|
||||
const u32 insn = is_executing ? 0 : *reinterpret_cast<u32*>(RIP(context));
|
||||
const bool is_writing = (insn & 0xbfff0000) == 0x0c000000
|
||||
|| (insn & 0xbfe00000) == 0x0c800000
|
||||
|| (insn & 0xbfdf0000) == 0x0d000000
|
||||
|| (insn & 0xbfc00000) == 0x0d800000
|
||||
|| (insn & 0x3f400000) == 0x08000000
|
||||
|| (insn & 0x3bc00000) == 0x39000000
|
||||
|| (insn & 0x3fc00000) == 0x3d800000
|
||||
|| (insn & 0x3bc00000) == 0x38000000
|
||||
|| (insn & 0x3fe00000) == 0x3c800000
|
||||
|| (insn & 0x3a400000) == 0x28000000;
|
||||
|
||||
#else
|
||||
#error "signal_handler not implemented"
|
||||
#endif
|
||||
|
||||
const u64 exec64 = (reinterpret_cast<u64>(info->si_addr) - reinterpret_cast<u64>(vm::g_exec_addr)) / 2;
|
||||
const auto cause = is_executing ? "executing" : is_writing ? "writing" : "reading";
|
||||
@@ -1809,6 +1839,26 @@ static void signal_handler(int /*sig*/, siginfo_t* info, void* uct) noexcept
|
||||
thread_ctrl::emergency_exit(msg);
|
||||
}
|
||||
|
||||
static void sigill_handler(int /*sig*/, siginfo_t* info, void* /*uct*/) noexcept
|
||||
{
|
||||
std::string msg = fmt::format("Illegal instruction at %p (%s).\n", info->si_addr, *reinterpret_cast<be_t<u128>*>(info->si_addr));
|
||||
|
||||
append_thread_name(msg);
|
||||
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
sys_log.fatal("\n%s", msg);
|
||||
|
||||
sys_log.notice("\n%s", dump_useful_thread_info());
|
||||
|
||||
// Convert to SIGTRAP
|
||||
raise(SIGTRAP);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_ctrl::emergency_exit(msg);
|
||||
}
|
||||
|
||||
void sigpipe_signaling_handler(int)
|
||||
{
|
||||
}
|
||||
@@ -1826,6 +1876,21 @@ const bool s_exception_handler_set = []() -> bool
|
||||
std::abort();
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (::sigaction(SIGBUS, &sa, NULL) == -1)
|
||||
{
|
||||
std::fprintf(stderr, "sigaction(SIGBUS) failed (%d).\n", errno);
|
||||
std::abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
sa.sa_sigaction = sigill_handler;
|
||||
if (::sigaction(SIGILL, &sa, NULL) == -1)
|
||||
{
|
||||
std::fprintf(stderr, "sigaction(SIGILL) failed (%d).\n", errno);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
sa.sa_handler = sigpipe_signaling_handler;
|
||||
if (::sigaction(SIGPIPE, &sa, NULL) == -1)
|
||||
{
|
||||
@@ -1844,11 +1909,7 @@ const bool s_terminate_handler_set = []() -> bool
|
||||
std::set_terminate([]()
|
||||
{
|
||||
if (IsDebuggerPresent())
|
||||
#ifdef _MSC_VER
|
||||
__debugbreak();
|
||||
#else
|
||||
__asm("int3;");
|
||||
#endif
|
||||
utils::trap();
|
||||
|
||||
report_fatal_error("RPCS3 has abnormally terminated.");
|
||||
});
|
||||
@@ -1897,6 +1958,11 @@ void thread_base::start()
|
||||
m_thread = ::_beginthreadex(nullptr, 0, entry_point, this, CREATE_SUSPENDED, nullptr);
|
||||
ensure(m_thread);
|
||||
ensure(::ResumeThread(reinterpret_cast<HANDLE>(+m_thread)) != -1);
|
||||
#elif defined(__APPLE__)
|
||||
pthread_attr_t stack_size_attr;
|
||||
pthread_attr_init(&stack_size_attr);
|
||||
pthread_attr_setstacksize(&stack_size_attr, 0x800000);
|
||||
ensure(pthread_create(reinterpret_cast<pthread_t*>(&m_thread.raw()), &stack_size_attr, entry_point, this) == 0);
|
||||
#else
|
||||
ensure(pthread_create(reinterpret_cast<pthread_t*>(&m_thread.raw()), nullptr, entry_point, this) == 0);
|
||||
#endif
|
||||
@@ -1922,7 +1988,7 @@ void thread_base::initialize(void (*error_cb)())
|
||||
{
|
||||
if (attempts == umax)
|
||||
{
|
||||
g_tls_wait_time += __rdtsc() - stamp0;
|
||||
g_tls_wait_time += utils::get_tsc() - stamp0;
|
||||
}
|
||||
else if (attempts > 1)
|
||||
{
|
||||
@@ -2083,6 +2149,8 @@ thread_base::native_entry thread_base::finalize(u64 _self) noexcept
|
||||
|
||||
std::fesetround(FE_TONEAREST);
|
||||
|
||||
gv_unset_zeroing_denormals();
|
||||
|
||||
static constexpr u64 s_stop_bit = 0x8000'0000'0000'0000ull;
|
||||
|
||||
static atomic_t<u64> s_pool_ctr = []
|
||||
@@ -2182,26 +2250,27 @@ thread_base::native_entry thread_base::finalize(u64 _self) noexcept
|
||||
|
||||
thread_base::native_entry thread_base::make_trampoline(u64(*entry)(thread_base* _base))
|
||||
{
|
||||
return build_function_asm<native_entry>([&](asmjit::X86Assembler& c, auto& args)
|
||||
return build_function_asm<native_entry>("", [&](native_asm& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
Label _ret = c.newLabel();
|
||||
c.push(x86::rbp);
|
||||
c.sub(x86::rsp, 0x20);
|
||||
|
||||
// Call entry point (TODO: support for detached threads missing?)
|
||||
c.call(imm_ptr(entry));
|
||||
c.call(entry);
|
||||
|
||||
// Call finalize, return if zero
|
||||
c.mov(args[0], x86::rax);
|
||||
c.call(imm_ptr<native_entry(*)(u64)>(finalize));
|
||||
c.call(static_cast<native_entry(*)(u64)>(&finalize));
|
||||
c.test(x86::rax, x86::rax);
|
||||
c.jz(_ret);
|
||||
|
||||
// Otherwise, call it as an entry point with first arg = new current thread
|
||||
c.mov(x86::rbp, x86::rax);
|
||||
c.call(imm_ptr(thread_ctrl::get_current));
|
||||
c.call(thread_ctrl::get_current);
|
||||
c.mov(args[0], x86::rax);
|
||||
c.add(x86::rsp, 0x28);
|
||||
c.jmp(x86::rbp);
|
||||
@@ -2209,6 +2278,7 @@ thread_base::native_entry thread_base::make_trampoline(u64(*entry)(thread_base*
|
||||
c.bind(_ret);
|
||||
c.add(x86::rsp, 0x28);
|
||||
c.ret();
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2351,7 +2421,7 @@ bool thread_base::join(bool dtor) const
|
||||
// Hacked for too sleepy threads (1ms) TODO: make sure it's unneeded and remove
|
||||
const auto timeout = dtor && Emu.IsStopped() ? atomic_wait_timeout{1'000'000} : atomic_wait_timeout::inf;
|
||||
|
||||
auto stamp0 = __rdtsc();
|
||||
auto stamp0 = utils::get_tsc();
|
||||
|
||||
for (u64 i = 0; (m_sync & 3) <= 1; i++)
|
||||
{
|
||||
@@ -2364,7 +2434,7 @@ bool thread_base::join(bool dtor) const
|
||||
|
||||
if (i >= 16 && !(i & (i - 1)) && timeout != atomic_wait_timeout::inf)
|
||||
{
|
||||
sig_log.error(u8"Thread [%s] is too sleepy. Waiting for it %.3fµs already!", *m_tname.load(), (__rdtsc() - stamp0) / (utils::get_tsc_freq() / 1000000.));
|
||||
sig_log.error(u8"Thread [%s] is too sleepy. Waiting for it %.3fµs already!", *m_tname.load(), (utils::get_tsc() - stamp0) / (utils::get_tsc_freq() / 1000000.));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2509,17 +2579,8 @@ void thread_base::exec()
|
||||
|
||||
sig_log.fatal("Thread terminated due to fatal error: %s", reason);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
#else
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
__asm("int3;");
|
||||
}
|
||||
#endif
|
||||
utils::trap();
|
||||
|
||||
if (const auto _this = g_tls_this_thread)
|
||||
{
|
||||
@@ -2841,7 +2902,7 @@ void thread_ctrl::set_native_priority(int priority)
|
||||
|
||||
if (int err = pthread_setschedparam(pthread_self(), policy, ¶m))
|
||||
{
|
||||
sig_log.error("pthraed_setschedparam() failed: %d", err);
|
||||
sig_log.error("pthread_setschedparam() failed: %d", err);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -478,7 +478,19 @@ class named_thread final : public Context, result_storage<Context>, thread_base
|
||||
return thread::finalize(thread_state::finished);
|
||||
}
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
static inline thread::native_entry trampoline = thread::make_trampoline(entry_point);
|
||||
#else
|
||||
static void* trampoline(void* arg)
|
||||
{
|
||||
if (const auto next = thread_base::finalize(entry_point(static_cast<thread_base*>(arg))))
|
||||
{
|
||||
return next(thread_ctrl::get_current());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
friend class thread_ctrl;
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ private:
|
||||
steady_clock::time_point m_end;
|
||||
|
||||
public:
|
||||
Timer() : m_stopped(false)
|
||||
Timer() : m_stopped(false), m_start(steady_clock::now())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -576,7 +576,7 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
|
||||
const u32 alloc_size = utils::align(static_cast<u32>(p.value.long_value) + alloc_at % 4096, 4096);
|
||||
|
||||
// Allocate map if needed, if allocated flags will indicate that bit 62 is set (unique identifier)
|
||||
auto alloc_map = vm::reserve_map(vm::any, alloc_at & -0x10000, utils::align(alloc_size, 0x10000), vm::page_size_64k | vm::preallocated | (1ull << 62));
|
||||
auto alloc_map = vm::reserve_map(vm::any, alloc_at & -0x10000, utils::align(alloc_size, 0x10000), vm::page_size_64k | (1ull << 62));
|
||||
|
||||
u64 flags = vm::alloc_unwritable;
|
||||
|
||||
|
||||
+10
-4
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
|
||||
template<typename T>
|
||||
struct size2_base
|
||||
@@ -670,17 +671,22 @@ struct area_base
|
||||
{
|
||||
return{ x1 / size.width, y1 / size.height, x2 / size.width, y2 / size.height };
|
||||
}
|
||||
constexpr area_base operator / (const T& value) const
|
||||
|
||||
template <typename U> requires (std::is_arithmetic_v<U>)
|
||||
constexpr area_base operator / (const U& value) const
|
||||
{
|
||||
return{ x1 / value, y1 / value, x2 / value, y2 / value };
|
||||
return area_base{static_cast<T>(x1 / value), static_cast<T>(y1 / value), static_cast<T>(x2 / value), static_cast<T>(y2 / value)};
|
||||
}
|
||||
|
||||
constexpr area_base operator * (const size2_base<T>& size) const
|
||||
{
|
||||
return{ x1 * size.width, y1 * size.height, x2 * size.width, y2 * size.height };
|
||||
}
|
||||
constexpr area_base operator * (const f32& value) const
|
||||
|
||||
template <typename U> requires (std::is_arithmetic_v<U>)
|
||||
constexpr area_base operator * (const U& value) const
|
||||
{
|
||||
return{ static_cast<T>(x1 * value), static_cast<T>(y1 * value), static_cast<T>(x2 * value), static_cast<T>(y2 * value) };
|
||||
return area_base{static_cast<T>(x1 * value), static_cast<T>(y1 * value), static_cast<T>(x2 * value), static_cast<T>(y2 * value)};
|
||||
}
|
||||
|
||||
template<typename NT>
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
#include "Utilities/simple_ringbuf.h"
|
||||
|
||||
simple_ringbuf::simple_ringbuf(u32 size)
|
||||
{
|
||||
set_buf_size(size);
|
||||
}
|
||||
|
||||
simple_ringbuf::simple_ringbuf(simple_ringbuf&& other)
|
||||
{
|
||||
rw_ptr = other.rw_ptr.load();
|
||||
buf_size = other.buf_size;
|
||||
buf = std::move(other.buf);
|
||||
initialized = other.initialized.observe();
|
||||
|
||||
other.buf_size = 0;
|
||||
other.rw_ptr = 0;
|
||||
other.initialized = false;
|
||||
}
|
||||
|
||||
simple_ringbuf& simple_ringbuf::operator=(simple_ringbuf&& other)
|
||||
{
|
||||
if (this == &other) return *this;
|
||||
|
||||
rw_ptr = other.rw_ptr.load();
|
||||
buf_size = other.buf_size;
|
||||
buf = std::move(other.buf);
|
||||
initialized = other.initialized.observe();
|
||||
|
||||
other.buf_size = 0;
|
||||
other.rw_ptr = 0;
|
||||
other.initialized = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
u32 simple_ringbuf::get_free_size() const
|
||||
{
|
||||
const u64 _rw_ptr = rw_ptr;
|
||||
const u32 rd = static_cast<u32>(_rw_ptr);
|
||||
const u32 wr = static_cast<u32>(_rw_ptr >> 32);
|
||||
|
||||
return wr >= rd ? buf_size - 1 - (wr - rd) : rd - wr - 1U;
|
||||
}
|
||||
|
||||
u32 simple_ringbuf::get_used_size() const
|
||||
{
|
||||
return buf_size - 1 - get_free_size();
|
||||
}
|
||||
|
||||
u32 simple_ringbuf::get_total_size() const
|
||||
{
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
void simple_ringbuf::set_buf_size(u32 size)
|
||||
{
|
||||
ensure(size);
|
||||
|
||||
this->buf_size = size + 1;
|
||||
buf = std::make_unique<u8[]>(this->buf_size);
|
||||
flush();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void simple_ringbuf::flush()
|
||||
{
|
||||
rw_ptr.atomic_op([&](u64 &val)
|
||||
{
|
||||
val = static_cast<u32>(val >> 32) | (val & 0xFFFFFFFF'00000000);
|
||||
});
|
||||
}
|
||||
|
||||
u32 simple_ringbuf::push(const void *data, u32 size)
|
||||
{
|
||||
ensure(data != nullptr && initialized.observe());
|
||||
|
||||
const u32 old = static_cast<u32>(rw_ptr.load() >> 32);
|
||||
const u32 to_push = std::min(size, get_free_size());
|
||||
auto b_data = static_cast<const u8*>(data);
|
||||
|
||||
if (!to_push) return 0;
|
||||
|
||||
if (old + to_push > buf_size)
|
||||
{
|
||||
const auto first_write_sz = buf_size - old;
|
||||
memcpy(&buf[old], b_data, first_write_sz);
|
||||
memcpy(&buf[0], b_data + first_write_sz, to_push - first_write_sz);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&buf[old], b_data, to_push);
|
||||
}
|
||||
|
||||
rw_ptr.atomic_op([&](u64 &val)
|
||||
{
|
||||
val = static_cast<u64>((old + to_push) % buf_size) << 32 | static_cast<u32>(val);
|
||||
});
|
||||
|
||||
return to_push;
|
||||
}
|
||||
|
||||
u32 simple_ringbuf::pop(void *data, u32 size)
|
||||
{
|
||||
ensure(data != nullptr && initialized.observe());
|
||||
|
||||
const u32 old = static_cast<u32>(rw_ptr.load());
|
||||
const u32 to_pop = std::min(size, get_used_size());
|
||||
u8 *b_data = static_cast<u8*>(data);
|
||||
|
||||
if (!to_pop) return 0;
|
||||
|
||||
if (old + to_pop > buf_size)
|
||||
{
|
||||
const auto first_read_sz = buf_size - old;
|
||||
memcpy(b_data, &buf[old], first_read_sz);
|
||||
memcpy(b_data + first_read_sz, &buf[0], to_pop - first_read_sz);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(b_data, &buf[old], to_pop);
|
||||
}
|
||||
|
||||
rw_ptr.atomic_op([&](u64 &val)
|
||||
{
|
||||
val = (old + to_pop) % buf_size | (val & 0xFFFFFFFF'00000000);
|
||||
});
|
||||
|
||||
return to_pop;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
|
||||
// Single reader/writer simple ringbuffer.
|
||||
// Counters are 32-bit.
|
||||
class simple_ringbuf
|
||||
{
|
||||
private:
|
||||
|
||||
atomic_t<u64> rw_ptr = 0;
|
||||
u32 buf_size = 0;
|
||||
std::unique_ptr<u8[]> buf{};
|
||||
atomic_t<bool> initialized = false;
|
||||
|
||||
public:
|
||||
|
||||
simple_ringbuf() {};
|
||||
simple_ringbuf(u32 size);
|
||||
|
||||
simple_ringbuf(const simple_ringbuf&) = delete;
|
||||
simple_ringbuf& operator=(const simple_ringbuf&) = delete;
|
||||
|
||||
simple_ringbuf(simple_ringbuf&& other);
|
||||
simple_ringbuf& operator=(simple_ringbuf&& other);
|
||||
|
||||
u32 get_free_size() const;
|
||||
u32 get_used_size() const;
|
||||
u32 get_total_size() const;
|
||||
|
||||
// Thread unsafe functions.
|
||||
void set_buf_size(u32 size);
|
||||
void flush(); // Could be safely called from reader.
|
||||
|
||||
u32 push(const void *data, u32 size);
|
||||
u32 pop(void *data, u32 size);
|
||||
};
|
||||
+164
-186
@@ -2,6 +2,7 @@
|
||||
YoRHa Theme for RPCS3
|
||||
by Ani @ https://github.com/AniLeo
|
||||
r1 (2018.02.27)
|
||||
r2 (2021.08.28)
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -33,93 +34,85 @@ QWidget {
|
||||
alternate-background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
/* Debugger: Sets font-family to default (any invalid value could be provided) */
|
||||
#debugger QListWidget, #debugger QTextEdit {
|
||||
font-family: none;
|
||||
}
|
||||
|
||||
|
||||
/* Log+TTY: Use flat dark color background with default font for better readability */
|
||||
#log_frame, #tty_frame {
|
||||
background: rgba(52, 49, 40, 0.9);
|
||||
font-size: 8.50pt;
|
||||
font-family: none;
|
||||
}
|
||||
|
||||
|
||||
/* Debugger: Restore original font size */
|
||||
#debugger QListWidget, #debugger QTextEdit {
|
||||
font-size: 9.50pt;
|
||||
}
|
||||
|
||||
|
||||
/* LLE: Style QListWidget checkboxes (QListWidget) */
|
||||
#lleList::indicator {
|
||||
border: 0.05em solid #4d4940;
|
||||
}
|
||||
#lleList::indicator::unchecked {
|
||||
background-color: #b3ac98;
|
||||
}
|
||||
#lleList::indicator::checked {
|
||||
background-color: #4d4940;
|
||||
}
|
||||
#lleList::indicator::disabled {
|
||||
background-color: #828790;
|
||||
}
|
||||
#lleList::item::selected {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
/* Style QTreeWidget checkboxes */
|
||||
QTreeWidget::indicator {
|
||||
border: 0.05em solid #4d4940;
|
||||
}
|
||||
QTreeWidget::indicator::unchecked {
|
||||
background-color: #b3ac98;
|
||||
}
|
||||
QTreeWidget::indicator::checked {
|
||||
background-color: #4d4940;
|
||||
}
|
||||
QTreeWidget::indicator::disabled {
|
||||
background-color: #828790;
|
||||
}
|
||||
QTreeWidget::item::selected {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
/* Mouse Tooltips */
|
||||
QToolTip {
|
||||
background-color: #b3ac98;
|
||||
color: #4d4940;
|
||||
border: 0.10em solid #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Main Window, Dialogs and some Dialogs that are actually widgets */
|
||||
QDialog, QWidget#trophy_manager, QWidget#cg_disasm, QMainWindow#main_window {
|
||||
/* Every dialog */
|
||||
QDialog {
|
||||
border-image: url("GuiConfigs/YoRHa-background.jpg");
|
||||
}
|
||||
|
||||
/*
|
||||
QTextEdit, QPlainTextEdit: Use flat dark color background with
|
||||
a solid border, smaller font size and
|
||||
default font family for better readability
|
||||
|
||||
RPCS3: Log, TTY, Log Viewer, CG Disasm
|
||||
*/
|
||||
QTextEdit, QPlainTextEdit {
|
||||
background: rgba(52, 49, 40, 0.9);
|
||||
border: 0.05em solid #4d4940;
|
||||
color: #b3ac98;
|
||||
font-family: none;
|
||||
font-size: 8.50pt;
|
||||
}
|
||||
|
||||
/*
|
||||
QListWidget, QTreeWidget: Style checkboxes and rows
|
||||
|
||||
RPCS3: LLE/HLE Selector, Debugger
|
||||
*/
|
||||
QListWidget::item {
|
||||
margin-top: 0.05em;
|
||||
margin-bottom: 0.05em;
|
||||
}
|
||||
QListWidget::indicator, QTreeWidget::indicator {
|
||||
border: 0.05em solid #4d4940;
|
||||
}
|
||||
QListWidget::indicator::unchecked, QTreeWidget::indicator::unchecked {
|
||||
background-color: #b3ac98;
|
||||
}
|
||||
QListWidget::indicator::checked, QTreeWidget::indicator::checked {
|
||||
background-color: #4d4940;
|
||||
}
|
||||
QListWidget::indicator::disabled, QTreeWidget::indicator::disabled {
|
||||
background-color: #828790;
|
||||
}
|
||||
QListWidget::item::selected, QTreeWidget::item::selected {
|
||||
background-color: #4d4940;
|
||||
}
|
||||
|
||||
/*
|
||||
QTableView: Style selected row
|
||||
|
||||
RPCS3: Game List
|
||||
*/
|
||||
QTableView {
|
||||
selection-background-color: #4d4940;
|
||||
}
|
||||
|
||||
/*
|
||||
QToolTip: Mouse Tooltips
|
||||
*/
|
||||
QToolTip {
|
||||
background-color: #b3ac98;
|
||||
border: 0.10em solid #4d4940;
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
/* Table headers */
|
||||
QHeaderView::section {
|
||||
text-transform: uppercase;
|
||||
background: #4d4940;
|
||||
color: #b3ac98;
|
||||
padding-left: 0.15em;
|
||||
padding-top: 0.15em;
|
||||
padding-bottom: 0.10em;
|
||||
padding-left: 0.20em;
|
||||
padding-top: 0.25em;
|
||||
margin-bottom: 0.05em;
|
||||
text-transform: uppercase;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
/* All other Tabs */
|
||||
QTabBar {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
QTabBar::tab {
|
||||
background: transparent;
|
||||
padding-left: 0.50em;
|
||||
@@ -134,75 +127,32 @@ QTabBar::tab::selected {
|
||||
border-bottom-style: solid;
|
||||
}
|
||||
|
||||
|
||||
/* Settings Dialog: Tabs */
|
||||
QTabBar#tab_bar_settings {
|
||||
border-bottom: 0.05em solid #4d4940;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
QTabBar::tab#tab_bar_settings {
|
||||
background: transparent;
|
||||
width: 5.20em;
|
||||
padding-left: 0.50em;
|
||||
padding-right: 0.50em;
|
||||
padding-top: 0.65em;
|
||||
padding-bottom: 0.65em;
|
||||
margin-right: 0.25em;
|
||||
font-size: 10.5pt;
|
||||
font-weight: 550;
|
||||
}
|
||||
QTabBar::tab:last#tab_bar_settings {
|
||||
margin-right: 0em;
|
||||
}
|
||||
QTabBar::tab:!selected:hover#tab_bar_settings {
|
||||
background: transparent;
|
||||
color: #4d4940;
|
||||
}
|
||||
QTabBar::tab::selected#tab_bar_settings {
|
||||
background: #4d4940;
|
||||
color: #aea993;
|
||||
border-bottom-style: solid;
|
||||
margin-top: 0.15em;
|
||||
}
|
||||
|
||||
|
||||
/* Checkboxes */
|
||||
QCheckBox::indicator {
|
||||
border-radius: 0.1em;
|
||||
border: 0.05em solid #4d4940;
|
||||
margin-top: 0.05em;
|
||||
width: 0.8em;
|
||||
height: 0.8em;
|
||||
}
|
||||
QCheckBox::indicator:checked {
|
||||
background-color: #4d4940; /* Dark */
|
||||
}
|
||||
QCheckBox::indicator:unchecked {
|
||||
background-color: #b3ac98; /* Light */
|
||||
}
|
||||
QCheckBox::indicator::disabled {
|
||||
background-color: #828790; /* Gray */
|
||||
}
|
||||
|
||||
|
||||
/* Radio Buttons */
|
||||
QRadioButton::indicator {
|
||||
border-radius: 0.4em;
|
||||
}
|
||||
/* Checkboxes and Radio Buttons */
|
||||
QCheckBox::indicator, QRadioButton::indicator {
|
||||
border: 0.05em solid #4d4940;
|
||||
margin-top: 0.05em;
|
||||
margin-bottom: 0.05em;
|
||||
width: 0.8em;
|
||||
height: 0.8em;
|
||||
}
|
||||
QRadioButton::indicator:checked {
|
||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
||||
background-color: #4d4940; /* Dark */
|
||||
}
|
||||
QRadioButton::indicator:unchecked {
|
||||
QCheckBox::indicator:unchecked, QRadioButton::indicator:unchecked {
|
||||
background-color: #b3ac98; /* Light */
|
||||
}
|
||||
QRadioButton::indicator::disabled {
|
||||
QCheckBox::indicator::disabled, QRadioButton::indicator::disabled {
|
||||
background-color: #828790; /* Gray */
|
||||
}
|
||||
|
||||
|
||||
/* Combo Boxes */
|
||||
QComboBox {
|
||||
background: transparent;
|
||||
@@ -220,13 +170,12 @@ QComboBox::disabled {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Group Boxes (Settings Dialog) */
|
||||
QGroupBox {
|
||||
margin-top: 1em;
|
||||
border: 0.05em solid #4d4940;
|
||||
text-transform: uppercase;
|
||||
font-size: 9.25pt;
|
||||
font-size: 9.00pt;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
@@ -235,7 +184,6 @@ QGroupBox::title {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Buttons */
|
||||
QPushButton {
|
||||
background: #b3ac98;
|
||||
@@ -244,40 +192,28 @@ QPushButton::disabled {
|
||||
background: #828790;
|
||||
}
|
||||
|
||||
|
||||
/* QSpinBox (Settings -> Emulator -> width/height) */
|
||||
/* QDoubleSpinBox (Pads -> Mouse Acceleration -> x/y) */
|
||||
/* QDoubleSpinBox (Pads -> Mouse Acceleration -> x/y) */
|
||||
QSpinBox, QDoubleSpinBox {
|
||||
/* background: transparent; - This hits a weird bug in Qt where background flickers */
|
||||
background-color: #b3ac98;
|
||||
border: 0.05em solid #4d4940;
|
||||
border-radius: 0.10em;
|
||||
}
|
||||
|
||||
QSpinBox::disabled, QDoubleSpinBox::disabled {
|
||||
background-color: #828790;
|
||||
}
|
||||
|
||||
/* Styles Sliders */
|
||||
QSlider::groove:horizontal {
|
||||
border: 0.10em solid #4d4940;
|
||||
border-radius: 0.10em;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
background: #4d4940;
|
||||
width: 0.50em;
|
||||
}
|
||||
|
||||
QSlider#sizeSlider::groove:horizontal {
|
||||
border: 0.10em solid #4d4940;
|
||||
border-radius: 0.10em;
|
||||
height: 1.5em;
|
||||
QSlider::disabled {
|
||||
background: #828790;
|
||||
}
|
||||
|
||||
/* Log and Debugger borders */
|
||||
QTextEdit {
|
||||
border: 0.05em solid #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* For dock buttons to be visible */
|
||||
QDockWidget {
|
||||
background: transparent;
|
||||
@@ -296,13 +232,11 @@ QDockWidget::close-button, QDockWidget::float-button {
|
||||
background-color: #b3ac98;
|
||||
}
|
||||
|
||||
|
||||
/* Disable ugly borders */
|
||||
QTabWidget::pane {
|
||||
border: 0em solid #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Top menu bar */
|
||||
QMenuBar {
|
||||
height:1.50em;
|
||||
@@ -319,7 +253,6 @@ QMenuBar::item:selected {
|
||||
color: #aea993
|
||||
}
|
||||
|
||||
|
||||
QMenu {
|
||||
background: #b3ac98;
|
||||
color: #4d4940;
|
||||
@@ -342,42 +275,6 @@ QMenu::item:disabled {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Pad Settings: Controller Image */
|
||||
QLabel#l_controller {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
|
||||
/* Game Grid Font */
|
||||
QTableWidget#game_grid {
|
||||
font-weight: 600;
|
||||
color: #4d4940;
|
||||
text-transform: uppercase;
|
||||
selection-color: #aea993;
|
||||
}
|
||||
QTableWidget#game_grid::item:selected:active {
|
||||
selection-background-color: #4d4940;
|
||||
}
|
||||
QTableWidget#game_grid::item:selected:!active {
|
||||
selection-background-color: #615c51;
|
||||
}
|
||||
|
||||
|
||||
/* Debug UI Settings buttons */
|
||||
QLabel#color_button {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
/* Search bar on main Toolbar */
|
||||
QLineEdit#mw_searchbar {
|
||||
margin-left: 0.7em;
|
||||
color: #4d4940;
|
||||
font-size: 10.25pt;
|
||||
}
|
||||
|
||||
|
||||
/* Uniform colors in Toolbar */
|
||||
QToolButton {
|
||||
background: transparent;
|
||||
@@ -388,18 +285,95 @@ QToolButton::hover {
|
||||
}
|
||||
|
||||
|
||||
/*** RPCS3 Specifics ***/
|
||||
|
||||
|
||||
/* Main Window, Dialogs and some Dialogs that are actually widgets */
|
||||
QWidget#trophy_manager, QWidget#cg_disasm, QWidget#log_viewer, QMainWindow#main_window {
|
||||
border-image: url("GuiConfigs/YoRHa-background.jpg");
|
||||
}
|
||||
|
||||
/*
|
||||
#debugger: Set font-family to default (any invalid value could be provided)
|
||||
Reset background, color and font size to the global values
|
||||
Add solid border
|
||||
*/
|
||||
#debugger QListWidget, #debugger QTextEdit {
|
||||
background: transparent;
|
||||
border: 0.05em solid #4d4940;
|
||||
color: #292929;
|
||||
font-family: none;
|
||||
font-size: 9.50pt;
|
||||
}
|
||||
|
||||
/* Pad Settings, Emulator Settings Dialogs: Tabs */
|
||||
#pad_settings_dialog QTabWidget::tab-bar {
|
||||
alignment: center;
|
||||
}
|
||||
QTabBar#tab_bar_settings, #pad_settings_dialog QTabBar {
|
||||
border-bottom: 0.05em solid #4d4940;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
QTabBar::tab#tab_bar_settings, #pad_settings_dialog QTabBar::tab {
|
||||
background: transparent;
|
||||
width: 5.20em;
|
||||
padding-left: 0.50em;
|
||||
padding-right: 0.50em;
|
||||
padding-top: 0.65em;
|
||||
padding-bottom: 0.65em;
|
||||
margin-right: 0.25em;
|
||||
font-size: 10.5pt;
|
||||
font-weight: 550;
|
||||
}
|
||||
QTabBar::tab:last#tab_bar_settings, #pad_settings_dialog QTabBar::tab:last {
|
||||
margin-right: 0em;
|
||||
}
|
||||
QTabBar::tab:!selected:hover#tab_bar_settings, #pad_settings_dialog QTabBar::tab:!selected:hover {
|
||||
background: transparent;
|
||||
color: #4d4940;
|
||||
}
|
||||
QTabBar::tab::selected#tab_bar_settings, #pad_settings_dialog QTabBar::tab::selected {
|
||||
background: #4d4940;
|
||||
color: #aea993;
|
||||
border-bottom-style: solid;
|
||||
margin-top: 0.15em;
|
||||
}
|
||||
|
||||
/* Pad Settings: Controller Image */
|
||||
QLabel#l_controller {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
/* Game Grid Font */
|
||||
QTableWidget#game_grid {
|
||||
font-weight: 600;
|
||||
color: #4d4940;
|
||||
text-transform: uppercase;
|
||||
selection-color: #aea993;
|
||||
}
|
||||
|
||||
/* Debug UI Settings buttons */
|
||||
QLabel#color_button {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Search bar on main Toolbar */
|
||||
QLineEdit#mw_searchbar {
|
||||
margin-left: 0.7em;
|
||||
color: #4d4940;
|
||||
font-size: 10.25pt;
|
||||
}
|
||||
|
||||
/* Set Theme UI colors */
|
||||
QLabel#gamelist_icon_background_color {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
|
||||
/* Set Windows Taskbar Thumbnail colors */
|
||||
QLabel#thumbnail_icon_color {
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
|
||||
QLabel#log_level_always {
|
||||
color: #00ffff; /* Cyan */
|
||||
}
|
||||
@@ -433,7 +407,6 @@ QLabel#log_stack {
|
||||
color: #b3ac98; /* Light */
|
||||
}
|
||||
|
||||
|
||||
/* Memory Viewer */
|
||||
QLabel#memory_viewer_address_panel {
|
||||
color: #0000ff; /* Font Color: Blue */
|
||||
@@ -445,7 +418,6 @@ QLabel#memory_viewer_ascii_panel {
|
||||
color: #4d4940; /* Font Color: Grey */
|
||||
}
|
||||
|
||||
|
||||
/* Debugger colors */
|
||||
QLabel#debugger_frame_breakpoint {
|
||||
color: #000000; /* Font Color: Black */
|
||||
@@ -456,9 +428,15 @@ QLabel#debugger_frame_pc {
|
||||
background-color: #00ff00; /* Green */
|
||||
}
|
||||
|
||||
|
||||
/* Trophy Notification Popup */
|
||||
QWidget#trophy_notification_frame {
|
||||
background-color: #b3ac98;
|
||||
color: #4d4940;
|
||||
}
|
||||
|
||||
/*
|
||||
#sizeSlider: Style the main window's icon size slider so it's not stretched
|
||||
*/
|
||||
QSlider#sizeSlider::groove:horizontal {
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -20,11 +20,20 @@ else()
|
||||
# Some distros have the compilers set to use PIE by default, but RPCS3 doesn't work with PIE, so we need to disable it.
|
||||
CHECK_CXX_COMPILER_FLAG("-no-pie" HAS_NO_PIE)
|
||||
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||
CHECK_CXX_COMPILER_FLAG("-msse -msse2 -mcx16" COMPILER_X86)
|
||||
CHECK_CXX_COMPILER_FLAG("-march=armv8.1-a" COMPILER_ARM)
|
||||
|
||||
add_compile_options(-Wall)
|
||||
add_compile_options(-fno-exceptions)
|
||||
add_compile_options(-fstack-protector)
|
||||
add_compile_options(-msse -msse2 -mcx16)
|
||||
|
||||
if (COMPILER_X86)
|
||||
add_compile_options(-msse -msse2 -mcx16)
|
||||
endif()
|
||||
|
||||
if (COMPILER_ARM)
|
||||
add_compile_options(-march=armv8.1-a)
|
||||
endif()
|
||||
|
||||
add_compile_options(-Werror=old-style-cast)
|
||||
add_compile_options(-Werror=sign-compare)
|
||||
@@ -81,7 +90,9 @@ else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
add_compile_options(-stdlib=libc++)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
add_compile_options(-stdlib=libc++)
|
||||
endif()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-no_pie")
|
||||
elseif(WIN32)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
@@ -61,6 +61,7 @@
|
||||
LLVMBitWriter.lib;
|
||||
LLVMCoroutines.lib;
|
||||
LLVMObjCARCOpts.lib;
|
||||
LLVMIntelJITEvents.lib;
|
||||
</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
@@ -62,6 +62,7 @@
|
||||
LLVMBitWriter.lib;
|
||||
LLVMCoroutines.lib;
|
||||
LLVMObjCARCOpts.lib;
|
||||
LLVMIntelJITEvents.lib;
|
||||
</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
namespace Darwin_Version
|
||||
{
|
||||
NSOperatingSystemVersion osver = NSProcessInfo.processInfo.operatingSystemVersion;
|
||||
|
||||
int getNSmajorVersion()
|
||||
{
|
||||
return osver.majorVersion;
|
||||
}
|
||||
|
||||
int getNSminorVersion()
|
||||
{
|
||||
return osver.minorVersion;
|
||||
}
|
||||
|
||||
int getNSpatchVersion()
|
||||
{
|
||||
return osver.patchVersion;
|
||||
}
|
||||
}
|
||||
+1
-1
Submodule llvm updated: 5836324d64...509d31ad89
@@ -39,9 +39,9 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G Ninja -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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm</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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm</CmakeReleaseCLI>
|
||||
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G Ninja -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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm</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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm</CmakeDebugCLI>
|
||||
<CmakeCleanCLI>echo Cleaning..
|
||||
for /F "delims= eol=|" %%f in ('
|
||||
dir /b ^| findstr /V "[^.]*\build[^.]*\.vcxproj"') do (
|
||||
|
||||
@@ -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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm</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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm</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_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_USE_INTEL_JITEVENTS=ON ../llvm</CmakeDebugCLI>
|
||||
<CmakeCleanCLI>echo Cleaning..
|
||||
for /F "delims= eol=|" %%f in ('
|
||||
dir /b ^| findstr /V "[^.]*\build[^.]*\.vcxproj"') do (
|
||||
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
// objdump injection utility for Linux perf tools.
|
||||
// Profiling JIT generated code is always problematic.
|
||||
// On Linux, perf annotation tools do not automatically
|
||||
// disassemble runtime-generated code.
|
||||
// However, it's possible to override objdump utility
|
||||
// which is used to disassemeble executables.
|
||||
// This tool intercepts objdump commands, and if they
|
||||
// correspond to JIT generated objects in RPCS3,
|
||||
// it should be able to correctly disassemble them.
|
||||
// Usage:
|
||||
// 1. Make sure ~/.cache/rpcs3/ASMJIT directory exists.
|
||||
// 2. Build this utility, for example:
|
||||
// g++-11 objdump.cpp -o objdump
|
||||
// 3. Run perf, for example:
|
||||
// perf record -b -p `pgrep rpcs3`
|
||||
// 4. Specify --objdump override, for example:
|
||||
// perf report --objdump=./objdump --gtk
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <unistd.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <charconv>
|
||||
|
||||
std::string to_hex(std::uint64_t value, bool prfx = true)
|
||||
{
|
||||
char buf[20]{}, *ptr = buf + 19;
|
||||
do *--ptr = "0123456789abcdef"[value % 16], value /= 16; while (value);
|
||||
if (!prfx) return ptr;
|
||||
*--ptr = 'x';
|
||||
*--ptr = '0';
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::string home;
|
||||
|
||||
if (const char* d = ::getenv("XDG_CACHE_HOME"))
|
||||
home = d;
|
||||
else if (const char* d = ::getenv("XDG_CONFIG_HOME"))
|
||||
home = d;
|
||||
else if (const char* d = ::getenv("HOME"))
|
||||
home = d, home += "/.cache";
|
||||
|
||||
// Get cache path
|
||||
home += "/rpcs3/ASMJIT/";
|
||||
|
||||
// Get objects
|
||||
int fd = open((home + ".objects").c_str(), O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
|
||||
// Map 4GiB (full size)
|
||||
const auto data = mmap(nullptr, 0x10000'0000, PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
struct entry
|
||||
{
|
||||
std::uint64_t addr;
|
||||
std::uint32_t size;
|
||||
std::uint32_t off;
|
||||
};
|
||||
|
||||
// Index part (precedes actual data)
|
||||
const auto index = static_cast<const entry*>(data);
|
||||
|
||||
const entry* found = nullptr;
|
||||
|
||||
std::string out_file;
|
||||
|
||||
std::vector<std::string> args;
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
// Replace args
|
||||
std::string arg = argv[i];
|
||||
|
||||
if (std::uintptr_t(data) != -1 && arg.find("--start-address=0x") == 0)
|
||||
{
|
||||
// Decode address and try to find the object
|
||||
std::uint64_t addr = -1;
|
||||
|
||||
std::from_chars(arg.data() + strlen("--start-address=0x"), arg.data() + arg.size(), addr, 16);
|
||||
|
||||
for (int j = 0; j < 0x100'0000; j++)
|
||||
{
|
||||
if (index[j].addr == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (index[j].addr == addr)
|
||||
{
|
||||
found = index + j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
// Extract object into a new file (read file name from the mapped memory)
|
||||
const char* name = static_cast<char*>(data) + found->off + found->size;
|
||||
|
||||
if (name[0])
|
||||
{
|
||||
out_file = home + name;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_file = "/tmp/rpcs3.objdump." + std::to_string(getpid());
|
||||
unlink(out_file.c_str());
|
||||
}
|
||||
|
||||
const int fd2 = open(out_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
|
||||
if (fd2 > 0)
|
||||
{
|
||||
// Don't overwrite if exists
|
||||
write(fd2, static_cast<char*>(data) + found->off, found->size);
|
||||
close(fd2);
|
||||
}
|
||||
|
||||
args.emplace_back("--adjust-vma=" + to_hex(addr));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (found && arg.find("--stop-address=0x") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (found && arg == "-d")
|
||||
{
|
||||
arg = "-D";
|
||||
}
|
||||
|
||||
if (arg == "-l")
|
||||
{
|
||||
arg = "-Mintel,x86-64";
|
||||
}
|
||||
|
||||
args.emplace_back(std::move(arg));
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
args.pop_back();
|
||||
args.emplace_back("-b");
|
||||
args.emplace_back("binary");
|
||||
args.emplace_back("-m");
|
||||
args.emplace_back("i386:x86-64");
|
||||
args.emplace_back(std::move(out_file));
|
||||
}
|
||||
|
||||
args[0] = "/usr/bin/objdump";
|
||||
|
||||
std::vector<char*> new_argv;
|
||||
|
||||
for (auto& arg : args)
|
||||
{
|
||||
new_argv.push_back(arg.data());
|
||||
}
|
||||
|
||||
new_argv.push_back(nullptr);
|
||||
|
||||
if (found)
|
||||
{
|
||||
int fds[2];
|
||||
pipe(fds);
|
||||
|
||||
if (fork() > 0)
|
||||
{
|
||||
close(fds[1]);
|
||||
char c = 0;
|
||||
std::string buf;
|
||||
|
||||
while (read(fds[0], &c, 1) != 0)
|
||||
{
|
||||
if (c)
|
||||
{
|
||||
buf += c;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
write(STDOUT_FILENO, buf.data(), buf.size());
|
||||
buf.clear();
|
||||
}
|
||||
}
|
||||
|
||||
c = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((dup2(fds[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
|
||||
close(fds[1]);
|
||||
close(fds[0]);
|
||||
// Fallthrough
|
||||
}
|
||||
}
|
||||
|
||||
return execv(new_argv[0], new_argv.data());
|
||||
}
|
||||
@@ -17,8 +17,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rpcs3.emu", "rpcs3.emu", "{
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XAudio", "rpcs3\XAudio.vcxproj", "{78CB2F39-B809-4A06-8329-8C0A19119D3D}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenAL", "rpcs3\OpenAL.vcxproj", "{30A05C4D-F5FD-421C-A864-17A64BDEAA75}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pnglibconf", "3rdparty\libpng\pnglibconf.vcxproj", "{EB33566E-DA7F-4D28-9077-88C0B7C77E35}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "3rdparty\libpng\libpng.vcxproj", "{D6973076-9317-4EF2-A0B8-B7A18AC0713E}"
|
||||
@@ -47,10 +45,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxpro
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038} = {C4A10229-4712-4BD2-B63E-50D93C67A038}
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D} = {78CB2F39-B809-4A06-8329-8C0A19119D3D}
|
||||
{3384223A-6D97-4799-9862-359F85312892} = {3384223A-6D97-4799-9862-359F85312892}
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {30A05C4D-F5FD-421C-A864-17A64BDEAA75}
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF} = {60F89955-91C6-3A36-8000-13C592FEC2DF}
|
||||
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {D6973076-9317-4EF2-A0B8-B7A18AC0713E}
|
||||
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2} = {9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}
|
||||
{FDA7B080-03B0-48C8-B24F-88118981422A} = {FDA7B080-03B0-48C8-B24F-88118981422A}
|
||||
{508c291a-3d18-49f5-b25d-f7c8db92cb21} = {508c291a-3d18-49f5-b25d-f7c8db92cb21}
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122} = {FDC361C5-7734-493B-8CFB-037308B35122}
|
||||
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}
|
||||
@@ -79,6 +79,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdParty", "3rdParty", "{6C
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build_clang_cl", "llvm_build\llvm_build_clang_cl.vcxproj", "{A37E4273-85DB-4217-B775-CE971B87D9DF}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Cubeb", "rpcs3\Cubeb.vcxproj", "{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcubeb", "3rdparty\cubeb\libcubeb.vcxproj", "{FDA7B080-03B0-48C8-B24F-88118981422A}"
|
||||
EndProject
|
||||
Project("{508c291a-3d18-49f5-b25d-f7c8db92cb21}") = "soundtouch", "3rdparty\SoundTouch\soundtouch.vcxproj", "{508c291a-3d18-49f5-b25d-f7c8db92cb21}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -103,10 +109,6 @@ Global
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.Build.0 = Debug|x64
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.ActiveCfg = Release|x64
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.Build.0 = Release|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.Build.0 = Debug|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.Build.0 = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.ActiveCfg = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.Build.0 = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release|x64.ActiveCfg = Release|x64
|
||||
@@ -161,6 +163,18 @@ Global
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Release|x64.ActiveCfg = Release|x64
|
||||
{A37E4273-85DB-4217-B775-CE971B87D9DF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A37E4273-85DB-4217-B775-CE971B87D9DF}.Release|x64.ActiveCfg = Release|x64
|
||||
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}.Debug|x64.Build.0 = Debug|x64
|
||||
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}.Release|x64.ActiveCfg = Release|x64
|
||||
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}.Release|x64.Build.0 = Release|x64
|
||||
{FDA7B080-03B0-48C8-B24F-88118981422A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FDA7B080-03B0-48C8-B24F-88118981422A}.Debug|x64.Build.0 = Debug|x64
|
||||
{FDA7B080-03B0-48C8-B24F-88118981422A}.Release|x64.ActiveCfg = Release|x64
|
||||
{FDA7B080-03B0-48C8-B24F-88118981422A}.Release|x64.Build.0 = Release|x64
|
||||
{508c291a-3d18-49f5-b25d-f7c8db92cb21}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{508c291a-3d18-49f5-b25d-f7c8db92cb21}.Debug|x64.Build.0 = Debug|x64
|
||||
{508c291a-3d18-49f5-b25d-f7c8db92cb21}.Release|x64.ActiveCfg = Release|x64
|
||||
{508c291a-3d18-49f5-b25d-f7c8db92cb21}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -171,7 +185,6 @@ Global
|
||||
{8BC303AB-25BE-4276-8E57-73F171B2D672} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
|
||||
{3384223A-6D97-4799-9862-359F85312892} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
@@ -186,6 +199,9 @@ Global
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
|
||||
{A37E4273-85DB-4217-B775-CE971B87D9DF} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
|
||||
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{FDA7B080-03B0-48C8-B24F-88118981422A} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
{508c291a-3d18-49f5-b25d-f7c8db92cb21} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {06CC7920-E085-4B81-9582-8DE8AAD42510}
|
||||
|
||||
+14
-23
@@ -3,6 +3,9 @@ if(USE_PRECOMPILED_HEADERS AND NOT COMMAND target_precompile_headers)
|
||||
include(cotire)
|
||||
endif()
|
||||
|
||||
# Define GNU standard installation directories
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Generate git-version.h at build time.
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/git-version.cmake)
|
||||
|
||||
@@ -23,6 +26,7 @@ elseif(NOT MSVC AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
add_definitions(-DDATADIR="${CMAKE_INSTALL_FULL_DATADIR}/rpcs3")
|
||||
# Optionally enable X11 for window management
|
||||
find_package(X11)
|
||||
if(X11_FOUND)
|
||||
@@ -151,10 +155,6 @@ elseif(UNIX)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git)
|
||||
elseif(WIN32)
|
||||
# TODO(cjj19970505@live.cn)
|
||||
# this is a single-config generator workaround
|
||||
# multi-config generator will fail.
|
||||
|
||||
# TODO(cjj19970505@live.cn)
|
||||
# offical Qt binaries are built with -MD(d) only as stated in offical wiki
|
||||
# https://wiki.qt.io/Technical_FAQ#Why_does_a_statically_built_Qt_use_the_dynamic_Visual_Studio_runtime_libraries_.3F_Do_I_need_to_deploy_those_with_my_application_.3F
|
||||
@@ -175,19 +175,10 @@ elseif(WIN32)
|
||||
list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../bin/")
|
||||
|
||||
# If Qt5 is installed from vcpkg
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../tools/qt5/debug/bin/")
|
||||
else()
|
||||
list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../tools/qt5/bin/")
|
||||
endif()
|
||||
|
||||
find_program(_WINDEPLOYQT
|
||||
NAMES windeployqt
|
||||
PATHS ${_QT5_TOOLS_PATHS}
|
||||
REQUIRED)
|
||||
message("Use windeployqt in ${_WINDEPLOYQT}")
|
||||
list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../tools/qt5$<$<CONFIG:Debug>:/debug>/bin/")
|
||||
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND set PATH=${_QT5_TOOLS_PATHS}$<SEMICOLON>%PATH%
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/bin" "$<TARGET_FILE_DIR:rpcs3>"
|
||||
# If Qt5 is installed from vcpkg, add binary path to PATH
|
||||
# otherwise windeployqt tool won't be able to locate necessary dlls
|
||||
@@ -198,21 +189,21 @@ endif()
|
||||
# Unix installation
|
||||
if(UNIX AND NOT APPLE)
|
||||
# Install the binary
|
||||
install(TARGETS rpcs3 RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
install(TARGETS rpcs3 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
# Install the application icon and menu item
|
||||
install(FILES rpcs3.svg
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps)
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps)
|
||||
install(FILES rpcs3.png
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps)
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps)
|
||||
install(FILES rpcs3.desktop
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
|
||||
install(FILES rpcs3.metainfo.xml
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo)
|
||||
# Install other files
|
||||
install(DIRECTORY ../bin/Icons
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/rpcs3)
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||
install(DIRECTORY ../bin/GuiConfigs
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/rpcs3)
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||
install(DIRECTORY ../bin/git
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/rpcs3)
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||
endif()
|
||||
|
||||
+10
-1
@@ -32,6 +32,8 @@
|
||||
#include "aes.h"
|
||||
#include "aesni.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
/*
|
||||
* 32-bit integer manipulation macros (little endian)
|
||||
*/
|
||||
@@ -459,8 +461,10 @@ int aes_setkey_enc( aes_context *ctx, const unsigned char *key, unsigned int key
|
||||
|
||||
ctx->rk = RK = ctx->buf;
|
||||
|
||||
#if defined(__SSE2__) || defined(_M_X64)
|
||||
if( aesni_supports( POLARSSL_AESNI_AES ) )
|
||||
return( aesni_setkey_enc( reinterpret_cast<unsigned char*>(ctx->rk), key, keysize ) );
|
||||
#endif
|
||||
|
||||
for( i = 0; i < (keysize >> 5); i++ )
|
||||
{
|
||||
@@ -562,12 +566,14 @@ int aes_setkey_dec( aes_context *ctx, const unsigned char *key, unsigned int key
|
||||
if( ret != 0 )
|
||||
return( ret );
|
||||
|
||||
#if defined(__SSE2__) || defined(_M_X64)
|
||||
if( aesni_supports( POLARSSL_AESNI_AES ) )
|
||||
{
|
||||
aesni_inverse_key( reinterpret_cast<unsigned char*>(ctx->rk),
|
||||
reinterpret_cast<const unsigned char*>(cty.rk), ctx->nr );
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
SK = cty.rk + cty.nr * 4;
|
||||
|
||||
@@ -593,7 +599,8 @@ int aes_setkey_dec( aes_context *ctx, const unsigned char *key, unsigned int key
|
||||
*RK++ = *SK++;
|
||||
|
||||
done:
|
||||
memset( &cty, 0, sizeof( aes_context ) );
|
||||
// Wipe the stack buffer clean
|
||||
std::fill_n(reinterpret_cast<volatile char*>(&cty), sizeof(cty), 0);
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@@ -655,8 +662,10 @@ int aes_crypt_ecb( aes_context *ctx,
|
||||
int i;
|
||||
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
|
||||
|
||||
#if defined(__SSE2__) || defined(_M_X64)
|
||||
if( aesni_supports( POLARSSL_AESNI_AES ) )
|
||||
return( aesni_crypt_ecb( ctx, mode, input, output ) );
|
||||
#endif
|
||||
|
||||
RK = ctx->rk;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#if defined(__SSE2__) || defined(_M_X64)
|
||||
|
||||
/*
|
||||
* AES-NI support functions
|
||||
*
|
||||
@@ -680,3 +682,5 @@ int aesni_setkey_enc( unsigned char *rk,
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+48
-58
@@ -549,6 +549,11 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
|
||||
bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
|
||||
{
|
||||
if ((npd->license & 0x3) != 0x3)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char dev[0x60] = { 0 };
|
||||
|
||||
// Build the dev buffer (first 0x60 bytes of NPD header in big-endian).
|
||||
@@ -566,12 +571,6 @@ bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
|
||||
u128 klic;
|
||||
std::memcpy(&klic, klicensee, sizeof(klic));
|
||||
|
||||
if (!klic)
|
||||
{
|
||||
// Allow empty dev hash.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate klicensee xor key.
|
||||
u128 key = klic ^ std::bit_cast<u128>(NP_OMAC_KEY_2);
|
||||
|
||||
@@ -579,13 +578,19 @@ 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, bool verbose)
|
||||
bool validate_npd_hashes(const char* 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;
|
||||
|
||||
@@ -704,14 +709,10 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
// 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, verbose))
|
||||
if (!validate_npd_hashes(real_file_name, devklic, &NPD, &EDAT, verbose))
|
||||
{
|
||||
// Ignore header validation in DEBUG data.
|
||||
if ((EDAT.flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
|
||||
{
|
||||
edat_log.error("NPD hash validation failed!");
|
||||
return true;
|
||||
}
|
||||
edat_log.error("NPD hash validation failed!");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Select EDAT key.
|
||||
@@ -784,7 +785,7 @@ u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
|
||||
return rifkey;
|
||||
}
|
||||
|
||||
bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID)
|
||||
bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID, u32* license)
|
||||
{
|
||||
// Setup NPD and EDAT/SDAT structs.
|
||||
NPD_HEADER NPD;
|
||||
@@ -808,17 +809,17 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
|
||||
// Perform header validation (EDAT only).
|
||||
char real_file_name[CRYPTO_MAX_PATH];
|
||||
extract_file_name(input_file_name.c_str(), real_file_name);
|
||||
if (!validate_npd_hashes(real_file_name, custom_klic, &NPD, false))
|
||||
if (!validate_npd_hashes(real_file_name, custom_klic, &NPD, &EDAT, false))
|
||||
{
|
||||
// Ignore header validation in DEBUG data.
|
||||
if ((EDAT.flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
|
||||
{
|
||||
edat_log.error("NPD hash validation failed!");
|
||||
return false;
|
||||
}
|
||||
edat_log.error("NPD hash validation failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
*contentID = std::string(reinterpret_cast<const char*>(NPD.content_id));
|
||||
std::string_view sv{NPD.content_id, std::size(NPD.content_id)};
|
||||
sv = sv.substr(0, sv.find_first_of('\0'));
|
||||
|
||||
if (contentID) *contentID = std::string(sv);
|
||||
if (license) *license = (NPD.license & 3);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -910,33 +911,13 @@ bool EDATADecrypter::ReadHeader()
|
||||
else
|
||||
{
|
||||
// verify key
|
||||
if (!validate_dev_klic(reinterpret_cast<uchar*>(&dev_key), &npdHeader))
|
||||
if (!validate_dev_klic(reinterpret_cast<uchar*>(&dec_key), &npdHeader))
|
||||
{
|
||||
edat_log.error("Failed validating klic");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select EDAT key.
|
||||
if ((npdHeader.license & 0x3) == 0x3) // Type 3: Use supplied devklic.
|
||||
dec_key = std::move(dev_key);
|
||||
else if ((npdHeader.license & 0x2) == 0x2) // Type 2: Use key from RAP file (RIF key).
|
||||
{
|
||||
dec_key = std::move(rif_key);
|
||||
|
||||
if (!dec_key)
|
||||
{
|
||||
edat_log.warning("Empty Dec key for local activation!");
|
||||
}
|
||||
}
|
||||
else if ((npdHeader.license & 0x1) == 0x1) // Type 1: Use network activation.
|
||||
{
|
||||
dec_key = std::move(rif_key);
|
||||
|
||||
if (!dec_key)
|
||||
{
|
||||
edat_log.warning("Empty Dec key for network activation!");
|
||||
}
|
||||
}
|
||||
// Use provided dec_key
|
||||
}
|
||||
|
||||
edata_file.seek(0);
|
||||
@@ -952,29 +933,37 @@ bool EDATADecrypter::ReadHeader()
|
||||
file_size = edatHeader.file_size;
|
||||
total_blocks = utils::aligned_div(edatHeader.file_size, edatHeader.block_size);
|
||||
|
||||
// Try decrypting the first block instead
|
||||
u8 data_sample[1];
|
||||
|
||||
if (file_size && !ReadData(0, data_sample, 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
|
||||
{
|
||||
if (pos > edatHeader.file_size)
|
||||
return 0;
|
||||
size = std::min<u64>(size, pos > edatHeader.file_size ? 0 : edatHeader.file_size - pos);
|
||||
|
||||
// now we need to offset things to account for the actual 'range' requested
|
||||
const u64 startOffset = pos % edatHeader.block_size;
|
||||
|
||||
const u32 num_blocks = static_cast<u32>(utils::aligned_div(startOffset + size, edatHeader.block_size));
|
||||
const u64 bufSize = num_blocks*edatHeader.block_size;
|
||||
if (data_buf_size < (bufSize))
|
||||
if (!size)
|
||||
{
|
||||
data_buf.reset(new u8[bufSize]);
|
||||
data_buf_size = bufSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// find and decrypt block range covering pos + size
|
||||
const u32 starting_block = static_cast<u32>(pos / edatHeader.block_size);
|
||||
const u32 ending_block = std::min(starting_block + num_blocks, total_blocks);
|
||||
// Now we need to offset things to account for the actual 'range' requested
|
||||
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)
|
||||
{
|
||||
edata_file.seek(0);
|
||||
@@ -984,6 +973,7 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
|
||||
edat_log.error("Error Decrypting data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
writeOffset += res;
|
||||
}
|
||||
|
||||
|
||||
+21
-17
@@ -16,9 +16,21 @@ constexpr u32 EDAT_DEBUG_DATA_FLAG = 0x80000000;
|
||||
|
||||
struct loaded_npdrm_keys
|
||||
{
|
||||
atomic_t<u128> devKlic{};
|
||||
atomic_t<u128> rifKey{};
|
||||
atomic_t<u128> dec_keys[16]{};
|
||||
atomic_t<u64> dec_keys_pos = 0;
|
||||
atomic_t<u32> npdrm_fds{0};
|
||||
|
||||
void install_decryption_key(u128 key)
|
||||
{
|
||||
dec_keys_pos.atomic_op([&](u64& pos) { dec_keys[pos++ % std::size(dec_keys)] = key; });
|
||||
}
|
||||
|
||||
// TODO: Check if correct for ELF files usage
|
||||
u128 last_key() const
|
||||
{
|
||||
const usz pos = dec_keys_pos;
|
||||
return pos ? dec_keys[(pos - 1) % std::size(dec_keys)].load() : u128{};
|
||||
}
|
||||
};
|
||||
|
||||
struct NPD_HEADER
|
||||
@@ -45,14 +57,14 @@ 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 bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID);
|
||||
extern bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID = nullptr, u32* license = nullptr);
|
||||
|
||||
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);
|
||||
|
||||
struct EDATADecrypter final : fs::file_base
|
||||
{
|
||||
// file stream
|
||||
const fs::file edata_file;
|
||||
fs::file edata_file;
|
||||
u64 file_size{0};
|
||||
u32 total_blocks{0};
|
||||
u64 pos{0};
|
||||
@@ -61,25 +73,17 @@ struct EDATADecrypter final : fs::file_base
|
||||
EDAT_HEADER edatHeader{};
|
||||
|
||||
// Internal data buffers.
|
||||
std::unique_ptr<u8[]> data_buf{};
|
||||
u64 data_buf_size{0};
|
||||
std::vector<u8> data_buf{};
|
||||
|
||||
u128 dec_key{};
|
||||
|
||||
// edat usage
|
||||
u128 rif_key{};
|
||||
u128 dev_key{};
|
||||
public:
|
||||
// SdataByFd usage
|
||||
EDATADecrypter(fs::file&& input)
|
||||
: edata_file(std::move(input)) {}
|
||||
// Edat usage
|
||||
EDATADecrypter(fs::file&& input, const u128& dev_key, const u128& rif_key)
|
||||
EDATADecrypter(fs::file&& input, u128 dec_key = {})
|
||||
: edata_file(std::move(input))
|
||||
, rif_key(rif_key)
|
||||
, dev_key(dev_key) {}
|
||||
, dec_key(dec_key)
|
||||
{
|
||||
}
|
||||
|
||||
~EDATADecrypter() override {}
|
||||
// false if invalid
|
||||
bool ReadHeader();
|
||||
u64 ReadData(u64 pos, u8* data, u64 size);
|
||||
|
||||
+22
-1
@@ -1343,6 +1343,27 @@ static bool IsSelfElf32(const fs::file& f)
|
||||
return (elf_class[4] == 1);
|
||||
}
|
||||
|
||||
static bool IsDebugSelf(const fs::file& f)
|
||||
{
|
||||
if (f.size() < 0x18)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the key version.
|
||||
f.seek(0x08);
|
||||
|
||||
const u16 key_version = f.read<le_t<u16>>();
|
||||
|
||||
// Check for DEBUG version.
|
||||
if (key_version == 0x80 || key_version == 0xc0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CheckDebugSelf(fs::file& s)
|
||||
{
|
||||
if (s.size() < 0x18)
|
||||
@@ -1442,7 +1463,7 @@ bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key)
|
||||
|
||||
self.seek(0);
|
||||
|
||||
if (self.size() >= 4 && self.read<u32>() == "SCE\0"_u32)
|
||||
if (self.size() >= 4 && self.read<u32>() == "SCE\0"_u32 && !IsDebugSelf(self))
|
||||
{
|
||||
// Check the ELF file class (32 or 64 bit).
|
||||
const bool isElf32 = IsSelfElf32(self);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
@@ -11,9 +11,8 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{30A05C4D-F5FD-421C-A864-17A64BDEAA75}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>OpenAL</RootNamespace>
|
||||
<ProjectGuid>{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}</ProjectGuid>
|
||||
<RootNamespace>Cubeb</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
@@ -37,36 +36,28 @@
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'" Label="PropertySheets">
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_debug.props" />
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_llvm.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'" Label="PropertySheets">
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_release.props" />
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_llvm.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\3rdparty\OpenAL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\3rdparty\cubeb\cubeb\include\;..\3rdparty\cubeb\extra\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Emu\Audio\AL\OpenALBackend.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Emu\Audio\AL\OpenALBackend.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="emucore.vcxproj">
|
||||
<Project>{c4a10229-4712-4bd2-b63e-50d93c67a038}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Emu\Audio\Cubeb\CubebBackend.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Emu\Audio\Cubeb\CubebBackend.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1,19 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<UniqueIdentifier>{F573EFFC-2BB8-43DF-AEFA-4E9EA31A817F}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Emu\Audio\AL\OpenALBackend.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Emu\Audio\AL\OpenALBackend.cpp">
|
||||
<ClCompile Include="Emu\Audio\Cubeb\CubebBackend.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Emu\Audio\Cubeb\CubebBackend.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,212 +0,0 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "OpenALBackend.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "OpenAL32.lib")
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(OpenAL);
|
||||
|
||||
#define checkForAlError(sit) do { ALenum g_last_al_error = alGetError(); if(g_last_al_error != AL_NO_ERROR) OpenAL.error("%s: OpenAL error 0x%04x", sit, g_last_al_error); } while(0)
|
||||
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) { OpenAL.error("%s: OpenALC error 0x%04x", sit, g_last_alc_error); return; }} while(0)
|
||||
|
||||
OpenALBackend::OpenALBackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
ALCint attribs[] = {ALC_FREQUENCY, DEFAULT_AUDIO_SAMPLING_RATE, 0, 0};
|
||||
|
||||
ALCdevice* m_device = alcOpenDevice(nullptr);
|
||||
checkForAlcError("alcOpenDevice");
|
||||
|
||||
ALCcontext* m_context = alcCreateContext(m_device, attribs);
|
||||
checkForAlcError("alcCreateContext");
|
||||
|
||||
alcMakeContextCurrent(m_context);
|
||||
checkForAlcError("alcMakeContextCurrent");
|
||||
|
||||
switch (m_channels)
|
||||
{
|
||||
case 2:
|
||||
m_format = (m_sample_size == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
|
||||
break;
|
||||
case 6:
|
||||
m_format = (m_sample_size == 2) ? AL_FORMAT_51CHN16 : AL_FORMAT_51CHN32;
|
||||
break;
|
||||
default:
|
||||
m_format = (m_sample_size == 2) ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenALBackend::~OpenALBackend()
|
||||
{
|
||||
if (alIsSource(m_source))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
if (ALCcontext* m_context = alcGetCurrentContext())
|
||||
{
|
||||
ALCdevice* m_device = alcGetContextsDevice(m_context);
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(m_context);
|
||||
alcCloseDevice(m_device);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenALBackend::Play()
|
||||
{
|
||||
AUDIT(alIsSource(m_source));
|
||||
|
||||
ALint state;
|
||||
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
|
||||
checkForAlError("Play->alGetSourcei(AL_SOURCE_STATE)");
|
||||
|
||||
if (state != AL_PLAYING)
|
||||
{
|
||||
alSourcePlay(m_source);
|
||||
checkForAlError("Play->alSourcePlay");
|
||||
}
|
||||
}
|
||||
|
||||
void OpenALBackend::Pause()
|
||||
{
|
||||
AUDIT(alIsSource(m_source));
|
||||
|
||||
alSourcePause(m_source);
|
||||
checkForAlError("Pause->alSourcePause");
|
||||
}
|
||||
|
||||
bool OpenALBackend::IsPlaying()
|
||||
{
|
||||
AUDIT(alIsSource(m_source));
|
||||
|
||||
ALint state;
|
||||
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
|
||||
checkForAlError("IsPlaying->alGetSourcei(AL_SOURCE_STATE)");
|
||||
|
||||
return state == AL_PLAYING;
|
||||
}
|
||||
|
||||
void OpenALBackend::Open(u32 num_buffers)
|
||||
{
|
||||
AUDIT(!alIsSource(m_source));
|
||||
|
||||
// Initialize Source
|
||||
alGenSources(1, &m_source);
|
||||
checkForAlError("Open->alGenSources");
|
||||
|
||||
alSourcei(m_source, AL_LOOPING, AL_FALSE);
|
||||
checkForAlError("Open->alSourcei");
|
||||
|
||||
// Initialize Buffers
|
||||
alGenBuffers(num_buffers, m_buffers);
|
||||
checkForAlError("Open->alGenBuffers");
|
||||
|
||||
m_num_buffers = num_buffers;
|
||||
m_num_unqueued = num_buffers;
|
||||
}
|
||||
|
||||
void OpenALBackend::Close()
|
||||
{
|
||||
if (alIsSource(m_source))
|
||||
{
|
||||
// Stop & Kill Source
|
||||
Pause();
|
||||
alDeleteSources(1, &m_source);
|
||||
|
||||
// Free Buffers
|
||||
alDeleteBuffers(m_num_buffers, m_buffers);
|
||||
checkForAlError("alDeleteBuffers");
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenALBackend::AddData(const void* src, u32 num_samples)
|
||||
{
|
||||
AUDIT(alIsSource(m_source));
|
||||
|
||||
// Unqueue processed buffers, if any
|
||||
unqueue_processed();
|
||||
|
||||
// Fail if there are no free buffers remaining
|
||||
if (m_num_unqueued == 0)
|
||||
{
|
||||
OpenAL.warning("No unqueued buffers remaining");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy data to the next available buffer
|
||||
alBufferData(m_buffers[m_next_buffer], m_format, src, num_samples * m_sample_size, m_sampling_rate);
|
||||
checkForAlError("AddData->alBufferData");
|
||||
|
||||
// Enqueue buffer
|
||||
alSourceQueueBuffers(m_source, 1, &m_buffers[m_next_buffer]);
|
||||
checkForAlError("AddData->alSourceQueueBuffers");
|
||||
|
||||
m_num_unqueued--;
|
||||
m_next_buffer = (m_next_buffer + 1) % m_num_buffers;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenALBackend::Flush()
|
||||
{
|
||||
AUDIT(alIsSource(m_source));
|
||||
|
||||
// Stop source first
|
||||
alSourceStop(m_source);
|
||||
checkForAlError("Flush->alSourceStop");
|
||||
|
||||
// Unqueue processed buffers (should now be all of them)
|
||||
unqueue_processed();
|
||||
}
|
||||
|
||||
void OpenALBackend::unqueue_processed()
|
||||
{
|
||||
AUDIT(alIsSource(m_source));
|
||||
|
||||
// Get number of buffers
|
||||
ALint num_processed;
|
||||
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &num_processed);
|
||||
checkForAlError("Flush->alGetSourcei(AL_BUFFERS_PROCESSED)");
|
||||
|
||||
if (num_processed > 0)
|
||||
{
|
||||
// Unqueue all buffers
|
||||
ALuint x[MAX_AUDIO_BUFFERS];
|
||||
alSourceUnqueueBuffers(m_source, num_processed, x);
|
||||
checkForAlError("Flush->alSourceUnqueueBuffers");
|
||||
|
||||
m_num_unqueued += num_processed;
|
||||
}
|
||||
}
|
||||
|
||||
u64 OpenALBackend::GetNumEnqueuedSamples()
|
||||
{
|
||||
AUDIT(alIsSource(m_source));
|
||||
|
||||
// Get number of buffers queued
|
||||
ALint num_queued;
|
||||
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &num_queued);
|
||||
checkForAlError("GetNumEnqueuedSamples->alGetSourcei(AL_BUFFERS_QUEUED)");
|
||||
AUDIT(static_cast<u32>(num_queued) <= m_num_buffers - m_num_unqueued);
|
||||
|
||||
// Get sample position
|
||||
ALint sample_pos;
|
||||
alGetSourcei(m_source, AL_SAMPLE_OFFSET, &sample_pos);
|
||||
checkForAlError("GetNumEnqueuedSamples->alGetSourcei(AL_SAMPLE_OFFSET)");
|
||||
|
||||
// Return
|
||||
return (num_queued * AUDIO_BUFFER_SAMPLES) + (sample_pos % AUDIO_BUFFER_SAMPLES);
|
||||
}
|
||||
|
||||
f32 OpenALBackend::SetFrequencyRatio(f32 new_ratio)
|
||||
{
|
||||
new_ratio = std::clamp(new_ratio, 0.5f, 2.0f);
|
||||
|
||||
alSourcef(m_source, AL_PITCH, new_ratio);
|
||||
checkForAlError("SetFrequencyRatio->alSourcei(AL_PITCH)");
|
||||
|
||||
return new_ratio;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
#include "3rdparty/OpenAL/include/alext.h"
|
||||
|
||||
class OpenALBackend : public AudioBackend
|
||||
{
|
||||
private:
|
||||
ALint m_format{};
|
||||
ALuint m_source{};
|
||||
ALuint m_buffers[MAX_AUDIO_BUFFERS]{};
|
||||
ALsizei m_num_buffers{};
|
||||
|
||||
u32 m_next_buffer = 0;
|
||||
u32 m_num_unqueued = 0;
|
||||
|
||||
void unqueue_processed();
|
||||
|
||||
public:
|
||||
OpenALBackend();
|
||||
~OpenALBackend() override;
|
||||
|
||||
const char* GetName() const override { return "OpenAL"; }
|
||||
|
||||
static const u32 capabilities = PLAY_PAUSE_FLUSH | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO;
|
||||
u32 GetCapabilities() const override { return capabilities; }
|
||||
|
||||
void Open(u32 num_buffers) override;
|
||||
void Close() override;
|
||||
|
||||
void Play() override;
|
||||
void Pause() override;
|
||||
bool IsPlaying() override;
|
||||
|
||||
bool AddData(const void* src, u32 num_samples) override;
|
||||
void Flush() override;
|
||||
|
||||
u64 GetNumEnqueuedSamples() override;
|
||||
f32 SetFrequencyRatio(f32 new_ratio) override;
|
||||
};
|
||||
@@ -1,166 +0,0 @@
|
||||
#ifndef HAVE_ALSA
|
||||
#error "ALSA support disabled but still being built."
|
||||
#endif
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
#include "ALSABackend.h"
|
||||
|
||||
LOG_CHANNEL(ALSA);
|
||||
|
||||
static void error(int err, const char* reason)
|
||||
{
|
||||
ALSA.error("ALSA: %s failed: %s\n", reason, snd_strerror(err));
|
||||
}
|
||||
|
||||
static bool check(int err, const char* reason)
|
||||
{
|
||||
if (err < 0)
|
||||
{
|
||||
error(err, reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ALSABackend::ALSABackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
}
|
||||
|
||||
ALSABackend::~ALSABackend()
|
||||
{
|
||||
if (tls_sw_params || tls_hw_params || tls_handle)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
void ALSABackend::Open(u32 num_buffers)
|
||||
{
|
||||
if (!check(snd_pcm_open(&tls_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK), "snd_pcm_open"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_malloc(&tls_hw_params), "snd_pcm_hw_params_malloc"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_any(tls_handle, tls_hw_params), "snd_pcm_hw_params_any"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_set_access(tls_handle, tls_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_set_format(tls_handle, tls_hw_params, m_convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
|
||||
return;
|
||||
|
||||
uint rate = m_sampling_rate;
|
||||
if (!check(snd_pcm_hw_params_set_rate_near(tls_handle, tls_hw_params, &rate, nullptr), "snd_pcm_hw_params_set_rate_near"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_set_channels(tls_handle, tls_hw_params, m_channels), "snd_pcm_hw_params_set_channels"))
|
||||
return;
|
||||
|
||||
//uint period = 5333;
|
||||
//if (!check(snd_pcm_hw_params_set_period_time_near(tls_handle, tls_hw_params, &period, nullptr), "snd_pcm_hw_params_set_period_time_near"))
|
||||
// return;
|
||||
|
||||
//if (!check(snd_pcm_hw_params_set_periods(tls_handle, tls_hw_params, 4, 0), "snd_pcm_hw_params_set_periods"))
|
||||
// return;
|
||||
|
||||
snd_pcm_uframes_t bufsize_frames = num_buffers * AUDIO_BUFFER_SAMPLES;
|
||||
snd_pcm_uframes_t period_frames = AUDIO_BUFFER_SAMPLES;
|
||||
|
||||
if (!check(snd_pcm_hw_params_set_buffer_size_near(tls_handle, tls_hw_params, &bufsize_frames), "snd_pcm_hw_params_set_buffer_size_near"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_set_period_size_near(tls_handle, tls_hw_params, &period_frames, 0), "snd_pcm_hw_params_set_period_size"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params(tls_handle, tls_hw_params), "snd_pcm_hw_params"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_get_buffer_size(tls_hw_params, &bufsize_frames), "snd_pcm_hw_params_get_buffer_size"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_get_period_size(tls_hw_params, &period_frames, nullptr), "snd_pcm_hw_params_get_period_size"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_sw_params_malloc(&tls_sw_params), "snd_pcm_sw_params_malloc"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_sw_params_current(tls_handle, tls_sw_params), "snd_pcm_sw_params_current"))
|
||||
return;
|
||||
|
||||
period_frames *= m_start_threshold;
|
||||
|
||||
if (!check(snd_pcm_sw_params_set_start_threshold(tls_handle, tls_sw_params, period_frames + 1), "snd_pcm_sw_params_set_start_threshold"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_sw_params_set_stop_threshold(tls_handle, tls_sw_params, bufsize_frames), "snd_pcm_sw_params_set_stop_threshold"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_sw_params(tls_handle, tls_sw_params), "snd_pcm_sw_params"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_prepare(tls_handle), "snd_pcm_prepare"))
|
||||
return;
|
||||
|
||||
ALSA.notice("bufsize_frames=%u, period_frames=%u", bufsize_frames, period_frames);
|
||||
}
|
||||
|
||||
void ALSABackend::Close()
|
||||
{
|
||||
if (tls_sw_params)
|
||||
{
|
||||
snd_pcm_sw_params_free(tls_sw_params);
|
||||
tls_sw_params = nullptr;
|
||||
}
|
||||
|
||||
if (tls_hw_params)
|
||||
{
|
||||
snd_pcm_hw_params_free(tls_hw_params);
|
||||
tls_hw_params = nullptr;
|
||||
}
|
||||
|
||||
if (tls_handle)
|
||||
{
|
||||
snd_pcm_close(tls_handle);
|
||||
tls_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ALSABackend::AddData(const void* src, u32 num_samples)
|
||||
{
|
||||
u32 num_frames = num_samples / m_channels;
|
||||
|
||||
int res = snd_pcm_writei(tls_handle, src, num_frames);
|
||||
|
||||
if (res == -EAGAIN)
|
||||
{
|
||||
ALSA.warning("EAGAIN");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
res = snd_pcm_recover(tls_handle, res, 0);
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
ALSA.warning("Failed to recover (%d)", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res + 0u != num_frames)
|
||||
{
|
||||
ALSA.warning("Error (%d)", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef HAVE_ALSA
|
||||
#error "ALSA support disabled but still being built."
|
||||
#endif
|
||||
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
class ALSABackend : public AudioBackend
|
||||
{
|
||||
snd_pcm_t* tls_handle{};
|
||||
snd_pcm_hw_params_t* tls_hw_params{};
|
||||
snd_pcm_sw_params_t* tls_sw_params{};
|
||||
|
||||
public:
|
||||
ALSABackend();
|
||||
virtual ~ALSABackend() override;
|
||||
|
||||
ALSABackend(const ALSABackend&) = delete;
|
||||
ALSABackend& operator=(const ALSABackend&) = delete;
|
||||
|
||||
virtual const char* GetName() const override { return "ALSA"; }
|
||||
|
||||
static const u32 capabilities = 0;
|
||||
virtual u32 GetCapabilities() const override { return capabilities; }
|
||||
|
||||
virtual void Open(u32) override;
|
||||
virtual void Close() override;
|
||||
|
||||
virtual bool AddData(const void* src, u32 num_samples) override;
|
||||
};
|
||||
@@ -2,105 +2,35 @@
|
||||
#include "AudioBackend.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
AudioBackend::AudioBackend()
|
||||
{
|
||||
m_convert_to_u16 = static_cast<bool>(g_cfg.audio.convert_to_u16);
|
||||
m_sample_size = m_convert_to_u16 ? sizeof(u16) : sizeof(float);
|
||||
m_start_threshold = g_cfg.audio.start_threshold;
|
||||
|
||||
const u32 sampling_period_multiplier_u32 = g_cfg.audio.sampling_period_multiplier;
|
||||
|
||||
if (sampling_period_multiplier_u32 == 100)
|
||||
{
|
||||
m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
|
||||
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
|
||||
m_sampling_rate = static_cast<u32>(f32{ DEFAULT_AUDIO_SAMPLING_RATE } *sampling_rate_multiplier);
|
||||
}
|
||||
|
||||
const audio_downmix downmix = g_cfg.audio.audio_channel_downmix.get();
|
||||
|
||||
switch (downmix)
|
||||
{
|
||||
case audio_downmix::no_downmix:
|
||||
m_channels = 8;
|
||||
break;
|
||||
case audio_downmix::downmix_to_stereo:
|
||||
m_channels = 2;
|
||||
break;
|
||||
case audio_downmix::downmix_to_5_1:
|
||||
m_channels = 6;
|
||||
break;
|
||||
case audio_downmix::use_application_settings:
|
||||
m_channels = 2; // TODO
|
||||
break;
|
||||
default:
|
||||
fmt::throw_exception("Unknown audio channel mode %s (%d)", downmix, static_cast<int>(downmix));
|
||||
}
|
||||
}
|
||||
AudioBackend::AudioBackend() {}
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
u32 AudioBackend::get_sampling_rate() const
|
||||
{
|
||||
return m_sampling_rate;
|
||||
return static_cast<std::underlying_type_t<decltype(m_sampling_rate)>>(m_sampling_rate);
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_sample_size() const
|
||||
{
|
||||
return m_sample_size;
|
||||
return static_cast<std::underlying_type_t<decltype(m_sample_size)>>(m_sample_size);
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_channels() const
|
||||
{
|
||||
return m_channels;
|
||||
return static_cast<std::underlying_type_t<decltype(m_channels)>>(m_channels);
|
||||
}
|
||||
|
||||
bool AudioBackend::get_convert_to_u16() const
|
||||
bool AudioBackend::get_convert_to_s16() const
|
||||
{
|
||||
return m_convert_to_u16;
|
||||
return m_sample_size == AudioSampleSize::S16;
|
||||
}
|
||||
|
||||
bool AudioBackend::has_capability(u32 cap) const
|
||||
void AudioBackend::convert_to_s16(u32 cnt, const f32* src, void* dst)
|
||||
{
|
||||
return (cap & GetCapabilities()) == cap;
|
||||
}
|
||||
|
||||
void AudioBackend::dump_capabilities(std::string& out) const
|
||||
{
|
||||
u32 count = 0;
|
||||
const u32 capabilities = GetCapabilities();
|
||||
|
||||
if (capabilities & PLAY_PAUSE_FLUSH)
|
||||
for (usz i = 0; i < cnt; i++)
|
||||
{
|
||||
fmt::append(out, "PLAY_PAUSE_FLUSH");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (capabilities & IS_PLAYING)
|
||||
{
|
||||
fmt::append(out, "%sIS_PLAYING", count > 0 ? " | " : "");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (capabilities & GET_NUM_ENQUEUED_SAMPLES)
|
||||
{
|
||||
fmt::append(out, "%sGET_NUM_ENQUEUED_SAMPLES", count > 0 ? " | " : "");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (capabilities & SET_FREQUENCY_RATIO)
|
||||
{
|
||||
fmt::append(out, "%sSET_FREQUENCY_RATIO", count > 0 ? " | " : "");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
fmt::append(out, "NONE");
|
||||
static_cast<s16 *>(dst)[i] = static_cast<s16>(std::clamp(src[i] * 32768.5f, -32768.0f, 32767.0f));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,20 +7,37 @@ enum : u32
|
||||
{
|
||||
DEFAULT_AUDIO_SAMPLING_RATE = 48000,
|
||||
MAX_AUDIO_BUFFERS = 64,
|
||||
AUDIO_BUFFER_SAMPLES = 256
|
||||
AUDIO_BUFFER_SAMPLES = 256,
|
||||
AUDIO_MAX_CHANNELS = 8,
|
||||
};
|
||||
|
||||
enum class AudioFreq : u32
|
||||
{
|
||||
FREQ_32K = 32000,
|
||||
FREQ_44K = 44100,
|
||||
FREQ_48K = 48000,
|
||||
FREQ_88K = 88200,
|
||||
FREQ_96K = 96000,
|
||||
FREQ_176K = 176400,
|
||||
FREQ_192K = 192000,
|
||||
};
|
||||
|
||||
enum class AudioSampleSize : u32
|
||||
{
|
||||
FLOAT = sizeof(float),
|
||||
S16 = sizeof(s16),
|
||||
};
|
||||
|
||||
enum class AudioChannelCnt : u32
|
||||
{
|
||||
STEREO = 2,
|
||||
SURROUND_5_1 = 6,
|
||||
SURROUND_7_1 = 8,
|
||||
};
|
||||
|
||||
class AudioBackend
|
||||
{
|
||||
public:
|
||||
enum Capabilities : u32
|
||||
{
|
||||
PLAY_PAUSE_FLUSH = 0x1, // Implements Play, Pause, Flush
|
||||
IS_PLAYING = 0x2, // Implements IsPlaying
|
||||
GET_NUM_ENQUEUED_SAMPLES = 0x4, // Implements GetNumEnqueuedSamples
|
||||
SET_FREQUENCY_RATIO = 0x8, // Implements SetFrequencyRatio
|
||||
};
|
||||
|
||||
AudioBackend();
|
||||
|
||||
virtual ~AudioBackend() = default;
|
||||
@@ -28,71 +45,37 @@ public:
|
||||
/*
|
||||
* Pure virtual methods
|
||||
*/
|
||||
virtual const char* GetName() const = 0;
|
||||
virtual u32 GetCapabilities() const = 0;
|
||||
virtual std::string_view GetName() const = 0;
|
||||
|
||||
virtual void Open(u32 num_buffers) = 0;
|
||||
virtual void Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) = 0;
|
||||
virtual void Close() = 0;
|
||||
|
||||
virtual bool AddData(const void* src, u32 num_samples) = 0;
|
||||
// Sets write callback. It's called when backend requests new data to be sent
|
||||
// Callback should return number of submitted bytes. Calling other backend functions from callback is unsafe
|
||||
virtual void SetWriteCallback(std::function<u32(u32 /* byte_cnt */, void * /* buffer */)> cb) = 0;
|
||||
|
||||
// Returns length of one callback frame in seconds.
|
||||
virtual f64 GetCallbackFrameLen() = 0;
|
||||
|
||||
// Returns true if audio is currently being played, false otherwise
|
||||
virtual bool IsPlaying() = 0;
|
||||
|
||||
// Start playing enqueued data
|
||||
virtual void Play() = 0;
|
||||
|
||||
// Pause playing enqueued data
|
||||
virtual void Pause() = 0;
|
||||
|
||||
/*
|
||||
* This virtual method should be reimplemented if backend can fail to be initialized under non-error conditions
|
||||
* eg. when there is no audio devices attached
|
||||
*/
|
||||
virtual bool Initialized() const { return true; }
|
||||
virtual bool Initialized() { return true; }
|
||||
|
||||
/*
|
||||
* Virtual methods - should be implemented depending on backend capabilities
|
||||
* This virtual method should be reimplemented if backend can fail during normal operation
|
||||
*/
|
||||
|
||||
// Start playing enqueued data
|
||||
// Should be implemented if capabilities & PLAY_PAUSE_FLUSH
|
||||
virtual void Play()
|
||||
{
|
||||
fmt::throw_exception("Play() not implemented");
|
||||
}
|
||||
|
||||
// Pause playing enqueued data
|
||||
// Should be implemented if capabilities & PLAY_PAUSE_FLUSH
|
||||
virtual void Pause()
|
||||
{
|
||||
fmt::throw_exception("Pause() not implemented");
|
||||
}
|
||||
|
||||
// Pause audio, and unqueue all currently queued buffers
|
||||
// Should be implemented if capabilities & PLAY_PAUSE_FLUSH
|
||||
virtual void Flush()
|
||||
{
|
||||
|
||||
fmt::throw_exception("Flush() not implemented");
|
||||
}
|
||||
|
||||
// Returns true if audio is currently being played, false otherwise
|
||||
// Should be implemented if capabilities & IS_PLAYING
|
||||
virtual bool IsPlaying()
|
||||
{
|
||||
fmt::throw_exception("IsPlaying() not implemented");
|
||||
}
|
||||
|
||||
// Returns the number of currently enqueued samples
|
||||
// Should be implemented if capabilities & GET_NUM_ENQUEUED_SAMPLES
|
||||
virtual u64 GetNumEnqueuedSamples()
|
||||
{
|
||||
fmt::throw_exception("GetNumEnqueuedSamples() not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sets a new frequency ratio. Backend is allowed to modify the ratio value, e.g. clamping it to the allowed range
|
||||
// Returns the new frequency ratio set
|
||||
// Should be implemented if capabilities & SET_FREQUENCY_RATIO
|
||||
virtual f32 SetFrequencyRatio(f32 /* new_ratio */) // returns the new ratio
|
||||
{
|
||||
fmt::throw_exception("SetFrequencyRatio() not implemented");
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
virtual bool Operational() { return true; }
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
@@ -103,16 +86,15 @@ public:
|
||||
|
||||
u32 get_channels() const;
|
||||
|
||||
bool get_convert_to_u16() const;
|
||||
bool get_convert_to_s16() const;
|
||||
|
||||
bool has_capability(u32 cap) const;
|
||||
|
||||
void dump_capabilities(std::string& out) const;
|
||||
/*
|
||||
* Convert float buffer to s16 one. src and dst could be the same. cnt is number of buffer elements.
|
||||
*/
|
||||
static void convert_to_s16(u32 cnt, const f32* src, void* dst);
|
||||
|
||||
protected:
|
||||
bool m_convert_to_u16 = false;
|
||||
u32 m_sample_size = sizeof(float);
|
||||
u32 m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
u32 m_channels = 0;
|
||||
u32 m_start_threshold = 1;
|
||||
AudioSampleSize m_sample_size = AudioSampleSize::FLOAT;
|
||||
AudioFreq m_sampling_rate = AudioFreq::FREQ_48K;
|
||||
AudioChannelCnt m_channels = AudioChannelCnt::STEREO;
|
||||
};
|
||||
|
||||
@@ -4,11 +4,22 @@
|
||||
#include "Utilities/date_time.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
AudioDumper::AudioDumper(u16 ch)
|
||||
: m_header(ch)
|
||||
AudioDumper::AudioDumper()
|
||||
{
|
||||
if (GetCh())
|
||||
}
|
||||
|
||||
AudioDumper::~AudioDumper()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void AudioDumper::Open(u16 ch, u32 sample_rate, u32 sample_size)
|
||||
{
|
||||
Close();
|
||||
|
||||
if (ch)
|
||||
{
|
||||
m_header = WAVHeader(ch, sample_rate, sample_size);
|
||||
std::string path = fs::get_cache_dir() + "audio_";
|
||||
if (const std::string id = Emu.GetTitleID(); !id.empty())
|
||||
{
|
||||
@@ -20,12 +31,14 @@ AudioDumper::AudioDumper(u16 ch)
|
||||
}
|
||||
}
|
||||
|
||||
AudioDumper::~AudioDumper()
|
||||
void AudioDumper::Close()
|
||||
{
|
||||
if (GetCh())
|
||||
{
|
||||
m_output.seek(0);
|
||||
m_output.write(m_header); // rewrite file header
|
||||
m_output.close();
|
||||
m_header.FMT.NumChannels = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,19 +30,19 @@ struct WAVHeader
|
||||
u32 SampleRate; // 48000
|
||||
u32 ByteRate; // SampleRate * NumChannels * BitsPerSample/8
|
||||
u16 BlockAlign; // NumChannels * BitsPerSample/8
|
||||
u16 BitsPerSample; // sizeof(float) * 8
|
||||
u16 BitsPerSample; // SampleSize * 8
|
||||
|
||||
FMTHeader() = default;
|
||||
|
||||
FMTHeader(u16 ch)
|
||||
FMTHeader(u16 ch, u32 sample_rate, u32 sample_size)
|
||||
: ID("fmt "_u32)
|
||||
, Size(16)
|
||||
, AudioFormat(3)
|
||||
, AudioFormat(sample_size == sizeof(float) ? 3 : 1)
|
||||
, NumChannels(ch)
|
||||
, SampleRate(48000)
|
||||
, ByteRate(SampleRate * ch * sizeof(float))
|
||||
, BlockAlign(ch * sizeof(float))
|
||||
, BitsPerSample(sizeof(float) * 8)
|
||||
, SampleRate(sample_rate)
|
||||
, ByteRate(SampleRate * ch * sample_size)
|
||||
, BlockAlign(ch * sample_size)
|
||||
, BitsPerSample(sample_size * 8)
|
||||
{
|
||||
}
|
||||
} FMT;
|
||||
@@ -52,9 +52,9 @@ struct WAVHeader
|
||||
|
||||
WAVHeader() = default;
|
||||
|
||||
WAVHeader(u16 ch)
|
||||
WAVHeader(u16 ch, u32 sample_rate, u32 sample_size)
|
||||
: RIFF(sizeof(RIFFHeader) + sizeof(FMTHeader))
|
||||
, FMT(ch)
|
||||
, FMT(ch, sample_rate, sample_size)
|
||||
, ID("data"_u32)
|
||||
, Size(0)
|
||||
{
|
||||
@@ -67,9 +67,12 @@ class AudioDumper
|
||||
fs::file m_output{};
|
||||
|
||||
public:
|
||||
AudioDumper(u16 ch);
|
||||
AudioDumper();
|
||||
~AudioDumper();
|
||||
|
||||
void Open(u16 ch, u32 sample_rate, u32 sample_size);
|
||||
void Close();
|
||||
|
||||
void WriteData(const void* buffer, u32 size);
|
||||
u16 GetCh() const { return m_header.FMT.NumChannels; }
|
||||
};
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
#include "Emu/Audio/Cubeb/CubebBackend.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "util/logs.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <system_error>
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(Cubeb);
|
||||
|
||||
CubebBackend::CubebBackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Cubeb requires COM to be initialized on the thread calling cubeb_init on Windows
|
||||
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
m_com_init_success = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (int err = cubeb_init(&m_ctx, "RPCS3", nullptr))
|
||||
{
|
||||
Cubeb.error("cubeb_init() failed: 0x%08x", err);
|
||||
m_ctx = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
Cubeb.notice("Using backend %s", cubeb_get_backend_id(m_ctx));
|
||||
}
|
||||
|
||||
CubebBackend::~CubebBackend()
|
||||
{
|
||||
Close();
|
||||
|
||||
if (m_ctx)
|
||||
{
|
||||
cubeb_destroy(m_ctx);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (m_com_init_success)
|
||||
{
|
||||
CoUninitialize();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CubebBackend::Initialized()
|
||||
{
|
||||
return m_ctx != nullptr;
|
||||
}
|
||||
|
||||
bool CubebBackend::Operational()
|
||||
{
|
||||
return m_ctx != nullptr && m_stream != nullptr && !m_reset_req.observe();
|
||||
}
|
||||
|
||||
void CubebBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
|
||||
{
|
||||
if (m_ctx == nullptr) return;
|
||||
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
CloseUnlocked();
|
||||
|
||||
m_sampling_rate = freq;
|
||||
m_sample_size = sample_size;
|
||||
m_channels = ch_cnt;
|
||||
full_sample_size = get_channels() * get_sample_size();
|
||||
|
||||
cubeb_stream_params stream_param{};
|
||||
stream_param.format = get_convert_to_s16() ? CUBEB_SAMPLE_S16NE : CUBEB_SAMPLE_FLOAT32NE;
|
||||
stream_param.rate = get_sampling_rate();
|
||||
stream_param.channels = get_channels();
|
||||
stream_param.layout = [&]()
|
||||
{
|
||||
switch (ch_cnt)
|
||||
{
|
||||
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:
|
||||
ensure(false);
|
||||
return CUBEB_LAYOUT_UNDEFINED;
|
||||
}
|
||||
}();
|
||||
|
||||
u32 min_latency{};
|
||||
if (int err = cubeb_get_min_latency(m_ctx, &stream_param, &min_latency))
|
||||
{
|
||||
Cubeb.error("cubeb_get_min_latency() failed: 0x%08x", err);
|
||||
}
|
||||
|
||||
const u32 stream_latency = std::max(static_cast<u32>(AUDIO_MIN_LATENCY * get_sampling_rate()), min_latency);
|
||||
if (int err = cubeb_stream_init(m_ctx, &m_stream, "Main stream", nullptr, nullptr, nullptr, &stream_param, stream_latency, data_cb, state_cb, this))
|
||||
{
|
||||
m_stream = nullptr;
|
||||
Cubeb.error("cubeb_stream_init() failed: 0x%08x", err);
|
||||
}
|
||||
|
||||
if (m_stream == nullptr)
|
||||
{
|
||||
Cubeb.error("Failed to open audio backend. Make sure that no other application is running that might block audio access (e.g. Netflix).");
|
||||
CloseUnlocked();
|
||||
return;
|
||||
}
|
||||
|
||||
if (int err = cubeb_stream_set_volume(m_stream, 1.0))
|
||||
{
|
||||
Cubeb.error("cubeb_stream_set_volume() failed: 0x%08x", err);
|
||||
}
|
||||
|
||||
if (int err = cubeb_stream_start(m_stream))
|
||||
{
|
||||
Cubeb.error("cubeb_stream_start() failed: 0x%08x", err);
|
||||
}
|
||||
}
|
||||
|
||||
void CubebBackend::CloseUnlocked()
|
||||
{
|
||||
if (m_stream == nullptr) return;
|
||||
|
||||
if (int err = cubeb_stream_stop(m_stream))
|
||||
{
|
||||
Cubeb.error("cubeb_stream_stop() failed: 0x%08x", err);
|
||||
}
|
||||
|
||||
cubeb_stream_destroy(m_stream);
|
||||
|
||||
m_playing = false;
|
||||
m_stream = nullptr;
|
||||
m_last_sample.fill(0);
|
||||
}
|
||||
|
||||
void CubebBackend::Close()
|
||||
{
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
CloseUnlocked();
|
||||
}
|
||||
|
||||
void CubebBackend::Play()
|
||||
{
|
||||
if (m_playing) return;
|
||||
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_playing = true;
|
||||
}
|
||||
|
||||
void CubebBackend::Pause()
|
||||
{
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_playing = false;
|
||||
m_last_sample.fill(0);
|
||||
}
|
||||
|
||||
bool CubebBackend::IsPlaying()
|
||||
{
|
||||
return m_playing;
|
||||
}
|
||||
|
||||
void CubebBackend::SetWriteCallback(std::function<u32(u32, void *)> cb)
|
||||
{
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_write_callback = cb;
|
||||
}
|
||||
|
||||
f64 CubebBackend::GetCallbackFrameLen()
|
||||
{
|
||||
u32 stream_latency{};
|
||||
if (int err = cubeb_stream_get_latency(m_stream, &stream_latency))
|
||||
{
|
||||
Cubeb.error("cubeb_stream_get_latency() failed: 0x%08x", err);
|
||||
}
|
||||
|
||||
return std::max<f64>(AUDIO_MIN_LATENCY, static_cast<f64>(stream_latency) / get_sampling_rate());
|
||||
}
|
||||
|
||||
long CubebBackend::data_cb(cubeb_stream* /* stream */, void* user_ptr, void const* /* input_buffer */, void* output_buffer, long nframes)
|
||||
{
|
||||
CubebBackend* const cubeb = static_cast<CubebBackend*>(user_ptr);
|
||||
std::unique_lock lock(cubeb->m_cb_mutex, std::defer_lock);
|
||||
|
||||
if (nframes && lock.try_lock() && cubeb->m_write_callback && cubeb->m_playing)
|
||||
{
|
||||
const u32 sample_size = cubeb->full_sample_size.observe();
|
||||
const u32 bytes_req = nframes * sample_size;
|
||||
u32 written = std::min(cubeb->m_write_callback(bytes_req, output_buffer), bytes_req);
|
||||
written -= written % sample_size;
|
||||
|
||||
if (written >= sample_size)
|
||||
{
|
||||
memcpy(cubeb->m_last_sample.data(), static_cast<u8*>(output_buffer) + written - sample_size, sample_size);
|
||||
}
|
||||
|
||||
for (u32 i = written; i < bytes_req; i += sample_size)
|
||||
{
|
||||
memcpy(static_cast<u8*>(output_buffer) + i, cubeb->m_last_sample.data(), sample_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stream parameters are modified only after stream_destroy. stream_destroy will return
|
||||
// only after this callback returns, so it's safe to access full_sample_size here.
|
||||
memset(output_buffer, 0, nframes * cubeb->full_sample_size.observe());
|
||||
}
|
||||
|
||||
return nframes;
|
||||
}
|
||||
|
||||
void CubebBackend::state_cb(cubeb_stream* /* stream */, void* user_ptr, cubeb_state state)
|
||||
{
|
||||
CubebBackend* const cubeb = static_cast<CubebBackend*>(user_ptr);
|
||||
|
||||
if (state == CUBEB_STATE_ERROR)
|
||||
{
|
||||
Cubeb.error("Stream entered error state");
|
||||
cubeb->m_reset_req = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "Utilities/mutex.h"
|
||||
#include "util/atomic.hpp"
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
#include "cubeb/cubeb.h"
|
||||
|
||||
class CubebBackend final : public AudioBackend
|
||||
{
|
||||
public:
|
||||
CubebBackend();
|
||||
~CubebBackend() override;
|
||||
|
||||
CubebBackend(const CubebBackend&) = delete;
|
||||
CubebBackend& operator=(const CubebBackend&) = delete;
|
||||
|
||||
std::string_view GetName() const override { return "Cubeb"sv; }
|
||||
|
||||
bool Initialized() override;
|
||||
bool Operational() override;
|
||||
|
||||
void Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
|
||||
void Close() override;
|
||||
|
||||
void SetWriteCallback(std::function<u32(u32, void *)> cb) override;
|
||||
f64 GetCallbackFrameLen() override;
|
||||
|
||||
void Play() override;
|
||||
void Pause() override;
|
||||
bool IsPlaying() override;
|
||||
|
||||
private:
|
||||
static constexpr f64 AUDIO_MIN_LATENCY = 512.0 / 48000; // 10ms
|
||||
|
||||
cubeb* m_ctx = nullptr;
|
||||
cubeb_stream* m_stream = nullptr;
|
||||
#ifdef _WIN32
|
||||
bool m_com_init_success = false;
|
||||
#endif
|
||||
|
||||
shared_mutex m_cb_mutex{};
|
||||
std::function<u32(u32, void *)> m_write_callback{};
|
||||
std::array<u8, sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)> m_last_sample{};
|
||||
atomic_t<u8> full_sample_size = 0;
|
||||
|
||||
bool m_playing = false;
|
||||
atomic_t<bool> m_reset_req = false;
|
||||
|
||||
// Cubeb callbacks
|
||||
static long data_cb(cubeb_stream* stream, void* user_ptr, void const* input_buffer, void* output_buffer, long nframes);
|
||||
static void state_cb(cubeb_stream* stream, void* user_ptr, cubeb_state state);
|
||||
|
||||
void CloseUnlocked();
|
||||
};
|
||||
@@ -12,28 +12,41 @@ LOG_CHANNEL(FAudio_, "FAudio");
|
||||
FAudioBackend::FAudioBackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
u32 res = FAudioCreate(&m_instance, 0, FAUDIO_DEFAULT_PROCESSOR);
|
||||
FAudio *instance;
|
||||
|
||||
u32 res = FAudioCreate(&instance, 0, FAUDIO_DEFAULT_PROCESSOR);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudioCreate() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudioCreate() failed(0x%08x)", res);
|
||||
return;
|
||||
}
|
||||
|
||||
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, m_channels, 48000, 0, 0, nullptr);
|
||||
res = FAudio_CreateMasteringVoice(instance, &m_master_voice, FAUDIO_DEFAULT_CHANNELS, FAUDIO_DEFAULT_SAMPLERATE, 0, 0, nullptr);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
|
||||
FAudio_StopEngine(instance);
|
||||
return;
|
||||
}
|
||||
|
||||
OnProcessingPassStart = nullptr;
|
||||
OnProcessingPassEnd = nullptr;
|
||||
OnCriticalError = OnCriticalError_func;
|
||||
|
||||
res = FAudio_RegisterForCallbacks(instance, this);
|
||||
if (res)
|
||||
{
|
||||
// Some error recovery functionality will be lost, but otherwise backend is operational
|
||||
FAudio_.error("FAudio_RegisterForCallbacks() failed(0x%08x)", res);
|
||||
}
|
||||
|
||||
// All succeeded, "commit"
|
||||
m_instance = instance;
|
||||
}
|
||||
|
||||
FAudioBackend::~FAudioBackend()
|
||||
{
|
||||
if (m_source_voice != nullptr)
|
||||
{
|
||||
FAudioSourceVoice_Stop(m_source_voice, 0, FAUDIO_COMMIT_NOW);
|
||||
FAudioVoice_DestroyVoice(m_source_voice);
|
||||
}
|
||||
Close();
|
||||
|
||||
if (m_master_voice != nullptr)
|
||||
{
|
||||
@@ -49,127 +62,203 @@ FAudioBackend::~FAudioBackend()
|
||||
|
||||
void FAudioBackend::Play()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
if (m_source_voice == nullptr)
|
||||
{
|
||||
FAudio_.error("Play() called uninitialized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_playing) return;
|
||||
|
||||
const u32 res = FAudioSourceVoice_Start(m_source_voice, 0, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudioSourceVoice_Start() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudioSourceVoice_Start() failed(0x%08x)", res);
|
||||
}
|
||||
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_playing = true;
|
||||
}
|
||||
|
||||
void FAudioBackend::Pause()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
if (m_source_voice)
|
||||
{
|
||||
u32 res = FAudioSourceVoice_Stop(m_source_voice, 0, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.error("FAudioSourceVoice_Stop() failed(0x%08x)", res);
|
||||
}
|
||||
|
||||
if (res = FAudioSourceVoice_FlushSourceBuffers(m_source_voice))
|
||||
{
|
||||
FAudio_.error("FAudioSourceVoice_FlushSourceBuffers() failed(0x%08x)", res);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FAudio_.error("Pause() called uninitialized");
|
||||
}
|
||||
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_playing = false;
|
||||
m_last_sample.fill(0);
|
||||
}
|
||||
|
||||
void FAudioBackend::CloseUnlocked()
|
||||
{
|
||||
if (m_source_voice == nullptr) return;
|
||||
|
||||
const u32 res = FAudioSourceVoice_Stop(m_source_voice, 0, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudioSourceVoice_Stop() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudioSourceVoice_Stop() failed(0x%08x)", res);
|
||||
}
|
||||
}
|
||||
|
||||
void FAudioBackend::Flush()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
const u32 res = FAudioSourceVoice_FlushSourceBuffers(m_source_voice);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudioSourceVoice_FlushSourceBuffers() failed(0x%08x)", res);
|
||||
}
|
||||
}
|
||||
|
||||
bool FAudioBackend::IsPlaying()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
FAudioVoiceState state;
|
||||
FAudioSourceVoice_GetState(m_source_voice, &state, FAUDIO_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
||||
FAudioVoice_DestroyVoice(m_source_voice);
|
||||
m_playing = false;
|
||||
m_source_voice = nullptr;
|
||||
m_data_buf = nullptr;
|
||||
m_data_buf_len = 0;
|
||||
m_last_sample.fill(0);
|
||||
}
|
||||
|
||||
void FAudioBackend::Close()
|
||||
{
|
||||
Pause();
|
||||
Flush();
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
CloseUnlocked();
|
||||
}
|
||||
|
||||
void FAudioBackend::Open(u32 /* num_buffers */)
|
||||
bool FAudioBackend::Initialized()
|
||||
{
|
||||
return m_instance != nullptr;
|
||||
}
|
||||
|
||||
bool FAudioBackend::Operational()
|
||||
{
|
||||
return m_instance != nullptr && m_source_voice != nullptr && !m_reset_req.observe();
|
||||
}
|
||||
|
||||
void FAudioBackend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
|
||||
{
|
||||
if (m_instance == nullptr) return;
|
||||
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
CloseUnlocked();
|
||||
|
||||
m_sampling_rate = freq;
|
||||
m_sample_size = sample_size;
|
||||
m_channels = ch_cnt;
|
||||
|
||||
FAudioWaveFormatEx waveformatex;
|
||||
waveformatex.wFormatTag = m_convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = m_channels;
|
||||
waveformatex.nSamplesPerSec = m_sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<u32>(m_sampling_rate * m_channels * m_sample_size);
|
||||
waveformatex.nBlockAlign = m_channels * m_sample_size;
|
||||
waveformatex.wBitsPerSample = m_sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
waveformatex.wFormatTag = get_convert_to_s16() ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = get_channels();
|
||||
waveformatex.nSamplesPerSec = get_sampling_rate();
|
||||
waveformatex.nAvgBytesPerSec = static_cast<u32>(get_sampling_rate() * get_channels() * get_sample_size());
|
||||
waveformatex.nBlockAlign = get_channels() * get_sample_size();
|
||||
waveformatex.wBitsPerSample = get_sample_size() * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
const u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, nullptr, nullptr, nullptr);
|
||||
OnVoiceProcessingPassStart = OnVoiceProcessingPassStart_func;
|
||||
OnVoiceProcessingPassEnd = nullptr;
|
||||
OnStreamEnd = nullptr;
|
||||
OnBufferStart = nullptr;
|
||||
OnBufferEnd = nullptr;
|
||||
OnLoopEnd = nullptr;
|
||||
OnVoiceError = nullptr;
|
||||
|
||||
const u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, this, nullptr, nullptr);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudio_CreateSourceVoice() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudio_CreateSourceVoice() failed(0x%08x)", res);
|
||||
}
|
||||
|
||||
if (m_source_voice == nullptr)
|
||||
{
|
||||
FAudio_.fatal("Failed to open audio backend. Make sure that no other application is running that might block audio access (e.g. Netflix).");
|
||||
return;
|
||||
}
|
||||
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
FAudioVoice_SetVolume(m_source_voice, 1.0f, FAUDIO_COMMIT_NOW);
|
||||
|
||||
m_data_buf_len = get_sampling_rate() * get_sample_size() * get_channels() * INTERNAL_BUF_SIZE_MS * static_cast<u32>(FAUDIO_DEFAULT_FREQ_RATIO) / 1000;
|
||||
m_data_buf = std::make_unique<u8[]>(m_data_buf_len);
|
||||
}
|
||||
|
||||
bool FAudioBackend::AddData(const void* src, u32 num_samples)
|
||||
bool FAudioBackend::IsPlaying()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
return m_playing;
|
||||
}
|
||||
|
||||
FAudioVoiceState state;
|
||||
FAudioSourceVoice_GetState(m_source_voice, &state, FAUDIO_VOICE_NOSAMPLESPLAYED);
|
||||
void FAudioBackend::SetWriteCallback(std::function<u32(u32, void *)> cb)
|
||||
{
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_write_callback = cb;
|
||||
}
|
||||
|
||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||
f64 FAudioBackend::GetCallbackFrameLen()
|
||||
{
|
||||
constexpr f64 _10ms = 0.01;
|
||||
|
||||
if (m_instance == nullptr)
|
||||
{
|
||||
FAudio_.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
|
||||
return false;
|
||||
FAudio_.error("GetCallbackFrameLen() called uninitialized");
|
||||
return _10ms;
|
||||
}
|
||||
|
||||
FAudioBuffer buffer;
|
||||
buffer.AudioBytes = num_samples * m_sample_size;
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = FAUDIO_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
buffer.LoopLength = 0;
|
||||
buffer.pAudioData = static_cast<const u8*>(src);
|
||||
buffer.pContext = nullptr;
|
||||
buffer.PlayBegin = 0;
|
||||
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
|
||||
f64 min_latency{};
|
||||
|
||||
const u32 res = FAudioSourceVoice_SubmitSourceBuffer(m_source_voice, &buffer, nullptr);
|
||||
if (res)
|
||||
u32 samples_per_q = 0, freq = 0;
|
||||
FAudio_GetProcessingQuantum(m_instance, &samples_per_q, &freq);
|
||||
|
||||
if (freq)
|
||||
{
|
||||
FAudio_.fatal("FAudioSourceVoice_SubmitSourceBuffer() failed(0x%08x)", res);
|
||||
return false;
|
||||
min_latency = static_cast<f64>(samples_per_q) / freq;
|
||||
}
|
||||
|
||||
return true;
|
||||
return std::max<f64>(min_latency, _10ms);
|
||||
}
|
||||
|
||||
u64 FAudioBackend::GetNumEnqueuedSamples()
|
||||
void FAudioBackend::OnVoiceProcessingPassStart_func(FAudioVoiceCallback *cb_obj, u32 BytesRequired)
|
||||
{
|
||||
FAudioVoiceState state;
|
||||
FAudioSourceVoice_GetState(m_source_voice, &state, 0);
|
||||
FAudioBackend *faudio = static_cast<FAudioBackend *>(cb_obj);
|
||||
|
||||
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
|
||||
return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
|
||||
}
|
||||
|
||||
f32 FAudioBackend::SetFrequencyRatio(f32 new_ratio)
|
||||
{
|
||||
new_ratio = std::clamp(new_ratio, FAUDIO_MIN_FREQ_RATIO, FAUDIO_DEFAULT_FREQ_RATIO);
|
||||
|
||||
const u32 res = FAudioSourceVoice_SetFrequencyRatio(m_source_voice, new_ratio, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
std::unique_lock lock(faudio->m_cb_mutex, std::defer_lock);
|
||||
if (BytesRequired && lock.try_lock() && faudio->m_write_callback && faudio->m_playing)
|
||||
{
|
||||
FAudio_.fatal("FAudioSourceVoice_SetFrequencyRatio() failed(0x%08x)", res);
|
||||
return 1.0f;
|
||||
}
|
||||
ensure(BytesRequired <= faudio->m_data_buf_len, "FAudio internal buffer is too small. Report to developers!");
|
||||
|
||||
return new_ratio;
|
||||
const u32 sample_size = faudio->get_sample_size() * faudio->get_channels();
|
||||
u32 written = std::min(faudio->m_write_callback(BytesRequired, faudio->m_data_buf.get()), BytesRequired);
|
||||
written -= written % sample_size;
|
||||
|
||||
if (written >= sample_size)
|
||||
{
|
||||
memcpy(faudio->m_last_sample.data(), faudio->m_data_buf.get() + written - sample_size, sample_size);
|
||||
}
|
||||
|
||||
for (u32 i = written; i < BytesRequired; i += sample_size)
|
||||
{
|
||||
memcpy(faudio->m_data_buf.get() + i, faudio->m_last_sample.data(), sample_size);
|
||||
}
|
||||
|
||||
FAudioBuffer buffer{};
|
||||
buffer.AudioBytes = BytesRequired;
|
||||
buffer.LoopBegin = FAUDIO_NO_LOOP_REGION;
|
||||
buffer.pAudioData = static_cast<const u8*>(faudio->m_data_buf.get());
|
||||
|
||||
const u32 res = FAudioSourceVoice_SubmitSourceBuffer(faudio->m_source_voice, &buffer, nullptr);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.error("FAudioSourceVoice_SubmitSourceBuffer() failed(0x%08x)", res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FAudioBackend::OnCriticalError_func(FAudioEngineCallback *cb_obj, u32 Error)
|
||||
{
|
||||
FAudio_.error("OnCriticalError() failed(0x%08x)", Error);
|
||||
|
||||
FAudioBackend *faudio = static_cast<FAudioBackend *>(cb_obj);
|
||||
faudio->m_reset_req = true;
|
||||
}
|
||||
|
||||
@@ -4,16 +4,14 @@
|
||||
#error "FAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include "Utilities/mutex.h"
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
#include "FAudio.h"
|
||||
|
||||
class FAudioBackend : public AudioBackend
|
||||
class FAudioBackend : public AudioBackend, public FAudioVoiceCallback, public FAudioEngineCallback
|
||||
{
|
||||
private:
|
||||
FAudio* m_instance{};
|
||||
FAudioMasteringVoice* m_master_voice{};
|
||||
FAudioSourceVoice* m_source_voice{};
|
||||
|
||||
public:
|
||||
FAudioBackend();
|
||||
~FAudioBackend() override;
|
||||
@@ -21,27 +19,42 @@ public:
|
||||
FAudioBackend(const FAudioBackend&) = delete;
|
||||
FAudioBackend& operator=(const FAudioBackend&) = delete;
|
||||
|
||||
const char* GetName() const override
|
||||
{
|
||||
return "FAudio";
|
||||
}
|
||||
std::string_view GetName() const override { return "FAudio"sv; }
|
||||
|
||||
static const u32 capabilities = PLAY_PAUSE_FLUSH | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO;
|
||||
u32 GetCapabilities() const override
|
||||
{
|
||||
return capabilities;
|
||||
}
|
||||
bool Initialized() override;
|
||||
bool Operational() override;
|
||||
|
||||
void Open(u32 /* num_buffers */) override;
|
||||
void Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
|
||||
void Close() override;
|
||||
|
||||
void SetWriteCallback(std::function<u32(u32, void *)> cb) override;
|
||||
f64 GetCallbackFrameLen() override;
|
||||
|
||||
void Play() override;
|
||||
void Pause() override;
|
||||
bool IsPlaying() override;
|
||||
|
||||
bool AddData(const void* src, u32 num_samples) override;
|
||||
void Flush() override;
|
||||
private:
|
||||
static constexpr u32 INTERNAL_BUF_SIZE_MS = 25;
|
||||
|
||||
u64 GetNumEnqueuedSamples() override;
|
||||
f32 SetFrequencyRatio(f32 new_ratio) override;
|
||||
FAudio* m_instance{};
|
||||
FAudioMasteringVoice* m_master_voice{};
|
||||
FAudioSourceVoice* m_source_voice{};
|
||||
|
||||
shared_mutex m_cb_mutex{};
|
||||
std::function<u32(u32, void *)> m_write_callback{};
|
||||
std::unique_ptr<u8[]> m_data_buf{};
|
||||
u64 m_data_buf_len = 0;
|
||||
std::array<u8, sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)> m_last_sample{};
|
||||
|
||||
bool m_playing = false;
|
||||
atomic_t<bool> m_reset_req = false;
|
||||
|
||||
// FAudio voice callbacks
|
||||
static void OnVoiceProcessingPassStart_func(FAudioVoiceCallback *cb_obj, u32 BytesRequired);
|
||||
|
||||
// FAudio engine callbacks
|
||||
static void OnCriticalError_func(FAudioEngineCallback *cb_obj, u32 Error);
|
||||
|
||||
void CloseUnlocked();
|
||||
};
|
||||
|
||||
@@ -6,19 +6,20 @@ class NullAudioBackend : public AudioBackend
|
||||
{
|
||||
public:
|
||||
NullAudioBackend() {}
|
||||
virtual ~NullAudioBackend() {}
|
||||
~NullAudioBackend() {}
|
||||
|
||||
virtual const char* GetName() const override { return "Null"; }
|
||||
std::string_view GetName() const override { return "Null"sv; }
|
||||
|
||||
static const u32 capabilities = PLAY_PAUSE_FLUSH;
|
||||
virtual u32 GetCapabilities() const override { return capabilities; }
|
||||
void Open(AudioFreq /* freq */, AudioSampleSize /* sample_size */, AudioChannelCnt /* ch_cnt */) override { m_playing = false; }
|
||||
void Close() override { m_playing = false; }
|
||||
|
||||
virtual void Open(u32) override {}
|
||||
virtual void Close() override {}
|
||||
void SetWriteCallback(std::function<u32(u32, void *)> /* cb */) override {};
|
||||
f64 GetCallbackFrameLen() override { return 0.01; };
|
||||
|
||||
virtual void Play() override {}
|
||||
virtual void Pause() override {}
|
||||
void Play() override { m_playing = true; }
|
||||
void Pause() override { m_playing = false; }
|
||||
bool IsPlaying() override { return m_playing; }
|
||||
|
||||
virtual bool AddData(const void*, u32) override { return true; }
|
||||
virtual void Flush() override {}
|
||||
private:
|
||||
bool m_playing = false;
|
||||
};
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#ifndef HAVE_PULSE
|
||||
#error "PulseAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
#include "Emu/System.h"
|
||||
#include "PulseBackend.h"
|
||||
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
|
||||
PulseBackend::PulseBackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
}
|
||||
|
||||
PulseBackend::~PulseBackend()
|
||||
{
|
||||
this->Close();
|
||||
}
|
||||
|
||||
void PulseBackend::Close()
|
||||
{
|
||||
if (this->connection)
|
||||
{
|
||||
pa_simple_free(this->connection);
|
||||
this->connection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void PulseBackend::Open(u32 /* num_buffers */)
|
||||
{
|
||||
pa_sample_spec ss;
|
||||
ss.format = (m_sample_size == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
|
||||
ss.rate = m_sampling_rate;
|
||||
|
||||
pa_channel_map channel_map;
|
||||
|
||||
if (m_channels == 2)
|
||||
{
|
||||
channel_map.channels = 2;
|
||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||
}
|
||||
else if (m_channels == 6)
|
||||
{
|
||||
channel_map.channels = 6;
|
||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
|
||||
channel_map.map[3] = PA_CHANNEL_POSITION_LFE;
|
||||
channel_map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
|
||||
channel_map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel_map.channels = 8;
|
||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
|
||||
channel_map.map[3] = PA_CHANNEL_POSITION_LFE;
|
||||
channel_map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
|
||||
channel_map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
|
||||
channel_map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
|
||||
channel_map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
|
||||
}
|
||||
ss.channels = channel_map.channels;
|
||||
|
||||
int err;
|
||||
this->connection = pa_simple_new(NULL, "RPCS3", PA_STREAM_PLAYBACK, NULL, "Game", &ss, &channel_map, NULL, &err);
|
||||
if (!this->connection)
|
||||
{
|
||||
fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
bool PulseBackend::AddData(const void* src, u32 num_samples)
|
||||
{
|
||||
AUDIT(this->connection);
|
||||
|
||||
int err;
|
||||
if (pa_simple_write(this->connection, src, num_samples * m_sample_size, &err) < 0)
|
||||
{
|
||||
fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef HAVE_PULSE
|
||||
#error "PulseAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
#include <pulse/simple.h>
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
class PulseBackend : public AudioBackend
|
||||
{
|
||||
public:
|
||||
PulseBackend();
|
||||
virtual ~PulseBackend() override;
|
||||
|
||||
PulseBackend(const PulseBackend&) = delete;
|
||||
PulseBackend& operator=(const PulseBackend&) = delete;
|
||||
|
||||
virtual const char* GetName() const override { return "Pulse"; }
|
||||
|
||||
static const u32 capabilities = 0;
|
||||
virtual u32 GetCapabilities() const override { return capabilities; }
|
||||
|
||||
virtual void Open(u32) override;
|
||||
virtual void Close() override;
|
||||
|
||||
virtual bool AddData(const void* src, u32 num_samples) override;
|
||||
|
||||
private:
|
||||
pa_simple* connection{};
|
||||
};
|
||||
@@ -22,24 +22,24 @@ XAudio2Backend::XAudio2Backend()
|
||||
// In order to prevent errors on CreateMasteringVoice, apparently we need CoInitializeEx according to:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/xaudio2fx/nf-xaudio2fx-xaudio2createvolumemeter
|
||||
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
if (FAILED(hr) && hr != RPC_E_CHANGED_MODE)
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
XAudio.error("CoInitializeEx() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return;
|
||||
m_com_init_success = true;
|
||||
}
|
||||
|
||||
hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||
hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_USE_DEFAULT_PROCESSOR);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("XAudio2Create() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return;
|
||||
}
|
||||
|
||||
hr = instance->CreateMasteringVoice(&m_master_voice, m_channels, 48000);
|
||||
|
||||
hr = instance->RegisterForCallbacks(this);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return;
|
||||
// Some error recovery functionality will be lost, but otherwise backend is operational
|
||||
XAudio.error("RegisterForCallbacks() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
|
||||
// All succeeded, "commit"
|
||||
@@ -47,150 +47,244 @@ XAudio2Backend::XAudio2Backend()
|
||||
}
|
||||
|
||||
XAudio2Backend::~XAudio2Backend()
|
||||
{
|
||||
Close();
|
||||
|
||||
if (m_xaudio2_instance != nullptr)
|
||||
{
|
||||
m_xaudio2_instance->StopEngine();
|
||||
|
||||
// TODO: Enabling this might crash afterwards in ComPtr::InternalRelease.
|
||||
// Maybe it's both trying to do the same thing?
|
||||
//m_xaudio2_instance->Release();
|
||||
}
|
||||
|
||||
if (m_com_init_success)
|
||||
{
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
bool XAudio2Backend::Initialized()
|
||||
{
|
||||
return m_xaudio2_instance != nullptr;
|
||||
}
|
||||
|
||||
bool XAudio2Backend::Operational()
|
||||
{
|
||||
if (m_dev_listener.output_device_changed())
|
||||
{
|
||||
m_reset_req = true;
|
||||
}
|
||||
|
||||
return m_xaudio2_instance != nullptr && m_source_voice != nullptr && !m_reset_req.observe();
|
||||
}
|
||||
|
||||
void XAudio2Backend::Play()
|
||||
{
|
||||
if (m_source_voice == nullptr)
|
||||
{
|
||||
XAudio.error("Play() called uninitialized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_playing) return;
|
||||
|
||||
const HRESULT hr = m_source_voice->Start();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("Start() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_playing = true;
|
||||
}
|
||||
|
||||
void XAudio2Backend::CloseUnlocked()
|
||||
{
|
||||
if (m_source_voice != nullptr)
|
||||
{
|
||||
m_source_voice->Stop();
|
||||
const HRESULT hr = m_source_voice->Stop();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("Stop() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
|
||||
m_source_voice->DestroyVoice();
|
||||
m_source_voice = nullptr;
|
||||
}
|
||||
|
||||
if (m_master_voice != nullptr)
|
||||
{
|
||||
m_master_voice->DestroyVoice();
|
||||
m_master_voice = nullptr;
|
||||
}
|
||||
|
||||
if (m_xaudio2_instance != nullptr)
|
||||
{
|
||||
m_xaudio2_instance->StopEngine();
|
||||
}
|
||||
}
|
||||
|
||||
void XAudio2Backend::Play()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
const HRESULT hr = m_source_voice->Start();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.fatal("Start() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
m_playing = false;
|
||||
m_data_buf = nullptr;
|
||||
m_data_buf_len = 0;
|
||||
m_last_sample.fill(0);
|
||||
}
|
||||
|
||||
void XAudio2Backend::Close()
|
||||
{
|
||||
Pause();
|
||||
Flush();
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
CloseUnlocked();
|
||||
}
|
||||
|
||||
void XAudio2Backend::Pause()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
const HRESULT hr = m_source_voice->Stop();
|
||||
if (FAILED(hr))
|
||||
if (m_source_voice)
|
||||
{
|
||||
XAudio.fatal("Stop() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
HRESULT hr = m_source_voice->Stop();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("Stop() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
|
||||
hr = m_source_voice->FlushSourceBuffers();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("FlushSourceBuffers() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XAudio.error("Pause() called uninitialized");
|
||||
}
|
||||
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_playing = false;
|
||||
m_last_sample.fill(0);
|
||||
}
|
||||
|
||||
void XAudio2Backend::Open(u32 /* num_buffers */)
|
||||
void XAudio2Backend::Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt)
|
||||
{
|
||||
WAVEFORMATEX waveformatex{};
|
||||
waveformatex.wFormatTag = m_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = m_channels;
|
||||
waveformatex.nSamplesPerSec = m_sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(m_sampling_rate * m_channels * m_sample_size);
|
||||
waveformatex.nBlockAlign = m_channels * m_sample_size;
|
||||
waveformatex.wBitsPerSample = m_sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
CloseUnlocked();
|
||||
|
||||
const HRESULT hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
if (FAILED(hr))
|
||||
if (m_xaudio2_instance == nullptr)
|
||||
{
|
||||
XAudio.fatal("CreateSourceVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
XAudio.error("Open() called unitiliazed");
|
||||
return;
|
||||
}
|
||||
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
HRESULT hr = m_xaudio2_instance->CreateMasteringVoice(&m_master_voice);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
XAudio.error("Failed to open audio backend. Make sure that no other application is running that might block audio access (e.g. Netflix).");
|
||||
m_reset_req = true;
|
||||
return;
|
||||
}
|
||||
|
||||
m_sampling_rate = freq;
|
||||
m_sample_size = sample_size;
|
||||
m_channels = ch_cnt;
|
||||
|
||||
WAVEFORMATEX waveformatex{};
|
||||
waveformatex.wFormatTag = get_convert_to_s16() ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = get_channels();
|
||||
waveformatex.nSamplesPerSec = get_sampling_rate();
|
||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(get_sampling_rate() * get_channels() * get_sample_size());
|
||||
waveformatex.nBlockAlign = get_channels() * get_sample_size();
|
||||
waveformatex.wBitsPerSample = get_sample_size() * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO, this);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("CreateSourceVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return;
|
||||
}
|
||||
|
||||
ensure(m_source_voice != nullptr);
|
||||
m_source_voice->SetVolume(1.0f);
|
||||
|
||||
m_data_buf_len = get_sampling_rate() * get_sample_size() * get_channels() * INTERNAL_BUF_SIZE_MS * static_cast<u32>(XAUDIO2_DEFAULT_FREQ_RATIO) / 1000;
|
||||
m_data_buf = std::make_unique<u8[]>(m_data_buf_len);
|
||||
}
|
||||
|
||||
bool XAudio2Backend::IsPlaying()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
m_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
||||
return m_playing;
|
||||
}
|
||||
|
||||
bool XAudio2Backend::AddData(const void* src, u32 num_samples)
|
||||
void XAudio2Backend::SetWriteCallback(std::function<u32(u32, void *)> cb)
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_write_callback = cb;
|
||||
}
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
m_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
|
||||
f64 XAudio2Backend::GetCallbackFrameLen()
|
||||
{
|
||||
constexpr f64 _10ms = 0.01;
|
||||
|
||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||
if (m_source_voice == nullptr)
|
||||
{
|
||||
XAudio.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
|
||||
return false;
|
||||
XAudio.error("GetCallbackFrameLen() called uninitialized");
|
||||
return _10ms;
|
||||
}
|
||||
|
||||
XAUDIO2_BUFFER buffer{};
|
||||
buffer.AudioBytes = num_samples * m_sample_size;
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
buffer.LoopLength = 0;
|
||||
buffer.pAudioData = static_cast<const BYTE*>(src);
|
||||
buffer.pContext = nullptr;
|
||||
buffer.PlayBegin = 0;
|
||||
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
|
||||
void *ext;
|
||||
f64 min_latency{};
|
||||
|
||||
const HRESULT hr = m_source_voice->SubmitSourceBuffer(&buffer);
|
||||
HRESULT hr = m_xaudio2_instance->QueryInterface(IID_IXAudio2Extension, &ext);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.fatal("AddData() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return false;
|
||||
XAudio.error("QueryInterface() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XAudio2Backend::Flush()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
const HRESULT hr = m_source_voice->FlushSourceBuffers();
|
||||
if (FAILED(hr))
|
||||
else
|
||||
{
|
||||
XAudio.fatal("FlushSourceBuffers() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
u32 samples_per_q = 0, freq = 0;
|
||||
static_cast<IXAudio2Extension *>(ext)->GetProcessingQuantum(&samples_per_q, &freq);
|
||||
|
||||
if (freq)
|
||||
{
|
||||
min_latency = static_cast<f64>(samples_per_q) / freq;
|
||||
}
|
||||
}
|
||||
|
||||
return std::max<f64>(min_latency, _10ms); // 10ms is the minimum for XAudio
|
||||
}
|
||||
|
||||
u64 XAudio2Backend::GetNumEnqueuedSamples()
|
||||
void XAudio2Backend::OnVoiceProcessingPassStart(UINT32 BytesRequired)
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
m_source_voice->GetState(&state);
|
||||
|
||||
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
|
||||
return static_cast<u64>(AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
|
||||
}
|
||||
|
||||
f32 XAudio2Backend::SetFrequencyRatio(f32 new_ratio)
|
||||
{
|
||||
new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
|
||||
const HRESULT hr = m_source_voice->SetFrequencyRatio(new_ratio);
|
||||
if (FAILED(hr))
|
||||
std::unique_lock lock(m_cb_mutex, std::defer_lock);
|
||||
if (BytesRequired && lock.try_lock() && m_write_callback && m_playing)
|
||||
{
|
||||
XAudio.fatal("SetFrequencyRatio() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return 1.0f;
|
||||
}
|
||||
ensure(BytesRequired <= m_data_buf_len, "XAudio internal buffer is too small. Report to developers!");
|
||||
|
||||
return new_ratio;
|
||||
const u32 sample_size = get_sample_size() * get_channels();
|
||||
u32 written = std::min(m_write_callback(BytesRequired, m_data_buf.get()), BytesRequired);
|
||||
written -= written % sample_size;
|
||||
|
||||
if (written >= sample_size)
|
||||
{
|
||||
memcpy(m_last_sample.data(), m_data_buf.get() + written - sample_size, sample_size);
|
||||
}
|
||||
|
||||
for (u32 i = written; i < BytesRequired; i += sample_size)
|
||||
{
|
||||
memcpy(m_data_buf.get() + i, m_last_sample.data(), sample_size);
|
||||
}
|
||||
|
||||
XAUDIO2_BUFFER buffer{};
|
||||
buffer.AudioBytes = BytesRequired;
|
||||
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
|
||||
buffer.pAudioData = static_cast<const BYTE*>(m_data_buf.get());
|
||||
|
||||
const HRESULT hr = m_source_voice->SubmitSourceBuffer(&buffer);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("SubmitSourceBuffer() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XAudio2Backend::OnCriticalError(HRESULT Error)
|
||||
{
|
||||
XAudio.error("OnCriticalError() called: %s (0x%08x)", std::system_category().message(Error), static_cast<u32>(Error));
|
||||
m_reset_req = true;
|
||||
}
|
||||
|
||||
@@ -4,19 +4,16 @@
|
||||
#error "XAudio2 can only be built on Windows."
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include "Utilities/mutex.h"
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
#include "Emu/Audio/audio_device_listener.h"
|
||||
|
||||
#include <xaudio2redist.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
|
||||
class XAudio2Backend final : public AudioBackend
|
||||
class XAudio2Backend final : public AudioBackend, public IXAudio2VoiceCallback, public IXAudio2EngineCallback
|
||||
{
|
||||
private:
|
||||
Microsoft::WRL::ComPtr<IXAudio2> m_xaudio2_instance{};
|
||||
IXAudio2MasteringVoice* m_master_voice{};
|
||||
IXAudio2SourceVoice* m_source_voice{};
|
||||
|
||||
public:
|
||||
XAudio2Backend();
|
||||
~XAudio2Backend() override;
|
||||
@@ -24,23 +21,53 @@ public:
|
||||
XAudio2Backend(const XAudio2Backend&) = delete;
|
||||
XAudio2Backend& operator=(const XAudio2Backend&) = delete;
|
||||
|
||||
const char* GetName() const override { return "XAudio2"; }
|
||||
std::string_view GetName() const override { return "XAudio2"sv; }
|
||||
|
||||
static const u32 capabilities = PLAY_PAUSE_FLUSH | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO;
|
||||
u32 GetCapabilities() const override { return capabilities; }
|
||||
bool Initialized() override;
|
||||
bool Operational() override;
|
||||
|
||||
bool Initialized() const override { return m_xaudio2_instance != nullptr; }
|
||||
|
||||
void Open(u32 /* num_buffers */) override;
|
||||
void Open(AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override;
|
||||
void Close() override;
|
||||
|
||||
void SetWriteCallback(std::function<u32(u32, void *)> cb) override;
|
||||
f64 GetCallbackFrameLen() override;
|
||||
|
||||
void Play() override;
|
||||
void Pause() override;
|
||||
bool IsPlaying() override;
|
||||
|
||||
bool AddData(const void* src, u32 num_samples) override;
|
||||
void Flush() override;
|
||||
private:
|
||||
static constexpr u32 INTERNAL_BUF_SIZE_MS = 25;
|
||||
|
||||
u64 GetNumEnqueuedSamples() override;
|
||||
f32 SetFrequencyRatio(f32 new_ratio) override;
|
||||
Microsoft::WRL::ComPtr<IXAudio2> m_xaudio2_instance{};
|
||||
IXAudio2MasteringVoice* m_master_voice{};
|
||||
IXAudio2SourceVoice* m_source_voice{};
|
||||
bool m_com_init_success = false;
|
||||
|
||||
shared_mutex m_cb_mutex{};
|
||||
std::function<u32(u32, void *)> m_write_callback{};
|
||||
std::unique_ptr<u8[]> m_data_buf{};
|
||||
u64 m_data_buf_len = 0;
|
||||
std::array<u8, sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)> m_last_sample{};
|
||||
|
||||
bool m_playing = false;
|
||||
atomic_t<bool> m_reset_req = false;
|
||||
|
||||
audio_device_listener m_dev_listener{};
|
||||
|
||||
// XAudio voice callbacks
|
||||
void OnVoiceProcessingPassStart(UINT32 BytesRequired) override;
|
||||
void OnVoiceProcessingPassEnd() override {}
|
||||
void OnStreamEnd() override {}
|
||||
void OnBufferStart(void* /* pBufferContext */) override {}
|
||||
void OnBufferEnd(void* /* pBufferContext*/) override {}
|
||||
void OnLoopEnd(void* /* pBufferContext */) override {}
|
||||
void OnVoiceError(void* /* pBufferContext */, HRESULT /* Error */) override {}
|
||||
|
||||
// XAudio engine callbacks
|
||||
void OnProcessingPassStart() override {};
|
||||
void OnProcessingPassEnd() override {};
|
||||
void OnCriticalError(HRESULT Error) override;
|
||||
|
||||
void CloseUnlocked();
|
||||
};
|
||||
|
||||
@@ -10,15 +10,26 @@ LOG_CHANNEL(IO);
|
||||
audio_device_listener::audio_device_listener()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
m_com_init_success = true;
|
||||
}
|
||||
|
||||
// Try to register a listener for device changes
|
||||
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_device_enumerator));
|
||||
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_device_enumerator));
|
||||
if (hr != S_OK)
|
||||
{
|
||||
IO.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
else if (m_device_enumerator)
|
||||
{
|
||||
m_device_enumerator->RegisterEndpointNotificationCallback(&m_listener);
|
||||
hr = m_device_enumerator->RegisterEndpointNotificationCallback(this);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
IO.error("RegisterEndpointNotificationCallback() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
m_device_enumerator->Release();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -32,11 +43,27 @@ audio_device_listener::~audio_device_listener()
|
||||
#ifdef _WIN32
|
||||
if (m_device_enumerator != nullptr)
|
||||
{
|
||||
m_device_enumerator->UnregisterEndpointNotificationCallback(this);
|
||||
m_device_enumerator->Release();
|
||||
}
|
||||
|
||||
if (m_com_init_success)
|
||||
{
|
||||
CoUninitialize();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool audio_device_listener::input_device_changed()
|
||||
{
|
||||
return m_input_device_changed.test_and_reset();
|
||||
}
|
||||
|
||||
bool audio_device_listener::output_device_changed()
|
||||
{
|
||||
return m_output_device_changed.test_and_reset();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
template <>
|
||||
void fmt_class_string<ERole>::format(std::string& out, u64 arg)
|
||||
@@ -70,7 +97,7 @@ void fmt_class_string<EDataFlow>::format(std::string& out, u64 arg)
|
||||
});
|
||||
}
|
||||
|
||||
HRESULT audio_device_listener::listener::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id)
|
||||
HRESULT audio_device_listener::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id)
|
||||
{
|
||||
IO.notice("OnDefaultDeviceChanged(flow=%s, role=%s, new_default_device_id=0x%x)", flow, role, new_default_device_id);
|
||||
|
||||
@@ -80,8 +107,9 @@ HRESULT audio_device_listener::listener::OnDefaultDeviceChanged(EDataFlow flow,
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Only listen for console and communication device changes.
|
||||
if ((role != eConsole && role != eCommunications) || (flow != eRender && flow != eCapture))
|
||||
// Listen only for one device role, otherwise we're going to receive more than one
|
||||
// notification for flow type
|
||||
if (role != eConsole)
|
||||
{
|
||||
IO.notice("OnDefaultDeviceChanged(): we don't care about this device");
|
||||
return S_OK;
|
||||
@@ -90,15 +118,27 @@ HRESULT audio_device_listener::listener::OnDefaultDeviceChanged(EDataFlow flow,
|
||||
const std::wstring tmp(new_default_device_id);
|
||||
const std::string new_device_id = wchar_to_utf8(tmp.c_str());
|
||||
|
||||
if (device_id != new_device_id)
|
||||
if (flow == eRender || flow == eAll)
|
||||
{
|
||||
device_id = new_device_id;
|
||||
|
||||
IO.warning("Default device changed: new device = '%s'", device_id);
|
||||
|
||||
if (auto& g_audio = g_fxo->get<cell_audio>(); g_fxo->is_init<cell_audio>())
|
||||
if (output_device_id != new_device_id)
|
||||
{
|
||||
g_audio.m_update_configuration = true;
|
||||
output_device_id = new_device_id;
|
||||
|
||||
IO.warning("Default output device changed: new device = '%s'", output_device_id);
|
||||
|
||||
m_output_device_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (flow == eCapture || flow == eAll)
|
||||
{
|
||||
if (input_device_id != new_device_id)
|
||||
{
|
||||
input_device_id = new_device_id;
|
||||
|
||||
IO.warning("Default input device changed: new device = '%s'", input_device_id);
|
||||
|
||||
m_input_device_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,28 +4,39 @@
|
||||
#include <MMDeviceAPI.h>
|
||||
#endif
|
||||
|
||||
#include "util/atomic.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
class audio_device_listener : public IMMNotificationClient
|
||||
#else
|
||||
class audio_device_listener
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
audio_device_listener();
|
||||
~audio_device_listener();
|
||||
|
||||
bool input_device_changed();
|
||||
bool output_device_changed();
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
struct listener : public IMMNotificationClient
|
||||
{
|
||||
std::string device_id;
|
||||
std::string input_device_id;
|
||||
std::string output_device_id;
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef() override { return 1; };
|
||||
IFACEMETHODIMP_(ULONG) Release() override { return 1; };
|
||||
IFACEMETHODIMP QueryInterface(REFIID /*iid*/, void** /*object*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnPropertyValueChanged(LPCWSTR /*device_id*/, const PROPERTYKEY /*key*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnDeviceAdded(LPCWSTR /*device_id*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnDeviceRemoved(LPCWSTR /*device_id*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnDeviceStateChanged(LPCWSTR /*device_id*/, DWORD /*new_state*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id) override;
|
||||
} m_listener;
|
||||
IFACEMETHODIMP_(ULONG) AddRef() override { return 1; };
|
||||
IFACEMETHODIMP_(ULONG) Release() override { return 1; };
|
||||
IFACEMETHODIMP QueryInterface(REFIID /*iid*/, void** /*object*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnPropertyValueChanged(LPCWSTR /*device_id*/, const PROPERTYKEY /*key*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnDeviceAdded(LPCWSTR /*device_id*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnDeviceRemoved(LPCWSTR /*device_id*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnDeviceStateChanged(LPCWSTR /*device_id*/, DWORD /*new_state*/) override { return S_OK; };
|
||||
IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id) override;
|
||||
|
||||
IMMDeviceEnumerator* m_device_enumerator = nullptr;
|
||||
bool m_com_init_success = false;
|
||||
#endif
|
||||
|
||||
atomic_t<bool> m_input_device_changed = false;
|
||||
atomic_t<bool> m_output_device_changed = false;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Audio/audio_resampler.h"
|
||||
#include <algorithm>
|
||||
|
||||
audio_resampler::audio_resampler()
|
||||
{
|
||||
resampler.setSetting(SETTING_SEQUENCE_MS, 20); // Resampler frame size (reduce latency at cost of slight sound quality degradation)
|
||||
resampler.setSetting(SETTING_USE_QUICKSEEK, 1); // Use fast quick seeking algorithm (substantally reduces computation time)
|
||||
}
|
||||
|
||||
audio_resampler::~audio_resampler()
|
||||
{
|
||||
}
|
||||
|
||||
void audio_resampler::set_params(AudioChannelCnt ch_cnt, AudioFreq freq)
|
||||
{
|
||||
flush();
|
||||
resampler.setChannels(static_cast<u32>(ch_cnt));
|
||||
resampler.setSampleRate(static_cast<u32>(freq));
|
||||
}
|
||||
|
||||
f64 audio_resampler::set_tempo(f64 new_tempo)
|
||||
{
|
||||
new_tempo = std::clamp(new_tempo, RESAMPLER_MIN_FREQ_VAL, RESAMPLER_MAX_FREQ_VAL);
|
||||
resampler.setTempo(new_tempo);
|
||||
return new_tempo;
|
||||
}
|
||||
|
||||
void audio_resampler::put_samples(const f32* buf, u32 sample_cnt)
|
||||
{
|
||||
resampler.putSamples(buf, sample_cnt);
|
||||
}
|
||||
|
||||
std::pair<f32* /* buffer */, u32 /* samples */> audio_resampler::get_samples(u32 sample_cnt)
|
||||
{
|
||||
f32 *const buf = resampler.bufBegin();
|
||||
return std::make_pair(buf, resampler.receiveSamples(sample_cnt));
|
||||
}
|
||||
|
||||
u32 audio_resampler::samples_available() const
|
||||
{
|
||||
return resampler.numSamples();
|
||||
}
|
||||
|
||||
f64 audio_resampler::get_resample_ratio()
|
||||
{
|
||||
return resampler.getInputOutputSampleRatio();
|
||||
}
|
||||
|
||||
void audio_resampler::flush()
|
||||
{
|
||||
resampler.clear();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsuggest-override"
|
||||
#endif
|
||||
#include "SoundTouch.h"
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
constexpr f64 RESAMPLER_MAX_FREQ_VAL = 1.0;
|
||||
constexpr f64 RESAMPLER_MIN_FREQ_VAL = 0.1;
|
||||
|
||||
class audio_resampler
|
||||
{
|
||||
public:
|
||||
audio_resampler();
|
||||
~audio_resampler();
|
||||
|
||||
void set_params(AudioChannelCnt ch_cnt, AudioFreq freq);
|
||||
f64 set_tempo(f64 new_tempo);
|
||||
|
||||
void put_samples(const f32* buf, u32 sample_cnt);
|
||||
std::pair<f32* /* buffer */, u32 /* samples */> get_samples(u32 sample_cnt);
|
||||
|
||||
u32 samples_available() const;
|
||||
f64 get_resample_ratio();
|
||||
|
||||
void flush();
|
||||
|
||||
private:
|
||||
soundtouch::SoundTouch resampler{};
|
||||
};
|
||||
+23
-15
@@ -1,4 +1,4 @@
|
||||
add_library(rpcs3_emu
|
||||
add_library(rpcs3_emu
|
||||
cache_utils.cpp
|
||||
IdManager.cpp
|
||||
localized_string.cpp
|
||||
@@ -54,10 +54,16 @@ target_sources(rpcs3_emu PRIVATE
|
||||
../../Utilities/mutex.cpp
|
||||
../../Utilities/rXml.cpp
|
||||
../../Utilities/sema.cpp
|
||||
../../Utilities/simple_ringbuf.cpp
|
||||
../../Utilities/StrFmt.cpp
|
||||
../../Utilities/Thread.cpp
|
||||
../../Utilities/version.cpp
|
||||
)
|
||||
if(APPLE)
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
../../darwin/util/sysinfo_darwin.mm
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(rpcs3_emu PUBLIC "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
@@ -108,24 +114,12 @@ target_sources(rpcs3_emu PRIVATE
|
||||
# Audio
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
Audio/audio_device_listener.cpp
|
||||
Audio/audio_resampler.cpp
|
||||
Audio/AudioDumper.cpp
|
||||
Audio/AudioBackend.cpp
|
||||
Audio/AL/OpenALBackend.cpp
|
||||
Audio/Cubeb/CubebBackend.cpp
|
||||
)
|
||||
|
||||
if(USE_ALSA)
|
||||
find_package(ALSA)
|
||||
if(ALSA_FOUND)
|
||||
target_sources(rpcs3_emu PRIVATE Audio/ALSA/ALSABackend.cpp)
|
||||
target_link_libraries(rpcs3_emu PUBLIC 3rdparty::alsa)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_PULSE AND PULSE_FOUND)
|
||||
target_sources(rpcs3_emu PRIVATE Audio/Pulse/PulseBackend.cpp)
|
||||
target_link_libraries(rpcs3_emu PUBLIC 3rdparty::pulse)
|
||||
endif()
|
||||
|
||||
if(USE_FAUDIO)
|
||||
find_package(SDL2)
|
||||
if(SDL2_FOUND AND NOT SDL2_VERSION VERSION_LESS 2.0.9)
|
||||
@@ -147,6 +141,13 @@ target_link_libraries(rpcs3_emu
|
||||
PUBLIC
|
||||
3rdparty::openal)
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
PUBLIC
|
||||
3rdparty::cubeb)
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
PUBLIC
|
||||
3rdparty::soundtouch)
|
||||
|
||||
# Cell
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
@@ -370,13 +371,19 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Io/GHLtar.cpp
|
||||
Io/Buzz.cpp
|
||||
Io/Turntable.cpp
|
||||
Io/usio.cpp
|
||||
)
|
||||
|
||||
# Np
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
NP/fb_helpers.cpp
|
||||
NP/np_cache.cpp
|
||||
NP/np_contexts.cpp
|
||||
NP/np_dnshook.cpp
|
||||
NP/np_handler.cpp
|
||||
NP/np_helpers.cpp
|
||||
NP/np_notifications.cpp
|
||||
NP/np_requests.cpp
|
||||
NP/signaling_handler.cpp
|
||||
NP/np_structs_extra.cpp
|
||||
NP/rpcn_client.cpp
|
||||
@@ -396,6 +403,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
RSX/GSRender.cpp
|
||||
RSX/RSXFIFO.cpp
|
||||
RSX/rsx_methods.cpp
|
||||
RSX/rsx_vertex_data.cpp
|
||||
RSX/RSXOffload.cpp
|
||||
RSX/RSXTexture.cpp
|
||||
RSX/RSXThread.cpp
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
DECLARE(cpu_thread::g_threads_created){0};
|
||||
DECLARE(cpu_thread::g_threads_deleted){0};
|
||||
@@ -410,20 +412,6 @@ void cpu_thread::operator()()
|
||||
{
|
||||
thread_ctrl::set_thread_affinity_mask(thread_ctrl::get_affinity_mask(id_type() == 1 ? thread_class::ppu : thread_class::spu));
|
||||
}
|
||||
if (id_type() == 2)
|
||||
{
|
||||
// force input/output denormals to zero for SPU threads (FTZ/DAZ)
|
||||
_mm_setcsr( _mm_getcsr() | 0x8040 );
|
||||
|
||||
const volatile int a = 0x1fc00000;
|
||||
__m128 b = _mm_castsi128_ps(_mm_set1_epi32(a));
|
||||
int c = _mm_cvtsi128_si32(_mm_castps_si128(_mm_mul_ps(b,b)));
|
||||
|
||||
if (c != 0)
|
||||
{
|
||||
sys_log.fatal("Could not disable denormals.");
|
||||
}
|
||||
}
|
||||
|
||||
while (!g_fxo->is_init<cpu_profiler>())
|
||||
{
|
||||
|
||||
@@ -179,7 +179,7 @@ public:
|
||||
// Callback for thread_ctrl::wait or RSX wait
|
||||
virtual void cpu_wait(bs_t<cpu_flag> old);
|
||||
|
||||
// Callback for function abortion stats on Emu.Stop()
|
||||
// Callback for function abortion stats on Emu.Kill()
|
||||
virtual void cpu_on_stop() {}
|
||||
|
||||
// For internal use
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "CPUTranslator.h"
|
||||
|
||||
#include "util/v128.hpp"
|
||||
#include "util/v128sse.hpp"
|
||||
#include "util/simd.hpp"
|
||||
|
||||
llvm::LLVMContext g_llvm_ctx;
|
||||
|
||||
@@ -85,29 +85,35 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
|
||||
m_use_ssse3 = false;
|
||||
}
|
||||
|
||||
// Test AVX feature (TODO)
|
||||
if (cpu == "sandybridge" ||
|
||||
cpu == "ivybridge" ||
|
||||
cpu == "bdver1")
|
||||
{
|
||||
m_use_avx = true;
|
||||
}
|
||||
|
||||
// Test FMA feature (TODO)
|
||||
if (cpu == "haswell" ||
|
||||
cpu == "broadwell" ||
|
||||
cpu == "skylake" ||
|
||||
cpu == "alderlake" ||
|
||||
cpu == "bdver2" ||
|
||||
cpu == "bdver3" ||
|
||||
cpu == "bdver4" ||
|
||||
cpu.startswith("znver"))
|
||||
{
|
||||
m_use_fma = true;
|
||||
m_use_avx = true;
|
||||
}
|
||||
|
||||
// Test AVX-512 feature (TODO)
|
||||
if (cpu == "skylake-avx512" ||
|
||||
cpu == "cascadelake" ||
|
||||
cpu == "cannonlake" ||
|
||||
cpu == "cooperlake" ||
|
||||
cpu == "icelake" ||
|
||||
cpu == "icelake-client" ||
|
||||
cpu == "icelake-server" ||
|
||||
cpu == "tigerlake" ||
|
||||
cpu == "rocketlake")
|
||||
cpu == "cooperlake")
|
||||
{
|
||||
m_use_avx = true;
|
||||
m_use_fma = true;
|
||||
m_use_avx512 = true;
|
||||
}
|
||||
@@ -128,6 +134,9 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
|
||||
cpu == "rocketlake" ||
|
||||
cpu == "sapphirerapids")
|
||||
{
|
||||
m_use_avx = true;
|
||||
m_use_fma = true;
|
||||
m_use_avx512 = true;
|
||||
m_use_avx512_icl = true;
|
||||
m_use_vnni = true;
|
||||
}
|
||||
@@ -139,9 +148,9 @@ llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type) const
|
||||
uint s2 = val->getType()->getScalarSizeInBits();
|
||||
|
||||
if (type->isVectorTy())
|
||||
s1 *= llvm::cast<llvm::VectorType>(type)->getNumElements();
|
||||
s1 *= llvm::cast<llvm::FixedVectorType>(type)->getNumElements();
|
||||
if (val->getType()->isVectorTy())
|
||||
s2 *= llvm::cast<llvm::VectorType>(val->getType())->getNumElements();
|
||||
s2 *= llvm::cast<llvm::FixedVectorType>(val->getType())->getNumElements();
|
||||
|
||||
if (s1 != s2)
|
||||
{
|
||||
@@ -183,7 +192,7 @@ std::pair<bool, v128> cpu_translator::get_const_vector<v128>(llvm::Value* c, u32
|
||||
fmt::throw_exception("[0x%x, %u] Not a vector", _pos, _line);
|
||||
}
|
||||
|
||||
if (auto v = llvm::cast<llvm::VectorType>(t); v->getScalarSizeInBits() * v->getNumElements() != 128)
|
||||
if (auto v = llvm::cast<llvm::FixedVectorType>(t); v->getScalarSizeInBits() * v->getNumElements() != 128)
|
||||
{
|
||||
fmt::throw_exception("[0x%x, %u] Bad vector size: i%ux%u", _pos, _line, v->getScalarSizeInBits(), v->getNumElements());
|
||||
}
|
||||
@@ -197,13 +206,18 @@ std::pair<bool, v128> cpu_translator::get_const_vector<v128>(llvm::Value* c, u32
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string result;
|
||||
llvm::raw_string_ostream out(result);
|
||||
c->print(out, true);
|
||||
out.flush();
|
||||
|
||||
if (llvm::isa<llvm::ConstantExpr>(c))
|
||||
{
|
||||
// Sorry, if we cannot evaluate it we cannot use it
|
||||
fmt::throw_exception("[0x%x, %u] Constant Expression!", _pos, _line);
|
||||
fmt::throw_exception("[0x%x, %u] Constant Expression!\n%s", _pos, _line, result);
|
||||
}
|
||||
|
||||
fmt::throw_exception("[0x%x, %u] Unexpected constant type", _pos, _line);
|
||||
fmt::throw_exception("[0x%x, %u] Unexpected constant type!\n%s", _pos, _line, result);
|
||||
}
|
||||
|
||||
const auto sct = t->getScalarType();
|
||||
@@ -267,7 +281,7 @@ llvm::Constant* cpu_translator::make_const_vector<v128>(v128 v, llvm::Type* t, u
|
||||
}
|
||||
|
||||
ensure(t->isVectorTy());
|
||||
ensure(128 == t->getScalarSizeInBits() * llvm::cast<llvm::VectorType>(t)->getNumElements());
|
||||
ensure(128 == t->getScalarSizeInBits() * llvm::cast<llvm::FixedVectorType>(t)->getNumElements());
|
||||
|
||||
const auto sct = t->getScalarType();
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
|
||||
#endif
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
@@ -43,6 +44,18 @@ enum class i4 : char
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept LLVMType = (std::is_pointer_v<T>) && (std::is_base_of_v<llvm::Type, std::remove_pointer_t<T>>);
|
||||
|
||||
template <typename T>
|
||||
concept LLVMValue = (std::is_pointer_v<T>) && (std::is_base_of_v<llvm::Value, std::remove_pointer_t<T>>);
|
||||
|
||||
template <typename T>
|
||||
concept DSLValue = requires (T& v)
|
||||
{
|
||||
{ v.eval(std::declval<llvm::IRBuilder<>*>()) } -> LLVMValue;
|
||||
};
|
||||
|
||||
template <typename T = void>
|
||||
struct llvm_value_t
|
||||
{
|
||||
@@ -2886,6 +2899,9 @@ protected:
|
||||
// Allow FMA
|
||||
bool m_use_fma = false;
|
||||
|
||||
// Allow AVX
|
||||
bool m_use_avx = false;
|
||||
|
||||
// Allow skylake-x tier AVX-512
|
||||
bool m_use_avx512 = false;
|
||||
|
||||
@@ -2945,11 +2961,11 @@ public:
|
||||
}
|
||||
|
||||
// Call external function: provide name and function pointer
|
||||
template <typename RT, typename... FArgs, typename... Args>
|
||||
template <typename RetT = void, typename RT, typename... FArgs, LLVMValue... Args>
|
||||
llvm::CallInst* call(std::string_view lame, RT(*_func)(FArgs...), Args... args)
|
||||
{
|
||||
static_assert(sizeof...(FArgs) == sizeof...(Args), "spu_llvm_recompiler::call(): unexpected arg number");
|
||||
const auto type = llvm::FunctionType::get(get_type<RT>(), {args->getType()...}, false);
|
||||
const auto type = llvm::FunctionType::get(get_type<std::conditional_t<std::is_void_v<RetT>, RT, RetT>>(), {args->getType()...}, false);
|
||||
const auto func = llvm::cast<llvm::Function>(m_module->getOrInsertFunction({lame.data(), lame.size()}, type).getCallee());
|
||||
#ifdef _WIN32
|
||||
func->setCallingConv(llvm::CallingConv::Win64);
|
||||
@@ -2963,6 +2979,22 @@ public:
|
||||
return inst;
|
||||
}
|
||||
|
||||
template <typename RT, typename... FArgs, DSLValue... Args> requires (sizeof...(Args) != 0)
|
||||
auto call(std::string_view name, RT(*_func)(FArgs...), Args&&... args)
|
||||
{
|
||||
llvm_value_t<RT> r;
|
||||
r.value = call(name, _func, std::forward<Args>(args).eval(m_ir)...);
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename RT, DSLValue... Args>
|
||||
auto call(llvm::Function* func, Args&&... args)
|
||||
{
|
||||
llvm_value_t<RT> r;
|
||||
r.value = m_ir->CreateCall(func, {std::forward<Args>(args).eval(m_ir)...});
|
||||
return r;
|
||||
}
|
||||
|
||||
// Bitcast with immediate constant folding
|
||||
llvm::Value* bitcast(llvm::Value* val, llvm::Type* type) const;
|
||||
|
||||
@@ -3493,10 +3525,10 @@ public:
|
||||
shuffle.value = m_ir->CreateZExt(shuffle.value, get_type<u32[32]>());
|
||||
intermediate.value = m_ir->CreateShuffleVector(data0, data1, shuffle.value);
|
||||
|
||||
// expand the shuffle index to 256 bits with zeroes
|
||||
// expand the shuffle index to 256 bits with zeroes
|
||||
shuffleindex.value = m_ir->CreateShuffleVector(index, zeroes, shuffle.value);
|
||||
|
||||
// permute
|
||||
// permute
|
||||
intermediate.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_permvar_qi_256), {intermediate.value, shuffleindex.value});
|
||||
|
||||
// convert the 256 bit vector back to 128 bits
|
||||
@@ -3648,19 +3680,4 @@ struct fmt_unveil<llvm::TypeSize, void>
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wignored-attributes"
|
||||
#endif
|
||||
|
||||
template <>
|
||||
inline llvm::Type* cpu_translator::get_type<__m128i>()
|
||||
{
|
||||
return llvm::VectorType::get(llvm::Type::getInt8Ty(m_context), 16, false);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -269,8 +269,12 @@ public:
|
||||
bool just_started = false;
|
||||
bool just_finished = false;
|
||||
|
||||
AVCodec* codec = nullptr;
|
||||
const AVCodec* codec = nullptr;
|
||||
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(59, 0, 0)
|
||||
const AVInputFormat* input_format = nullptr;
|
||||
#else
|
||||
AVInputFormat* input_format = nullptr;
|
||||
#endif
|
||||
AVCodecContext* ctx = nullptr;
|
||||
AVFormatContext* fmt = nullptr;
|
||||
u8* io_buf;
|
||||
|
||||
@@ -51,7 +51,7 @@ error_code cellAtracCreateDecoder(vm::ptr<CellAtracHandle> pHandle, vm::ptr<u8>
|
||||
{
|
||||
cellAtrac.warning("cellAtracCreateDecoder(pHandle=*0x%x, pucWorkMem=*0x%x, uiPpuThreadPriority=%d, uiSpuThreadPriority=%d)", pHandle, pucWorkMem, uiPpuThreadPriority, uiSpuThreadPriority);
|
||||
|
||||
pHandle->pucWorkMem = pucWorkMem;
|
||||
std::memcpy(pHandle->ucWorkMem, pucWorkMem.get_ptr(), CELL_ATRAC_HANDLE_SIZE);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ error_code cellAtracCreateDecoderExt(vm::ptr<CellAtracHandle> pHandle, vm::ptr<u
|
||||
{
|
||||
cellAtrac.warning("cellAtracCreateDecoderExt(pHandle=*0x%x, pucWorkMem=*0x%x, uiPpuThreadPriority=%d, pExtRes=*0x%x)", pHandle, pucWorkMem, uiPpuThreadPriority, pExtRes);
|
||||
|
||||
pHandle->pucWorkMem = pucWorkMem;
|
||||
std::memcpy(pHandle->ucWorkMem, pucWorkMem.get_ptr(), CELL_ATRAC_HANDLE_SIZE);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ error_code cellAtracGetStreamDataInfo(vm::ptr<CellAtracHandle> pHandle, vm::pptr
|
||||
{
|
||||
cellAtrac.warning("cellAtracGetStreamDataInfo(pHandle=*0x%x, ppucWritePointer=**0x%x, puiWritableByte=*0x%x, puiReadPosition=*0x%x)", pHandle, ppucWritePointer, puiWritableByte, puiReadPosition);
|
||||
|
||||
*ppucWritePointer = pHandle->pucWorkMem;
|
||||
ppucWritePointer->set(pHandle.addr());
|
||||
*puiWritableByte = 0x1000;
|
||||
*puiReadPosition = 0;
|
||||
return CELL_OK;
|
||||
@@ -206,7 +206,7 @@ error_code cellAtracGetBufferInfoForResetting(vm::ptr<CellAtracHandle> pHandle,
|
||||
{
|
||||
cellAtrac.warning("cellAtracGetBufferInfoForResetting(pHandle=*0x%x, uiSample=0x%x, pBufferInfo=*0x%x)", pHandle, uiSample, pBufferInfo);
|
||||
|
||||
pBufferInfo->pucWriteAddr = pHandle->pucWorkMem;
|
||||
pBufferInfo->pucWriteAddr.set(pHandle.addr());
|
||||
pBufferInfo->uiWritableByte = 0x1000;
|
||||
pBufferInfo->uiMinWriteByte = 0;
|
||||
pBufferInfo->uiReadPosition = 0;
|
||||
|
||||
@@ -43,15 +43,12 @@ enum
|
||||
|
||||
struct alignas(8) CellAtracHandle
|
||||
{
|
||||
vm::ptr<u8> pucWorkMem;
|
||||
// ...
|
||||
u8 ucWorkMem[CELL_ATRAC_HANDLE_SIZE];
|
||||
};
|
||||
|
||||
CHECK_MAX_SIZE(CellAtracHandle, 512);
|
||||
|
||||
struct CellAtracBufferInfo
|
||||
{
|
||||
vm::ptr<u8> pucWriteAddr;
|
||||
vm::bptr<u8> pucWriteAddr;
|
||||
be_t<u32> uiWritableByte;
|
||||
be_t<u32> uiMinWriteByte;
|
||||
be_t<u32> uiReadPosition;
|
||||
@@ -59,6 +56,6 @@ struct CellAtracBufferInfo
|
||||
|
||||
struct CellAtracExtRes
|
||||
{
|
||||
vm::ptr<struct CellSpurs> pSpurs;
|
||||
vm::bptr<struct CellSpurs> pSpurs;
|
||||
u8 priority[8];
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user