Compare commits
167 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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
|
||||
|
||||
@@ -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
|
||||
|
||||
+5
-1
@@ -5,7 +5,7 @@
|
||||
[submodule "asmjit"]
|
||||
path = 3rdparty/asmjit/asmjit
|
||||
url = ../../asmjit/asmjit.git
|
||||
branch = oldstable
|
||||
branch = aarch64
|
||||
ignore = dirty
|
||||
[submodule "llvm"]
|
||||
path = llvm
|
||||
@@ -68,3 +68,7 @@
|
||||
path = 3rdparty/flatbuffers
|
||||
url = ../../google/flatbuffers.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/cubeb/cubeb"]
|
||||
path = 3rdparty/cubeb/cubeb
|
||||
url = ../../mozilla/cubeb.git
|
||||
ignore = dirty
|
||||
|
||||
Vendored
+2
-34
@@ -128,38 +128,8 @@ target_include_directories(3rdparty_stblib INTERFACE stblib/include)
|
||||
# DiscordRPC
|
||||
add_subdirectory(discord-rpc)
|
||||
|
||||
|
||||
# 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()
|
||||
# Cubeb
|
||||
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
|
||||
|
||||
# libevdev
|
||||
set(LIBEVDEV_TARGET 3rdparty_dummy_lib)
|
||||
@@ -334,8 +304,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})
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/FAudio updated: 28528bc885...caf9754455
Vendored
+1
-1
Submodule 3rdparty/asmjit/asmjit updated: 723f58581a...eae7197fce
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
Submodule 3rdparty/glslang/glslang updated: 2fb89a0072...c9706bdda0
Vendored
+19
-2
@@ -13,6 +13,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 +35,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 +48,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)
|
||||
@@ -54,6 +63,14 @@ if(WITH_LLVM)
|
||||
|
||||
set(LLVM_LIBS LLVMMCJIT LLVMX86CodeGen LLVMX86AsmParser)
|
||||
|
||||
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})
|
||||
target_include_directories(3rdparty_llvm INTERFACE ${LLVM_INCLUDE_DIRS})
|
||||
|
||||
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
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/xxHash updated: 94e5f23e73...35b0373c69
+4
-4
@@ -29,11 +29,11 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
|
||||
|
||||
#### 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
|
||||
@@ -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
|
||||
|
||||
|
||||
+6
-8
@@ -15,8 +15,6 @@ 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)
|
||||
@@ -56,12 +54,12 @@ if(MSVC)
|
||||
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()
|
||||
|
||||
|
||||
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,10 +69,10 @@ 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.
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
+27
-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"
|
||||
@@ -1658,7 +1659,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 +2040,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)
|
||||
{
|
||||
|
||||
+42
-54
@@ -205,8 +205,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 +279,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 +338,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 +350,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 +363,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 +374,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 +458,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 +472,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 +804,6 @@ namespace fs
|
||||
}
|
||||
|
||||
file make_gather(std::vector<file>);
|
||||
|
||||
stx::generator<dir_entry&> list_dir_recursively(std::string path);
|
||||
}
|
||||
|
||||
+123
-78
@@ -16,6 +16,15 @@
|
||||
|
||||
LOG_CHANNEL(jit_log, "JIT");
|
||||
|
||||
void jit_announce(uptr func, usz size, std::string_view name)
|
||||
{
|
||||
#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 +113,32 @@ 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 = ensure(code->codeSize());
|
||||
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 +146,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 +195,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 +209,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 +221,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 +248,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 +291,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 +349,19 @@ 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", [&](x86::Assembler& c, auto& args)
|
||||
{
|
||||
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);
|
||||
});
|
||||
|
||||
func_ptr = reinterpret_cast<u64>(func);
|
||||
@@ -368,6 +369,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 +428,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 +763,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 +812,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);
|
||||
|
||||
+145
-55
@@ -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)
|
||||
@@ -27,6 +31,17 @@
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
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 +51,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 +86,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 +119,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 +127,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 +139,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 +166,22 @@ namespace asmjit
|
||||
c.or_(to.r64(), x86::rdx);
|
||||
}
|
||||
}
|
||||
|
||||
using imm_ptr = Imm;
|
||||
}
|
||||
|
||||
// Build runtime function with asmjit::X86Assembler
|
||||
template <typename FT, typename F>
|
||||
inline FT build_function_asm(F&& builder)
|
||||
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;
|
||||
std::array<x86::Gp, 4> args;
|
||||
#ifdef _WIN32
|
||||
args[0] = x86::rcx;
|
||||
args[1] = x86::rdx;
|
||||
@@ -154,59 +194,109 @@ inline FT build_function_asm(F&& builder)
|
||||
args[3] = x86::rcx;
|
||||
#endif
|
||||
|
||||
X86Assembler compiler(&code);
|
||||
x86::Assembler compiler(&code);
|
||||
compiler.addEncodingOptions(EncodingOptions::kOptimizedAlign);
|
||||
builder(std::ref(compiler), args);
|
||||
ensure(compiler.getLastError() == 0);
|
||||
const auto result = rt._add(&code);
|
||||
jit_announce(result, code.codeSize(), name);
|
||||
return reinterpret_cast<FT>(uptr(result));
|
||||
}
|
||||
|
||||
FT result;
|
||||
#ifdef __APPLE__
|
||||
template <typename FT, usz = 4096>
|
||||
class built_function
|
||||
{
|
||||
FT m_func;
|
||||
|
||||
if (rt.add(&result, &code))
|
||||
public:
|
||||
built_function(const built_function&) = delete;
|
||||
|
||||
built_function& operator=(const built_function&) = delete;
|
||||
|
||||
template <typename F>
|
||||
built_function(std::string_view name, F&& builder)
|
||||
: m_func(ensure(build_function_asm<FT>(name, std::forward<F>(builder))))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
operator FT() const noexcept
|
||||
{
|
||||
return m_func;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto operator()(Args&&... args) const noexcept
|
||||
{
|
||||
return m_func(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
#else
|
||||
template <typename FT, usz Size = 4096>
|
||||
class built_function
|
||||
{
|
||||
alignas(4096) uchar m_data[Size];
|
||||
|
||||
public:
|
||||
built_function(const built_function&) = delete;
|
||||
|
||||
built_function& operator=(const built_function&) = delete;
|
||||
|
||||
template <typename F>
|
||||
built_function(std::string_view name, F&& builder)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
inline_runtime rt(m_data, Size);
|
||||
|
||||
CodeHolder code;
|
||||
code.init(rt.environment());
|
||||
|
||||
std::array<x86::Gp, 4> args;
|
||||
#ifdef _WIN32
|
||||
args[0] = x86::rcx;
|
||||
args[1] = x86::rdx;
|
||||
args[2] = x86::r8;
|
||||
args[3] = x86::r9;
|
||||
#else
|
||||
args[0] = x86::rdi;
|
||||
args[1] = x86::rsi;
|
||||
args[2] = x86::rdx;
|
||||
args[3] = x86::rcx;
|
||||
#endif
|
||||
|
||||
x86::Assembler compiler(&code);
|
||||
compiler.addEncodingOptions(EncodingOptions::kOptimizedAlign);
|
||||
builder(std::ref(compiler), args);
|
||||
jit_announce(rt._add(&code), code.codeSize(), name);
|
||||
}
|
||||
|
||||
operator FT() const noexcept
|
||||
{
|
||||
return FT(+m_data);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto operator()(Args&&... args) const noexcept
|
||||
{
|
||||
return FT(+m_data)(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#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 +311,7 @@ public:
|
||||
// Get LLVM context
|
||||
auto& get_context()
|
||||
{
|
||||
return m_context;
|
||||
return *m_context;
|
||||
}
|
||||
|
||||
auto& get_engine() const
|
||||
|
||||
+16
-7
@@ -6,6 +6,8 @@
|
||||
#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);
|
||||
@@ -22,17 +24,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 +43,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 +61,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 +70,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;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-3
@@ -1582,7 +1582,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) [type=u%u]", 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", d_size * 8);
|
||||
}
|
||||
|
||||
while (Emu.IsPaused())
|
||||
@@ -1826,6 +1826,14 @@ 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_handler = sigpipe_signaling_handler;
|
||||
if (::sigaction(SIGPIPE, &sa, NULL) == -1)
|
||||
{
|
||||
@@ -2182,7 +2190,7 @@ 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>("thread_base_trampoline", [&](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -2195,7 +2203,7 @@ thread_base::native_entry thread_base::make_trampoline(u64(*entry)(thread_base*
|
||||
|
||||
// Call finalize, return if zero
|
||||
c.mov(args[0], x86::rax);
|
||||
c.call(imm_ptr<native_entry(*)(u64)>(finalize));
|
||||
c.call(imm_ptr(static_cast<native_entry(*)(u64)>(&finalize)));
|
||||
c.test(x86::rax, x86::rax);
|
||||
c.jz(_ret);
|
||||
|
||||
|
||||
@@ -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,96 @@
|
||||
#include "Utilities/simple_ringbuf.h"
|
||||
|
||||
simple_ringbuf::simple_ringbuf(u32 size)
|
||||
{
|
||||
set_buf_size(size);
|
||||
}
|
||||
|
||||
u32 simple_ringbuf::get_free_size()
|
||||
{
|
||||
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()
|
||||
{
|
||||
return buf_size - 1 - get_free_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,31 @@
|
||||
#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);
|
||||
|
||||
u32 get_free_size();
|
||||
u32 get_used_size();
|
||||
|
||||
// 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);
|
||||
};
|
||||
Binary file not shown.
@@ -81,7 +81,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>
|
||||
|
||||
+1
-1
Submodule llvm updated: 5836324d64...1c0ca194dc
@@ -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 (
|
||||
|
||||
@@ -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,11 @@ 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}
|
||||
{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 +78,10 @@ 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
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -103,10 +106,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 +160,14 @@ 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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -171,7 +178,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 +192,8 @@ 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}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {06CC7920-E085-4B81-9582-8DE8AAD42510}
|
||||
|
||||
+12
-8
@@ -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)
|
||||
@@ -198,21 +202,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()
|
||||
|
||||
+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,67 +2,29 @@
|
||||
#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
|
||||
@@ -75,24 +37,6 @@ void AudioBackend::dump_capabilities(std::string& out) const
|
||||
u32 count = 0;
|
||||
const u32 capabilities = GetCapabilities();
|
||||
|
||||
if (capabilities & PLAY_PAUSE_FLUSH)
|
||||
{
|
||||
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 ? " | " : "");
|
||||
|
||||
@@ -7,7 +7,33 @@ enum : u32
|
||||
{
|
||||
DEFAULT_AUDIO_SAMPLING_RATE = 48000,
|
||||
MAX_AUDIO_BUFFERS = 64,
|
||||
AUDIO_BUFFER_SAMPLES = 256
|
||||
AUDIO_BUFFER_SAMPLES = 256,
|
||||
AUDIO_MIN_LATENCY = 512,
|
||||
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
|
||||
@@ -15,10 +41,7 @@ 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
|
||||
SET_FREQUENCY_RATIO = 0x1, // Implements SetFrequencyRatio
|
||||
};
|
||||
|
||||
AudioBackend();
|
||||
@@ -28,62 +51,43 @@ public:
|
||||
/*
|
||||
* Pure virtual methods
|
||||
*/
|
||||
virtual const char* GetName() const = 0;
|
||||
virtual std::string_view GetName() const = 0;
|
||||
virtual u32 GetCapabilities() 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; }
|
||||
|
||||
/*
|
||||
* This virtual method should be reimplemented if backend can fail during normal operation
|
||||
*/
|
||||
virtual bool Operational() { return true; }
|
||||
|
||||
/*
|
||||
* Virtual methods - should be implemented depending on backend capabilities
|
||||
*/
|
||||
|
||||
// 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
|
||||
@@ -93,7 +97,6 @@ public:
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
@@ -103,16 +106,14 @@ 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;
|
||||
|
||||
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,8 +4,8 @@
|
||||
#include "Utilities/date_time.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
AudioDumper::AudioDumper(u16 ch)
|
||||
: m_header(ch)
|
||||
AudioDumper::AudioDumper(u16 ch, u32 sample_rate, u32 sample_size)
|
||||
: m_header(ch, sample_rate, sample_size)
|
||||
{
|
||||
if (GetCh())
|
||||
{
|
||||
|
||||
@@ -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,7 +67,7 @@ class AudioDumper
|
||||
fs::file m_output{};
|
||||
|
||||
public:
|
||||
AudioDumper(u16 ch);
|
||||
AudioDumper(u16 ch, u32 sample_rate, u32 sample_size);
|
||||
~AudioDumper();
|
||||
|
||||
void WriteData(const void* buffer, u32 size);
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
#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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (int err = cubeb_stream_init(m_ctx, &m_stream, "Main stream", nullptr, nullptr, nullptr, &stream_param, std::max<u32>(AUDIO_MIN_LATENCY, min_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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
memset(m_last_sample, 0, sizeof(m_last_sample));
|
||||
}
|
||||
|
||||
void CubebBackend::Close()
|
||||
{
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
CloseUnlocked();
|
||||
}
|
||||
|
||||
void CubebBackend::Play()
|
||||
{
|
||||
if (m_playing) return;
|
||||
|
||||
if (int err = cubeb_stream_start(m_stream))
|
||||
{
|
||||
Cubeb.error("cubeb_stream_start() failed: 0x%08x", err);
|
||||
}
|
||||
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_playing = true;
|
||||
}
|
||||
|
||||
void CubebBackend::Pause()
|
||||
{
|
||||
if (int err = cubeb_stream_stop(m_stream))
|
||||
{
|
||||
Cubeb.error("cubeb_stream_stop() failed: 0x%08x", err);
|
||||
}
|
||||
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_playing = false;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return static_cast<f64>(std::max<u32>(AUDIO_MIN_LATENCY, min_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->get_sample_size() * cubeb->get_channels();
|
||||
const u32 bytes_req = nframes * cubeb->get_sample_size() * cubeb->get_channels();
|
||||
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, 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, sample_size);
|
||||
}
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
static const u32 capabilities = 0;
|
||||
u32 GetCapabilities() const override { return capabilities; }
|
||||
|
||||
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:
|
||||
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{};
|
||||
u8 m_last_sample[sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)]{};
|
||||
|
||||
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,222 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
memset(m_last_sample, 0, sizeof(m_last_sample));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
FAudioVoiceState state;
|
||||
FAudioSourceVoice_GetState(m_source_voice, &state, FAUDIO_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||
{
|
||||
FAudio_.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const u32 res = FAudioSourceVoice_SubmitSourceBuffer(m_source_voice, &buffer, nullptr);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudioSourceVoice_SubmitSourceBuffer() failed(0x%08x)", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 FAudioBackend::GetNumEnqueuedSamples()
|
||||
{
|
||||
FAudioVoiceState state;
|
||||
FAudioSourceVoice_GetState(m_source_voice, &state, 0);
|
||||
|
||||
// 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);
|
||||
return m_playing;
|
||||
}
|
||||
|
||||
f32 FAudioBackend::SetFrequencyRatio(f32 new_ratio)
|
||||
{
|
||||
new_ratio = std::clamp(new_ratio, FAUDIO_MIN_FREQ_RATIO, FAUDIO_DEFAULT_FREQ_RATIO);
|
||||
|
||||
if (m_source_voice == nullptr)
|
||||
{
|
||||
FAudio_.error("SetFrequencyRatio() called uninitialized");
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
const u32 res = FAudioSourceVoice_SetFrequencyRatio(m_source_voice, new_ratio, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudioSourceVoice_SetFrequencyRatio() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudioSourceVoice_SetFrequencyRatio() failed(0x%08x)", res);
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return new_ratio;
|
||||
}
|
||||
|
||||
void FAudioBackend::SetWriteCallback(std::function<u32(u32, void *)> cb)
|
||||
{
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_write_callback = cb;
|
||||
}
|
||||
|
||||
f64 FAudioBackend::GetCallbackFrameLen()
|
||||
{
|
||||
constexpr f64 _10ms = 0.01;
|
||||
|
||||
if (m_instance == nullptr)
|
||||
{
|
||||
FAudio_.error("GetCallbackFrameLen() called uninitialized");
|
||||
return _10ms;
|
||||
}
|
||||
|
||||
f64 min_latency{};
|
||||
|
||||
u32 samples_per_q = 0, freq = 0;
|
||||
FAudio_GetProcessingQuantum(m_instance, &samples_per_q, &freq);
|
||||
|
||||
if (freq)
|
||||
{
|
||||
min_latency = static_cast<f64>(samples_per_q) / freq;
|
||||
}
|
||||
|
||||
return std::max<f64>(min_latency, _10ms);
|
||||
}
|
||||
|
||||
void FAudioBackend::OnVoiceProcessingPassStart_func(FAudioVoiceCallback *cb_obj, u32 BytesRequired)
|
||||
{
|
||||
FAudioBackend *faudio = static_cast<FAudioBackend *>(cb_obj);
|
||||
|
||||
std::unique_lock lock(faudio->m_cb_mutex, std::defer_lock);
|
||||
if (BytesRequired && lock.try_lock() && faudio->m_write_callback && faudio->m_playing)
|
||||
{
|
||||
ensure(BytesRequired <= faudio->m_data_buf_len, "FAudio internal buffer is too small. Report to developers!");
|
||||
|
||||
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, 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, 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,47 @@ 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;
|
||||
}
|
||||
static const u32 capabilities = SET_FREQUENCY_RATIO;
|
||||
u32 GetCapabilities() const override { return capabilities; }
|
||||
|
||||
void Open(u32 /* num_buffers */) override;
|
||||
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;
|
||||
|
||||
bool AddData(const void* src, u32 num_samples) override;
|
||||
void Flush() override;
|
||||
|
||||
u64 GetNumEnqueuedSamples() override;
|
||||
f32 SetFrequencyRatio(f32 new_ratio) override;
|
||||
|
||||
private:
|
||||
static constexpr u32 INTERNAL_BUF_SIZE_MS = 25;
|
||||
|
||||
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;
|
||||
u8 m_last_sample[sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)]{};
|
||||
|
||||
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,23 @@ 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; }
|
||||
static const u32 capabilities = 0;
|
||||
u32 GetCapabilities() const override { return capabilities; }
|
||||
|
||||
virtual void Open(u32) override {}
|
||||
virtual void Close() override {}
|
||||
void Open(AudioFreq /* freq */, AudioSampleSize /* sample_size */, AudioChannelCnt /* ch_cnt */) override { m_playing = false; }
|
||||
void Close() override { m_playing = false; }
|
||||
|
||||
virtual void Play() override {}
|
||||
virtual void Pause() override {}
|
||||
void SetWriteCallback(std::function<u32(u32, void *)> /* cb */) override {};
|
||||
f64 GetCallbackFrameLen() override { return 0.01; };
|
||||
|
||||
virtual bool AddData(const void*, u32) override { return true; }
|
||||
virtual void Flush() override {}
|
||||
void Play() override { m_playing = true; }
|
||||
void Pause() override { m_playing = false; }
|
||||
bool IsPlaying() override { return m_playing; }
|
||||
|
||||
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"
|
||||
@@ -48,149 +48,262 @@ XAudio2Backend::XAudio2Backend()
|
||||
|
||||
XAudio2Backend::~XAudio2Backend()
|
||||
{
|
||||
if (m_source_voice != nullptr)
|
||||
{
|
||||
m_source_voice->Stop();
|
||||
m_source_voice->DestroyVoice();
|
||||
}
|
||||
|
||||
if (m_master_voice != nullptr)
|
||||
{
|
||||
m_master_voice->DestroyVoice();
|
||||
}
|
||||
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()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
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.fatal("Start() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(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_master_voice != nullptr)
|
||||
{
|
||||
m_master_voice->DestroyVoice();
|
||||
m_master_voice = nullptr;
|
||||
}
|
||||
|
||||
if (m_source_voice != nullptr)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
m_playing = false;
|
||||
m_data_buf = nullptr;
|
||||
m_data_buf_len = 0;
|
||||
memset(m_last_sample, 0, sizeof(m_last_sample));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool XAudio2Backend::AddData(const void* src, u32 num_samples)
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
m_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||
{
|
||||
XAudio.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const HRESULT hr = m_source_voice->SubmitSourceBuffer(&buffer);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.fatal("AddData() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XAudio2Backend::Flush()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
const HRESULT hr = m_source_voice->FlushSourceBuffers();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.fatal("FlushSourceBuffers() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
}
|
||||
|
||||
u64 XAudio2Backend::GetNumEnqueuedSamples()
|
||||
{
|
||||
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);
|
||||
return m_playing;
|
||||
}
|
||||
|
||||
f32 XAudio2Backend::SetFrequencyRatio(f32 new_ratio)
|
||||
{
|
||||
if (m_source_voice == nullptr)
|
||||
{
|
||||
XAudio.error("SetFrequencyRatio() called uninitialized");
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
XAudio.fatal("SetFrequencyRatio() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
XAudio.error("SetFrequencyRatio() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return new_ratio;
|
||||
}
|
||||
|
||||
void XAudio2Backend::SetWriteCallback(std::function<u32(u32, void *)> cb)
|
||||
{
|
||||
std::lock_guard lock(m_cb_mutex);
|
||||
m_write_callback = cb;
|
||||
}
|
||||
|
||||
f64 XAudio2Backend::GetCallbackFrameLen()
|
||||
{
|
||||
constexpr f64 _10ms = 0.01;
|
||||
|
||||
if (m_source_voice == nullptr)
|
||||
{
|
||||
XAudio.error("GetCallbackFrameLen() called uninitialized");
|
||||
return _10ms;
|
||||
}
|
||||
|
||||
void *ext;
|
||||
f64 min_latency{};
|
||||
|
||||
HRESULT hr = m_xaudio2_instance->QueryInterface(IID_IXAudio2Extension, &ext);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("QueryInterface() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
void XAudio2Backend::OnVoiceProcessingPassStart(UINT32 BytesRequired)
|
||||
{
|
||||
std::unique_lock lock(m_cb_mutex, std::defer_lock);
|
||||
if (BytesRequired && lock.try_lock() && m_write_callback && m_playing)
|
||||
{
|
||||
ensure(BytesRequired <= m_data_buf_len, "XAudio internal buffer is too small. Report to developers!");
|
||||
|
||||
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, 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, 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,58 @@ 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;
|
||||
static const u32 capabilities = SET_FREQUENCY_RATIO;
|
||||
u32 GetCapabilities() const override { return capabilities; }
|
||||
|
||||
bool Initialized() const override { return m_xaudio2_instance != nullptr; }
|
||||
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;
|
||||
|
||||
u64 GetNumEnqueuedSamples() override;
|
||||
f32 SetFrequencyRatio(f32 new_ratio) override;
|
||||
|
||||
private:
|
||||
static constexpr u32 INTERNAL_BUF_SIZE_MS = 25;
|
||||
|
||||
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;
|
||||
u8 m_last_sample[sizeof(float) * static_cast<u32>(AudioChannelCnt::SURROUND_7_1)]{};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
+13
-15
@@ -1,4 +1,4 @@
|
||||
add_library(rpcs3_emu
|
||||
add_library(rpcs3_emu
|
||||
cache_utils.cpp
|
||||
IdManager.cpp
|
||||
localized_string.cpp
|
||||
@@ -54,6 +54,7 @@ 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
|
||||
@@ -110,22 +111,9 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Audio/audio_device_listener.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 +135,9 @@ target_link_libraries(rpcs3_emu
|
||||
PUBLIC
|
||||
3rdparty::openal)
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
PUBLIC
|
||||
3rdparty::cubeb)
|
||||
|
||||
# Cell
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
@@ -370,13 +361,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 +393,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
|
||||
|
||||
@@ -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,7 +2961,7 @@ public:
|
||||
}
|
||||
|
||||
// Call external function: provide name and function pointer
|
||||
template <typename RT, typename... FArgs, typename... Args>
|
||||
template <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");
|
||||
@@ -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
|
||||
@@ -3654,10 +3686,22 @@ struct fmt_unveil<llvm::TypeSize, void>
|
||||
#endif
|
||||
|
||||
template <>
|
||||
inline llvm::Type* cpu_translator::get_type<__m128i>()
|
||||
struct llvm_value_t<__m128> : llvm_value_t<f32[4]>
|
||||
{
|
||||
return llvm::VectorType::get(llvm::Type::getInt8Ty(m_context), 16, false);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct llvm_value_t<__m128d> : llvm_value_t<f64[2]>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct llvm_value_t<__m128i> : llvm_value_t<u8[16]>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
@@ -47,24 +47,50 @@ void fmt_class_string<CellAudioError>::format(std::string& out, u64 arg)
|
||||
cell_audio_config::cell_audio_config()
|
||||
{
|
||||
raw = audio::get_raw_config();
|
||||
reset();
|
||||
}
|
||||
|
||||
void cell_audio_config::reset()
|
||||
void cell_audio_config::reset(bool backend_changed)
|
||||
{
|
||||
backend.reset();
|
||||
backend = Emu.GetCallbacks().get_audio();
|
||||
if (!backend || backend_changed)
|
||||
{
|
||||
backend.reset();
|
||||
backend = Emu.GetCallbacks().get_audio();
|
||||
}
|
||||
|
||||
{
|
||||
std::string str;
|
||||
backend->dump_capabilities(str);
|
||||
cellAudio.notice("cellAudio initializing. Backend: %s, Capabilities: %s", backend->GetName(), str.c_str());
|
||||
}
|
||||
|
||||
const AudioFreq freq = AudioFreq::FREQ_48K;
|
||||
const AudioSampleSize sample_size = raw.convert_to_s16 ? AudioSampleSize::S16 : AudioSampleSize::FLOAT;
|
||||
const AudioChannelCnt ch_cnt = [&]()
|
||||
{
|
||||
switch (raw.downmix)
|
||||
{
|
||||
case audio_downmix::no_downmix: return AudioChannelCnt::SURROUND_7_1;
|
||||
case audio_downmix::downmix_to_5_1: return AudioChannelCnt::SURROUND_5_1;
|
||||
case audio_downmix::downmix_to_stereo: return AudioChannelCnt::STEREO;
|
||||
case audio_downmix::use_application_settings: return AudioChannelCnt::STEREO; // TODO
|
||||
default:
|
||||
fmt::throw_exception("Unknown audio channel mode %s (%d)", raw.downmix, static_cast<int>(raw.downmix));
|
||||
}
|
||||
}();
|
||||
|
||||
backend->Open(freq, sample_size, ch_cnt);
|
||||
|
||||
audio_channels = backend->get_channels();
|
||||
audio_sampling_rate = backend->get_sampling_rate();
|
||||
audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate;
|
||||
audio_sample_size = backend->get_sample_size();
|
||||
audio_min_buffer_duration = backend->GetCallbackFrameLen();
|
||||
|
||||
audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels;
|
||||
audio_buffer_size = audio_buffer_length * backend->get_sample_size();
|
||||
audio_buffer_size = audio_buffer_length * audio_sample_size;
|
||||
|
||||
desired_buffer_duration = raw.desired_buffer_duration * 1000llu;
|
||||
|
||||
buffering_enabled = raw.buffering_enabled && backend->has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING);
|
||||
buffering_enabled = raw.buffering_enabled && raw.renderer != audio_renderer::null;
|
||||
|
||||
minimum_block_period = audio_block_period / 2;
|
||||
maximum_block_period = (6 * audio_block_period) / 5;
|
||||
@@ -92,7 +118,6 @@ void cell_audio_config::reset()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
|
||||
: backend(_cfg.backend)
|
||||
, cfg(_cfg)
|
||||
@@ -113,32 +138,29 @@ audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
|
||||
// Init audio dumper if enabled
|
||||
if (g_cfg.audio.dump_to_file)
|
||||
{
|
||||
m_dump.reset(new AudioDumper(cfg.audio_channels));
|
||||
m_dump.reset(new AudioDumper(cfg.audio_channels, cfg.audio_sampling_rate, cfg.audio_sample_size));
|
||||
}
|
||||
|
||||
// Initialize backend
|
||||
const f64 buffer_dur_mult = [&]()
|
||||
{
|
||||
std::string str;
|
||||
backend->dump_capabilities(str);
|
||||
cellAudio.notice("cellAudio initializing. Backend: %s, Capabilities: %s", backend->GetName(), str.c_str());
|
||||
}
|
||||
const f64 min_buf_dur = _cfg.audio_min_buffer_duration + 0.01; // Add 10ms to allow jitter compensation
|
||||
if (cfg.raw.buffering_enabled)
|
||||
{
|
||||
return std::max<f64>(min_buf_dur, cfg.raw.desired_buffer_duration / 1000.0 * 2); // Allocate 2x buffer to keep buffering algorithm happy
|
||||
}
|
||||
|
||||
backend->Open(cfg.num_allocated_buffers);
|
||||
backend_open = true;
|
||||
return min_buf_dur;
|
||||
}();
|
||||
|
||||
ensure(!get_backend_playing());
|
||||
cb_ringbuf.set_buf_size(static_cast<u32>(_cfg.audio_channels * _cfg.audio_sampling_rate * _cfg.audio_sample_size * buffer_dur_mult));
|
||||
backend->SetWriteCallback(std::bind(&audio_ringbuffer::backend_write_callback, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
audio_ringbuffer::~audio_ringbuffer()
|
||||
{
|
||||
if (!backend_open)
|
||||
if (get_backend_playing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_backend_playing() && has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
|
||||
{
|
||||
backend->Pause();
|
||||
flush();
|
||||
}
|
||||
|
||||
backend->Close();
|
||||
@@ -159,6 +181,13 @@ f32 audio_ringbuffer::set_frequency_ratio(f32 new_ratio)
|
||||
return frequency_ratio;
|
||||
}
|
||||
|
||||
u32 audio_ringbuffer::backend_write_callback(u32 size, void *buf)
|
||||
{
|
||||
if (!backend_active.observe()) backend_active = true;
|
||||
|
||||
return cb_ringbuf.pop(buf, size);
|
||||
}
|
||||
|
||||
u64 audio_ringbuffer::get_timestamp()
|
||||
{
|
||||
return get_system_time();
|
||||
@@ -183,28 +212,28 @@ void audio_ringbuffer::enqueue(const float* in_buffer)
|
||||
m_dump->WriteData(buf, cfg.audio_buffer_size);
|
||||
}
|
||||
|
||||
// Enqueue audio
|
||||
const bool success = backend->AddData(buf, AUDIO_BUFFER_SAMPLES * cfg.audio_channels);
|
||||
if (!success)
|
||||
enqueued_samples += AUDIO_BUFFER_SAMPLES;
|
||||
|
||||
// Start playing audio
|
||||
play();
|
||||
|
||||
if (!backend_active.observe())
|
||||
{
|
||||
cellAudio.warning("Could not enqueue buffer onto audio backend. Attempting to recover...");
|
||||
flush();
|
||||
// backend is not ready yet
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
|
||||
{
|
||||
enqueued_samples += AUDIO_BUFFER_SAMPLES;
|
||||
// Enqueue audio
|
||||
const u32 data_size = AUDIO_BUFFER_SAMPLES * cfg.audio_sample_size * cfg.audio_channels;
|
||||
|
||||
// Start playing audio
|
||||
play();
|
||||
if (cb_ringbuf.get_free_size() >= data_size)
|
||||
{
|
||||
cb_ringbuf.push(buf, data_size);
|
||||
}
|
||||
}
|
||||
|
||||
void audio_ringbuffer::enqueue_silence(u32 buf_count)
|
||||
{
|
||||
AUDIT(has_capability(AudioBackend::PLAY_PAUSE_FLUSH));
|
||||
|
||||
for (u32 i = 0; i < buf_count; i++)
|
||||
{
|
||||
enqueue(silence_buffer);
|
||||
@@ -213,13 +242,7 @@ void audio_ringbuffer::enqueue_silence(u32 buf_count)
|
||||
|
||||
void audio_ringbuffer::play()
|
||||
{
|
||||
if (!has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
|
||||
{
|
||||
playing = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (playing && has_capability(AudioBackend::IS_PLAYING))
|
||||
if (playing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -239,19 +262,12 @@ void audio_ringbuffer::play()
|
||||
|
||||
void audio_ringbuffer::flush()
|
||||
{
|
||||
if (!has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
|
||||
{
|
||||
playing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//cellAudio.trace("Flushing an estimated %llu enqueued samples", enqueued_samples);
|
||||
|
||||
backend->Pause();
|
||||
cb_ringbuf.flush();
|
||||
playing = false;
|
||||
|
||||
backend->Flush();
|
||||
|
||||
if (frequency_ratio != 1.0f)
|
||||
{
|
||||
set_frequency_ratio(1.0f);
|
||||
@@ -266,16 +282,16 @@ u64 audio_ringbuffer::update()
|
||||
if (Emu.IsPaused())
|
||||
{
|
||||
// Emulator paused
|
||||
if (playing && has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
|
||||
if (playing)
|
||||
{
|
||||
backend->Pause();
|
||||
flush();
|
||||
}
|
||||
emu_paused = true;
|
||||
}
|
||||
else if (emu_paused)
|
||||
{
|
||||
// Emulator unpaused
|
||||
if (enqueued_samples > 0 && has_capability(AudioBackend::PLAY_PAUSE_FLUSH))
|
||||
if (enqueued_samples > 0)
|
||||
{
|
||||
play();
|
||||
}
|
||||
@@ -289,37 +305,7 @@ u64 audio_ringbuffer::update()
|
||||
// Calculate how many audio samples have played since last time
|
||||
if (cfg.buffering_enabled && (playing || new_playing))
|
||||
{
|
||||
if (has_capability(AudioBackend::GET_NUM_ENQUEUED_SAMPLES))
|
||||
{
|
||||
// Backend supports querying for the remaining playtime, so just ask it
|
||||
enqueued_samples = backend->GetNumEnqueuedSamples();
|
||||
}
|
||||
else
|
||||
{
|
||||
const u64 play_delta = (update_timestamp ? timestamp - std::max<u64>(play_timestamp, update_timestamp) : 0);
|
||||
|
||||
const u64 delta_samples_tmp = play_delta * static_cast<u64>(cfg.audio_sampling_rate * frequency_ratio) + last_remainder;
|
||||
last_remainder = delta_samples_tmp % 1'000'000;
|
||||
const u64 delta_samples = delta_samples_tmp / 1'000'000;
|
||||
|
||||
//cellAudio.error("play_delta=%llu delta_samples=%llu", play_delta, delta_samples);
|
||||
if (delta_samples > 0)
|
||||
{
|
||||
if (enqueued_samples < delta_samples)
|
||||
{
|
||||
enqueued_samples = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
enqueued_samples -= delta_samples;
|
||||
}
|
||||
|
||||
if (enqueued_samples == 0)
|
||||
{
|
||||
cellAudio.trace("Audio buffer about to underrun!");
|
||||
}
|
||||
}
|
||||
}
|
||||
enqueued_samples = cb_ringbuf.get_used_size() / cfg.audio_sample_size;
|
||||
}
|
||||
|
||||
// Update playing state
|
||||
@@ -549,16 +535,20 @@ namespace audio
|
||||
.desired_buffer_duration = g_cfg.audio.desired_buffer_duration,
|
||||
.enable_time_stretching = static_cast<bool>(g_cfg.audio.enable_time_stretching),
|
||||
.time_stretching_threshold = g_cfg.audio.time_stretching_threshold,
|
||||
.convert_to_u16 = static_cast<bool>(g_cfg.audio.convert_to_u16),
|
||||
.start_threshold = static_cast<u32>(g_cfg.audio.start_threshold),
|
||||
.sampling_period_multiplier = static_cast<u32>(g_cfg.audio.sampling_period_multiplier),
|
||||
.convert_to_s16 = static_cast<bool>(g_cfg.audio.convert_to_s16),
|
||||
.downmix = g_cfg.audio.audio_channel_downmix,
|
||||
.renderer = g_cfg.audio.renderer
|
||||
.renderer = g_cfg.audio.renderer,
|
||||
.provider = g_cfg.audio.provider
|
||||
};
|
||||
}
|
||||
|
||||
void configure_audio()
|
||||
{
|
||||
if (g_cfg.audio.provider != audio_provider::cell_audio)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto& g_audio = g_fxo->get<cell_audio>(); g_fxo->is_init<cell_audio>())
|
||||
{
|
||||
// Only reboot the audio renderer if a relevant setting changed
|
||||
@@ -569,20 +559,18 @@ namespace audio
|
||||
raw.buffering_enabled != new_raw.buffering_enabled ||
|
||||
raw.time_stretching_threshold != new_raw.time_stretching_threshold ||
|
||||
raw.enable_time_stretching != new_raw.enable_time_stretching ||
|
||||
raw.convert_to_u16 != new_raw.convert_to_u16 ||
|
||||
raw.start_threshold != new_raw.start_threshold ||
|
||||
raw.sampling_period_multiplier != new_raw.sampling_period_multiplier ||
|
||||
raw.convert_to_s16 != new_raw.convert_to_s16 ||
|
||||
raw.downmix != new_raw.downmix ||
|
||||
raw.renderer != new_raw.renderer)
|
||||
{
|
||||
g_audio.cfg.raw = new_raw;
|
||||
g_audio.m_update_configuration = true;
|
||||
g_audio.m_update_configuration = raw.renderer != new_raw.renderer ? audio_backend_update::ALL : audio_backend_update::PARAM;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cell_audio_thread::update_config()
|
||||
void cell_audio_thread::update_config(bool backend_changed)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
@@ -590,36 +578,81 @@ void cell_audio_thread::update_config()
|
||||
ringbuffer.reset();
|
||||
|
||||
// Reload config
|
||||
cfg.reset();
|
||||
cfg.reset(backend_changed);
|
||||
|
||||
// Allocate ringbuffer
|
||||
ringbuffer.reset(new audio_ringbuffer(cfg));
|
||||
|
||||
// Reset thread state
|
||||
reset_counters();
|
||||
}
|
||||
|
||||
void cell_audio_thread::operator()()
|
||||
void cell_audio_thread::reset_counters()
|
||||
{
|
||||
thread_ctrl::scoped_priority high_prio(+1);
|
||||
m_counter = 0;
|
||||
m_start_time = ringbuffer->get_timestamp();
|
||||
m_last_period_end = m_start_time;
|
||||
m_dynamic_period = 0;
|
||||
m_backend_failed = false;
|
||||
}
|
||||
|
||||
cell_audio_thread::cell_audio_thread()
|
||||
{
|
||||
if (cfg.raw.provider != audio_provider::cell_audio)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Init audio config
|
||||
cfg.reset();
|
||||
|
||||
// Allocate ringbuffer
|
||||
ringbuffer.reset(new audio_ringbuffer(cfg));
|
||||
|
||||
// Initialize loop variables
|
||||
m_counter = 0;
|
||||
m_start_time = ringbuffer->get_timestamp();
|
||||
m_last_period_end = m_start_time;
|
||||
m_dynamic_period = 0;
|
||||
reset_counters();
|
||||
}
|
||||
|
||||
void cell_audio_thread::operator()()
|
||||
{
|
||||
if (cfg.raw.provider != audio_provider::cell_audio)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
thread_ctrl::scoped_priority high_prio(+1);
|
||||
|
||||
u32 untouched_expected = 0;
|
||||
//u32 in_progress_expected = 0;
|
||||
|
||||
// Main cellAudio loop
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
if (m_update_configuration)
|
||||
const auto update_req = m_update_configuration.observe();
|
||||
if (update_req != audio_backend_update::NONE)
|
||||
{
|
||||
cellAudio.warning("Updating cell_audio_thread configuration");
|
||||
update_config();
|
||||
m_update_configuration = false;
|
||||
update_config(update_req == audio_backend_update::ALL);
|
||||
m_update_configuration = audio_backend_update::NONE;
|
||||
}
|
||||
|
||||
if (!ringbuffer->get_operational_status())
|
||||
{
|
||||
cellAudio.warning("Backend stopped unexpectedly (likely device change). Attempting to recover...");
|
||||
|
||||
if (m_backend_failed)
|
||||
{
|
||||
thread_ctrl::wait_for(500 * 1000);
|
||||
}
|
||||
|
||||
update_config(true);
|
||||
m_backend_failed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_backend_failed)
|
||||
{
|
||||
cellAudio.warning("Backend recovered");
|
||||
m_backend_failed = false;
|
||||
}
|
||||
|
||||
const u64 timestamp = ringbuffer->update();
|
||||
@@ -872,6 +905,19 @@ void cell_audio_thread::operator()()
|
||||
ringbuffer.reset();
|
||||
}
|
||||
|
||||
audio_port* cell_audio_thread::open_port()
|
||||
{
|
||||
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
|
||||
{
|
||||
if (ports[i].state.compare_and_swap_test(audio_port_state::closed, audio_port_state::opened))
|
||||
{
|
||||
return &ports[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <audio_downmix downmix>
|
||||
void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
||||
{
|
||||
@@ -1063,9 +1109,9 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
||||
{
|
||||
std::memset(out_buffer, 0, out_buffer_sz * sizeof(float));
|
||||
}
|
||||
else if (cfg.backend->get_convert_to_u16())
|
||||
else if (cfg.backend->get_convert_to_s16())
|
||||
{
|
||||
// convert the data from float to u16 with clipping:
|
||||
// convert the data from float to s16 with clipping:
|
||||
// 2x MULPS
|
||||
// 2x MAXPS (optional)
|
||||
// 2x MINPS (optional)
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "Emu/Memory/vm_ptr.h"
|
||||
#include "Utilities/Thread.h"
|
||||
#include "Utilities/simple_ringbuf.h"
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/Audio/audio_device_listener.h"
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
#include "Emu/Audio/AudioDumper.h"
|
||||
#include "Emu/system_config_types.h"
|
||||
@@ -73,6 +73,13 @@ enum
|
||||
CELL_AUDIO_STATUS_RUN = 2,
|
||||
};
|
||||
|
||||
enum class audio_backend_update : u32
|
||||
{
|
||||
NONE,
|
||||
PARAM,
|
||||
ALL,
|
||||
};
|
||||
|
||||
//libaudio datatypes
|
||||
struct CellAudioPortParam
|
||||
{
|
||||
@@ -196,11 +203,10 @@ struct cell_audio_config
|
||||
s64 desired_buffer_duration = 0;
|
||||
bool enable_time_stretching = false;
|
||||
s64 time_stretching_threshold = 0;
|
||||
bool convert_to_u16 = false;
|
||||
u32 start_threshold = 0;
|
||||
u32 sampling_period_multiplier = 0;
|
||||
bool convert_to_s16 = false;
|
||||
audio_downmix downmix = audio_downmix::downmix_to_stereo;
|
||||
audio_renderer renderer = audio_renderer::null;
|
||||
audio_provider provider = audio_provider::none;
|
||||
} raw;
|
||||
|
||||
std::shared_ptr<AudioBackend> backend = nullptr;
|
||||
@@ -208,6 +214,8 @@ struct cell_audio_config
|
||||
u32 audio_channels = 0;
|
||||
u32 audio_sampling_rate = 0;
|
||||
u32 audio_block_period = 0;
|
||||
u32 audio_sample_size = 0;
|
||||
f64 audio_min_buffer_duration = 0.0;
|
||||
|
||||
u32 audio_buffer_length = 0;
|
||||
u32 audio_buffer_size = 0;
|
||||
@@ -254,7 +262,7 @@ struct cell_audio_config
|
||||
/*
|
||||
* Config changes
|
||||
*/
|
||||
void reset();
|
||||
void reset(bool backend_changed = true);
|
||||
};
|
||||
|
||||
class audio_ringbuffer
|
||||
@@ -271,7 +279,9 @@ private:
|
||||
std::unique_ptr<float[]> buffer[MAX_AUDIO_BUFFERS];
|
||||
const float silence_buffer[u32{AUDIO_MAX_CHANNELS_COUNT} * u32{AUDIO_BUFFER_SAMPLES}] = { 0 };
|
||||
|
||||
bool backend_open = false;
|
||||
simple_ringbuf cb_ringbuf{};
|
||||
|
||||
atomic_t<bool> backend_active = false;
|
||||
bool playing = false;
|
||||
bool emu_paused = false;
|
||||
|
||||
@@ -287,9 +297,11 @@ private:
|
||||
|
||||
bool get_backend_playing() const
|
||||
{
|
||||
return has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING) ? backend->IsPlaying() : playing;
|
||||
return backend->IsPlaying();
|
||||
}
|
||||
|
||||
u32 backend_write_callback(u32 size, void *buf);
|
||||
|
||||
public:
|
||||
audio_ringbuffer(cell_audio_config &cfg);
|
||||
~audio_ringbuffer();
|
||||
@@ -343,7 +355,12 @@ public:
|
||||
return backend->has_capability(cap);
|
||||
}
|
||||
|
||||
const char* get_backend_name() const
|
||||
bool get_operational_status() const
|
||||
{
|
||||
return backend->Operational();
|
||||
}
|
||||
|
||||
std::string_view get_backend_name() const
|
||||
{
|
||||
return backend->GetName();
|
||||
}
|
||||
@@ -354,7 +371,6 @@ class cell_audio_thread
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<audio_ringbuffer> ringbuffer;
|
||||
audio_device_listener listener;
|
||||
|
||||
void reset_ports(s32 offset = 0);
|
||||
void advance(u64 timestamp, bool reset = true);
|
||||
@@ -368,11 +384,12 @@ private:
|
||||
return (time_left > 350) ? time_left - 250 : 100;
|
||||
}
|
||||
|
||||
void update_config();
|
||||
void update_config(bool backend_changed);
|
||||
void reset_counters();
|
||||
|
||||
public:
|
||||
cell_audio_config cfg;
|
||||
atomic_t<bool> m_update_configuration = false;
|
||||
atomic_t<audio_backend_update> m_update_configuration = audio_backend_update::NONE;
|
||||
|
||||
shared_mutex mutex;
|
||||
atomic_t<u32> init = 0;
|
||||
@@ -396,25 +413,13 @@ public:
|
||||
u64 m_start_time = 0;
|
||||
u64 m_dynamic_period = 0;
|
||||
f32 m_average_playtime = 0.0f;
|
||||
bool m_backend_failed = false;
|
||||
|
||||
cell_audio_thread();
|
||||
|
||||
void operator()();
|
||||
|
||||
cell_audio_thread()
|
||||
{
|
||||
}
|
||||
|
||||
audio_port* open_port()
|
||||
{
|
||||
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
|
||||
{
|
||||
if (ports[i].state.compare_and_swap_test(audio_port_state::closed, audio_port_state::opened))
|
||||
{
|
||||
return &ports[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
audio_port* open_port();
|
||||
|
||||
bool has_capability(u32 cap) const
|
||||
{
|
||||
|
||||
@@ -201,12 +201,17 @@ error_code cellVideoOutGetGamma(u32 videoOut, vm::ptr<f32> gamma)
|
||||
{
|
||||
cellAvconfExt.warning("cellVideoOutGetGamma(videoOut=%d, gamma=*0x%x)", videoOut, gamma);
|
||||
|
||||
if (!gamma)
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER;
|
||||
}
|
||||
|
||||
if (videoOut != CELL_VIDEO_OUT_PRIMARY)
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
|
||||
}
|
||||
|
||||
auto& conf = g_fxo->get<rsx::avconf>();
|
||||
const auto& conf = g_fxo->get<rsx::avconf>();
|
||||
|
||||
*gamma = conf.gamma;
|
||||
|
||||
@@ -301,6 +306,11 @@ error_code cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<f32> screenSize)
|
||||
{
|
||||
cellAvconfExt.warning("cellVideoOutGetScreenSize(videoOut=%d, screenSize=*0x%x)", videoOut, screenSize);
|
||||
|
||||
if (!screenSize)
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER;
|
||||
}
|
||||
|
||||
if (videoOut != CELL_VIDEO_OUT_PRIMARY)
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
|
||||
|
||||
@@ -433,6 +433,15 @@ error_code cellCameraInit()
|
||||
g_camera.attr[CELL_CAMERA_AGCHIGH] = { 64 };
|
||||
break;
|
||||
}
|
||||
|
||||
case fake_camera_type::uvc1_1:
|
||||
{
|
||||
g_camera.attr[CELL_CAMERA_DEVICEID] = { 0x5ca, 0x18d0 }; // KBCR-S01MU
|
||||
g_camera.attr[CELL_CAMERA_FORMATCAP] = { CELL_CAMERA_JPG | CELL_CAMERA_YUV422 };
|
||||
g_camera.attr[CELL_CAMERA_NUMFRAME] = { 1 }; // Amount of supported resolutions
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
cellCamera.todo("Trying to init cellCamera with un-researched camera type.");
|
||||
}
|
||||
|
||||
@@ -230,13 +230,13 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
||||
const auto& psf = psf::load_object(fs::file(local_dir +"/PARAM.SFO"));
|
||||
|
||||
// Some following fields may be zero in old FW 1.00 version PARAM.SFO
|
||||
if (psf.count("PARENTAL_LEVEL") != 0) get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
|
||||
if (psf.count("ATTRIBUTE") != 0) get->getParam.attribute = psf.at("ATTRIBUTE").as_integer();
|
||||
if (psf.count("RESOLUTION") != 0) get->getParam.resolution = psf.at("RESOLUTION").as_integer();
|
||||
if (psf.count("SOUND_FORMAT") != 0) get->getParam.soundFormat = psf.at("SOUND_FORMAT").as_integer();
|
||||
if (psf.count("TITLE") != 0) strcpy_trunc(get->getParam.title, psf.at("TITLE").as_string());
|
||||
if (psf.count("APP_VER") != 0) strcpy_trunc(get->getParam.dataVersion, psf.at("APP_VER").as_string());
|
||||
if (psf.count("TITLE_ID") != 0) strcpy_trunc(get->getParam.titleId, psf.at("TITLE_ID").as_string());
|
||||
if (psf.contains("PARENTAL_LEVEL")) get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
|
||||
if (psf.contains("ATTRIBUTE")) get->getParam.attribute = psf.at("ATTRIBUTE").as_integer();
|
||||
if (psf.contains("RESOLUTION")) get->getParam.resolution = psf.at("RESOLUTION").as_integer();
|
||||
if (psf.contains("SOUND_FORMAT")) get->getParam.soundFormat = psf.at("SOUND_FORMAT").as_integer();
|
||||
if (psf.contains("TITLE")) strcpy_trunc(get->getParam.title, psf.at("TITLE").as_string());
|
||||
if (psf.contains("APP_VER")) strcpy_trunc(get->getParam.dataVersion, psf.at("APP_VER").as_string());
|
||||
if (psf.contains("TITLE_ID")) strcpy_trunc(get->getParam.titleId, psf.at("TITLE_ID").as_string());
|
||||
|
||||
for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++)
|
||||
{
|
||||
@@ -1356,10 +1356,10 @@ error_code cellDiscGameGetBootDiscInfo(vm::ptr<CellDiscGameSystemFileParam> getP
|
||||
return CELL_DISCGAME_ERROR_NOT_DISCBOOT;
|
||||
}
|
||||
|
||||
const auto& psf = psf::load_object(fs::file(vfs::get(dir + "/PARAM.SFO")));
|
||||
const psf::registry psf = psf::load_object(fs::file(vfs::get(dir + "/PARAM.SFO")));
|
||||
|
||||
if (psf.count("PARENTAL_LEVEL") != 0) getParam->parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
|
||||
if (psf.count("TITLE_ID") != 0) strcpy_trunc(getParam->titleId, psf.at("TITLE_ID").as_string());
|
||||
if (psf.contains("PARENTAL_LEVEL")) getParam->parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();
|
||||
if (psf.contains("TITLE_ID")) strcpy_trunc(getParam->titleId, psf.at("TITLE_ID").as_string());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -497,7 +497,7 @@ static bool ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller
|
||||
return false;
|
||||
|
||||
ext.status = 0; // CELL_GEM_EXT_CONNECTED | CELL_GEM_EXT_EXT0 | CELL_GEM_EXT_EXT1
|
||||
ext.analog_left_x = pad->m_analog_left_x;
|
||||
ext.analog_left_x = pad->m_analog_left_x; // HACK: these pad members are actually only set in cellPad
|
||||
ext.analog_left_y = pad->m_analog_left_y;
|
||||
ext.analog_right_x = pad->m_analog_right_x;
|
||||
ext.analog_right_y = pad->m_analog_right_y;
|
||||
|
||||
@@ -109,9 +109,16 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
|
||||
sys_io.trace("cellKbCnvRawCode(arrange=%d, mkey=%d, led=%d, rawcode=0x%x)", arrange, mkey, led, rawcode);
|
||||
|
||||
// CELL_KB_RAWDAT
|
||||
if (rawcode <= 0x03 || rawcode == 0x29 || rawcode == 0x35 || (rawcode >= 0x39 && rawcode <= 0x53) || rawcode == 0x65 || rawcode == 0x88 || rawcode == 0x8A || rawcode == 0x8B)
|
||||
if (rawcode <= CELL_KEYC_E_UNDEF ||
|
||||
rawcode == CELL_KEYC_ESCAPE ||
|
||||
rawcode == CELL_KEYC_106_KANJI ||
|
||||
(rawcode >= CELL_KEYC_CAPS_LOCK && rawcode <= CELL_KEYC_NUM_LOCK) ||
|
||||
rawcode == CELL_KEYC_APPLICATION ||
|
||||
rawcode == CELL_KEYC_KANA ||
|
||||
rawcode == CELL_KEYC_HENKAN ||
|
||||
rawcode == CELL_KEYC_MUHENKAN)
|
||||
{
|
||||
return rawcode | 0x8000;
|
||||
return rawcode | CELL_KB_RAWDAT;
|
||||
}
|
||||
|
||||
const bool is_alt = mkey & (CELL_KB_MKEY_L_ALT | CELL_KB_MKEY_R_ALT);
|
||||
@@ -123,14 +130,14 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
|
||||
|
||||
if (is_num_lock)
|
||||
{
|
||||
if (rawcode == CELL_KEYC_KPAD_NUMLOCK) return 0x00 | 0x4000; // 'Num Lock'
|
||||
if (rawcode == CELL_KEYC_KPAD_SLASH) return 0x2F | 0x4000; // '/'
|
||||
if (rawcode == CELL_KEYC_KPAD_ASTERISK) return 0x2A | 0x4000; // '*'
|
||||
if (rawcode == CELL_KEYC_KPAD_MINUS) return 0x2D | 0x4000; // '-'
|
||||
if (rawcode == CELL_KEYC_KPAD_PLUS) return 0x2B | 0x4000; // '+'
|
||||
if (rawcode == CELL_KEYC_KPAD_ENTER) return 0x0A | 0x4000; // '\n'
|
||||
if (rawcode == CELL_KEYC_KPAD_0) return 0x30 | 0x4000; // '0'
|
||||
if (rawcode >= CELL_KEYC_KPAD_1 && rawcode <= CELL_KEYC_KPAD_9) return (rawcode - 0x28) | 0x4000; // '1' - '9'
|
||||
//if (rawcode == CELL_KEYC_KPAD_NUMLOCK) return 0x00 | CELL_KB_KEYPAD; // 'Num Lock' (unreachable)
|
||||
if (rawcode == CELL_KEYC_KPAD_SLASH) return 0x2F | CELL_KB_KEYPAD; // '/'
|
||||
if (rawcode == CELL_KEYC_KPAD_ASTERISK) return 0x2A | CELL_KB_KEYPAD; // '*'
|
||||
if (rawcode == CELL_KEYC_KPAD_MINUS) return 0x2D | CELL_KB_KEYPAD; // '-'
|
||||
if (rawcode == CELL_KEYC_KPAD_PLUS) return 0x2B | CELL_KB_KEYPAD; // '+'
|
||||
if (rawcode == CELL_KEYC_KPAD_ENTER) return 0x0A | CELL_KB_KEYPAD; // '\n'
|
||||
if (rawcode == CELL_KEYC_KPAD_0) return 0x30 | CELL_KB_KEYPAD; // '0'
|
||||
if (rawcode >= CELL_KEYC_KPAD_1 && rawcode <= CELL_KEYC_KPAD_9) return (rawcode - 0x28) | CELL_KB_KEYPAD; // '1' - '9'
|
||||
}
|
||||
|
||||
// ASCII
|
||||
@@ -223,7 +230,7 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
|
||||
if (rawcode == CELL_KEYC_Q) return get_ascii('q', 'Q', '@');
|
||||
}
|
||||
|
||||
if (rawcode >= 0x04 && rawcode <= 0x1D) // 'A' - 'Z'
|
||||
if (rawcode >= CELL_KEYC_A && rawcode <= CELL_KEYC_Z) // 'A' - 'Z'
|
||||
{
|
||||
rawcode -=
|
||||
(is_shift)
|
||||
@@ -231,13 +238,13 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
|
||||
: ((led & (CELL_KB_LED_CAPS_LOCK)) ? 0x20 : 0);
|
||||
return rawcode + 0x5D;
|
||||
}
|
||||
if (rawcode >= 0x1E && rawcode <= 0x26) return rawcode + 0x13; // '1' - '9'
|
||||
if (rawcode == 0x27) return 0x30; // '0'
|
||||
if (rawcode == 0x28) return 0x0A; // '\n'
|
||||
if (rawcode == 0x29) return 0x1B; // 'ESC'
|
||||
if (rawcode == 0x2A) return 0x08; // '\b'
|
||||
if (rawcode == 0x2B) return 0x09; // '\t'
|
||||
if (rawcode == 0x2C) return 0x20; // 'space'
|
||||
if (rawcode >= CELL_KEYC_1 && rawcode <= CELL_KEYC_9) return rawcode + 0x13; // '1' - '9'
|
||||
if (rawcode == CELL_KEYC_0) return 0x30; // '0'
|
||||
if (rawcode == CELL_KEYC_ENTER) return 0x0A; // '\n'
|
||||
//if (rawcode == CELL_KEYC_ESC) return 0x1B; // 'ESC' (unreachable)
|
||||
if (rawcode == CELL_KEYC_BS) return 0x08; // '\b'
|
||||
if (rawcode == CELL_KEYC_TAB) return 0x09; // '\t'
|
||||
if (rawcode == CELL_KEYC_SPACE) return 0x20; // 'space'
|
||||
|
||||
// TODO: Add more keys and layouts
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
|
||||
MsgDialogType type{};
|
||||
|
||||
std::function<void(s32 status)> on_close;
|
||||
std::function<void(s32 status)> on_close = nullptr;
|
||||
|
||||
virtual ~MsgDialogBase();
|
||||
virtual void Create(const std::string& msg, const std::string& title = "") = 0;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include "Emu/NP/np_handler.h"
|
||||
#include "Emu/NP/np_helpers.h"
|
||||
|
||||
LOG_CHANNEL(cellNetCtl);
|
||||
|
||||
@@ -93,7 +94,7 @@ error_code cellNetCtlInit()
|
||||
{
|
||||
cellNetCtl.warning("cellNetCtlInit()");
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_netctl_init)
|
||||
{
|
||||
@@ -109,7 +110,7 @@ void cellNetCtlTerm()
|
||||
{
|
||||
cellNetCtl.warning("cellNetCtlTerm()");
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
nph.is_netctl_init = false;
|
||||
}
|
||||
@@ -118,7 +119,7 @@ error_code cellNetCtlGetState(vm::ptr<s32> state)
|
||||
{
|
||||
cellNetCtl.trace("cellNetCtlGetState(state=*0x%x)", state);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_netctl_init)
|
||||
{
|
||||
@@ -139,7 +140,7 @@ error_code cellNetCtlAddHandler(vm::ptr<cellNetCtlHandler> handler, vm::ptr<void
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlAddHandler(handler=*0x%x, arg=*0x%x, hid=*0x%x)", handler, arg, hid);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_netctl_init)
|
||||
{
|
||||
@@ -158,7 +159,7 @@ error_code cellNetCtlDelHandler(s32 hid)
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlDelHandler(hid=0x%x)", hid);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_netctl_init)
|
||||
{
|
||||
@@ -177,7 +178,7 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
|
||||
{
|
||||
cellNetCtl.warning("cellNetCtlGetInfo(code=0x%x (%s), info=*0x%x)", code, InfoCodeToName(code), info);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_netctl_init)
|
||||
{
|
||||
@@ -209,9 +210,9 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
|
||||
case CELL_NET_CTL_INFO_LINK_TYPE: info->link_type = CELL_NET_CTL_LINK_TYPE_10BASE_FULL; break;
|
||||
case CELL_NET_CTL_INFO_IP_CONFIG: info->ip_config = CELL_NET_CTL_IP_STATIC; break;
|
||||
case CELL_NET_CTL_INFO_DEFAULT_ROUTE: strcpy_trunc(info->default_route, "192.168.1.1"); break;
|
||||
case CELL_NET_CTL_INFO_PRIMARY_DNS: strcpy_trunc(info->primary_dns, np_handler::ip_to_string(nph.get_dns_ip())); break;
|
||||
case CELL_NET_CTL_INFO_SECONDARY_DNS: strcpy_trunc(info->secondary_dns, np_handler::ip_to_string(nph.get_dns_ip())); break;
|
||||
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np_handler::ip_to_string(nph.get_local_ip_addr())); break;
|
||||
case CELL_NET_CTL_INFO_PRIMARY_DNS: strcpy_trunc(info->primary_dns, np::ip_to_string(nph.get_dns_ip())); break;
|
||||
case CELL_NET_CTL_INFO_SECONDARY_DNS: strcpy_trunc(info->secondary_dns, np::ip_to_string(nph.get_dns_ip())); break;
|
||||
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np::ip_to_string(nph.get_local_ip_addr())); break;
|
||||
case CELL_NET_CTL_INFO_NETMASK: strcpy_trunc(info->netmask, "255.255.255.255"); break;
|
||||
case CELL_NET_CTL_INFO_HTTP_PROXY_CONFIG: info->http_proxy_config = 0; break;
|
||||
case CELL_NET_CTL_INFO_DHCP_HOSTNAME: strcpy_trunc(info->dhcp_hostname, nph.get_hostname()); break;
|
||||
@@ -238,7 +239,7 @@ error_code cellNetCtlNetStartDialogLoadAsync(vm::cptr<CellNetCtlNetStartDialogPa
|
||||
{
|
||||
cellNetCtl.error("cellNetCtlNetStartDialogLoadAsync(param=*0x%x)", param);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_netctl_init)
|
||||
{
|
||||
@@ -270,7 +271,7 @@ error_code cellNetCtlNetStartDialogAbortAsync()
|
||||
{
|
||||
cellNetCtl.error("cellNetCtlNetStartDialogAbortAsync()");
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_netctl_init)
|
||||
{
|
||||
@@ -284,7 +285,7 @@ error_code cellNetCtlNetStartDialogUnloadAsync(vm::ptr<CellNetCtlNetStartDialogR
|
||||
{
|
||||
cellNetCtl.warning("cellNetCtlNetStartDialogUnloadAsync(result=*0x%x)", result);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_netctl_init)
|
||||
{
|
||||
@@ -311,7 +312,7 @@ error_code cellNetCtlGetNatInfo(vm::ptr<CellNetCtlNatInfo> natInfo)
|
||||
{
|
||||
cellNetCtl.warning("cellNetCtlGetNatInfo(natInfo=*0x%x)", natInfo);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_netctl_init)
|
||||
{
|
||||
|
||||
@@ -1457,7 +1457,7 @@ error_code cellRtcGetDaysInMonth(s32 year, s32 month)
|
||||
{
|
||||
cellRtc.todo("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month);
|
||||
|
||||
if ((year < 0) || (month < 0) || (month > 12))
|
||||
if ((year < 0) || (month <= 0) || (month > 12))
|
||||
{
|
||||
return CELL_RTC_ERROR_INVALID_ARG;
|
||||
}
|
||||
@@ -1467,7 +1467,7 @@ error_code cellRtcGetDaysInMonth(s32 year, s32 month)
|
||||
return not_an_error(DAYS_IN_MONTH[month + 11]);
|
||||
}
|
||||
|
||||
return not_an_error(DAYS_IN_MONTH[month + -1]);
|
||||
return not_an_error(DAYS_IN_MONTH[month - 1]);
|
||||
}
|
||||
|
||||
error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day)
|
||||
|
||||
@@ -117,6 +117,7 @@ struct savedata_manager
|
||||
{
|
||||
semaphore<> mutex;
|
||||
atomic_t<bool> enable_overlay{false};
|
||||
atomic_t<s32> last_cbresult_error_dialog{0}; // CBRESULT errors are negative
|
||||
};
|
||||
|
||||
static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir, const std::string& prefix)
|
||||
@@ -150,11 +151,11 @@ static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir,
|
||||
}
|
||||
|
||||
SaveDataEntry save_entry;
|
||||
save_entry.dirName = psf.at("SAVEDATA_DIRECTORY").as_string();
|
||||
save_entry.listParam = psf.at("SAVEDATA_LIST_PARAM").as_string();
|
||||
save_entry.title = psf.at("TITLE").as_string();
|
||||
save_entry.subtitle = psf.at("SUB_TITLE").as_string();
|
||||
save_entry.details = psf.at("DETAIL").as_string();
|
||||
save_entry.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
|
||||
save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
|
||||
save_entry.title = psf::get_string(psf, "TITLE");
|
||||
save_entry.subtitle = psf::get_string(psf, "SUB_TITLE");
|
||||
save_entry.details = psf::get_string(psf, "DETAIL");
|
||||
|
||||
for (const auto& entry2 : fs::dir(base_dir + entry.name))
|
||||
{
|
||||
@@ -312,9 +313,12 @@ static error_code display_callback_result_error_message(ppu_thread& ppu, const C
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "22"};
|
||||
}
|
||||
|
||||
// TODO: errDialog == CELL_SAVEDATA_ERRDIALOG_NOREPEAT
|
||||
if (errDialog != CELL_SAVEDATA_ERRDIALOG_ALWAYS)
|
||||
if (errDialog == CELL_SAVEDATA_ERRDIALOG_NONE ||
|
||||
(errDialog == CELL_SAVEDATA_ERRDIALOG_NOREPEAT && result.result == g_fxo->get<savedata_manager>().last_cbresult_error_dialog.exchange(result.result)))
|
||||
{
|
||||
// TODO: Find out if the "last error" is always tracked or only when NOREPEAT is set
|
||||
return CELL_SAVEDATA_ERROR_CBRESULT;
|
||||
}
|
||||
|
||||
// Yield before a blocking dialog is being spawned
|
||||
lv2_obj::sleep(ppu);
|
||||
@@ -571,6 +575,12 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncFixed funcFixed, PFuncStat funcStat,
|
||||
PFuncFile funcFile, u32 container, u32 unk_op_flags /*TODO*/, vm::ptr<void> userdata, u32 userId, PFuncDone funcDone)
|
||||
{
|
||||
if (const auto [ok, list] = setList.try_read(); ok)
|
||||
cellSaveData.notice("savedata_op(): setList = { .sortType=%d, .sortOrder=%d, .dirNamePrefix='%s' }", list.sortType, list.sortOrder, list.dirNamePrefix);
|
||||
|
||||
if (const auto [ok, buf] = setBuf.try_read(); ok)
|
||||
cellSaveData.notice("savedata_op(): setBuf = { .dirListMax=%d, .fileListMax=%d, .bufSize=%d }", buf.dirListMax, buf.fileListMax, buf.bufSize);
|
||||
|
||||
if (const auto ecode = savedata_check_args(operation, version, dirName, errDialog, setList, setBuf, funcList, funcFixed, funcStat,
|
||||
funcFile, container, unk_op_flags, userdata, userId, funcDone))
|
||||
{
|
||||
@@ -668,11 +678,11 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
}
|
||||
|
||||
SaveDataEntry save_entry2;
|
||||
save_entry2.dirName = psf.at("SAVEDATA_DIRECTORY").as_string();
|
||||
save_entry2.listParam = psf.at("SAVEDATA_LIST_PARAM").as_string();
|
||||
save_entry2.title = psf.at("TITLE").as_string();
|
||||
save_entry2.subtitle = psf.at("SUB_TITLE").as_string();
|
||||
save_entry2.details = psf.at("DETAIL").as_string();
|
||||
save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
|
||||
save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
|
||||
save_entry2.title = psf::get_string(psf, "TITLE");
|
||||
save_entry2.subtitle = psf::get_string(psf, "SUB_TITLE");
|
||||
save_entry2.details = psf::get_string(psf, "DETAIL");
|
||||
|
||||
for (const auto& entry2 : fs::dir(base_dir + entry.name))
|
||||
{
|
||||
@@ -1281,8 +1291,8 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
// This section contains the list of files in the save ordered as they would be in BSD filesystem
|
||||
std::vector<std::string> blist;
|
||||
|
||||
if (psf.count("RPCS3_BLIST"))
|
||||
blist = fmt::split(psf.at("RPCS3_BLIST").as_string(), {"/"}, false);
|
||||
if (const auto it = psf.find("RPCS3_BLIST"); it != psf.cend())
|
||||
blist = fmt::split(it->second.as_string(), {"/"}, false);
|
||||
|
||||
// Get save stats
|
||||
{
|
||||
@@ -1308,12 +1318,12 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
|
||||
if (!psf.empty())
|
||||
{
|
||||
statGet->getParam.parental_level = psf.at("PARENTAL_LEVEL").as_integer();
|
||||
statGet->getParam.attribute = psf.at("ATTRIBUTE").as_integer(); // ???
|
||||
strcpy_trunc(statGet->getParam.title, save_entry.title = psf.at("TITLE").as_string());
|
||||
strcpy_trunc(statGet->getParam.subTitle, save_entry.subtitle = psf.at("SUB_TITLE").as_string());
|
||||
strcpy_trunc(statGet->getParam.detail, save_entry.details = psf.at("DETAIL").as_string());
|
||||
strcpy_trunc(statGet->getParam.listParam, save_entry.listParam = psf.at("SAVEDATA_LIST_PARAM").as_string());
|
||||
statGet->getParam.parental_level = psf::get_integer(psf, "PARENTAL_LEVEL");
|
||||
statGet->getParam.attribute = psf::get_integer(psf, "ATTRIBUTE"); // ???
|
||||
strcpy_trunc(statGet->getParam.title, save_entry.title = psf::get_string(psf, "TITLE"));
|
||||
strcpy_trunc(statGet->getParam.subTitle, save_entry.subtitle = psf::get_string(psf, "SUB_TITLE"));
|
||||
strcpy_trunc(statGet->getParam.detail, save_entry.details = psf::get_string(psf, "DETAIL"));
|
||||
strcpy_trunc(statGet->getParam.listParam, save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM"));
|
||||
}
|
||||
|
||||
statGet->bind = 0;
|
||||
@@ -2046,14 +2056,14 @@ static NEVER_INLINE error_code savedata_get_list_item(vm::cptr<char> dirName, vm
|
||||
return CELL_SAVEDATA_ERROR_NODATA;
|
||||
}
|
||||
|
||||
auto psf = psf::load_object(fs::file(sfo));
|
||||
const psf::registry psf = psf::load_object(fs::file(sfo));
|
||||
|
||||
if (sysFileParam)
|
||||
{
|
||||
strcpy_trunc(sysFileParam->listParam, psf.at("SAVEDATA_LIST_PARAM").as_string());
|
||||
strcpy_trunc(sysFileParam->title, psf.at("TITLE").as_string());
|
||||
strcpy_trunc(sysFileParam->subTitle, psf.at("SUB_TITLE").as_string());
|
||||
strcpy_trunc(sysFileParam->detail, psf.at("DETAIL").as_string());
|
||||
strcpy_trunc(sysFileParam->listParam, psf::get_string(psf, "SAVEDATA_LIST_PARAM"));
|
||||
strcpy_trunc(sysFileParam->title, psf::get_string(psf, "TITLE"));
|
||||
strcpy_trunc(sysFileParam->subTitle, psf::get_string(psf, "SUB_TITLE"));
|
||||
strcpy_trunc(sysFileParam->detail, psf::get_string(psf, "DETAIL"));
|
||||
}
|
||||
|
||||
if (dir)
|
||||
|
||||
@@ -119,7 +119,7 @@ error_code cellVideoOutGetState(u32 videoOut, u32 deviceIndex, vm::ptr<CellVideo
|
||||
{
|
||||
case CELL_VIDEO_OUT_PRIMARY:
|
||||
{
|
||||
auto& conf = g_fxo->get<rsx::avconf>();
|
||||
const auto& conf = g_fxo->get<rsx::avconf>();
|
||||
state->state = CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED;
|
||||
state->colorSpace = CELL_VIDEO_OUT_COLOR_SPACE_RGB;
|
||||
state->displayMode.resolutionId = conf.state ? conf.resolution_id : g_video_out_resolution_id.at(g_cfg.video.resolution);
|
||||
@@ -197,13 +197,19 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptr<CellVideoOutConfiguration
|
||||
conf.resolution_y = res.height;
|
||||
conf.state = 1;
|
||||
|
||||
if (conf.aspect == CELL_VIDEO_OUT_ASPECT_AUTO)
|
||||
// TODO: What happens if the aspect is unknown? Let's treat it as auto for now.
|
||||
if (conf.aspect != CELL_VIDEO_OUT_ASPECT_4_3 && conf.aspect != CELL_VIDEO_OUT_ASPECT_16_9)
|
||||
{
|
||||
// Resolve 'auto' option to actual aspect ratio
|
||||
if (conf.aspect != CELL_VIDEO_OUT_ASPECT_AUTO)
|
||||
{
|
||||
cellSysutil.error("Selected unknown aspect 0x%x. Falling back to aspect %s.", conf.aspect, g_cfg.video.aspect_ratio.get());
|
||||
}
|
||||
|
||||
// Resolve 'auto' or unknown options to actual aspect ratio
|
||||
conf.aspect = g_video_out_aspect_id.at(g_cfg.video.aspect_ratio);
|
||||
}
|
||||
|
||||
cellSysutil.notice("Selected video resolution 0x%x", config->resolutionId);
|
||||
cellSysutil.notice("Selected video configuration: resolutionId=0x%x, aspect=0x%x=>0x%x, format=0x%x", config->resolutionId, config->aspect, conf.aspect, config->format);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -224,7 +230,7 @@ error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutConfig
|
||||
{
|
||||
case CELL_VIDEO_OUT_PRIMARY:
|
||||
{
|
||||
if (auto& conf = g_fxo->get<rsx::avconf>(); conf.state)
|
||||
if (const auto& conf = g_fxo->get<rsx::avconf>(); conf.state)
|
||||
{
|
||||
config->resolutionId = conf.resolution_id;
|
||||
config->format = conf.format;
|
||||
|
||||
@@ -34,7 +34,7 @@ enum CellVideoOutResolutionId : s32
|
||||
CELL_VIDEO_OUT_RESOLUTION_1280x1080 = 0xc,
|
||||
CELL_VIDEO_OUT_RESOLUTION_960x1080 = 0xd,
|
||||
CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING = 0x81,
|
||||
CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88,
|
||||
CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88,
|
||||
CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89,
|
||||
CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a,
|
||||
CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b,
|
||||
|
||||
+207
-181
File diff suppressed because it is too large
Load Diff
@@ -178,7 +178,7 @@ error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr<SceNpMatchin
|
||||
error_code sceNpMatching2Term(ppu_thread& ppu);
|
||||
error_code sceNpMatching2Term2();
|
||||
|
||||
error_code generic_match2_error_check(const named_thread<np_handler>& nph, SceNpMatching2ContextId ctxId, vm::cptr<void> reqParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
|
||||
error_code generic_match2_error_check(const named_thread<np::np_handler>& nph, SceNpMatching2ContextId ctxId, vm::cptr<void> reqParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
|
||||
{
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -207,7 +207,7 @@ error_code sceNp2Init(u32 poolsize, vm::ptr<void> poolptr)
|
||||
{
|
||||
sceNp2.warning("sceNp2Init(poolsize=0x%x, poolptr=*0x%x)", poolsize, poolptr);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
{
|
||||
std::lock_guard lock(nph.mutex_status);
|
||||
@@ -239,7 +239,7 @@ error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr<SceNpMatchin
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2Init2(stackSize=0x%x, priority=%d, param=*0x%x)", stackSize, priority, param);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_init)
|
||||
{
|
||||
@@ -265,7 +265,7 @@ error_code sceNp2Term(ppu_thread& ppu)
|
||||
{
|
||||
sceNp2.warning("sceNp2Term()");
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
{
|
||||
std::lock_guard lock(nph.mutex_status);
|
||||
@@ -295,7 +295,7 @@ error_code sceNpMatching2Term2()
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2Term2()");
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
{
|
||||
std::lock_guard lock(nph.mutex_status);
|
||||
@@ -321,7 +321,7 @@ error_code sceNpMatching2DestroyContext(SceNpMatching2ContextId ctxId)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2DestroyContext(ctxId=%d)", ctxId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -339,7 +339,7 @@ error_code sceNpMatching2LeaveLobby(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2LeaveLobby(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -352,7 +352,7 @@ error_code sceNpMatching2RegisterLobbyMessageCallback(SceNpMatching2ContextId ct
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2RegisterLobbyMessageCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -367,7 +367,7 @@ error_code sceNpMatching2GetWorldInfoList(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2GetWorldInfoList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -387,7 +387,7 @@ error_code sceNpMatching2RegisterLobbyEventCallback(SceNpMatching2ContextId ctxI
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2RegisterLobbyEventCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -402,7 +402,7 @@ error_code sceNpMatching2GetLobbyMemberDataInternalList(SceNpMatching2ContextId
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetLobbyMemberDataInternalList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -416,7 +416,7 @@ error_code sceNpMatching2SearchRoom(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2SearchRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -432,7 +432,7 @@ error_code sceNpMatching2SignalingGetConnectionStatus(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2SignalingGetConnectionStatus(ctxId=%d, roomId=%d, memberId=%d, connStatus=*0x%x, peerAddr=*0x%x, peerPort=*0x%x)", ctxId, roomId, memberId, connStatus, peerAddr, peerPort);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -468,7 +468,7 @@ error_code sceNpMatching2SetUserInfo(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SetUserInfo(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -481,7 +481,7 @@ error_code sceNpMatching2GetClanLobbyId(SceNpMatching2ContextId ctxId, SceNpClan
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetClanLobbyId(ctxId=%d, clanId=%d, lobbyId=*0x%x)", ctxId, clanId, lobbyId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -496,7 +496,7 @@ error_code sceNpMatching2GetLobbyMemberDataInternal(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetLobbyMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -509,7 +509,7 @@ error_code sceNpMatching2ContextStart(SceNpMatching2ContextId ctxId)
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2ContextStart(ctxId=%d)", ctxId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -537,7 +537,7 @@ error_code sceNpMatching2CreateServerContext(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2CreateServerContext(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -557,7 +557,7 @@ error_code sceNpMatching2GetMemoryInfo(vm::ptr<SceNpMatching2MemoryInfo> memInfo
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetMemoryInfo(memInfo=*0x%x)", memInfo);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -572,7 +572,7 @@ error_code sceNpMatching2LeaveRoom(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2LeaveRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -588,7 +588,7 @@ error_code sceNpMatching2SetRoomDataExternal(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2SetRoomDataExternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -602,9 +602,9 @@ error_code sceNpMatching2SetRoomDataExternal(
|
||||
error_code sceNpMatching2SignalingGetConnectionInfo(
|
||||
SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, SceNpMatching2RoomMemberId memberId, s32 code, vm::ptr<SceNpSignalingConnectionInfo> connInfo)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SignalingGetConnectionInfo(ctxId=%d, roomId=%d, memberId=%d, code=%d, connInfo=*0x%x)", ctxId, roomId, memberId, code, connInfo);
|
||||
sceNp2.warning("sceNpMatching2SignalingGetConnectionInfo(ctxId=%d, roomId=%d, memberId=%d, code=%d, connInfo=*0x%x)", ctxId, roomId, memberId, code, connInfo);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -663,9 +663,9 @@ error_code sceNpMatching2SignalingGetConnectionInfo(
|
||||
error_code sceNpMatching2SendRoomMessage(
|
||||
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2SendRoomMessageRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SendRoomMessage(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
sceNp2.warning("sceNpMatching2SendRoomMessage(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -681,7 +681,7 @@ error_code sceNpMatching2JoinLobby(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2JoinLobby(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -695,7 +695,7 @@ error_code sceNpMatching2GetRoomMemberDataExternalList(SceNpMatching2ContextId c
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetRoomMemberDataExternalList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -708,7 +708,7 @@ error_code sceNpMatching2AbortRequest(SceNpMatching2ContextId ctxId, SceNpMatchi
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2AbortRequest(ctxId=%d, reqId=%d)", ctxId, reqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -723,7 +723,7 @@ error_code sceNpMatching2GetServerInfo(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2GetServerInfo(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -738,7 +738,7 @@ error_code sceNpMatching2GetEventData(SceNpMatching2ContextId ctxId, SceNpMatchi
|
||||
{
|
||||
sceNp2.notice("sceNpMatching2GetEventData(ctxId=%d, eventKey=%d, buf=*0x%x, bufLen=%d)", ctxId, eventKey, buf, bufLen);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -750,20 +750,44 @@ error_code sceNpMatching2GetEventData(SceNpMatching2ContextId ctxId, SceNpMatchi
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return not_an_error(nph.get_match2_event(eventKey, static_cast<u8 *>(buf.get_ptr()), bufLen));
|
||||
return not_an_error(nph.get_match2_event(eventKey, buf.addr(), bufLen));
|
||||
}
|
||||
|
||||
error_code sceNpMatching2GetRoomSlotInfoLocal(SceNpMatching2ContextId ctxId, const SceNpMatching2RoomId roomId, vm::ptr<SceNpMatching2RoomSlotInfo> roomSlotInfo)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetRoomSlotInfoLocal(ctxId=%d, roomId=%d, roomSlotInfo=*0x%x)", ctxId, roomId, roomSlotInfo);
|
||||
sceNp2.notice("sceNpMatching2GetRoomSlotInfoLocal(ctxId=%d, roomId=%d, roomSlotInfo=*0x%x)", ctxId, roomId, roomSlotInfo);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (!ctxId)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
|
||||
if (!roomId)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID;
|
||||
}
|
||||
|
||||
if (!check_match2_context(ctxId))
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
|
||||
}
|
||||
|
||||
const auto [error, slots] = nph.local_get_room_slots(roomId);
|
||||
|
||||
if (error)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
memcpy(roomSlotInfo.get_ptr(), &slots.value(), sizeof(SceNpMatching2RoomSlotInfo));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -772,7 +796,7 @@ error_code sceNpMatching2SendLobbyChatMessage(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SendLobbyChatMessage(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -785,7 +809,7 @@ error_code sceNpMatching2AbortContextStart(SceNpMatching2ContextId ctxId)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2AbortContextStart(ctxId=%d)", ctxId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -797,16 +821,50 @@ error_code sceNpMatching2AbortContextStart(SceNpMatching2ContextId ctxId)
|
||||
|
||||
error_code sceNpMatching2GetRoomMemberIdListLocal(SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, s32 sortMethod, vm::ptr<SceNpMatching2RoomMemberId> memberId, u32 memberIdNum)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetRoomMemberIdListLocal(ctxId=%d, roomId=%d, sortMethod=%d, memberId=*0x%x, memberIdNum=%d)", ctxId, roomId, sortMethod, memberId, memberIdNum);
|
||||
sceNp2.notice("sceNpMatching2GetRoomMemberIdListLocal(ctxId=%d, roomId=%d, sortMethod=%d, memberId=*0x%x, memberIdNum=%d)", ctxId, roomId, sortMethod, memberId, memberIdNum);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
if (!ctxId)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
|
||||
if (!roomId)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID;
|
||||
}
|
||||
|
||||
if (sortMethod != SCE_NP_MATCHING2_SORT_METHOD_JOIN_DATE && sortMethod != SCE_NP_MATCHING2_SORT_METHOD_SLOT_NUMBER)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_SORT_METHOD;
|
||||
}
|
||||
|
||||
if (!check_match2_context(ctxId))
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
|
||||
}
|
||||
|
||||
const auto [error, vec_memberids] = nph.local_get_room_memberids(roomId, sortMethod);
|
||||
|
||||
if (error)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
u32 num_members = std::min(memberIdNum, static_cast<u32>(vec_memberids.size()));
|
||||
|
||||
for (u32 i = 0; i < num_members; i++)
|
||||
{
|
||||
memberId[i] = vec_memberids[i];
|
||||
}
|
||||
|
||||
return not_an_error(num_members);
|
||||
}
|
||||
|
||||
error_code sceNpMatching2JoinRoom(
|
||||
@@ -814,7 +872,7 @@ error_code sceNpMatching2JoinRoom(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2JoinRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -826,26 +884,56 @@ error_code sceNpMatching2JoinRoom(
|
||||
}
|
||||
|
||||
error_code sceNpMatching2GetRoomMemberDataInternalLocal(SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, SceNpMatching2RoomMemberId memberId, vm::cptr<SceNpMatching2AttributeId> attrId,
|
||||
u32 attrIdNum, vm::ptr<SceNpMatching2RoomMemberDataInternal> member, vm::ptr<char> buf, u64 bufLen)
|
||||
u32 attrIdNum, vm::ptr<SceNpMatching2RoomMemberDataInternal> member, vm::ptr<char> buf, u64 bufLen)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetRoomMemberDataInternalLocal(ctxId=%d, roomId=%d, memberId=%d, attrId=*0x%x, attrIdNum=%d, member=*0x%x, buf=*0x%x, bufLen=%d)", ctxId, roomId, memberId, attrId,
|
||||
attrIdNum, member, buf, bufLen);
|
||||
sceNp2.warning("sceNpMatching2GetRoomMemberDataInternalLocal(ctxId=%d, roomId=%d, memberId=%d, attrId=*0x%x, attrIdNum=%d, member=*0x%x, buf=*0x%x, bufLen=%d)", ctxId, roomId, memberId, attrId,
|
||||
attrIdNum, member, buf, bufLen);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
if (!ctxId)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
|
||||
if (!roomId)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID;
|
||||
}
|
||||
|
||||
if (!memberId)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_MEMBER_ID;
|
||||
}
|
||||
|
||||
std::vector<SceNpMatching2AttributeId> binattrs_list;
|
||||
for (u32 i = 0; i < attrIdNum; i++)
|
||||
{
|
||||
if (attrId[i] < SCE_NP_MATCHING2_ROOMMEMBER_BIN_ATTR_INTERNAL_1_ID || attrId[i] >= SCE_NP_MATCHING2_USER_BIN_ATTR_1_ID)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_ID;
|
||||
}
|
||||
binattrs_list.push_back(attrId[i]);
|
||||
}
|
||||
|
||||
if (!check_match2_context(ctxId))
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
|
||||
}
|
||||
|
||||
return nph.local_get_room_member_data(roomId, memberId, binattrs_list, member ? member.get_ptr() : nullptr, buf.addr(), bufLen);
|
||||
}
|
||||
|
||||
error_code sceNpMatching2GetCbQueueInfo(SceNpMatching2ContextId ctxId, vm::ptr<SceNpMatching2CbQueueInfo> queueInfo)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetCbQueueInfo(ctxId=%d, queueInfo=*0x%x)", ctxId, queueInfo);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -860,7 +948,7 @@ error_code sceNpMatching2KickoutRoomMember(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2KickoutRoomMember(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -873,7 +961,7 @@ error_code sceNpMatching2ContextStartAsync(SceNpMatching2ContextId ctxId, u32 ti
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2ContextStartAsync(ctxId=%d, timeout=%d)", ctxId, timeout);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -906,7 +994,7 @@ error_code sceNpMatching2SetSignalingOptParam(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SetSignalingOptParam(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -919,7 +1007,7 @@ error_code sceNpMatching2RegisterContextCallback(SceNpMatching2ContextId ctxId,
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2RegisterContextCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -946,7 +1034,7 @@ error_code sceNpMatching2SendRoomChatMessage(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SendRoomChatMessage(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -958,9 +1046,9 @@ error_code sceNpMatching2SendRoomChatMessage(
|
||||
error_code sceNpMatching2SetRoomDataInternal(
|
||||
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2SetRoomDataInternalRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SetRoomDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
sceNp2.warning("sceNpMatching2SetRoomDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -974,9 +1062,9 @@ error_code sceNpMatching2SetRoomDataInternal(
|
||||
error_code sceNpMatching2GetRoomDataInternal(
|
||||
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2GetRoomDataInternalRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetRoomDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
sceNp2.warning("sceNpMatching2GetRoomDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -992,7 +1080,7 @@ error_code sceNpMatching2SignalingGetPingInfo(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2SignalingGetPingInfo(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1005,9 +1093,9 @@ error_code sceNpMatching2SignalingGetPingInfo(
|
||||
|
||||
error_code sceNpMatching2GetServerIdListLocal(SceNpMatching2ContextId ctxId, vm::ptr<SceNpMatching2ServerId> serverId, u32 serverIdNum)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetServerIdListLocal(ctxId=%d, serverId=*0x%x, serverIdNum=%d)", ctxId, serverId, serverIdNum);
|
||||
sceNp2.notice("sceNpMatching2GetServerIdListLocal(ctxId=%d, serverId=*0x%x, serverIdNum=%d)", ctxId, serverId, serverIdNum);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1057,7 +1145,7 @@ error_code sceNpMatching2GrantRoomOwner(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GrantRoomOwner(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1071,7 +1159,7 @@ error_code sceNpMatching2CreateContext(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2CreateContext(npId=*0x%x, commId=*0x%x(%s), passPhrase=*0x%x, ctxId=*0x%x, option=%d)", npId, commId, commId ? commId->data : "", ctxId, option);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1092,7 +1180,7 @@ error_code sceNpMatching2GetSignalingOptParamLocal(SceNpMatching2ContextId ctxId
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetSignalingOptParamLocal(ctxId=%d, roomId=%d, signalingOptParam=*0x%x)", ctxId, roomId, signalingOptParam);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1106,7 +1194,7 @@ error_code sceNpMatching2RegisterSignalingCallback(SceNpMatching2ContextId ctxId
|
||||
{
|
||||
sceNp2.notice("sceNpMatching2RegisterSignalingCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1123,7 +1211,7 @@ error_code sceNpMatching2ClearEventData(SceNpMatching2ContextId ctxId, SceNpMatc
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2ClearEventData(ctxId=%d, eventKey=%d)", ctxId, eventKey);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1138,7 +1226,7 @@ error_code sceNpMatching2GetUserInfoList(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetUserInfoList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1152,7 +1240,7 @@ error_code sceNpMatching2GetRoomMemberDataInternal(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetRoomMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1164,14 +1252,16 @@ error_code sceNpMatching2GetRoomMemberDataInternal(
|
||||
error_code sceNpMatching2SetRoomMemberDataInternal(
|
||||
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2SetRoomMemberDataInternalRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SetRoomMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
sceNp2.warning("sceNpMatching2SetRoomMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
*assignedReqId = nph.set_roommemberdata_internal(ctxId, optParam, reqParam.get_ptr());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -1180,7 +1270,7 @@ error_code sceNpMatching2JoinProhibitiveRoom(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2JoinProhibitiveRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1196,7 +1286,7 @@ error_code sceNpMatching2SignalingSetCtxOpt(SceNpMatching2ContextId ctxId, s32 o
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SignalingSetCtxOpt(ctxId=%d, optname=%d, optval=%d)", ctxId, optname, optval);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1209,14 +1299,21 @@ error_code sceNpMatching2SignalingSetCtxOpt(SceNpMatching2ContextId ctxId, s32 o
|
||||
error_code sceNpMatching2DeleteServerContext(
|
||||
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2DeleteServerContextRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2DeleteServerContext(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
sceNp2.warning("sceNpMatching2DeleteServerContext(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
if (reqParam->serverId == 0)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID;
|
||||
}
|
||||
|
||||
*assignedReqId = nph.delete_server_context(ctxId, optParam, reqParam->serverId);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -1224,7 +1321,7 @@ error_code sceNpMatching2SetDefaultRequestOptParam(SceNpMatching2ContextId ctxId
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2SetDefaultRequestOptParam(ctxId=%d, optParam=*0x%x)", ctxId, optParam);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1249,7 +1346,7 @@ error_code sceNpMatching2RegisterRoomEventCallback(SceNpMatching2ContextId ctxId
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2RegisterRoomEventCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1265,24 +1362,56 @@ error_code sceNpMatching2RegisterRoomEventCallback(SceNpMatching2ContextId ctxId
|
||||
|
||||
error_code sceNpMatching2GetRoomPasswordLocal(SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, vm::ptr<b8> withPassword, vm::ptr<SceNpMatching2SessionPassword> roomPassword)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetRoomPasswordLocal(ctxId=%d, roomId=%d, withPassword=*0x%x, roomPassword=*0x%x)", ctxId, roomId, withPassword, roomPassword);
|
||||
sceNp2.notice("sceNpMatching2GetRoomPasswordLocal(ctxId=%d, roomId=%d, withPassword=*0x%x, roomPassword=*0x%x)", ctxId, roomId, withPassword, roomPassword);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (!ctxId)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
}
|
||||
|
||||
if (!roomId)
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID;
|
||||
}
|
||||
|
||||
if (!check_match2_context(ctxId))
|
||||
{
|
||||
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
|
||||
}
|
||||
|
||||
const auto [error, password] = nph.local_get_room_password(roomId);
|
||||
|
||||
if (error)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
if (password)
|
||||
{
|
||||
*withPassword = true;
|
||||
memcpy(roomPassword.get_ptr(), &*password, sizeof(SceNpMatching2SessionPassword));
|
||||
}
|
||||
else
|
||||
{
|
||||
*withPassword = false;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatching2GetRoomDataExternalList(
|
||||
SceNpMatching2ContextId ctxId, vm::cptr<SceNpMatching2GetRoomDataExternalListRequest> reqParam, vm::cptr<SceNpMatching2RequestOptParam> optParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetRoomDataExternalList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
sceNp2.warning("sceNpMatching2GetRoomDataExternalList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1298,7 +1427,7 @@ error_code sceNpMatching2CreateJoinRoom(
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2CreateJoinRoom(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1313,7 +1442,7 @@ error_code sceNpMatching2SignalingGetCtxOpt(SceNpMatching2ContextId ctxId, s32 o
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SignalingGetCtxOpt(ctxId=%d, optname=%d, optval=*0x%x)", ctxId, optname, optval);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1328,7 +1457,7 @@ error_code sceNpMatching2GetLobbyInfoList(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetLobbyInfoList(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1342,7 +1471,7 @@ error_code sceNpMatching2GetLobbyMemberIdListLocal(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2GetLobbyMemberIdListLocal(ctxId=%d, lobbyId=%d, memberId=*0x%x, memberIdNum=%d, me=*0x%x)", ctxId, lobbyId, memberId, memberIdNum, me);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1357,7 +1486,7 @@ error_code sceNpMatching2SendLobbyInvitation(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SendLobbyInvitation(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1370,7 +1499,7 @@ error_code sceNpMatching2ContextStop(SceNpMatching2ContextId ctxId)
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2ContextStop(ctxId=%d)", ctxId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1401,7 +1530,7 @@ error_code sceNpMatching2SetLobbyMemberDataInternal(
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SetLobbyMemberDataInternal(ctxId=%d, reqParam=*0x%x, optParam=*0x%x, assignedReqId=*0x%x)", ctxId, reqParam, optParam, assignedReqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
if (auto res = generic_match2_error_check(nph, ctxId, reqParam, assignedReqId); res != CELL_OK)
|
||||
{
|
||||
return res;
|
||||
@@ -1414,7 +1543,7 @@ error_code sceNpMatching2RegisterRoomMessageCallback(SceNpMatching2ContextId ctx
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2RegisterRoomMessageCallback(ctxId=%d, cbFunc=*0x%x, cbFuncArg=*0x%x)", ctxId, cbFunc, cbFuncArg);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1432,7 +1561,7 @@ error_code sceNpMatching2SignalingCancelPeerNetInfo(SceNpMatching2ContextId ctxI
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SignalingCancelPeerNetInfo(ctxId=%d, reqId=%d)", ctxId, reqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1446,7 +1575,7 @@ error_code sceNpMatching2SignalingGetLocalNetInfo(vm::ptr<SceNpMatching2Signalin
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SignalingGetLocalNetInfo(netinfo=*0x%x)", netinfo);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1466,7 +1595,7 @@ error_code sceNpMatching2SignalingGetPeerNetInfo(SceNpMatching2ContextId ctxId,
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SignalingGetPeerNetInfo(ctxId=%d, roomId=%d, roomMemberId=%d, reqId=*0x%x)", ctxId, roomId, roomMemberId, reqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1485,7 +1614,7 @@ error_code sceNpMatching2SignalingGetPeerNetInfoResult(SceNpMatching2ContextId c
|
||||
{
|
||||
sceNp2.todo("sceNpMatching2SignalingGetPeerNetInfoResult(ctxId=%d, reqId=%d, netinfo=*0x%x)", ctxId, reqId, netinfo);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP2_Match2_init)
|
||||
{
|
||||
@@ -1505,7 +1634,7 @@ error_code sceNpAuthOAuthInit()
|
||||
{
|
||||
sceNp2.todo("sceNpAuthOAuthInit()");
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP_Auth_init)
|
||||
{
|
||||
@@ -1521,7 +1650,7 @@ error_code sceNpAuthOAuthTerm()
|
||||
{
|
||||
sceNp2.todo("sceNpAuthOAuthTerm()");
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
// TODO: check if this might throw SCE_NP_OAUTH_ERROR_NOT_INITIALIZED
|
||||
nph.is_NP_Auth_init = false;
|
||||
@@ -1533,7 +1662,7 @@ error_code sceNpAuthCreateOAuthRequest()
|
||||
{
|
||||
sceNp2.todo("sceNpAuthCreateOAuthRequest()");
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP_Auth_init)
|
||||
{
|
||||
@@ -1547,7 +1676,7 @@ error_code sceNpAuthDeleteOAuthRequest(SceNpAuthOAuthRequestId reqId)
|
||||
{
|
||||
sceNp2.todo("sceNpAuthDeleteOAuthRequest(reqId=%d)", reqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP_Auth_init)
|
||||
{
|
||||
@@ -1561,7 +1690,7 @@ error_code sceNpAuthAbortOAuthRequest(SceNpAuthOAuthRequestId reqId)
|
||||
{
|
||||
sceNp2.todo("sceNpAuthAbortOAuthRequest(reqId=%d)", reqId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP_Auth_init)
|
||||
{
|
||||
@@ -1575,7 +1704,7 @@ error_code sceNpAuthGetAuthorizationCode(SceNpAuthOAuthRequestId reqId, vm::cptr
|
||||
{
|
||||
sceNp2.todo("sceNpAuthGetAuthorizationCode(reqId=%d, param=*0x%x, authCode=*0x%x, issuerId=%d)", reqId, param, authCode, issuerId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (!nph.is_NP_Auth_init)
|
||||
{
|
||||
|
||||
@@ -1388,9 +1388,9 @@ struct SceNpMatching2RoomDataInternalUpdateInfo
|
||||
vm::bptr<SceNpMatching2FlagAttr> prevFlagAttr;
|
||||
vm::bptr<SceNpMatching2RoomPasswordSlotMask> newRoomPasswordSlotMask;
|
||||
vm::bptr<SceNpMatching2RoomPasswordSlotMask> prevRoomPasswordSlotMask;
|
||||
vm::pptr<SceNpMatching2RoomGroup> newRoomGroup;
|
||||
vm::bpptr<SceNpMatching2RoomGroup> newRoomGroup;
|
||||
be_t<u32> newRoomGroupNum;
|
||||
vm::pptr<SceNpMatching2RoomBinAttrInternal> newRoomBinAttrInternal;
|
||||
vm::bpptr<SceNpMatching2RoomBinAttrInternal> newRoomBinAttrInternal;
|
||||
be_t<u32> newRoomBinAttrInternalNum;
|
||||
};
|
||||
|
||||
@@ -1401,7 +1401,7 @@ struct SceNpMatching2RoomMemberDataInternalUpdateInfo
|
||||
vm::bptr<SceNpMatching2FlagAttr> newFlagAttr;
|
||||
vm::bptr<SceNpMatching2FlagAttr> prevFlagAttr;
|
||||
vm::bptr<SceNpMatching2TeamId> newTeamId;
|
||||
vm::pptr<SceNpMatching2RoomMemberBinAttrInternal> newRoomMemberBinAttrInternal;
|
||||
vm::bpptr<SceNpMatching2RoomMemberBinAttrInternal> newRoomMemberBinAttrInternal;
|
||||
be_t<u32> newRoomMemberBinAttrInternalNum;
|
||||
};
|
||||
|
||||
@@ -1413,7 +1413,7 @@ struct SceNpMatching2RoomMessageInfo
|
||||
u8 padding[2];
|
||||
vm::bptr<SceNpMatching2RoomMessageDestination> dst;
|
||||
vm::bptr<SceNpUserInfo2> srcMember;
|
||||
vm::bcptr<void> msg;
|
||||
vm::bptr<void> msg;
|
||||
be_t<u32> msgLen;
|
||||
};
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ error_code sceNpSnsFbGetAccessToken(u32 handle, vm::cptr<SceNpSnsFbAccessTokenPa
|
||||
return SCE_NP_SNS_FB_ERROR_UNKNOWN_HANDLE;
|
||||
}
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.get_psn_status() == SCE_NP_MANAGER_STATUS_OFFLINE)
|
||||
{
|
||||
@@ -306,7 +306,7 @@ error_code sceNpSnsFbGetLongAccessToken(u32 handle, vm::cptr<SceNpSnsFbAccessTok
|
||||
return SCE_NP_SNS_FB_ERROR_UNKNOWN_HANDLE;
|
||||
}
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np_handler>>();
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.get_psn_status() == SCE_NP_MANAGER_STATUS_OFFLINE)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@ void fmt_class_string<ppu_attr>::format(std::string& out, u64 arg)
|
||||
case ppu_attr::known_size: return "known_size";
|
||||
case ppu_attr::no_return: return "no_return";
|
||||
case ppu_attr::no_size: return "no_size";
|
||||
case ppu_attr::has_mfvscr: return "has_mfvscr";
|
||||
case ppu_attr::__bitset_enum_max: break;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ enum class ppu_attr : u32
|
||||
known_size,
|
||||
no_return,
|
||||
no_size,
|
||||
has_mfvscr,
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
|
||||
@@ -1910,14 +1910,14 @@ std::vector<ppu_function_t>& ppu_function_manager::access(bool ghc)
|
||||
|
||||
static std::vector<ppu_function_t> list_ghc
|
||||
{
|
||||
build_function_asm<ppu_function_t>([](asmjit::X86Assembler& c, auto& args)
|
||||
build_function_asm<ppu_function_t>("ppu_unregistered", [](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
c.mov(args[0], x86::rbp);
|
||||
c.jmp(imm_ptr(list[0]));
|
||||
}),
|
||||
build_function_asm<ppu_function_t>([](asmjit::X86Assembler& c, auto& args)
|
||||
build_function_asm<ppu_function_t>("ppu_return", [](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -1937,7 +1937,7 @@ u32 ppu_function_manager::add_function(ppu_function_t function)
|
||||
list.push_back(function);
|
||||
|
||||
// Generate trampoline
|
||||
list2.push_back(build_function_asm<ppu_function_t>([&](asmjit::X86Assembler& c, auto& args)
|
||||
list2.push_back(build_function_asm<ppu_function_t>("ppu_trampolinea", [&](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
|
||||
@@ -528,14 +528,14 @@ inline v128 vec_handle_denormal(ppu_thread& ppu, v128 a)
|
||||
|
||||
bool ppu_interpreter::MFVSCR(ppu_thread& ppu, ppu_opcode_t op)
|
||||
{
|
||||
ppu.vr[op.vd] = v128::from32(0, 0, 0, u32{ppu.sat} | (u32{ppu.nj} << 16));
|
||||
ppu.vr[op.vd] = v128::from32(0, 0, 0, u32{ppu.sat != v128{}} | (u32{ppu.nj} << 16));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ppu_interpreter::MTVSCR(ppu_thread& ppu, ppu_opcode_t op)
|
||||
{
|
||||
const u32 vscr = ppu.vr[op.vb]._u32[3];
|
||||
ppu.sat = (vscr & 1) != 0;
|
||||
ppu.sat = v128::from32((vscr & 1) != 0);
|
||||
ppu.nj = (vscr & 0x10000) != 0;
|
||||
ppu.jm_mask = ppu.nj ? ppu_inf_u32 : 0x7fff'ffff;
|
||||
return true;
|
||||
@@ -577,12 +577,12 @@ bool ppu_interpreter_precise::VADDSBS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum < INT8_MIN)
|
||||
{
|
||||
d._s8[i] = INT8_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (sum > INT8_MAX)
|
||||
{
|
||||
d._s8[i] = INT8_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -612,12 +612,12 @@ bool ppu_interpreter_precise::VADDSHS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum < INT16_MIN)
|
||||
{
|
||||
d._s16[i] = INT16_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (sum > INT16_MAX)
|
||||
{
|
||||
d._s16[i] = INT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -654,12 +654,12 @@ bool ppu_interpreter_precise::VADDSWS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum < INT32_MIN)
|
||||
{
|
||||
d._s32[i] = INT32_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (sum > INT32_MAX)
|
||||
{
|
||||
d._s32[i] = INT32_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -695,7 +695,7 @@ bool ppu_interpreter_precise::VADDUBS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum > UINT8_MAX)
|
||||
{
|
||||
d._u8[i] = UINT8_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -731,7 +731,7 @@ bool ppu_interpreter_precise::VADDUHS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum > UINT16_MAX)
|
||||
{
|
||||
d._u16[i] = UINT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -770,7 +770,7 @@ bool ppu_interpreter_precise::VADDUWS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum > UINT32_MAX)
|
||||
{
|
||||
d._u32[i] = UINT32_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -988,13 +988,13 @@ bool ppu_interpreter_precise::VCTSXS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
d._s32[i] = sign ? 0x80000000 : 0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
else if (exp2 > 30)
|
||||
{
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
d._s32[i] = sign ? 0x80000000 : 0x7FFFFFFF;
|
||||
}
|
||||
else if (exp2 < 0)
|
||||
@@ -1041,13 +1041,13 @@ bool ppu_interpreter_precise::VCTUXS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
d._u32[i] = sign ? 0 : 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
else if (exp2 > 31)
|
||||
{
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
d._u32[i] = sign ? 0 : 0xFFFFFFFF;
|
||||
}
|
||||
else if (exp2 < 0)
|
||||
@@ -1056,7 +1056,7 @@ bool ppu_interpreter_precise::VCTUXS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
}
|
||||
else if (sign)
|
||||
{
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
d._u32[i] = 0;
|
||||
}
|
||||
else
|
||||
@@ -1180,12 +1180,12 @@ bool ppu_interpreter_precise::VMHADDSHS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum < INT16_MIN)
|
||||
{
|
||||
d._s16[i] = INT16_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (sum > INT16_MAX)
|
||||
{
|
||||
d._s16[i] = INT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1229,12 +1229,12 @@ bool ppu_interpreter_precise::VMHRADDSHS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum < INT16_MIN)
|
||||
{
|
||||
d._s16[i] = INT16_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (sum > INT16_MAX)
|
||||
{
|
||||
d._s16[i] = INT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1420,12 +1420,12 @@ bool ppu_interpreter_precise::VMSUMSHS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result > 0x7fffffff)
|
||||
{
|
||||
saturated = 0x7fffffff;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (result < INT32_MIN)
|
||||
{
|
||||
saturated = 0x80000000;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
saturated = static_cast<s32>(result);
|
||||
@@ -1517,7 +1517,7 @@ bool ppu_interpreter_precise::VMSUMUHS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result > 0xffffffffu)
|
||||
{
|
||||
saturated = 0xffffffff;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
saturated = static_cast<u32>(result);
|
||||
@@ -1666,12 +1666,12 @@ bool ppu_interpreter_precise::VPKSHSS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result < INT8_MIN)
|
||||
{
|
||||
d._s8[i + 8] = INT8_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (result > INT8_MAX)
|
||||
{
|
||||
d._s8[i + 8] = INT8_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1683,12 +1683,12 @@ bool ppu_interpreter_precise::VPKSHSS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result < INT8_MIN)
|
||||
{
|
||||
d._s8[i] = INT8_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (result > INT8_MAX)
|
||||
{
|
||||
d._s8[i] = INT8_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1717,7 +1717,7 @@ bool ppu_interpreter_precise::VPKSHUS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
const auto all_bits = a | b;
|
||||
if ((all_bits._u64[0] | all_bits._u64[1]) & mask)
|
||||
{
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1744,12 +1744,12 @@ bool ppu_interpreter_precise::VPKSWSS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result < INT16_MIN)
|
||||
{
|
||||
d._s16[i + 4] = INT16_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (result > INT16_MAX)
|
||||
{
|
||||
d._s16[i + 4] = INT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1761,12 +1761,12 @@ bool ppu_interpreter_precise::VPKSWSS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result < INT16_MIN)
|
||||
{
|
||||
d._s16[i] = INT16_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (result > INT16_MAX)
|
||||
{
|
||||
d._s16[i] = INT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1828,12 +1828,12 @@ bool ppu_interpreter_precise::VPKSWUS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result > UINT16_MAX)
|
||||
{
|
||||
result = UINT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (result < 0)
|
||||
{
|
||||
result = 0;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
|
||||
d._u16[h + 4] = result;
|
||||
@@ -1843,12 +1843,12 @@ bool ppu_interpreter_precise::VPKSWUS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result > UINT16_MAX)
|
||||
{
|
||||
result = UINT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (result < 0)
|
||||
{
|
||||
result = 0;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
|
||||
d._u16[h] = result;
|
||||
@@ -1909,7 +1909,7 @@ bool ppu_interpreter_precise::VPKUHUS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result > UINT8_MAX)
|
||||
{
|
||||
result = UINT8_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
|
||||
d._u8[b + 8] = static_cast<u8>(result);
|
||||
@@ -1919,7 +1919,7 @@ bool ppu_interpreter_precise::VPKUHUS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result > UINT8_MAX)
|
||||
{
|
||||
result = UINT8_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
|
||||
d._u8[b] = static_cast<u8>(result);
|
||||
@@ -1980,7 +1980,7 @@ bool ppu_interpreter_precise::VPKUWUS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result > UINT16_MAX)
|
||||
{
|
||||
result = UINT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
|
||||
d._u16[h + 4] = result;
|
||||
@@ -1990,7 +1990,7 @@ bool ppu_interpreter_precise::VPKUWUS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result > UINT16_MAX)
|
||||
{
|
||||
result = UINT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
|
||||
d._u16[h] = result;
|
||||
@@ -2430,12 +2430,12 @@ bool ppu_interpreter_precise::VSUBSBS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (diff < INT8_MIN)
|
||||
{
|
||||
d._s8[i] = INT8_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (diff > INT8_MAX)
|
||||
{
|
||||
d._s8[i] = INT8_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2465,12 +2465,12 @@ bool ppu_interpreter_precise::VSUBSHS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (diff < INT16_MIN)
|
||||
{
|
||||
d._s16[i] = INT16_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (diff > INT16_MAX)
|
||||
{
|
||||
d._s16[i] = INT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2518,12 +2518,12 @@ bool ppu_interpreter_precise::VSUBSWS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result < INT32_MIN)
|
||||
{
|
||||
d._s32[w] = INT32_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (result > INT32_MAX)
|
||||
{
|
||||
d._s32[w] = INT32_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
d._s32[w] = static_cast<s32>(result);
|
||||
@@ -2556,12 +2556,12 @@ bool ppu_interpreter_precise::VSUBUBS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (diff < 0)
|
||||
{
|
||||
d._u8[i] = 0;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (diff > UINT8_MAX)
|
||||
{
|
||||
d._u8[i] = UINT8_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2597,12 +2597,12 @@ bool ppu_interpreter_precise::VSUBUHS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (diff < 0)
|
||||
{
|
||||
d._u16[i] = 0;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (diff > UINT16_MAX)
|
||||
{
|
||||
d._u16[i] = UINT16_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2652,7 +2652,7 @@ bool ppu_interpreter_precise::VSUBUWS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (result < 0)
|
||||
{
|
||||
d._u32[w] = 0;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
d._u32[w] = static_cast<u32>(result);
|
||||
@@ -2704,12 +2704,12 @@ bool ppu_interpreter_precise::VSUMSWS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum > INT32_MAX)
|
||||
{
|
||||
d._s32[0] = INT32_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (sum < INT32_MIN)
|
||||
{
|
||||
d._s32[0] = INT32_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
d._s32[0] = static_cast<s32>(sum);
|
||||
@@ -2756,12 +2756,12 @@ bool ppu_interpreter_precise::VSUM2SWS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum > INT32_MAX)
|
||||
{
|
||||
d._s32[n * 2] = INT32_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (sum < INT32_MIN)
|
||||
{
|
||||
d._s32[n * 2] = INT32_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
d._s32[n * 2] = static_cast<s32>(sum);
|
||||
@@ -2820,12 +2820,12 @@ bool ppu_interpreter_precise::VSUM4SBS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum > INT32_MAX)
|
||||
{
|
||||
d._s32[w] = INT32_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (sum < INT32_MIN)
|
||||
{
|
||||
d._s32[w] = INT32_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
d._s32[w] = static_cast<s32>(sum);
|
||||
@@ -2880,12 +2880,12 @@ bool ppu_interpreter_precise::VSUM4SHS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum > INT32_MAX)
|
||||
{
|
||||
d._s32[w] = INT32_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else if (sum < INT32_MIN)
|
||||
{
|
||||
d._s32[w] = INT32_MIN;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
d._s32[w] = static_cast<s32>(sum);
|
||||
@@ -2936,7 +2936,7 @@ bool ppu_interpreter_precise::VSUM4UBS(ppu_thread& ppu, ppu_opcode_t op)
|
||||
if (sum > UINT32_MAX)
|
||||
{
|
||||
d._u32[w] = UINT32_MAX;
|
||||
ppu.sat = true;
|
||||
ppu.sat._u32[0] = 1;
|
||||
}
|
||||
else
|
||||
d._u32[w] = static_cast<u32>(sum);
|
||||
|
||||
+150
-227
@@ -65,8 +65,6 @@
|
||||
#include "util/v128sse.hpp"
|
||||
#include "util/sysinfo.hpp"
|
||||
|
||||
const bool s_use_ssse3 = utils::has_ssse3();
|
||||
|
||||
extern atomic_t<u64> g_watchdog_hold_ctr;
|
||||
|
||||
// Should be of the same type
|
||||
@@ -149,7 +147,7 @@ static bool ppu_break(ppu_thread& ppu, ppu_opcode_t op);
|
||||
|
||||
extern void do_cell_atomic_128_store(u32 addr, const void* to_write);
|
||||
|
||||
const auto ppu_gateway = build_function_asm<void(*)(ppu_thread*)>([](asmjit::X86Assembler& c, auto& args)
|
||||
const auto ppu_gateway = built_function<void(*)(ppu_thread*)>("ppu_gateway", [](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
// Gateway for PPU, converts from native to GHC calling convention, also saves RSP value for escape
|
||||
using namespace asmjit;
|
||||
@@ -250,7 +248,7 @@ const auto ppu_gateway = build_function_asm<void(*)(ppu_thread*)>([](asmjit::X86
|
||||
c.ret();
|
||||
});
|
||||
|
||||
const extern auto ppu_escape = build_function_asm<void(*)(ppu_thread*)>([](asmjit::X86Assembler& c, auto& args)
|
||||
const extern auto ppu_escape = build_function_asm<void(*)(ppu_thread*)>("ppu_escape", [](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -258,12 +256,13 @@ const extern auto ppu_escape = build_function_asm<void(*)(ppu_thread*)>([](asmji
|
||||
c.mov(x86::rsp, x86::qword_ptr(args[0], ::offset32(&ppu_thread::saved_native_sp)));
|
||||
|
||||
// Return to the return location
|
||||
c.jmp(x86::qword_ptr(x86::rsp, -8));
|
||||
c.sub(x86::rsp, 8);
|
||||
c.ret();
|
||||
});
|
||||
|
||||
void ppu_recompiler_fallback(ppu_thread& ppu);
|
||||
|
||||
const auto ppu_recompiler_fallback_ghc = build_function_asm<void(*)(ppu_thread& ppu)>([](asmjit::X86Assembler& c, auto& args)
|
||||
const auto ppu_recompiler_fallback_ghc = build_function_asm<void(*)(ppu_thread& ppu)>("ppu_trampolineb", [](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -551,7 +550,7 @@ struct ppu_far_jumps_t
|
||||
auto& opd = vm::_ref<ppu_func_opd_t>(target);
|
||||
target = opd.addr;
|
||||
|
||||
// We modify LR to custom values here
|
||||
// We modify LR to custom values here
|
||||
link = false;
|
||||
|
||||
if (ppu)
|
||||
@@ -566,7 +565,7 @@ struct ppu_far_jumps_t
|
||||
saved_info.saved_lr = std::exchange(ppu->lr, FIND_FUNC(ppu_return_from_far_jump));
|
||||
saved_info.saved_r2 = std::exchange(ppu->gpr[2], opd.rtoc);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (link && ppu)
|
||||
@@ -973,11 +972,43 @@ std::string ppu_thread::dump_regs() const
|
||||
fmt::append(ret, "XER: [CA=%u | OV=%u | SO=%u | CNT=%u]\n", xer.ca, xer.ov, xer.so, xer.cnt);
|
||||
fmt::append(ret, "VSCR: [SAT=%u | NJ=%u]\n", sat, nj);
|
||||
fmt::append(ret, "FPSCR: [FL=%u | FG=%u | FE=%u | FU=%u]\n", fpscr.fl, fpscr.fg, fpscr.fe, fpscr.fu);
|
||||
if (const u32 addr = raddr)
|
||||
|
||||
const u32 addr = raddr;
|
||||
|
||||
if (addr)
|
||||
fmt::append(ret, "Reservation Addr: 0x%x", addr);
|
||||
else
|
||||
fmt::append(ret, "Reservation Addr: none");
|
||||
|
||||
fmt::append(ret, "Reservation Data (entire cache line):\n");
|
||||
|
||||
be_t<u32> data[32]{};
|
||||
std::memcpy(data, rdata, sizeof(rdata)); // Show the data even if the reservation was lost inside the atomic loop
|
||||
|
||||
if (addr && !use_full_rdata)
|
||||
{
|
||||
const u32 offset = addr & 0x78;
|
||||
|
||||
fmt::append(ret, "[0x%02x] %08x %08x\n", offset, data[offset / sizeof(u32)], data[offset / sizeof(u32) + 1]);
|
||||
|
||||
// Asterisk marks the offset of data that had been given to the guest PPU code
|
||||
*(&ret.back() - (addr & 4 ? 9 : 18)) = '*';
|
||||
}
|
||||
else
|
||||
{
|
||||
for (usz i = 0; i < std::size(data); i += 4)
|
||||
{
|
||||
fmt::append(ret, "[0x%02x] %08x %08x %08x %08x\n", i * sizeof(data[0])
|
||||
, data[i + 0], data[i + 1], data[i + 2], data[i + 3]);
|
||||
}
|
||||
|
||||
if (addr)
|
||||
{
|
||||
// See the note above
|
||||
*(&ret.back() - (4 - (addr % 16 / 4)) * 9 - (8 - (addr % 128 / 16)) * std::size("[0x00]"sv)) = '*';
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1609,21 +1640,6 @@ void ppu_thread::stack_pop_verbose(u32 addr, u32 size) noexcept
|
||||
|
||||
extern ppu_function_t ppu_get_syscall(u64 code);
|
||||
|
||||
extern __m128 sse_exp2_ps(__m128 A);
|
||||
extern __m128 sse_log2_ps(__m128 A);
|
||||
extern __m128i sse_altivec_vperm(__m128i A, __m128i B, __m128i C);
|
||||
extern __m128i sse_altivec_vperm_v0(__m128i A, __m128i B, __m128i C);
|
||||
extern __m128i sse_altivec_lvsl(u64 addr);
|
||||
extern __m128i sse_altivec_lvsr(u64 addr);
|
||||
extern __m128i sse_cellbe_lvlx(u64 addr);
|
||||
extern __m128i sse_cellbe_lvrx(u64 addr);
|
||||
extern void sse_cellbe_stvlx(u64 addr, __m128i a);
|
||||
extern void sse_cellbe_stvrx(u64 addr, __m128i a);
|
||||
extern __m128i sse_cellbe_lvlx_v0(u64 addr);
|
||||
extern __m128i sse_cellbe_lvrx_v0(u64 addr);
|
||||
extern void sse_cellbe_stvlx_v0(u64 addr, __m128i a);
|
||||
extern void sse_cellbe_stvrx_v0(u64 addr, __m128i a);
|
||||
|
||||
void ppu_trap(ppu_thread& ppu, u64 addr)
|
||||
{
|
||||
ensure((addr & (~u64{0xffff'ffff} | 0x3)) == 0);
|
||||
@@ -1801,15 +1817,13 @@ extern u64 ppu_ldarx(ppu_thread& ppu, u32 addr)
|
||||
return ppu_load_acquire_reservation<u64>(ppu, addr);
|
||||
}
|
||||
|
||||
const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime, const void* _old, u64 _new)>([](asmjit::X86Assembler& c, auto& args)
|
||||
const auto ppu_stcx_accurate_tx = built_function<u64(*)(u32 raddr, u64 rtime, const void* _old, u64 _new)>("ppu_stcx_accurate_tx", [](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
Label fall = c.newLabel();
|
||||
Label fail = c.newLabel();
|
||||
Label _ret = c.newLabel();
|
||||
Label skip = c.newLabel();
|
||||
Label next = c.newLabel();
|
||||
Label load = c.newLabel();
|
||||
|
||||
//if (utils::has_avx() && !s_tsx_avx)
|
||||
@@ -1819,11 +1833,7 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
|
||||
|
||||
// Create stack frame if necessary (Windows ABI has only 6 volatile vector registers)
|
||||
c.push(x86::rbp);
|
||||
c.push(x86::r13);
|
||||
c.push(x86::r12);
|
||||
c.push(x86::rbx);
|
||||
c.push(x86::r14);
|
||||
c.push(x86::r15);
|
||||
c.sub(x86::rsp, 40);
|
||||
#ifdef _WIN32
|
||||
if (!s_tsx_avx)
|
||||
@@ -1834,7 +1844,7 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
|
||||
#endif
|
||||
|
||||
// Prepare registers
|
||||
build_swap_rdx_with(c, args, x86::r12);
|
||||
build_swap_rdx_with(c, args, x86::r10);
|
||||
c.mov(x86::rbp, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
|
||||
c.lea(x86::rbp, x86::qword_ptr(x86::rbp, args[0]));
|
||||
c.and_(x86::rbp, -128);
|
||||
@@ -1842,19 +1852,17 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
|
||||
c.prefetchw(x86::byte_ptr(x86::rbp, 64));
|
||||
c.movzx(args[0].r32(), args[0].r16());
|
||||
c.shr(args[0].r32(), 1);
|
||||
c.lea(x86::rbx, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
|
||||
c.and_(x86::rbx, -128 / 2);
|
||||
c.prefetchw(x86::byte_ptr(x86::rbx));
|
||||
c.lea(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
|
||||
c.and_(x86::r11, -128 / 2);
|
||||
c.and_(args[0].r32(), 63);
|
||||
c.mov(x86::r13, args[1]);
|
||||
|
||||
// Prepare data
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vmovups(x86::ymm0, x86::yword_ptr(args[2], 0));
|
||||
c.vmovups(x86::ymm1, x86::yword_ptr(args[2], 32));
|
||||
c.vmovups(x86::ymm2, x86::yword_ptr(args[2], 64));
|
||||
c.vmovups(x86::ymm3, x86::yword_ptr(args[2], 96));
|
||||
c.vmovups(x86::ymm0, x86::ymmword_ptr(args[2], 0));
|
||||
c.vmovups(x86::ymm1, x86::ymmword_ptr(args[2], 32));
|
||||
c.vmovups(x86::ymm2, x86::ymmword_ptr(args[2], 64));
|
||||
c.vmovups(x86::ymm3, x86::ymmword_ptr(args[2], 96));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1870,34 +1878,29 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
|
||||
|
||||
// Alloc r14 to stamp0
|
||||
const auto stamp0 = x86::r14;
|
||||
const auto stamp1 = x86::r15;
|
||||
build_get_tsc(c, stamp0);
|
||||
|
||||
// Begin transaction
|
||||
Label tx0 = build_transaction_enter(c, fall, [&]()
|
||||
Label fail2 = c.newLabel();
|
||||
|
||||
Label tx1 = build_transaction_enter(c, fall, [&]()
|
||||
{
|
||||
build_get_tsc(c, stamp1);
|
||||
c.sub(stamp1, stamp0);
|
||||
c.xor_(x86::eax, x86::eax);
|
||||
c.cmp(stamp1, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit1)));
|
||||
build_get_tsc(c);
|
||||
c.sub(x86::rax, stamp0);
|
||||
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
|
||||
c.jae(fall);
|
||||
});
|
||||
|
||||
// Check pause flag
|
||||
c.bt(x86::dword_ptr(args[2], ::offset32(&ppu_thread::state) - ::offset32(&ppu_thread::rdata)), static_cast<u32>(cpu_flag::pause));
|
||||
c.jc(fall);
|
||||
c.xbegin(tx0);
|
||||
c.mov(x86::rax, x86::qword_ptr(x86::rbx));
|
||||
c.test(x86::eax, vm::rsrv_unique_lock);
|
||||
c.jnz(skip);
|
||||
c.and_(x86::rax, -128);
|
||||
c.cmp(x86::rax, x86::r13);
|
||||
c.jne(fail);
|
||||
c.xbegin(tx1);
|
||||
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vxorps(x86::ymm0, x86::ymm0, x86::yword_ptr(x86::rbp, 0));
|
||||
c.vxorps(x86::ymm1, x86::ymm1, x86::yword_ptr(x86::rbp, 32));
|
||||
c.vxorps(x86::ymm2, x86::ymm2, x86::yword_ptr(x86::rbp, 64));
|
||||
c.vxorps(x86::ymm3, x86::ymm3, x86::yword_ptr(x86::rbp, 96));
|
||||
c.vxorps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(x86::rbp, 0));
|
||||
c.vxorps(x86::ymm1, x86::ymm1, x86::ymmword_ptr(x86::rbp, 32));
|
||||
c.vxorps(x86::ymm2, x86::ymm2, x86::ymmword_ptr(x86::rbp, 64));
|
||||
c.vxorps(x86::ymm3, x86::ymm3, x86::ymmword_ptr(x86::rbp, 96));
|
||||
c.vorps(x86::ymm0, x86::ymm0, x86::ymm1);
|
||||
c.vorps(x86::ymm1, x86::ymm2, x86::ymm3);
|
||||
c.vorps(x86::ymm0, x86::ymm1, x86::ymm0);
|
||||
@@ -1928,145 +1931,22 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
|
||||
// Store 8 bytes
|
||||
c.mov(x86::qword_ptr(x86::rbp, args[0], 1, 0), args[3]);
|
||||
|
||||
// Update reservation
|
||||
c.sub(x86::qword_ptr(x86::rbx), -128);
|
||||
c.xend();
|
||||
build_get_tsc(c);
|
||||
c.sub(x86::rax, stamp0);
|
||||
c.jmp(_ret);
|
||||
|
||||
// XABORT is expensive so finish with xend instead
|
||||
c.bind(fail);
|
||||
|
||||
// Load old data to store back in rdata
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vmovaps(x86::ymm0, x86::yword_ptr(x86::rbp, 0));
|
||||
c.vmovaps(x86::ymm1, x86::yword_ptr(x86::rbp, 32));
|
||||
c.vmovaps(x86::ymm2, x86::yword_ptr(x86::rbp, 64));
|
||||
c.vmovaps(x86::ymm3, x86::yword_ptr(x86::rbp, 96));
|
||||
}
|
||||
else
|
||||
{
|
||||
c.movaps(x86::xmm0, x86::oword_ptr(x86::rbp, 0));
|
||||
c.movaps(x86::xmm1, x86::oword_ptr(x86::rbp, 16));
|
||||
c.movaps(x86::xmm2, x86::oword_ptr(x86::rbp, 32));
|
||||
c.movaps(x86::xmm3, x86::oword_ptr(x86::rbp, 48));
|
||||
c.movaps(x86::xmm4, x86::oword_ptr(x86::rbp, 64));
|
||||
c.movaps(x86::xmm5, x86::oword_ptr(x86::rbp, 80));
|
||||
c.movaps(x86::xmm6, x86::oword_ptr(x86::rbp, 96));
|
||||
c.movaps(x86::xmm7, x86::oword_ptr(x86::rbp, 112));
|
||||
}
|
||||
|
||||
c.xend();
|
||||
c.jmp(load);
|
||||
|
||||
c.bind(skip);
|
||||
c.xend();
|
||||
build_get_tsc(c, stamp1);
|
||||
//c.jmp(fall);
|
||||
|
||||
c.bind(fall);
|
||||
|
||||
Label fall2 = c.newLabel();
|
||||
Label fail2 = c.newLabel();
|
||||
Label fail3 = c.newLabel();
|
||||
|
||||
// Lightened transaction: only compare and swap data
|
||||
c.bind(next);
|
||||
|
||||
// Try to "lock" reservation
|
||||
c.mov(x86::eax, 1);
|
||||
c.lock().xadd(x86::qword_ptr(x86::rbx), x86::rax);
|
||||
c.test(x86::eax, vm::rsrv_unique_lock);
|
||||
c.jnz(fail2);
|
||||
|
||||
// Check if already updated
|
||||
c.and_(x86::rax, -128);
|
||||
c.cmp(x86::rax, x86::r13);
|
||||
c.jne(fail2);
|
||||
|
||||
// Exclude some time spent on touching memory: stamp1 contains last success or failure
|
||||
c.mov(x86::rax, stamp1);
|
||||
c.sub(x86::rax, stamp0);
|
||||
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
|
||||
c.jae(fall2);
|
||||
build_get_tsc(c, stamp1);
|
||||
c.sub(stamp1, x86::rax);
|
||||
|
||||
Label tx1 = build_transaction_enter(c, fall2, [&]()
|
||||
{
|
||||
build_get_tsc(c);
|
||||
c.sub(x86::rax, stamp1);
|
||||
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
|
||||
c.jae(fall2);
|
||||
c.test(x86::qword_ptr(x86::rbx), 127 - 1);
|
||||
c.jnz(fall2);
|
||||
});
|
||||
c.prefetchw(x86::byte_ptr(x86::rbp, 0));
|
||||
c.prefetchw(x86::byte_ptr(x86::rbp, 64));
|
||||
|
||||
// Check pause flag
|
||||
c.bt(x86::dword_ptr(args[2], ::offset32(&ppu_thread::state) - ::offset32(&ppu_thread::rdata)), static_cast<u32>(cpu_flag::pause));
|
||||
c.jc(fall2);
|
||||
c.mov(x86::rax, x86::qword_ptr(x86::rbx));
|
||||
c.and_(x86::rax, -128);
|
||||
c.cmp(x86::rax, x86::r13);
|
||||
c.jne(fail2);
|
||||
c.xbegin(tx1);
|
||||
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vxorps(x86::ymm0, x86::ymm0, x86::yword_ptr(x86::rbp, 0));
|
||||
c.vxorps(x86::ymm1, x86::ymm1, x86::yword_ptr(x86::rbp, 32));
|
||||
c.vxorps(x86::ymm2, x86::ymm2, x86::yword_ptr(x86::rbp, 64));
|
||||
c.vxorps(x86::ymm3, x86::ymm3, x86::yword_ptr(x86::rbp, 96));
|
||||
c.vorps(x86::ymm0, x86::ymm0, x86::ymm1);
|
||||
c.vorps(x86::ymm1, x86::ymm2, x86::ymm3);
|
||||
c.vorps(x86::ymm0, x86::ymm1, x86::ymm0);
|
||||
c.vptest(x86::ymm0, x86::ymm0);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.xorps(x86::xmm0, x86::oword_ptr(x86::rbp, 0));
|
||||
c.xorps(x86::xmm1, x86::oword_ptr(x86::rbp, 16));
|
||||
c.xorps(x86::xmm2, x86::oword_ptr(x86::rbp, 32));
|
||||
c.xorps(x86::xmm3, x86::oword_ptr(x86::rbp, 48));
|
||||
c.xorps(x86::xmm4, x86::oword_ptr(x86::rbp, 64));
|
||||
c.xorps(x86::xmm5, x86::oword_ptr(x86::rbp, 80));
|
||||
c.xorps(x86::xmm6, x86::oword_ptr(x86::rbp, 96));
|
||||
c.xorps(x86::xmm7, x86::oword_ptr(x86::rbp, 112));
|
||||
c.orps(x86::xmm0, x86::xmm1);
|
||||
c.orps(x86::xmm2, x86::xmm3);
|
||||
c.orps(x86::xmm4, x86::xmm5);
|
||||
c.orps(x86::xmm6, x86::xmm7);
|
||||
c.orps(x86::xmm0, x86::xmm2);
|
||||
c.orps(x86::xmm4, x86::xmm6);
|
||||
c.orps(x86::xmm0, x86::xmm4);
|
||||
c.ptest(x86::xmm0, x86::xmm0);
|
||||
}
|
||||
|
||||
c.jnz(fail3);
|
||||
|
||||
// Store 8 bytes
|
||||
c.mov(x86::qword_ptr(x86::rbp, args[0], 1, 0), args[3]);
|
||||
|
||||
c.xend();
|
||||
c.lock().add(x86::qword_ptr(x86::rbx), 127);
|
||||
c.lock().add(x86::qword_ptr(x86::r11), 64);
|
||||
build_get_tsc(c);
|
||||
c.sub(x86::rax, stamp0);
|
||||
c.jmp(_ret);
|
||||
|
||||
// XABORT is expensive so try to finish with xend instead
|
||||
c.bind(fail3);
|
||||
c.bind(fail);
|
||||
|
||||
// Load old data to store back in rdata
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vmovaps(x86::ymm0, x86::yword_ptr(x86::rbp, 0));
|
||||
c.vmovaps(x86::ymm1, x86::yword_ptr(x86::rbp, 32));
|
||||
c.vmovaps(x86::ymm2, x86::yword_ptr(x86::rbp, 64));
|
||||
c.vmovaps(x86::ymm3, x86::yword_ptr(x86::rbp, 96));
|
||||
c.vmovaps(x86::ymm0, x86::ymmword_ptr(x86::rbp, 0));
|
||||
c.vmovaps(x86::ymm1, x86::ymmword_ptr(x86::rbp, 32));
|
||||
c.vmovaps(x86::ymm2, x86::ymmword_ptr(x86::rbp, 64));
|
||||
c.vmovaps(x86::ymm3, x86::ymmword_ptr(x86::rbp, 96));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2083,21 +1963,21 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
|
||||
c.xend();
|
||||
c.jmp(fail2);
|
||||
|
||||
c.bind(fall2);
|
||||
c.bind(fall);
|
||||
c.mov(x86::rax, -1);
|
||||
c.jmp(_ret);
|
||||
|
||||
c.bind(fail2);
|
||||
c.lock().sub(x86::qword_ptr(x86::rbx), 1);
|
||||
c.lock().sub(x86::qword_ptr(x86::r11), 64);
|
||||
c.bind(load);
|
||||
|
||||
// Store previous data back to rdata
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vmovaps(x86::yword_ptr(args[2], 0), x86::ymm0);
|
||||
c.vmovaps(x86::yword_ptr(args[2], 32), x86::ymm1);
|
||||
c.vmovaps(x86::yword_ptr(args[2], 64), x86::ymm2);
|
||||
c.vmovaps(x86::yword_ptr(args[2], 96), x86::ymm3);
|
||||
c.vmovaps(x86::ymmword_ptr(args[2], 0), x86::ymm0);
|
||||
c.vmovaps(x86::ymmword_ptr(args[2], 32), x86::ymm1);
|
||||
c.vmovaps(x86::ymmword_ptr(args[2], 64), x86::ymm2);
|
||||
c.vmovaps(x86::ymmword_ptr(args[2], 96), x86::ymm3);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2132,12 +2012,17 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
|
||||
}
|
||||
|
||||
c.add(x86::rsp, 40);
|
||||
c.pop(x86::r15);
|
||||
c.pop(x86::r14);
|
||||
c.pop(x86::rbx);
|
||||
c.pop(x86::r12);
|
||||
c.pop(x86::r13);
|
||||
c.pop(x86::rbp);
|
||||
|
||||
#ifdef __linux__
|
||||
// Hack for perf profiling (TODO)
|
||||
Label ret2 = c.newLabel();
|
||||
c.lea(x86::rdx, x86::qword_ptr(ret2));
|
||||
c.push(x86::rdx);
|
||||
c.push(x86::rdx);
|
||||
c.bind(ret2);
|
||||
#endif
|
||||
c.ret();
|
||||
});
|
||||
|
||||
@@ -2197,6 +2082,23 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
{
|
||||
if (ppu.use_full_rdata) [[unlikely]]
|
||||
{
|
||||
auto [_oldd, _ok] = res.fetch_op([&](u64& r)
|
||||
{
|
||||
if ((r & -128) != rtime || (r & 127))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
r += vm::rsrv_unique_lock;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!_ok)
|
||||
{
|
||||
// Already locked or updated: give up
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_use_rtm) [[likely]]
|
||||
{
|
||||
switch (u64 count = ppu_stcx_accurate_tx(addr & -8, rtime, ppu.rdata, std::bit_cast<u64>(new_data)))
|
||||
@@ -2211,12 +2113,12 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
if ((res & -128) == rtime && cmp_rdata(ppu.rdata, all_data))
|
||||
{
|
||||
sdata.release(new_data);
|
||||
res += 127;
|
||||
res += 64;
|
||||
return true;
|
||||
}
|
||||
|
||||
mov_rdata_nt(ppu.rdata, all_data);
|
||||
res -= 1;
|
||||
res -= 64;
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -2268,23 +2170,6 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
return true;
|
||||
}
|
||||
|
||||
auto [_oldd, _ok] = res.fetch_op([&](u64& r)
|
||||
{
|
||||
if ((r & -128) != rtime || (r & 127))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
r += vm::rsrv_unique_lock;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!_ok)
|
||||
{
|
||||
// Already locked or updated: give up
|
||||
return false;
|
||||
}
|
||||
|
||||
// Align address: we do not need the lower 7 bits anymore
|
||||
addr &= -128;
|
||||
|
||||
@@ -2324,7 +2209,7 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
// Aligned 8-byte reservations will be used here
|
||||
addr &= -8;
|
||||
|
||||
const u64 lock_bits = g_cfg.core.spu_accurate_dma ? vm::rsrv_unique_lock : 1;
|
||||
const u64 lock_bits = vm::rsrv_unique_lock;
|
||||
|
||||
auto [_oldd, _ok] = res.fetch_op([&](u64& r)
|
||||
{
|
||||
@@ -2333,7 +2218,6 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Despite using shared lock, doesn't allow other shared locks (TODO)
|
||||
r += lock_bits;
|
||||
return true;
|
||||
});
|
||||
@@ -2967,14 +2851,6 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
{ "__ldarx", reinterpret_cast<u64>(ppu_ldarx) },
|
||||
{ "__stwcx", reinterpret_cast<u64>(ppu_stwcx) },
|
||||
{ "__stdcx", reinterpret_cast<u64>(ppu_stdcx) },
|
||||
{ "__vexptefp", reinterpret_cast<u64>(sse_exp2_ps) },
|
||||
{ "__vlogefp", reinterpret_cast<u64>(sse_log2_ps) },
|
||||
{ "__lvsl", reinterpret_cast<u64>(sse_altivec_lvsl) },
|
||||
{ "__lvsr", reinterpret_cast<u64>(sse_altivec_lvsr) },
|
||||
{ "__lvlx", s_use_ssse3 ? reinterpret_cast<u64>(sse_cellbe_lvlx) : reinterpret_cast<u64>(sse_cellbe_lvlx_v0) },
|
||||
{ "__lvrx", s_use_ssse3 ? reinterpret_cast<u64>(sse_cellbe_lvrx) : reinterpret_cast<u64>(sse_cellbe_lvrx_v0) },
|
||||
{ "__stvlx", s_use_ssse3 ? reinterpret_cast<u64>(sse_cellbe_stvlx) : reinterpret_cast<u64>(sse_cellbe_stvlx_v0) },
|
||||
{ "__stvrx", s_use_ssse3 ? reinterpret_cast<u64>(sse_cellbe_stvrx) : reinterpret_cast<u64>(sse_cellbe_stvrx_v0) },
|
||||
{ "__dcbz", reinterpret_cast<u64>(+[](u32 addr){ alignas(64) static constexpr u8 z[128]{}; do_cell_atomic_128_store(addr, z); }) },
|
||||
{ "__resupdate", reinterpret_cast<u64>(vm::reservation_update) },
|
||||
{ "__resinterp", reinterpret_cast<u64>(ppu_reservation_fallback) },
|
||||
@@ -3067,6 +2943,44 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
|
||||
bool compiled_new = false;
|
||||
|
||||
bool has_mfvscr = false;
|
||||
|
||||
for (auto& func : info.funcs)
|
||||
{
|
||||
if (func.size == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& [addr, size] : func.blocks)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (u32 i = addr; i < addr + size; i += 4)
|
||||
{
|
||||
if (g_ppu_itype.decode(vm::read32(i)) == ppu_itype::MFVSCR)
|
||||
{
|
||||
ppu_log.warning("MFVSCR found");
|
||||
has_mfvscr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_mfvscr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_mfvscr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (!jit_mod.init && fpos < info.funcs.size())
|
||||
{
|
||||
// Initialize compiler instance
|
||||
@@ -3108,6 +3022,12 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
// Fixup some information
|
||||
entry.name = fmt::format("__0x%x", entry.addr - reloc);
|
||||
|
||||
if (has_mfvscr)
|
||||
{
|
||||
// TODO
|
||||
entry.attr += ppu_attr::has_mfvscr;
|
||||
}
|
||||
|
||||
if (entry.blocks.empty())
|
||||
{
|
||||
entry.blocks.emplace(func.addr, func.size);
|
||||
@@ -3225,6 +3145,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
accurate_cache_line_stores,
|
||||
reservations_128_byte,
|
||||
greedy_mode,
|
||||
has_mfvscr,
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
@@ -3246,9 +3167,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
settings += ppu_settings::reservations_128_byte;
|
||||
if (g_cfg.core.ppu_llvm_greedy_mode)
|
||||
settings += ppu_settings::greedy_mode;
|
||||
if (has_mfvscr)
|
||||
settings += ppu_settings::has_mfvscr;
|
||||
|
||||
// Write version, hash, CPU, settings
|
||||
fmt::append(obj_name, "v4-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
|
||||
fmt::append(obj_name, "v5-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
|
||||
@@ -222,27 +222,6 @@ public:
|
||||
}
|
||||
xer;
|
||||
|
||||
/*
|
||||
Saturation. A sticky status bit indicating that some field in a saturating instruction saturated since the last
|
||||
time SAT was cleared. In other words when SAT = '1' it remains set to '1' until it is cleared to '0' by an
|
||||
mtvscr instruction.
|
||||
1 The vector saturate instruction implicitly sets when saturation has occurred on the results one of
|
||||
the vector instructions having saturate in its name:
|
||||
Move To VSCR (mtvscr)
|
||||
Vector Add Integer with Saturation (vaddubs, vadduhs, vadduws, vaddsbs, vaddshs,
|
||||
vaddsws)
|
||||
Vector Subtract Integer with Saturation (vsububs, vsubuhs, vsubuws, vsubsbs, vsubshs,
|
||||
vsubsws)
|
||||
Vector Multiply-Add Integer with Saturation (vmhaddshs, vmhraddshs)
|
||||
Vector Multiply-Sum with Saturation (vmsumuhs, vmsumshs, vsumsws)
|
||||
Vector Sum-Across with Saturation (vsumsws, vsum2sws, vsum4sbs, vsum4shs,
|
||||
vsum4ubs)
|
||||
Vector Pack with Saturation (vpkuhus, vpkuwus, vpkshus, vpkswus, vpkshss, vpkswss)
|
||||
Vector Convert to Fixed-Point with Saturation (vctuxs, vctsxs)
|
||||
0 Indicates no saturation occurred; mtvscr can explicitly clear this bit.
|
||||
*/
|
||||
bool sat{};
|
||||
|
||||
/*
|
||||
Non-Java. A mode control bit that determines whether vector floating-point operations will be performed
|
||||
in a Java-IEEE-C9X-compliant mode or a possibly faster non-Java/non-IEEE mode.
|
||||
@@ -255,6 +234,9 @@ public:
|
||||
*/
|
||||
bool nj = true;
|
||||
|
||||
// Sticky saturation bit
|
||||
v128 sat{};
|
||||
|
||||
// Optimization: precomputed java-mode mask for handling denormals
|
||||
u32 jm_mask = 0x7f80'0000;
|
||||
|
||||
|
||||
+466
-526
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,9 @@ class PPUTranslator final : public cpu_translator
|
||||
// Current position-independent address
|
||||
u64 m_addr = 0;
|
||||
|
||||
// Function attributes
|
||||
bs_t<ppu_attr> m_attr{};
|
||||
|
||||
// Relocation info
|
||||
const ppu_segment* m_reloc = nullptr;
|
||||
|
||||
@@ -76,8 +79,8 @@ class PPUTranslator final : public cpu_translator
|
||||
DEF_VALUE(m_ov, m_g_ov, 168) // XER.OV bit, overflow flag
|
||||
DEF_VALUE(m_ca, m_g_ca, 169) // XER.CA bit, carry flag
|
||||
DEF_VALUE(m_cnt, m_g_cnt, 170) // XER.CNT
|
||||
DEF_VALUE(m_sat, m_g_sat, 171) // VSCR.SAT bit, sticky saturation flag
|
||||
DEF_VALUE(m_nj, m_g_nj, 172) // VSCR.NJ bit, non-Java mode
|
||||
DEF_VALUE(m_nj, m_g_nj, 171) // VSCR.NJ bit, non-Java mode
|
||||
DEF_VALUE(m_sat, m_g_sat, 173) // VSCR.SAT bit, sticky saturation flag
|
||||
DEF_VALUE(m_jm_mask, m_g_jm_mask, 174) // Java-Mode helper mask
|
||||
|
||||
#undef DEF_VALUE
|
||||
@@ -87,7 +90,7 @@ public:
|
||||
value_t<T> get_vr(u32 vr)
|
||||
{
|
||||
value_t<T> result;
|
||||
result.value = m_ir->CreateBitCast(GetVr(vr, VrType::vi32), value_t<T>::get_type(m_context));
|
||||
result.value = bitcast(GetVr(vr, VrType::vi32), value_t<T>::get_type(m_context));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -115,6 +118,17 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
// Update sticky VSCR.SAT bit (|=)
|
||||
template <typename T>
|
||||
void set_sat(T&& expr)
|
||||
{
|
||||
if (m_attr & ppu_attr::has_mfvscr)
|
||||
{
|
||||
const auto val = expr.eval(m_ir);
|
||||
RegStore(m_ir->CreateOr(bitcast(RegLoad(m_sat), val->getType()), val), m_sat);
|
||||
}
|
||||
}
|
||||
|
||||
// Get current instruction address
|
||||
llvm::Value* GetAddr(u64 _add = 0);
|
||||
|
||||
@@ -170,14 +184,6 @@ public:
|
||||
// Load vr
|
||||
llvm::Value* GetVr(u32 vr, VrType);
|
||||
|
||||
// Load VRs
|
||||
template<typename... Vrs>
|
||||
std::array<llvm::Value*, sizeof...(Vrs)> GetVrs(VrType type, Vrs... regs)
|
||||
{
|
||||
static_assert(sizeof...(Vrs), "Empty VR list");
|
||||
return{ GetVr(regs, type)... };
|
||||
}
|
||||
|
||||
// Set vr to the specified value
|
||||
void SetVr(u32 vr, llvm::Value*);
|
||||
|
||||
@@ -193,15 +199,6 @@ public:
|
||||
// Broadcast specified value
|
||||
llvm::Value* Broadcast(llvm::Value* value, u32 count);
|
||||
|
||||
// Saturate scalar or vector given the comparison operand and the extreme value to compare with (second result is the comparison result)
|
||||
std::pair<llvm::Value*, llvm::Value*> Saturate(llvm::Value* value, llvm::CmpInst::Predicate inst, llvm::Value* extreme);
|
||||
|
||||
// Saturate signed value (second result is the disjunction of comparison results)
|
||||
std::pair<llvm::Value*, llvm::Value*> SaturateSigned(llvm::Value* value, u64 min, u64 max);
|
||||
|
||||
// Multiply FP value or vector by the pow(2, scale)
|
||||
llvm::Value* Scale(llvm::Value* value, s32 scale);
|
||||
|
||||
// Create shuffle instruction with constant args
|
||||
llvm::Value* Shuffle(llvm::Value* left, llvm::Value* right, std::initializer_list<u32> indices);
|
||||
|
||||
@@ -279,9 +276,6 @@ public:
|
||||
// Set XER.OV bit, and update XER.SO bit (|=)
|
||||
void SetOverflow(llvm::Value*);
|
||||
|
||||
// Update sticky VSCR.SAT bit (|=)
|
||||
void SetSat(llvm::Value*);
|
||||
|
||||
// Check condition for trap instructions
|
||||
llvm::Value* CheckTrapCondition(u32 to, llvm::Value* left, llvm::Value* right);
|
||||
|
||||
|
||||
@@ -96,15 +96,15 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
using namespace asmjit;
|
||||
|
||||
StringLogger logger;
|
||||
logger.addOptions(Logger::kOptionBinaryForm);
|
||||
logger.addFlags(FormatFlags::kMachineCode);
|
||||
|
||||
std::string log;
|
||||
|
||||
CodeHolder code;
|
||||
code.init(m_asmrt.getCodeInfo());
|
||||
code._globalHints = asmjit::CodeEmitter::kHintOptimizedAlign;
|
||||
code.init(m_asmrt.environment());
|
||||
|
||||
X86Assembler compiler(&code);
|
||||
x86::Assembler compiler(&code);
|
||||
compiler.addEncodingOptions(EncodingOptions::kOptimizedAlign);
|
||||
this->c = &compiler;
|
||||
|
||||
if (g_cfg.core.spu_debug && !add_loc->logged.exchange(1))
|
||||
@@ -137,7 +137,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
this->qw1 = &x86::rcx;
|
||||
#endif
|
||||
|
||||
const std::array<const X86Xmm*, 16> vec_vars
|
||||
const std::array<const x86::Xmm*, 16> vec_vars
|
||||
{
|
||||
&x86::xmm0,
|
||||
&x86::xmm1,
|
||||
@@ -281,9 +281,9 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
c->vzeroupper();
|
||||
}
|
||||
}
|
||||
else if (utils::has_avx512() && g_cfg.core.full_width_avx512)
|
||||
else if (utils::has_avx512() && false)
|
||||
{
|
||||
// AVX-512 optimized check using 512-bit registers
|
||||
// AVX-512 optimized check using 512-bit registers (disabled)
|
||||
words_align = 64;
|
||||
|
||||
const u32 starta = start & -64;
|
||||
@@ -333,20 +333,20 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
});
|
||||
|
||||
c->setExtraReg(x86::k7);
|
||||
c->z().vmovdqa32(x86::zmm0, x86::zword_ptr(*qw1, j - ls_off));
|
||||
c->z().vmovdqa32(x86::zmm0, x86::zmmword_ptr(*qw1, j - ls_off));
|
||||
}
|
||||
else
|
||||
{
|
||||
c->vmovdqa32(x86::zmm0, x86::zword_ptr(*qw1, j - ls_off));
|
||||
c->vmovdqa32(x86::zmm0, x86::zmmword_ptr(*qw1, j - ls_off));
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
c->vpcmpud(x86::k1, x86::zmm0, x86::zword_ptr(x86::rax, code_off), 4);
|
||||
c->vpcmpud(x86::k1, x86::zmm0, x86::zmmword_ptr(x86::rax, code_off), 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
c->vpcmpud(x86::k3, x86::zmm0, x86::zword_ptr(x86::rax, code_off), 4);
|
||||
c->vpcmpud(x86::k3, x86::zmm0, x86::zmmword_ptr(x86::rax, code_off), 4);
|
||||
c->korw(x86::k1, x86::k3, x86::k1);
|
||||
}
|
||||
|
||||
@@ -378,15 +378,15 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
|
||||
if (cmask == 0xff)
|
||||
{
|
||||
c->vmovdqa(x86::ymm0, x86::yword_ptr(*ls, starta));
|
||||
c->vmovdqa(x86::ymm0, x86::ymmword_ptr(*ls, starta));
|
||||
}
|
||||
else
|
||||
{
|
||||
c->vpxor(x86::ymm0, x86::ymm0, x86::ymm0);
|
||||
c->vpblendd(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta), cmask);
|
||||
c->vpblendd(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta), cmask);
|
||||
}
|
||||
|
||||
c->vpxor(x86::ymm0, x86::ymm0, x86::yword_ptr(label_code));
|
||||
c->vpxor(x86::ymm0, x86::ymm0, x86::ymmword_ptr(label_code));
|
||||
c->vptest(x86::ymm0, x86::ymm0);
|
||||
c->jnz(label_diff);
|
||||
|
||||
@@ -401,9 +401,9 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
const u32 cmask1 = get_code_mask(starta + 32, enda);
|
||||
|
||||
c->vpxor(x86::ymm0, x86::ymm0, x86::ymm0);
|
||||
c->vpblendd(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta), cmask0);
|
||||
c->vpblendd(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta + 32), cmask1);
|
||||
c->vpxor(x86::ymm0, x86::ymm0, x86::yword_ptr(label_code));
|
||||
c->vpblendd(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta), cmask0);
|
||||
c->vpblendd(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta + 32), cmask1);
|
||||
c->vpxor(x86::ymm0, x86::ymm0, x86::ymmword_ptr(label_code));
|
||||
c->vptest(x86::ymm0, x86::ymm0);
|
||||
c->jnz(label_diff);
|
||||
|
||||
@@ -453,21 +453,21 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
xmm2z = true;
|
||||
}
|
||||
|
||||
c->vpblendd(x86::ymm1, x86::ymm2, x86::yword_ptr(*qw1, j - ls_off), cmask);
|
||||
c->vpblendd(x86::ymm1, x86::ymm2, x86::ymmword_ptr(*qw1, j - ls_off), cmask);
|
||||
}
|
||||
else
|
||||
{
|
||||
c->vmovdqa32(x86::ymm1, x86::yword_ptr(*qw1, j - ls_off));
|
||||
c->vmovdqa32(x86::ymm1, x86::ymmword_ptr(*qw1, j - ls_off));
|
||||
}
|
||||
|
||||
// Perform bitwise comparison and accumulate
|
||||
if (first)
|
||||
{
|
||||
c->vpxor(x86::ymm0, x86::ymm1, x86::yword_ptr(x86::rax, code_off));
|
||||
c->vpxor(x86::ymm0, x86::ymm1, x86::ymmword_ptr(x86::rax, code_off));
|
||||
}
|
||||
else
|
||||
{
|
||||
c->vpternlogd(x86::ymm0, x86::ymm1, x86::yword_ptr(x86::rax, code_off), 0xf6 /* orAxorBC */);
|
||||
c->vpternlogd(x86::ymm0, x86::ymm1, x86::ymmword_ptr(x86::rax, code_off), 0xf6 /* orAxorBC */);
|
||||
}
|
||||
|
||||
for (u32 i = j; i < j + 32; i += 4)
|
||||
@@ -500,15 +500,15 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
|
||||
if (cmask == 0xff)
|
||||
{
|
||||
c->vmovaps(x86::ymm0, x86::yword_ptr(*ls, starta));
|
||||
c->vmovaps(x86::ymm0, x86::ymmword_ptr(*ls, starta));
|
||||
}
|
||||
else
|
||||
{
|
||||
c->vxorps(x86::ymm0, x86::ymm0, x86::ymm0);
|
||||
c->vblendps(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta), cmask);
|
||||
c->vblendps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta), cmask);
|
||||
}
|
||||
|
||||
c->vxorps(x86::ymm0, x86::ymm0, x86::yword_ptr(label_code));
|
||||
c->vxorps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(label_code));
|
||||
c->vptest(x86::ymm0, x86::ymm0);
|
||||
c->jnz(label_diff);
|
||||
|
||||
@@ -523,9 +523,9 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
const u32 cmask1 = get_code_mask(starta + 32, enda);
|
||||
|
||||
c->vxorps(x86::ymm0, x86::ymm0, x86::ymm0);
|
||||
c->vblendps(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta), cmask0);
|
||||
c->vblendps(x86::ymm0, x86::ymm0, x86::yword_ptr(*ls, starta + 32), cmask1);
|
||||
c->vxorps(x86::ymm0, x86::ymm0, x86::yword_ptr(label_code));
|
||||
c->vblendps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta), cmask0);
|
||||
c->vblendps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(*ls, starta + 32), cmask1);
|
||||
c->vxorps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(label_code));
|
||||
c->vptest(x86::ymm0, x86::ymm0);
|
||||
c->jnz(label_diff);
|
||||
|
||||
@@ -586,21 +586,21 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
xmm2z = true;
|
||||
}
|
||||
|
||||
c->vblendps(reg1, x86::ymm2, x86::yword_ptr(*ls, j - ls_off), cmask);
|
||||
c->vblendps(reg1, x86::ymm2, x86::ymmword_ptr(*ls, j - ls_off), cmask);
|
||||
}
|
||||
else
|
||||
{
|
||||
c->vmovaps(reg1, x86::yword_ptr(*ls, j - ls_off));
|
||||
c->vmovaps(reg1, x86::ymmword_ptr(*ls, j - ls_off));
|
||||
}
|
||||
|
||||
// Perform bitwise comparison and accumulate
|
||||
if (!order++)
|
||||
{
|
||||
c->vxorps(reg0, reg1, x86::yword_ptr(x86::rax, code_off));
|
||||
c->vxorps(reg0, reg1, x86::ymmword_ptr(x86::rax, code_off));
|
||||
}
|
||||
else
|
||||
{
|
||||
c->vxorps(reg1, reg1, x86::yword_ptr(x86::rax, code_off));
|
||||
c->vxorps(reg1, reg1, x86::ymmword_ptr(x86::rax, code_off));
|
||||
c->vorps(reg0, reg1, reg0);
|
||||
}
|
||||
|
||||
@@ -800,7 +800,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
{
|
||||
if (m_preds.count(pos))
|
||||
{
|
||||
c->align(kAlignCode, 16);
|
||||
c->align(AlignMode::kCode, 16);
|
||||
}
|
||||
|
||||
c->bind(found->second);
|
||||
@@ -832,7 +832,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
}
|
||||
|
||||
// Simply return
|
||||
c->align(kAlignCode, 16);
|
||||
c->align(AlignMode::kCode, 16);
|
||||
c->bind(label_stop);
|
||||
c->add(x86::rsp, 0x28);
|
||||
c->ret();
|
||||
@@ -840,7 +840,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
if (g_cfg.core.spu_verification)
|
||||
{
|
||||
// Dispatch
|
||||
c->align(kAlignCode, 16);
|
||||
c->align(AlignMode::kCode, 16);
|
||||
c->bind(label_diff);
|
||||
c->inc(SPU_OFF_64(block_failure));
|
||||
c->add(x86::rsp, 0x28);
|
||||
@@ -855,7 +855,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
// Build instruction dispatch table
|
||||
if (instr_table.isValid())
|
||||
{
|
||||
c->align(kAlignData, 8);
|
||||
c->align(AlignMode::kData, 8);
|
||||
c->bind(instr_table);
|
||||
|
||||
// Get actual instruction table bounds
|
||||
@@ -877,7 +877,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
}
|
||||
}
|
||||
|
||||
c->align(kAlignData, words_align);
|
||||
c->align(AlignMode::kData, words_align);
|
||||
c->bind(label_code);
|
||||
for (u32 d : words)
|
||||
c->dd(d);
|
||||
@@ -893,17 +893,16 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
xmm_consts.clear();
|
||||
|
||||
// Compile and get function address
|
||||
spu_function_t fn;
|
||||
spu_function_t fn = reinterpret_cast<spu_function_t>(m_asmrt._add(&code));
|
||||
|
||||
if (auto err = m_asmrt.add(&fn, &code))
|
||||
if (!fn)
|
||||
{
|
||||
if (err == asmjit::ErrorCode::kErrorNoVirtualMemory)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
spu_log.fatal("Failed to build a function");
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_announce(fn, code.codeSize(), fmt::format("spu-b-%s", fmt::base57(be_t<u64>(m_hash_start))));
|
||||
}
|
||||
|
||||
// Install compiled function pointer
|
||||
const bool added = !add_loc->compiled && add_loc->compiled.compare_and_swap_test(nullptr, fn);
|
||||
@@ -923,7 +922,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
||||
{
|
||||
// Add ASMJIT logs
|
||||
fmt::append(log, "Address: %p\n\n", fn);
|
||||
log += logger.getString();
|
||||
log.append(logger._content.data(), logger._content.size());
|
||||
log += "\n\n\n";
|
||||
|
||||
// Append log file
|
||||
@@ -958,7 +957,7 @@ spu_recompiler::XmmLink spu_recompiler::XmmGet(s8 reg, XmmType type) // get xmm
|
||||
return result;
|
||||
}
|
||||
|
||||
inline asmjit::X86Mem spu_recompiler::XmmConst(const v128& data)
|
||||
inline asmjit::x86::Mem spu_recompiler::XmmConst(const v128& data)
|
||||
{
|
||||
// Find existing const
|
||||
auto& xmm_label = xmm_consts[std::make_pair(data._u64[0], data._u64[1])];
|
||||
@@ -969,7 +968,7 @@ inline asmjit::X86Mem spu_recompiler::XmmConst(const v128& data)
|
||||
|
||||
consts.emplace_back([=, this]
|
||||
{
|
||||
c->align(asmjit::kAlignData, 16);
|
||||
c->align(asmjit::AlignMode::kData, 16);
|
||||
c->bind(xmm_label);
|
||||
c->dq(data._u64[0]);
|
||||
c->dq(data._u64[1]);
|
||||
@@ -979,17 +978,17 @@ inline asmjit::X86Mem spu_recompiler::XmmConst(const v128& data)
|
||||
return asmjit::x86::oword_ptr(xmm_label);
|
||||
}
|
||||
|
||||
inline asmjit::X86Mem spu_recompiler::XmmConst(const __m128& data)
|
||||
inline asmjit::x86::Mem spu_recompiler::XmmConst(const __m128& data)
|
||||
{
|
||||
return XmmConst(v128::fromF(data));
|
||||
}
|
||||
|
||||
inline asmjit::X86Mem spu_recompiler::XmmConst(const __m128i& data)
|
||||
inline asmjit::x86::Mem spu_recompiler::XmmConst(const __m128i& data)
|
||||
{
|
||||
return XmmConst(v128::fromV(data));
|
||||
}
|
||||
|
||||
inline asmjit::X86Mem spu_recompiler::get_pc(u32 addr)
|
||||
inline asmjit::x86::Mem spu_recompiler::get_pc(u32 addr)
|
||||
{
|
||||
return asmjit::x86::qword_ptr(*pc0, addr - m_base);
|
||||
}
|
||||
@@ -1104,7 +1103,7 @@ void spu_recompiler::branch_indirect(spu_opcode_t op, bool jt, bool ret)
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->add(x86::rsp, 0x28);
|
||||
c->jmp(imm_ptr<void(*)(spu_thread*)>(_throw));
|
||||
c->jmp(imm_ptr(+_throw));
|
||||
|
||||
// Save addr in srr0 and disable interrupts
|
||||
c->bind(intr);
|
||||
@@ -1119,7 +1118,7 @@ void spu_recompiler::branch_indirect(spu_opcode_t op, bool jt, bool ret)
|
||||
c->test(*addr, 0xff80007f);
|
||||
c->cmovnz(*addr, rip->r32());
|
||||
c->shr(*addr, 5);
|
||||
c->align(kAlignCode, 16);
|
||||
c->align(AlignMode::kCode, 16);
|
||||
c->bind(no_intr);
|
||||
}
|
||||
|
||||
@@ -1206,7 +1205,7 @@ void spu_recompiler::branch_set_link(u32 target)
|
||||
after.emplace_back([=, this, target = local->second]
|
||||
{
|
||||
// Clear return info after use
|
||||
c->align(kAlignCode, 16);
|
||||
c->align(AlignMode::kCode, 16);
|
||||
c->bind(ret);
|
||||
c->mov(qw1->r32(), SPU_OFF_32(gpr, 1, &v128::_u32, 3));
|
||||
c->and_(qw1->r32(), 0x3fff0);
|
||||
@@ -1242,9 +1241,9 @@ void spu_recompiler::fall(spu_opcode_t op)
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->mov(arg1->r32(), op.opcode);
|
||||
c->mov(*qw0, asmjit::imm_ptr(asmjit::Internal::ptr_cast<void*>(g_spu_interpreter_fast.decode(op.opcode))));
|
||||
c->mov(*qw0, asmjit::imm_ptr(g_spu_interpreter_fast.decode(op.opcode)));
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(asmjit::imm_ptr<void(*)(spu_thread*, u32, spu_inter_func_t)>(gate));
|
||||
c->call(asmjit::imm_ptr(+gate));
|
||||
}
|
||||
|
||||
void spu_recompiler::UNK(spu_opcode_t op)
|
||||
@@ -1262,7 +1261,7 @@ void spu_recompiler::UNK(spu_opcode_t op)
|
||||
c->mov(arg1->r32(), op.opcode);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->add(asmjit::x86::rsp, 0x28);
|
||||
c->jmp(asmjit::imm_ptr<void(*)(spu_thread*, u32)>(gate));
|
||||
c->jmp(asmjit::imm_ptr(+gate));
|
||||
m_pos = -1;
|
||||
}
|
||||
|
||||
@@ -1291,7 +1290,7 @@ void spu_recompiler::STOP(spu_opcode_t op)
|
||||
c->mov(arg1->r32(), op.opcode & 0x3fff);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr(spu_stop));
|
||||
c->align(kAlignCode, 16);
|
||||
c->align(AlignMode::kCode, 16);
|
||||
c->bind(ret);
|
||||
|
||||
c->add(SPU_OFF_32(pc), 4);
|
||||
@@ -1358,14 +1357,14 @@ void spu_recompiler::RDCH(spu_opcode_t op)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
auto read_channel = [&](X86Mem channel_ptr, bool sync = true)
|
||||
auto read_channel = [&](x86::Mem channel_ptr, bool sync = true)
|
||||
{
|
||||
Label wait = c->newLabel();
|
||||
Label again = c->newLabel();
|
||||
Label ret = c->newLabel();
|
||||
c->mov(addr->r64(), channel_ptr);
|
||||
c->xor_(qw0->r32(), qw0->r32());
|
||||
c->align(kAlignCode, 16);
|
||||
c->align(AlignMode::kCode, 16);
|
||||
c->bind(again);
|
||||
c->bt(addr->r64(), spu_channel::off_count);
|
||||
c->jnc(wait);
|
||||
@@ -1376,7 +1375,7 @@ void spu_recompiler::RDCH(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->mov(arg1->r32(), op.ra);
|
||||
c->mov(arg1->r32(), +op.ra);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr(spu_rdch));
|
||||
c->jmp(ret);
|
||||
@@ -1478,13 +1477,12 @@ void spu_recompiler::RDCH(spu_opcode_t op)
|
||||
*_res = v128::from32r(out);
|
||||
};
|
||||
|
||||
using ftype = void (*)(spu_thread*, v128*);
|
||||
c->lea(addr->r64(), get_pc(m_pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->lea(*arg1, SPU_OFF_128(gpr, op.rt));
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(g_cfg.core.spu_loop_detection ? asmjit::imm_ptr<ftype>(sub1) : asmjit::imm_ptr<ftype>(sub2));
|
||||
c->call(asmjit::imm_ptr(g_cfg.core.spu_loop_detection ? +sub1 : +sub2));
|
||||
return;
|
||||
}
|
||||
case SPU_RdEventMask:
|
||||
@@ -1519,7 +1517,7 @@ void spu_recompiler::RDCH(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(m_pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->mov(arg1->r32(), op.ra);
|
||||
c->mov(arg1->r32(), +op.ra);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr(spu_rdch));
|
||||
c->movd(x86::xmm0, *addr);
|
||||
@@ -1536,7 +1534,7 @@ void spu_recompiler::RCHCNT(spu_opcode_t op)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
auto ch_cnt = [&](X86Mem channel_ptr, bool inv = false)
|
||||
auto ch_cnt = [&](x86::Mem channel_ptr, bool inv = false)
|
||||
{
|
||||
// Load channel count
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
@@ -1627,7 +1625,7 @@ void spu_recompiler::RCHCNT(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(m_pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->mov(arg1->r32(), op.ra);
|
||||
c->mov(arg1->r32(), +op.ra);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr(spu_rchcnt));
|
||||
break;
|
||||
@@ -2316,7 +2314,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
|
||||
Label ret = c->newLabel();
|
||||
c->mov(qw0->r32(), SPU_OFF_32(gpr, op.rt, &v128::_u32, 3));
|
||||
c->mov(addr->r64(), SPU_OFF_64(ch_out_mbox));
|
||||
c->align(kAlignCode, 16);
|
||||
c->align(AlignMode::kCode, 16);
|
||||
c->bind(again);
|
||||
c->mov(qw0->r32(), qw0->r32());
|
||||
c->bt(addr->r64(), spu_channel::off_count);
|
||||
@@ -2328,7 +2326,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->mov(arg1->r32(), op.ra);
|
||||
c->mov(arg1->r32(), +op.ra);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr(spu_wrch));
|
||||
c->jmp(ret);
|
||||
@@ -2355,7 +2353,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->lea(arg1->r32(), MFC_WrTagMask);
|
||||
c->mov(arg1->r32(), MFC_WrTagMask);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr(spu_wrch));
|
||||
c->jmp(ret);
|
||||
@@ -2379,7 +2377,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->mov(arg1->r32(), op.ra);
|
||||
c->mov(arg1->r32(), +op.ra);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr(spu_wrch));
|
||||
c->jmp(ret);
|
||||
@@ -2472,7 +2470,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
|
||||
c->btr(SPU_OFF_32(ch_stall_mask), arg1->r32());
|
||||
c->jnc(ret);
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr<void(*)(spu_thread*, u32)>(sub));
|
||||
c->call(imm_ptr(+sub));
|
||||
c->bind(ret);
|
||||
return;
|
||||
}
|
||||
@@ -2484,7 +2482,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
|
||||
};
|
||||
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr<void(*)(spu_thread*)>(sub));
|
||||
c->call(imm_ptr(+sub));
|
||||
c->mov(qw0->r32(), SPU_OFF_32(gpr, op.rt, &v128::_u32, 3));
|
||||
c->mov(SPU_OFF_32(ch_dec_value), qw0->r32());
|
||||
return;
|
||||
@@ -2511,7 +2509,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(m_pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->mov(arg1->r32(), op.ra);
|
||||
c->mov(arg1->r32(), +op.ra);
|
||||
c->mov(qw0->r32(), SPU_OFF_32(gpr, op.rt, &v128::_u32, 3));
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(imm_ptr(spu_wrch));
|
||||
@@ -2525,7 +2523,7 @@ void spu_recompiler::BIZ(spu_opcode_t op)
|
||||
|
||||
after.emplace_back([=, this, jt = m_targets[m_pos].size() > 1]
|
||||
{
|
||||
c->align(asmjit::kAlignCode, 16);
|
||||
c->align(asmjit::AlignMode::kCode, 16);
|
||||
c->bind(branch_label);
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
@@ -2541,7 +2539,7 @@ void spu_recompiler::BINZ(spu_opcode_t op)
|
||||
|
||||
after.emplace_back([=, this, jt = m_targets[m_pos].size() > 1]
|
||||
{
|
||||
c->align(asmjit::kAlignCode, 16);
|
||||
c->align(asmjit::AlignMode::kCode, 16);
|
||||
c->bind(branch_label);
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
@@ -2557,7 +2555,7 @@ void spu_recompiler::BIHZ(spu_opcode_t op)
|
||||
|
||||
after.emplace_back([=, this, jt = m_targets[m_pos].size() > 1]
|
||||
{
|
||||
c->align(asmjit::kAlignCode, 16);
|
||||
c->align(asmjit::AlignMode::kCode, 16);
|
||||
c->bind(branch_label);
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
@@ -2573,7 +2571,7 @@ void spu_recompiler::BIHNZ(spu_opcode_t op)
|
||||
|
||||
after.emplace_back([=, this, jt = m_targets[m_pos].size() > 1]
|
||||
{
|
||||
c->align(asmjit::kAlignCode, 16);
|
||||
c->align(asmjit::AlignMode::kCode, 16);
|
||||
c->bind(branch_label);
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
@@ -2665,13 +2663,13 @@ void spu_recompiler::BISLED(spu_opcode_t op)
|
||||
|
||||
asmjit::Label branch_label = c->newLabel();
|
||||
c->mov(*arg0, *cpu);
|
||||
c->call(asmjit::imm_ptr<u32(*)(spu_thread*)>(get_events));
|
||||
c->call(asmjit::imm_ptr(+get_events));
|
||||
c->test(*addr, 1);
|
||||
c->jne(branch_label);
|
||||
|
||||
after.emplace_back([=, this]()
|
||||
{
|
||||
c->align(asmjit::kAlignCode, 16);
|
||||
c->align(asmjit::AlignMode::kCode, 16);
|
||||
c->bind(branch_label);
|
||||
c->and_(*addr, 0x3fffc);
|
||||
branch_indirect(op, true, false);
|
||||
@@ -2891,7 +2889,7 @@ void spu_recompiler::CDX(spu_opcode_t op)
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vr);
|
||||
c->mov(*qw0, asmjit::imm_u(0x0001020304050607));
|
||||
c->mov(*qw0, asmjit::Imm(0x0001020304050607ull));
|
||||
c->mov(asmjit::x86::qword_ptr(*cpu, addr->r64(), 0, offset32(&spu_thread::gpr, op.rt)), *qw0);
|
||||
}
|
||||
|
||||
@@ -3024,7 +3022,7 @@ void spu_recompiler::CBD(spu_opcode_t op)
|
||||
//}
|
||||
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
|
||||
if (op.i7) c->add(*addr, op.i7);
|
||||
if (op.i7) c->add(*addr, +op.i7);
|
||||
c->not_(*addr);
|
||||
c->and_(*addr, 0xf);
|
||||
|
||||
@@ -3048,7 +3046,7 @@ void spu_recompiler::CHD(spu_opcode_t op)
|
||||
//}
|
||||
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
|
||||
if (op.i7) c->add(*addr, op.i7);
|
||||
if (op.i7) c->add(*addr, +op.i7);
|
||||
c->not_(*addr);
|
||||
c->and_(*addr, 0xe);
|
||||
|
||||
@@ -3072,7 +3070,7 @@ void spu_recompiler::CWD(spu_opcode_t op)
|
||||
//}
|
||||
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
|
||||
if (op.i7) c->add(*addr, op.i7);
|
||||
if (op.i7) c->add(*addr, +op.i7);
|
||||
c->not_(*addr);
|
||||
c->and_(*addr, 0xc);
|
||||
|
||||
@@ -3096,14 +3094,14 @@ void spu_recompiler::CDD(spu_opcode_t op)
|
||||
//}
|
||||
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
|
||||
if (op.i7) c->add(*addr, op.i7);
|
||||
if (op.i7) c->add(*addr, +op.i7);
|
||||
c->not_(*addr);
|
||||
c->and_(*addr, 0x8);
|
||||
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vr);
|
||||
c->mov(*qw0, asmjit::imm_u(0x0001020304050607));
|
||||
c->mov(*qw0, asmjit::Imm(0x0001020304050607ull));
|
||||
c->mov(asmjit::x86::qword_ptr(*cpu, addr->r64(), 0, offset32(&spu_thread::gpr, op.rt)), *qw0);
|
||||
}
|
||||
|
||||
@@ -4044,7 +4042,7 @@ void spu_recompiler::BRZ(spu_opcode_t op)
|
||||
|
||||
after.emplace_back([=, this]()
|
||||
{
|
||||
c->align(asmjit::kAlignCode, 16);
|
||||
c->align(asmjit::AlignMode::kCode, 16);
|
||||
c->bind(branch_label);
|
||||
branch_fixed(target);
|
||||
});
|
||||
@@ -4084,7 +4082,7 @@ void spu_recompiler::BRNZ(spu_opcode_t op)
|
||||
|
||||
after.emplace_back([=, this]()
|
||||
{
|
||||
c->align(asmjit::kAlignCode, 16);
|
||||
c->align(asmjit::AlignMode::kCode, 16);
|
||||
c->bind(branch_label);
|
||||
branch_fixed(target);
|
||||
});
|
||||
@@ -4105,7 +4103,7 @@ void spu_recompiler::BRHZ(spu_opcode_t op)
|
||||
|
||||
after.emplace_back([=, this]()
|
||||
{
|
||||
c->align(asmjit::kAlignCode, 16);
|
||||
c->align(asmjit::AlignMode::kCode, 16);
|
||||
c->bind(branch_label);
|
||||
branch_fixed(target);
|
||||
});
|
||||
@@ -4126,7 +4124,7 @@ void spu_recompiler::BRHNZ(spu_opcode_t op)
|
||||
|
||||
after.emplace_back([=, this]()
|
||||
{
|
||||
c->align(asmjit::kAlignCode, 16);
|
||||
c->align(asmjit::AlignMode::kCode, 16);
|
||||
c->bind(branch_label);
|
||||
branch_fixed(target);
|
||||
});
|
||||
@@ -4455,7 +4453,7 @@ void spu_recompiler::CGTBI(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::HGTI(spu_opcode_t op)
|
||||
{
|
||||
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_s32, 3), op.si10);
|
||||
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_s32, 3), +op.si10);
|
||||
|
||||
asmjit::Label label = c->newLabel();
|
||||
asmjit::Label ret = c->newLabel();
|
||||
@@ -4499,7 +4497,7 @@ void spu_recompiler::CLGTBI(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::HLGTI(spu_opcode_t op)
|
||||
{
|
||||
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_u32, 3), op.si10);
|
||||
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_u32, 3), +op.si10);
|
||||
|
||||
asmjit::Label label = c->newLabel();
|
||||
asmjit::Label ret = c->newLabel();
|
||||
@@ -4561,7 +4559,7 @@ void spu_recompiler::CEQBI(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::HEQI(spu_opcode_t op)
|
||||
{
|
||||
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_u32, 3), op.si10);
|
||||
c->cmp(SPU_OFF_32(gpr, op.ra, &v128::_u32, 3), +op.si10);
|
||||
|
||||
asmjit::Label label = c->newLabel();
|
||||
asmjit::Label ret = c->newLabel();
|
||||
@@ -4632,12 +4630,12 @@ void spu_recompiler::SHUFB(spu_opcode_t op)
|
||||
c->vpcmpub(asmjit::x86::k1, vc, XmmConst(_mm_set1_epi8(-0x40)), 5 /* GE */);
|
||||
c->vpxor(vm, vc, XmmConst(_mm_set1_epi8(0xf)));
|
||||
c->setExtraReg(asmjit::x86::k1);
|
||||
c->z().vblendmb(vc, vc, XmmConst(_mm_set1_epi8(-1))); // {k1}
|
||||
c->z().vpblendmb(vc, vc, XmmConst(_mm_set1_epi8(-1))); // {k1}
|
||||
c->vpcmpub(asmjit::x86::k2, vm, XmmConst(_mm_set1_epi8(-0x20)), 5 /* GE */);
|
||||
c->vptestmb(asmjit::x86::k1, vm, XmmConst(_mm_set1_epi8(0x10)));
|
||||
c->vpshufb(vt, va, vm);
|
||||
c->setExtraReg(asmjit::x86::k2);
|
||||
c->z().vblendmb(va, va, XmmConst(_mm_set1_epi8(0x7f))); // {k2}
|
||||
c->z().vpblendmb(va, va, XmmConst(_mm_set1_epi8(0x7f))); // {k2}
|
||||
c->setExtraReg(asmjit::x86::k1);
|
||||
c->vpshufb(vt, vb, vm); // {k1}
|
||||
c->vpternlogd(vt, va, vc, 0xf6 /* orAxorBC */);
|
||||
|
||||
@@ -24,23 +24,23 @@ private:
|
||||
u32 m_base;
|
||||
|
||||
// emitter:
|
||||
asmjit::X86Assembler* c;
|
||||
asmjit::x86::Assembler* c;
|
||||
|
||||
// arguments:
|
||||
const asmjit::X86Gp* cpu;
|
||||
const asmjit::X86Gp* ls;
|
||||
const asmjit::X86Gp* rip;
|
||||
const asmjit::X86Gp* pc0;
|
||||
const asmjit::x86::Gp* cpu;
|
||||
const asmjit::x86::Gp* ls;
|
||||
const asmjit::x86::Gp* rip;
|
||||
const asmjit::x86::Gp* pc0;
|
||||
|
||||
// Native args or temp variables:
|
||||
const asmjit::X86Gp* arg0;
|
||||
const asmjit::X86Gp* arg1;
|
||||
const asmjit::X86Gp* qw0;
|
||||
const asmjit::X86Gp* qw1;
|
||||
const asmjit::x86::Gp* arg0;
|
||||
const asmjit::x86::Gp* arg1;
|
||||
const asmjit::x86::Gp* qw0;
|
||||
const asmjit::x86::Gp* qw1;
|
||||
|
||||
// temporary:
|
||||
const asmjit::X86Gp* addr;
|
||||
std::array<const asmjit::X86Xmm*, 16> vec;
|
||||
const asmjit::x86::Gp* addr;
|
||||
std::array<const asmjit::x86::Xmm*, 16> vec;
|
||||
|
||||
// workload for the end of function:
|
||||
std::vector<std::function<void()>> after;
|
||||
@@ -60,10 +60,10 @@ private:
|
||||
|
||||
class XmmLink
|
||||
{
|
||||
const asmjit::X86Xmm* m_var;
|
||||
const asmjit::x86::Xmm* m_var;
|
||||
|
||||
public:
|
||||
XmmLink(const asmjit::X86Xmm*& xmm_var)
|
||||
XmmLink(const asmjit::x86::Xmm*& xmm_var)
|
||||
: m_var(xmm_var)
|
||||
{
|
||||
xmm_var = nullptr;
|
||||
@@ -71,7 +71,7 @@ private:
|
||||
|
||||
XmmLink(XmmLink&&) = default; // MoveConstructible + delete copy constructor and copy/move operators
|
||||
|
||||
operator const asmjit::X86Xmm&() const
|
||||
operator const asmjit::x86::Xmm&() const
|
||||
{
|
||||
return *m_var;
|
||||
}
|
||||
@@ -87,11 +87,11 @@ private:
|
||||
XmmLink XmmAlloc();
|
||||
XmmLink XmmGet(s8 reg, XmmType type);
|
||||
|
||||
asmjit::X86Mem XmmConst(const v128& data);
|
||||
asmjit::X86Mem XmmConst(const __m128& data);
|
||||
asmjit::X86Mem XmmConst(const __m128i& data);
|
||||
asmjit::x86::Mem XmmConst(const v128& data);
|
||||
asmjit::x86::Mem XmmConst(const __m128& data);
|
||||
asmjit::x86::Mem XmmConst(const __m128i& data);
|
||||
|
||||
asmjit::X86Mem get_pc(u32 addr);
|
||||
asmjit::x86::Mem get_pc(u32 addr);
|
||||
void branch_fixed(u32 target, bool absolute = false);
|
||||
void branch_indirect(spu_opcode_t op, bool jt = false, bool ret = true);
|
||||
void branch_set_link(u32 target);
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace asmjit
|
||||
static constexpr spu_opcode_t s_op{};
|
||||
|
||||
template <uint I, uint N>
|
||||
static void build_spu_gpr_load(X86Assembler& c, X86Xmm x, const bf_t<u32, I, N>&, bool store = false)
|
||||
static void build_spu_gpr_load(x86::Assembler& c, x86::Xmm x, const bf_t<u32, I, N>&, bool store = false)
|
||||
{
|
||||
static_assert(N == 7, "Invalid bitfield");
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace asmjit
|
||||
}
|
||||
|
||||
template <uint I, uint N>
|
||||
static void build_spu_gpr_store(X86Assembler& c, X86Xmm x, const bf_t<u32, I, N>&, bool store = true)
|
||||
static void build_spu_gpr_store(x86::Assembler& c, x86::Xmm x, const bf_t<u32, I, N>&, bool store = true)
|
||||
{
|
||||
build_spu_gpr_load(c, x, bf_t<u32, I, N>{}, store);
|
||||
}
|
||||
@@ -1733,7 +1733,7 @@ bool spu_interpreter::SHUFB(spu_thread& spu, spu_opcode_t op)
|
||||
return true;
|
||||
}
|
||||
|
||||
const spu_inter_func_t optimized_shufb = build_function_asm<spu_inter_func_t>([](asmjit::X86Assembler& c, auto& /*args*/)
|
||||
const spu_inter_func_t optimized_shufb = build_function_asm<spu_inter_func_t>("spu_shufb", [](asmjit::x86::Assembler& c, auto& /*args*/)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -1793,7 +1793,7 @@ const spu_inter_func_t optimized_shufb = build_function_asm<spu_inter_func_t>([]
|
||||
c.mov(x86::eax, 1);
|
||||
c.ret();
|
||||
|
||||
c.align(kAlignData, 16);
|
||||
c.align(AlignMode::kData, 16);
|
||||
c.bind(xc0);
|
||||
c.dq(0xc0c0c0c0c0c0c0c0);
|
||||
c.dq(0xc0c0c0c0c0c0c0c0);
|
||||
|
||||
@@ -160,7 +160,7 @@ DECLARE(spu_runtime::tr_all) = []
|
||||
return reinterpret_cast<spu_function_t>(trptr);
|
||||
}();
|
||||
|
||||
DECLARE(spu_runtime::g_gateway) = build_function_asm<spu_function_t>([](asmjit::X86Assembler& c, auto& args)
|
||||
DECLARE(spu_runtime::g_gateway) = built_function<spu_function_t>("spu_gateway", [](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
// Gateway for SPU dispatcher, converts from native to GHC calling convention, also saves RSP value for spu_escape
|
||||
using namespace asmjit;
|
||||
@@ -249,7 +249,7 @@ DECLARE(spu_runtime::g_gateway) = build_function_asm<spu_function_t>([](asmjit::
|
||||
c.ret();
|
||||
});
|
||||
|
||||
DECLARE(spu_runtime::g_escape) = build_function_asm<void(*)(spu_thread*)>([](asmjit::X86Assembler& c, auto& args)
|
||||
DECLARE(spu_runtime::g_escape) = build_function_asm<void(*)(spu_thread*)>("spu_escape", [](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -257,10 +257,11 @@ DECLARE(spu_runtime::g_escape) = build_function_asm<void(*)(spu_thread*)>([](asm
|
||||
c.mov(x86::rsp, x86::qword_ptr(args[0], ::offset32(&spu_thread::saved_native_sp)));
|
||||
|
||||
// Return to the return location
|
||||
c.jmp(x86::qword_ptr(x86::rsp, -8));
|
||||
c.sub(x86::rsp, 8);
|
||||
c.ret();
|
||||
});
|
||||
|
||||
DECLARE(spu_runtime::g_tail_escape) = build_function_asm<void(*)(spu_thread*, spu_function_t, u8*)>([](asmjit::X86Assembler& c, auto& args)
|
||||
DECLARE(spu_runtime::g_tail_escape) = build_function_asm<void(*)(spu_thread*, spu_function_t, u8*)>("spu_tail_escape", [](asmjit::x86::Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -268,14 +269,15 @@ DECLARE(spu_runtime::g_tail_escape) = build_function_asm<void(*)(spu_thread*, sp
|
||||
c.mov(x86::rsp, x86::qword_ptr(args[0], ::offset32(&spu_thread::saved_native_sp)));
|
||||
|
||||
// Adjust stack for initial call instruction in the gateway
|
||||
c.sub(x86::rsp, 8);
|
||||
c.sub(x86::rsp, 16);
|
||||
|
||||
// Tail call, GHC CC (second arg)
|
||||
c.mov(x86::r13, args[0]);
|
||||
c.mov(x86::rbp, x86::qword_ptr(args[0], ::offset32(&spu_thread::ls)));
|
||||
c.mov(x86::r12, args[2]);
|
||||
c.xor_(x86::ebx, x86::ebx);
|
||||
c.jmp(args[1]);
|
||||
c.mov(x86::qword_ptr(x86::rsp), args[1]);
|
||||
c.ret();
|
||||
});
|
||||
|
||||
DECLARE(spu_runtime::g_interpreter_table) = {};
|
||||
@@ -1066,6 +1068,8 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
|
||||
|
||||
workload.clear();
|
||||
result = reinterpret_cast<spu_function_t>(reinterpret_cast<u64>(wxptr));
|
||||
|
||||
jit_announce(wxptr, raw - wxptr, "spu_ubertrampoline");
|
||||
}
|
||||
|
||||
if (auto _old = stuff_it->trampoline.compare_and_swap(nullptr, result))
|
||||
@@ -3480,7 +3484,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||
#endif
|
||||
|
||||
// Get function chunk name
|
||||
const std::string name = fmt::format("spu-chunk-0x%05x", addr);
|
||||
const std::string name = fmt::format("spu-cx%05x-%s", addr, fmt::base57(be_t<u64>{m_hash_start}));
|
||||
llvm::Function* result = llvm::cast<llvm::Function>(m_module->getOrInsertFunction(name, chunk_type).getCallee());
|
||||
|
||||
// Set parameters
|
||||
@@ -3505,7 +3509,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||
// 5. $3
|
||||
const auto func_type = get_ftype<u32[4], u8*, u8*, u32, u32[4], u32[4]>();
|
||||
|
||||
const std::string fname = fmt::format("spu-function-0x%05x", addr);
|
||||
const std::string fname = fmt::format("spu-fx%05x-%s", addr, fmt::base57(be_t<u64>{m_hash_start}));
|
||||
llvm::Function* fn = llvm::cast<llvm::Function>(m_module->getOrInsertFunction(fname, func_type).getCallee());
|
||||
|
||||
fn->setLinkage(llvm::GlobalValue::InternalLinkage);
|
||||
@@ -4485,13 +4489,13 @@ public:
|
||||
elements = 16;
|
||||
dwords = 8;
|
||||
}
|
||||
else if (true)
|
||||
else if (m_use_avx)
|
||||
{
|
||||
stride = 32;
|
||||
elements = 8;
|
||||
dwords = 4;
|
||||
}
|
||||
else // TODO: Use this path when the cpu doesn't support AVX
|
||||
else
|
||||
{
|
||||
stride = 16;
|
||||
elements = 4;
|
||||
@@ -4539,7 +4543,7 @@ public:
|
||||
{
|
||||
vls = m_ir->CreateAlignedLoad(_ptr<u32[16]>(data_addr, j - starta), llvm::MaybeAlign{4});
|
||||
}
|
||||
else if (true)
|
||||
else if (m_use_avx)
|
||||
{
|
||||
vls = m_ir->CreateAlignedLoad(_ptr<u32[8]>(data_addr, j - starta), llvm::MaybeAlign{4});
|
||||
}
|
||||
@@ -4573,7 +4577,7 @@ public:
|
||||
{
|
||||
acc = m_ir->CreateBitCast(acc, get_type<u64[8]>());
|
||||
}
|
||||
else if (true)
|
||||
else if (m_use_avx)
|
||||
{
|
||||
acc = m_ir->CreateBitCast(acc, get_type<u64[4]>());
|
||||
}
|
||||
@@ -5600,7 +5604,7 @@ public:
|
||||
|
||||
if (atomic)
|
||||
{
|
||||
const auto val = m_ir->CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, ptr, m_ir->getInt64(0), llvm::AtomicOrdering::Acquire);
|
||||
const auto val = m_ir->CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, ptr, m_ir->getInt64(0), llvm::MaybeAlign{8}, llvm::AtomicOrdering::Acquire);
|
||||
val0 = val;
|
||||
}
|
||||
else
|
||||
@@ -6889,12 +6893,23 @@ public:
|
||||
set_vr(op.rt, pshufb(a, sh));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static llvm_calli<u32[4], T> orx(T&& a)
|
||||
{
|
||||
return {"spu_orx", {std::forward<T>(a)}};
|
||||
}
|
||||
|
||||
void ORX(spu_opcode_t op)
|
||||
{
|
||||
const auto a = get_vr(op.ra);
|
||||
const auto x = zshuffle(a, 2, 3, 0, 1) | a;
|
||||
const auto y = zshuffle(x, 1, 0, 3, 2) | x;
|
||||
set_vr(op.rt, zshuffle(y, 4, 4, 4, 3));
|
||||
register_intrinsic("spu_orx", [&](llvm::CallInst* ci)
|
||||
{
|
||||
const auto a = value<u32[4]>(ci->getOperand(0));
|
||||
const auto x = zshuffle(a, 2, 3, 0, 1) | a;
|
||||
const auto y = zshuffle(x, 1, 0, 3, 2) | x;
|
||||
return zshuffle(y, 4, 4, 4, 3);
|
||||
});
|
||||
|
||||
set_vr(op.rt, orx(get_vr(op.ra)));
|
||||
}
|
||||
|
||||
void CBD(spu_opcode_t op)
|
||||
@@ -7641,7 +7656,7 @@ public:
|
||||
if (auto [ok, bs] = match_expr(b, byteswap(match<u8[16]>())); ok)
|
||||
{
|
||||
// Undo endian swapping, and rely on pshufb/vperm2b to re-reverse endianness
|
||||
if (m_use_avx512_icl && (op.ra != op.rb))
|
||||
if (false)
|
||||
{
|
||||
if (perm_only)
|
||||
{
|
||||
@@ -7649,7 +7664,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
const auto m = gf2p8affineqb(c, build<u8[16]>(0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20), 0x7f);
|
||||
const auto m = gf2p8affineqb(c, build<u8[16]>(0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40), 0x7f);
|
||||
const auto mm = select(noncast<s8[16]>(m) >= 0, splat<u8[16]>(0), m);
|
||||
const auto ab = vperm2b256to128(as, bs, c);
|
||||
set_vr(op.rt4, select(noncast<s8[16]>(c) >= 0, ab, mm));
|
||||
@@ -7703,7 +7718,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (m_use_avx512_icl && (op.ra != op.rb || m_interp_magn))
|
||||
if (false)
|
||||
{
|
||||
if (perm_only)
|
||||
{
|
||||
@@ -7711,7 +7726,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
const auto m = gf2p8affineqb(c, build<u8[16]>(0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20), 0x7f);
|
||||
const auto m = gf2p8affineqb(c, build<u8[16]>(0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40), 0x7f);
|
||||
const auto mm = select(noncast<s8[16]>(m) >= 0, splat<u8[16]>(0), m);
|
||||
const auto cr = eval(~c);
|
||||
const auto ab = vperm2b256to128(b, a, cr);
|
||||
@@ -9234,7 +9249,7 @@ public:
|
||||
|
||||
const auto rt = get_vr<u8[16]>(op.rt);
|
||||
|
||||
// Checking for zero doeesn't care about the order of the bytes,
|
||||
// Checking for zero doesn't care about the order of the bytes,
|
||||
// so load the data before it's byteswapped
|
||||
if (auto [ok, as] = match_expr(rt, byteswap(match<u8[16]>())); ok)
|
||||
{
|
||||
@@ -9246,6 +9261,22 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
const auto ox = get_vr<u32[4]>(op.rt);
|
||||
|
||||
// Instead of extracting the value generated by orx, just test the input to orx with ptest
|
||||
if (auto [ok, as] = match_expr(ox, orx(match<u32[4]>())); ok)
|
||||
{
|
||||
m_block->block_end = m_ir->GetInsertBlock();
|
||||
const auto a = extract(bitcast<u64[2]>(as), 0);
|
||||
const auto b = extract(bitcast<u64[2]>(as), 1);
|
||||
const auto cond = eval((a | b) == 0);
|
||||
const auto addr = eval(extract(get_vr(op.ra), 3) & 0x3fffc);
|
||||
const auto target = add_block_indirect(op, addr);
|
||||
m_ir->CreateCondBr(cond.value, target, add_block_next());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Check sign bit instead (optimization)
|
||||
if (match_vr<s32[4], s64[2]>(op.rt, [&](auto c, auto MP)
|
||||
{
|
||||
@@ -9279,7 +9310,7 @@ public:
|
||||
|
||||
const auto rt = get_vr<u8[16]>(op.rt);
|
||||
|
||||
// Checking for zero doeesn't care about the order of the bytes,
|
||||
// Checking for zero doesn't care about the order of the bytes,
|
||||
// so load the data before it's byteswapped
|
||||
if (auto [ok, as] = match_expr(rt, byteswap(match<u8[16]>())); ok)
|
||||
{
|
||||
@@ -9291,6 +9322,21 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
const auto ox = get_vr<u32[4]>(op.rt);
|
||||
|
||||
// Instead of extracting the value generated by orx, just test the input to orx with ptest
|
||||
if (auto [ok, as] = match_expr(ox, orx(match<u32[4]>())); ok)
|
||||
{
|
||||
m_block->block_end = m_ir->GetInsertBlock();
|
||||
const auto a = extract(bitcast<u64[2]>(as), 0);
|
||||
const auto b = extract(bitcast<u64[2]>(as), 1);
|
||||
const auto cond = eval((a | b) != 0);
|
||||
const auto addr = eval(extract(get_vr(op.ra), 3) & 0x3fffc);
|
||||
const auto target = add_block_indirect(op, addr);
|
||||
m_ir->CreateCondBr(cond.value, target, add_block_next());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Check sign bit instead (optimization)
|
||||
if (match_vr<s32[4], s64[2]>(op.rt, [&](auto c, auto MP)
|
||||
@@ -9514,7 +9560,7 @@ public:
|
||||
|
||||
const auto rt = get_vr<u8[16]>(op.rt);
|
||||
|
||||
// Checking for zero doeesn't care about the order of the bytes,
|
||||
// Checking for zero doesn't care about the order of the bytes,
|
||||
// so load the data before it's byteswapped
|
||||
if (auto [ok, as] = match_expr(rt, byteswap(match<u8[16]>())); ok)
|
||||
{
|
||||
@@ -9527,6 +9573,23 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const auto ox = get_vr<u32[4]>(op.rt);
|
||||
|
||||
// Instead of extracting the value generated by orx, just test the input to orx with ptest
|
||||
if (auto [ok, as] = match_expr(ox, orx(match<u32[4]>())); ok)
|
||||
{
|
||||
if (target != m_pos + 4)
|
||||
{
|
||||
m_block->block_end = m_ir->GetInsertBlock();
|
||||
const auto a = extract(bitcast<u64[2]>(as), 0);
|
||||
const auto b = extract(bitcast<u64[2]>(as), 1);
|
||||
const auto cond = eval((a | b) == 0);
|
||||
m_ir->CreateCondBr(cond.value, add_block(target), add_block(m_pos + 4));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check sign bit instead (optimization)
|
||||
if (match_vr<s32[4], s64[2]>(op.rt, [&](auto c, auto MP)
|
||||
{
|
||||
@@ -9573,7 +9636,7 @@ public:
|
||||
|
||||
const auto rt = get_vr<u8[16]>(op.rt);
|
||||
|
||||
// Checking for zero doeesn't care about the order of the bytes,
|
||||
// Checking for zero doesn't care about the order of the bytes,
|
||||
// so load the data before it's byteswapped
|
||||
if (auto [ok, as] = match_expr(rt, byteswap(match<u8[16]>())); ok)
|
||||
{
|
||||
@@ -9586,6 +9649,22 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const auto ox = get_vr<u32[4]>(op.rt);
|
||||
|
||||
// Instead of extracting the value generated by orx, just test the input to orx with ptest
|
||||
if (auto [ok, as] = match_expr(ox, orx(match<u32[4]>())); ok)
|
||||
{
|
||||
if (target != m_pos + 4)
|
||||
{
|
||||
m_block->block_end = m_ir->GetInsertBlock();
|
||||
const auto a = extract(bitcast<u64[2]>(as), 0);
|
||||
const auto b = extract(bitcast<u64[2]>(as), 1);
|
||||
const auto cond = eval((a | b) != 0);
|
||||
m_ir->CreateCondBr(cond.value, add_block(target), add_block(m_pos + 4));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check sign bit instead (optimization)
|
||||
if (match_vr<s32[4], s64[2]>(op.rt, [&](auto c, auto MP)
|
||||
{
|
||||
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
static std::array<atomic_t<spu_function_t>, (1 << 20)>* const g_dispatcher;
|
||||
|
||||
// Recompiler entry point
|
||||
static const spu_function_t g_gateway;
|
||||
static const built_function<spu_function_t> g_gateway;
|
||||
|
||||
// Longjmp to the end of the gateway function (native CC)
|
||||
static void(*const g_escape)(spu_thread*);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user