mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-04-12 20:41:32 -06:00
Merge branch 'master' into wiimote-to-guncon3
This commit is contained in:
commit
bf29b23ed7
@ -17,7 +17,7 @@ brew install -f --overwrite --quiet ccache "llvm@$LLVM_COMPILER_VER"
|
||||
brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER"
|
||||
if [ "$AARCH64" -eq 1 ]; then
|
||||
brew install -f --overwrite --quiet googletest opencv@4 sdl3 vulkan-headers vulkan-loader molten-vk
|
||||
brew unlink --quiet ffmpeg fmt qtbase qtsvg qtdeclarative protobuf
|
||||
brew unlink --quiet ffmpeg fmt qtbase qtsvg qtdeclarative
|
||||
else
|
||||
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet python@3.14 opencv@4 "llvm@$LLVM_COMPILER_VER" sdl3 vulkan-headers vulkan-loader molten-vk
|
||||
@ -122,6 +122,7 @@ cmake .. \
|
||||
-DUSE_SYSTEM_MVK=ON \
|
||||
-DUSE_SYSTEM_SDL=ON \
|
||||
-DUSE_SYSTEM_OPENCV=ON \
|
||||
-DUSE_SYSTEM_PROTOBUF=ON \
|
||||
-G Ninja
|
||||
fi
|
||||
|
||||
|
||||
8
.github/workflows/rpcs3.yml
vendored
8
.github/workflows/rpcs3.yml
vendored
@ -30,23 +30,23 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-24.04
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.8"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.9"
|
||||
build_sh: "/rpcs3/.ci/build-linux.sh"
|
||||
compiler: clang
|
||||
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
|
||||
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
|
||||
- os: ubuntu-24.04
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.8"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.9"
|
||||
build_sh: "/rpcs3/.ci/build-linux.sh"
|
||||
compiler: gcc
|
||||
- os: ubuntu-24.04-arm
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.8"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.9"
|
||||
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
|
||||
compiler: clang
|
||||
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
|
||||
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
|
||||
- os: ubuntu-24.04-arm
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.8"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.9"
|
||||
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
|
||||
compiler: gcc
|
||||
name: RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }}
|
||||
|
||||
2
3rdparty/FAudio
vendored
2
3rdparty/FAudio
vendored
@ -1 +1 @@
|
||||
Subproject commit e67d761ead486de3e69fa11705456bf94df734ca
|
||||
Subproject commit dc034fc671b07bbd14e8410d5dd6be6da38fdf6d
|
||||
2
3rdparty/OpenAL/openal-soft
vendored
2
3rdparty/OpenAL/openal-soft
vendored
@ -1 +1 @@
|
||||
Subproject commit 75c00596307bf05ba7bbc8c7022836bf52f17477
|
||||
Subproject commit c41d64c6a35f6174bf4a27010aeac52a8d3bb2c6
|
||||
2
3rdparty/curl/curl
vendored
2
3rdparty/curl/curl
vendored
@ -1 +1 @@
|
||||
Subproject commit 400fffa90f30c7a2dc762fa33009d24851bd2016
|
||||
Subproject commit 8c908d2d0a6d32abdedda2c52e90bd56ec76c24d
|
||||
28
3rdparty/curl/libcurl.vcxproj
vendored
28
3rdparty/curl/libcurl.vcxproj
vendored
@ -79,12 +79,16 @@
|
||||
<ClCompile Include="curl\lib\cookie.c" />
|
||||
<ClCompile Include="curl\lib\cshutdn.c" />
|
||||
<ClCompile Include="curl\lib\curlx\base64.c" />
|
||||
<ClCompile Include="curl\lib\curlx\basename.c" />
|
||||
<ClCompile Include="curl\lib\curlx\dynbuf.c" />
|
||||
<ClCompile Include="curl\lib\curlx\fopen.c" />
|
||||
<ClCompile Include="curl\lib\curlx\inet_ntop.c" />
|
||||
<ClCompile Include="curl\lib\curlx\inet_pton.c" />
|
||||
<ClCompile Include="curl\lib\curlx\multibyte.c" />
|
||||
<ClCompile Include="curl\lib\curlx\nonblock.c" />
|
||||
<ClCompile Include="curl\lib\curlx\snprintf.c" />
|
||||
<ClCompile Include="curl\lib\curlx\strcopy.c" />
|
||||
<ClCompile Include="curl\lib\curlx\strdup.c" />
|
||||
<ClCompile Include="curl\lib\curlx\strerr.c" />
|
||||
<ClCompile Include="curl\lib\curlx\strparse.c" />
|
||||
<ClCompile Include="curl\lib\curlx\timediff.c" />
|
||||
@ -106,6 +110,7 @@
|
||||
<ClCompile Include="curl\lib\curl_rtmp.c" />
|
||||
<ClCompile Include="curl\lib\curl_sasl.c" />
|
||||
<ClCompile Include="curl\lib\curl_sha512_256.c" />
|
||||
<ClCompile Include="curl\lib\curl_share.c" />
|
||||
<ClCompile Include="curl\lib\curl_sspi.c" />
|
||||
<ClCompile Include="curl\lib\curl_threads.c" />
|
||||
<ClCompile Include="curl\lib\curl_trc.c" />
|
||||
@ -169,14 +174,13 @@
|
||||
<ClCompile Include="curl\lib\progress.c" />
|
||||
<ClCompile Include="curl\lib\psl.c" />
|
||||
<ClCompile Include="curl\lib\rand.c" />
|
||||
<ClCompile Include="curl\lib\rename.c" />
|
||||
<ClCompile Include="curl\lib\ratelimit.c" />
|
||||
<ClCompile Include="curl\lib\request.c" />
|
||||
<ClCompile Include="curl\lib\rtsp.c" />
|
||||
<ClCompile Include="curl\lib\select.c" />
|
||||
<ClCompile Include="curl\lib\sendf.c" />
|
||||
<ClCompile Include="curl\lib\setopt.c" />
|
||||
<ClCompile Include="curl\lib\sha256.c" />
|
||||
<ClCompile Include="curl\lib\share.c" />
|
||||
<ClCompile Include="curl\lib\slist.c" />
|
||||
<ClCompile Include="curl\lib\smb.c" />
|
||||
<ClCompile Include="curl\lib\smtp.c" />
|
||||
@ -184,10 +188,8 @@
|
||||
<ClCompile Include="curl\lib\socks.c" />
|
||||
<ClCompile Include="curl\lib\socks_gssapi.c" />
|
||||
<ClCompile Include="curl\lib\socks_sspi.c" />
|
||||
<ClCompile Include="curl\lib\speedcheck.c" />
|
||||
<ClCompile Include="curl\lib\splay.c" />
|
||||
<ClCompile Include="curl\lib\strcase.c" />
|
||||
<ClCompile Include="curl\lib\strdup.c" />
|
||||
<ClCompile Include="curl\lib\strequal.c" />
|
||||
<ClCompile Include="curl\lib\strerror.c" />
|
||||
<ClCompile Include="curl\lib\system_win32.c" />
|
||||
@ -204,6 +206,7 @@
|
||||
<ClCompile Include="curl\lib\version.c" />
|
||||
<ClCompile Include="curl\lib\vquic\curl_ngtcp2.c" />
|
||||
<ClCompile Include="curl\lib\vquic\curl_quiche.c" />
|
||||
<ClCompile Include="curl\lib\vssh\vssh.c" />
|
||||
<ClCompile Include="curl\lib\vtls\apple.c" />
|
||||
<ClCompile Include="curl\lib\vtls\cipher_suite.c" />
|
||||
<ClCompile Include="curl\lib\vtls\hostcheck.c" />
|
||||
@ -224,13 +227,11 @@
|
||||
<ClCompile Include="curl\lib\vauth\spnego_sspi.c" />
|
||||
<ClCompile Include="curl\lib\vauth\vauth.c" />
|
||||
<ClCompile Include="curl\lib\vquic\vquic.c" />
|
||||
<ClCompile Include="curl\lib\vssh\curl_path.c" />
|
||||
<ClCompile Include="curl\lib\vssh\libssh.c" />
|
||||
<ClCompile Include="curl\lib\vssh\libssh2.c" />
|
||||
<ClCompile Include="curl\lib\vtls\gtls.c" />
|
||||
<ClCompile Include="curl\lib\vtls\keylog.c" />
|
||||
<ClCompile Include="curl\lib\vtls\mbedtls.c" />
|
||||
<ClCompile Include="curl\lib\vtls\mbedtls_threadlock.c" />
|
||||
<ClCompile Include="curl\lib\vtls\openssl.c" />
|
||||
<ClCompile Include="curl\lib\vtls\schannel.c" />
|
||||
<ClCompile Include="curl\lib\vtls\schannel_verify.c" />
|
||||
@ -272,6 +273,7 @@
|
||||
<ClInclude Include="curl\lib\cookie.h" />
|
||||
<ClInclude Include="curl\lib\cshutdn.h" />
|
||||
<ClInclude Include="curl\lib\curlx\base64.h" />
|
||||
<ClInclude Include="curl\lib\curlx\basename.h" />
|
||||
<ClInclude Include="curl\lib\curlx\binmode.h" />
|
||||
<ClInclude Include="curl\lib\curlx\curlx.h" />
|
||||
<ClInclude Include="curl\lib\curlx\dynbuf.h" />
|
||||
@ -280,6 +282,9 @@
|
||||
<ClInclude Include="curl\lib\curlx\inet_pton.h" />
|
||||
<ClInclude Include="curl\lib\curlx\multibyte.h" />
|
||||
<ClInclude Include="curl\lib\curlx\nonblock.h" />
|
||||
<ClInclude Include="curl\lib\curlx\snprintf.h" />
|
||||
<ClInclude Include="curl\lib\curlx\strcopy.h" />
|
||||
<ClInclude Include="curl\lib\curlx\strdup.h" />
|
||||
<ClInclude Include="curl\lib\curlx\strerr.h" />
|
||||
<ClInclude Include="curl\lib\curlx\strparse.h" />
|
||||
<ClInclude Include="curl\lib\curlx\timediff.h" />
|
||||
@ -300,9 +305,7 @@
|
||||
<ClInclude Include="curl\lib\curl_ldap.h" />
|
||||
<ClInclude Include="curl\lib\curl_md4.h" />
|
||||
<ClInclude Include="curl\lib\curl_md5.h" />
|
||||
<ClInclude Include="curl\lib\curl_memory.h" />
|
||||
<ClInclude Include="curl\lib\curl_memrchr.h" />
|
||||
<ClInclude Include="curl\lib\curl_mem_undef.h" />
|
||||
<ClInclude Include="curl\lib\curl_ntlm_core.h" />
|
||||
<ClInclude Include="curl\lib\curl_printf.h" />
|
||||
<ClInclude Include="curl\lib\curl_range.h" />
|
||||
@ -312,6 +315,7 @@
|
||||
<ClInclude Include="curl\lib\curl_setup_once.h" />
|
||||
<ClInclude Include="curl\lib\curl_sha256.h" />
|
||||
<ClInclude Include="curl\lib\curl_sha512_256.h" />
|
||||
<ClInclude Include="curl\lib\curl_share.h" />
|
||||
<ClInclude Include="curl\lib\curl_sspi.h" />
|
||||
<ClInclude Include="curl\lib\curl_threads.h" />
|
||||
<ClInclude Include="curl\lib\curl_trc.h" />
|
||||
@ -352,7 +356,6 @@
|
||||
<ClInclude Include="curl\lib\imap.h" />
|
||||
<ClInclude Include="curl\lib\llist.h" />
|
||||
<ClInclude Include="curl\lib\macos.h" />
|
||||
<ClInclude Include="curl\lib\memdebug.h" />
|
||||
<ClInclude Include="curl\lib\mime.h" />
|
||||
<ClInclude Include="curl\lib\mqtt.h" />
|
||||
<ClInclude Include="curl\lib\multihandle.h" />
|
||||
@ -367,7 +370,7 @@
|
||||
<ClInclude Include="curl\lib\progress.h" />
|
||||
<ClInclude Include="curl\lib\psl.h" />
|
||||
<ClInclude Include="curl\lib\rand.h" />
|
||||
<ClInclude Include="curl\lib\rename.h" />
|
||||
<ClInclude Include="curl\lib\ratelimit.h" />
|
||||
<ClInclude Include="curl\lib\request.h" />
|
||||
<ClInclude Include="curl\lib\rtsp.h" />
|
||||
<ClInclude Include="curl\lib\select.h" />
|
||||
@ -376,7 +379,6 @@
|
||||
<ClInclude Include="curl\lib\setup-os400.h" />
|
||||
<ClInclude Include="curl\lib\setup-vms.h" />
|
||||
<ClInclude Include="curl\lib\setup-win32.h" />
|
||||
<ClInclude Include="curl\lib\share.h" />
|
||||
<ClInclude Include="curl\lib\sigpipe.h" />
|
||||
<ClInclude Include="curl\lib\slist.h" />
|
||||
<ClInclude Include="curl\lib\smb.h" />
|
||||
@ -384,7 +386,6 @@
|
||||
<ClInclude Include="curl\lib\sockaddr.h" />
|
||||
<ClInclude Include="curl\lib\socketpair.h" />
|
||||
<ClInclude Include="curl\lib\socks.h" />
|
||||
<ClInclude Include="curl\lib\speedcheck.h" />
|
||||
<ClInclude Include="curl\lib\splay.h" />
|
||||
<ClInclude Include="curl\lib\strcase.h" />
|
||||
<ClInclude Include="curl\lib\strdup.h" />
|
||||
@ -405,6 +406,7 @@
|
||||
<ClInclude Include="curl\lib\vquic\curl_ngtcp2.h" />
|
||||
<ClInclude Include="curl\lib\vquic\curl_quiche.h" />
|
||||
<ClInclude Include="curl\lib\vquic\vquic_int.h" />
|
||||
<ClInclude Include="curl\lib\vssh\vssh.h" />
|
||||
<ClInclude Include="curl\lib\vtls\apple.h" />
|
||||
<ClInclude Include="curl\lib\vtls\cipher_suite.h" />
|
||||
<ClInclude Include="curl\lib\vtls\hostcheck.h" />
|
||||
@ -418,12 +420,10 @@
|
||||
<ClInclude Include="curl\lib\vauth\ntlm.h" />
|
||||
<ClInclude Include="curl\lib\vauth\vauth.h" />
|
||||
<ClInclude Include="curl\lib\vquic\vquic.h" />
|
||||
<ClInclude Include="curl\lib\vssh\curl_path.h" />
|
||||
<ClInclude Include="curl\lib\vssh\ssh.h" />
|
||||
<ClInclude Include="curl\lib\vtls\gtls.h" />
|
||||
<ClInclude Include="curl\lib\vtls\keylog.h" />
|
||||
<ClInclude Include="curl\lib\vtls\mbedtls.h" />
|
||||
<ClInclude Include="curl\lib\vtls\mbedtls_threadlock.h" />
|
||||
<ClInclude Include="curl\lib\vtls\openssl.h" />
|
||||
<ClInclude Include="curl\lib\vtls\schannel.h" />
|
||||
<ClInclude Include="curl\lib\vtls\vtls.h" />
|
||||
|
||||
84
3rdparty/curl/libcurl.vcxproj.filters
vendored
84
3rdparty/curl/libcurl.vcxproj.filters
vendored
@ -204,9 +204,6 @@
|
||||
<ClCompile Include="curl\lib\rand.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\rename.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\rtsp.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -222,9 +219,6 @@
|
||||
<ClCompile Include="curl\lib\sha256.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\share.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\slist.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -246,18 +240,12 @@
|
||||
<ClCompile Include="curl\lib\socks_sspi.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\speedcheck.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\splay.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\strcase.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\strdup.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\strerror.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -318,9 +306,6 @@
|
||||
<ClCompile Include="curl\lib\vauth\vauth.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\vssh\curl_path.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\vssh\libssh.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -333,9 +318,6 @@
|
||||
<ClCompile Include="curl\lib\vtls\mbedtls.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\vtls\mbedtls_threadlock.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\vtls\openssl.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -549,6 +531,27 @@
|
||||
<ClCompile Include="curl\lib\curlx\strerr.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curlx\strcopy.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\vssh\vssh.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curl_share.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\ratelimit.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curlx\basename.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curlx\snprintf.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curlx\strdup.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="curl\include\curl\curl.h">
|
||||
@ -653,9 +656,6 @@
|
||||
<ClInclude Include="curl\lib\curl_md5.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_memory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_memrchr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -758,9 +758,6 @@
|
||||
<ClInclude Include="curl\lib\llist.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\memdebug.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\mime.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -791,9 +788,6 @@
|
||||
<ClInclude Include="curl\lib\rand.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\rename.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\rtsp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -812,9 +806,6 @@
|
||||
<ClInclude Include="curl\lib\setup-vms.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\share.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\sigpipe.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -836,9 +827,6 @@
|
||||
<ClInclude Include="curl\lib\socks.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\speedcheck.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\splay.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -887,9 +875,6 @@
|
||||
<ClInclude Include="curl\lib\vauth\vauth.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\vssh\curl_path.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\vssh\ssh.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -899,9 +884,6 @@
|
||||
<ClInclude Include="curl\lib\vtls\mbedtls.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\vtls\mbedtls_threadlock.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\vtls\openssl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -1103,9 +1085,6 @@
|
||||
<ClInclude Include="curl\lib\cf-ip-happy.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_mem_undef.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_fopen.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -1121,6 +1100,27 @@
|
||||
<ClInclude Include="curl\lib\curlx\strerr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curlx\snprintf.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curlx\strcopy.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\vssh\vssh.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_share.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\ratelimit.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curlx\basename.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curlx\strdup.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="curl\lib\libcurl.rc">
|
||||
|
||||
2
3rdparty/libsdl-org/SDL
vendored
2
3rdparty/libsdl-org/SDL
vendored
@ -1 +1 @@
|
||||
Subproject commit a962f40bbba175e9716557a25d5d7965f134a3d3
|
||||
Subproject commit 683181b47cfabd293e3ea409f838915b8297a4fd
|
||||
2
3rdparty/yaml-cpp/yaml-cpp
vendored
2
3rdparty/yaml-cpp/yaml-cpp
vendored
@ -1 +1 @@
|
||||
Subproject commit 05c44fcd18074836e21e1eda9fc02b3a4a1529b5
|
||||
Subproject commit 51a5d623e3fde1f58829a56ba910f1cb33596222
|
||||
2
3rdparty/zlib/zlib
vendored
2
3rdparty/zlib/zlib
vendored
@ -1 +1 @@
|
||||
Subproject commit 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf
|
||||
Subproject commit da607da739fa6047df13e66a2af6b8bec7c2a498
|
||||
@ -13,12 +13,12 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11)
|
||||
message(FATAL_ERROR "RPCS3 requires at least gcc-11.")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13)
|
||||
message(FATAL_ERROR "RPCS3 requires at least gcc-13.")
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0)
|
||||
message(FATAL_ERROR "RPCS3 requires at least clang-12.0.")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0)
|
||||
message(FATAL_ERROR "RPCS3 requires at least clang-19.0.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@ -416,7 +416,7 @@ void cfg::encode(YAML::Emitter& out, const cfg::_base& rhs)
|
||||
out << YAML::BeginMap;
|
||||
for (const auto& np : static_cast<const log_entry&>(rhs).get_map())
|
||||
{
|
||||
if (np.second == logs::level::notice) continue;
|
||||
if (np.second == logs::level::_default) continue;
|
||||
out << YAML::Key << np.first;
|
||||
out << YAML::Value << fmt::format("%s", np.second);
|
||||
}
|
||||
|
||||
@ -117,6 +117,7 @@ static fs::error to_error(DWORD e)
|
||||
case ERROR_NEGATIVE_SEEK: return fs::error::inval;
|
||||
case ERROR_DIRECTORY: return fs::error::inval;
|
||||
case ERROR_INVALID_NAME: return fs::error::inval;
|
||||
case ERROR_INVALID_FUNCTION: return fs::error::inval;
|
||||
case ERROR_SHARING_VIOLATION: return fs::error::acces;
|
||||
case ERROR_DIR_NOT_EMPTY: return fs::error::notempty;
|
||||
case ERROR_NOT_READY: return fs::error::noent;
|
||||
@ -398,12 +399,11 @@ namespace fs
|
||||
class windows_file final : public file_base
|
||||
{
|
||||
HANDLE m_handle;
|
||||
atomic_t<u64> m_pos;
|
||||
atomic_t<u64> m_pos {0};
|
||||
|
||||
public:
|
||||
windows_file(HANDLE handle)
|
||||
: m_handle(handle)
|
||||
, m_pos(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -417,10 +417,10 @@ namespace fs
|
||||
|
||||
stat_t get_stat() override
|
||||
{
|
||||
FILE_BASIC_INFO basic_info;
|
||||
FILE_BASIC_INFO basic_info {};
|
||||
ensure(GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))); // "file::stat"
|
||||
|
||||
stat_t info;
|
||||
stat_t info {};
|
||||
info.is_directory = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
info.is_writable = (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
info.size = this->size();
|
||||
@ -441,7 +441,7 @@ namespace fs
|
||||
|
||||
bool trunc(u64 length) override
|
||||
{
|
||||
FILE_END_OF_FILE_INFO _eof;
|
||||
FILE_END_OF_FILE_INFO _eof {};
|
||||
_eof.EndOfFile.QuadPart = length;
|
||||
|
||||
if (!SetFileInformationByHandle(m_handle, FileEndOfFileInfo, &_eof, sizeof(_eof)))
|
||||
@ -563,6 +563,7 @@ namespace fs
|
||||
|
||||
u64 size() override
|
||||
{
|
||||
// NOTE: this can fail if we access a mounted empty drive (e.g. after unmounting an iso).
|
||||
LARGE_INTEGER size;
|
||||
ensure(GetFileSizeEx(m_handle, &size)); // "file::size"
|
||||
|
||||
@ -579,12 +580,12 @@ namespace fs
|
||||
file_id id{"windows_file"};
|
||||
id.data.resize(sizeof(FILE_ID_INFO));
|
||||
|
||||
FILE_ID_INFO info;
|
||||
FILE_ID_INFO info {};
|
||||
|
||||
if (!GetFileInformationByHandleEx(m_handle, FileIdInfo, &info, sizeof(info)))
|
||||
{
|
||||
// Try GetFileInformationByHandle as a fallback
|
||||
BY_HANDLE_FILE_INFORMATION info2;
|
||||
BY_HANDLE_FILE_INFORMATION info2{};
|
||||
ensure(GetFileInformationByHandle(m_handle, &info2));
|
||||
|
||||
info = {};
|
||||
@ -625,7 +626,7 @@ namespace fs
|
||||
struct ::stat file_info;
|
||||
ensure(::fstat(m_fd, &file_info) == 0); // "file::stat"
|
||||
|
||||
stat_t info;
|
||||
stat_t info {};
|
||||
info.is_directory = S_ISDIR(file_info.st_mode);
|
||||
info.is_writable = file_info.st_mode & 0200; // HACK: approximation
|
||||
info.size = file_info.st_size;
|
||||
@ -1656,6 +1657,45 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the handle is actually valid.
|
||||
// This can fail on empty mounted drives (e.g. with ERROR_NOT_READY or ERROR_INVALID_FUNCTION).
|
||||
BY_HANDLE_FILE_INFORMATION info{};
|
||||
if (!GetFileInformationByHandle(handle, &info))
|
||||
{
|
||||
const DWORD last_error = GetLastError();
|
||||
CloseHandle(handle);
|
||||
|
||||
if (last_error == ERROR_INVALID_FUNCTION)
|
||||
{
|
||||
g_tls_error = fs::error::isdir;
|
||||
return;
|
||||
}
|
||||
|
||||
g_tls_error = to_error(last_error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
g_tls_error = fs::error::isdir;
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
g_tls_error = fs::error::acces;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((mode & fs::write) && (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
g_tls_error = fs::error::readonly;
|
||||
return;
|
||||
}
|
||||
|
||||
m_file = std::make_unique<windows_file>(handle);
|
||||
#else
|
||||
int flags = O_CLOEXEC; // Ensures all files are closed on execl for auto updater
|
||||
@ -2595,7 +2635,7 @@ bool fs::pending_file::commit(bool overwrite)
|
||||
while (file_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Get file ID (used to check for hardlinks)
|
||||
BY_HANDLE_FILE_INFORMATION file_info;
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
|
||||
if (!GetFileInformationByHandle(file_handle, &file_info) || file_info.nNumberOfLinks == 1)
|
||||
{
|
||||
|
||||
@ -66,13 +66,13 @@ namespace fs
|
||||
// File attributes (TODO)
|
||||
struct stat_t
|
||||
{
|
||||
bool is_directory;
|
||||
bool is_symlink;
|
||||
bool is_writable;
|
||||
u64 size;
|
||||
s64 atime;
|
||||
s64 mtime;
|
||||
s64 ctime;
|
||||
bool is_directory = false;
|
||||
bool is_symlink = false;
|
||||
bool is_writable = false;
|
||||
u64 size = 0;
|
||||
s64 atime = 0;
|
||||
s64 mtime = 0;
|
||||
s64 ctime = 0;
|
||||
|
||||
using enable_bitcopy = std::true_type;
|
||||
|
||||
|
||||
@ -14,6 +14,10 @@
|
||||
#define CAN_OVERCOMMIT
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(jit_log, "JIT");
|
||||
|
||||
void jit_announce(uptr func, usz size, std::string_view name)
|
||||
|
||||
@ -16,12 +16,12 @@
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#elif defined(__clang__)
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
@ -13,13 +13,13 @@ std::string wchar_to_utf8(std::wstring_view src);
|
||||
std::string utf16_to_utf8(std::u16string_view src);
|
||||
std::u16string utf8_to_utf16(std::string_view src);
|
||||
|
||||
// Copy null-terminated string from a std::string or a char array to a char array with truncation
|
||||
template <typename D, typename T>
|
||||
// Copy null-terminated string from a std::basic_string or a char array to a char array with truncation
|
||||
template <typename D, typename T> requires requires (D& d, T& t) { std::declval<decltype(&t[0])&>() = &d[0]; }
|
||||
inline void strcpy_trunc(D&& dst, const T& src)
|
||||
{
|
||||
const usz count = std::size(src) >= std::size(dst) ? std::max<usz>(std::size(dst), 1) - 1 : std::size(src);
|
||||
std::memcpy(std::data(dst), std::data(src), count);
|
||||
std::memset(std::data(dst) + count, 0, std::size(dst) - count);
|
||||
std::copy_n(std::data(src), count, std::data(dst));
|
||||
std::fill_n(std::data(dst) + count, std::size(dst) - count, std::remove_cvref_t<decltype(dst[0])>{});
|
||||
}
|
||||
|
||||
// Convert string to signed integer
|
||||
|
||||
@ -8,13 +8,17 @@
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Thread.h"
|
||||
#include "Utilities/JIT.h"
|
||||
#include <thread>
|
||||
#include <cfenv>
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
#include "Emu/CPU/Backends/AArch64/AArch64Signal.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_lib_stacktrace
|
||||
#include "rpcs3_version.h"
|
||||
#include <stacktrace>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <Psapi.h>
|
||||
@ -2801,6 +2805,16 @@ void thread_base::exec()
|
||||
|
||||
[[noreturn]] void thread_ctrl::emergency_exit(std::string_view reason)
|
||||
{
|
||||
// Print stacktrace
|
||||
#ifdef __cpp_lib_stacktrace
|
||||
if (rpcs3::is_local_build())
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << std::stacktrace::current();
|
||||
sys_log.notice("StackTrace\n\n%s\n", oss.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (const std::string info = dump_useful_thread_info(); !info.empty())
|
||||
{
|
||||
sys_log.notice("\n%s", info);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "util/atomic.hpp"
|
||||
#include "util/shared_ptr.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <string>
|
||||
|
||||
// Hardware core layout
|
||||
|
||||
@ -329,7 +329,7 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
|
||||
is_valid = false;
|
||||
continue;
|
||||
}
|
||||
else if (serial.size() != 9 || !std::all_of(serial.begin(), serial.end(), [](char c) { return std::isalnum(c); }))
|
||||
else if (serial.size() != 9 || !std::all_of(serial.begin(), serial.end(), [](char c) { return std::isalnum(static_cast<unsigned char>(c)); }))
|
||||
{
|
||||
append_log_message(log_messages, fmt::format("Error: Serial '%s' invalid (patch: %s, key: %s, location: %s, file: %s)", serial, description, main_key, get_yaml_node_location(serial_node), path), &patch_log.error);
|
||||
is_valid = false;
|
||||
|
||||
@ -821,6 +821,14 @@ struct color4_base
|
||||
a *= rhs;
|
||||
}
|
||||
|
||||
void operator += (const color4_base<T>& rhs)
|
||||
{
|
||||
r += rhs.r;
|
||||
g += rhs.g;
|
||||
b += rhs.b;
|
||||
a += rhs.a;
|
||||
}
|
||||
|
||||
constexpr color4_base<T> operator * (const color4_base<T>& rhs) const
|
||||
{
|
||||
return { r * rhs.r, g * rhs.g, b * rhs.b, a * rhs.a };
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<LanguageStandard Condition = "'$(VisualStudioVersion.Substring(0,2))'<'17'">stdcpplatest</LanguageStandard>
|
||||
<LanguageStandard Condition = "'$(VisualStudioVersion.Substring(0,2))'>='17'">stdcpp20</LanguageStandard>
|
||||
<LanguageStandard Condition = "'$(VisualStudioVersion.Substring(0,2))'>='17'">stdcpp23</LanguageStandard>
|
||||
<PreprocessorDefinitions>_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING=1;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<AdditionalOptions>-d2FH4- %(AdditionalOptions)</AdditionalOptions>
|
||||
|
||||
@ -8,7 +8,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/git-version.cmake)
|
||||
include(ConfigureCompiler)
|
||||
include(CheckFunctionExists)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
add_compile_definitions(DATADIR="${CMAKE_INSTALL_FULL_DATADIR}/rpcs3")
|
||||
@ -195,6 +195,7 @@ if(BUILD_RPCS3_TESTS)
|
||||
tests/test_address_range.cpp
|
||||
tests/test_rsx_cfg.cpp
|
||||
tests/test_rsx_fp_asm.cpp
|
||||
tests/test_dmux_pamf.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(rpcs3_test
|
||||
@ -202,6 +203,7 @@ if(BUILD_RPCS3_TESTS)
|
||||
rpcs3_lib
|
||||
rpcs3_emu
|
||||
GTest::gtest
|
||||
GTest::gmock
|
||||
)
|
||||
|
||||
target_include_directories(rpcs3_test
|
||||
|
||||
@ -501,6 +501,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
RSX/Overlays/overlays.cpp
|
||||
RSX/Overlays/overlay_animated_icon.cpp
|
||||
RSX/Overlays/overlay_animation.cpp
|
||||
RSX/Overlays/overlay_audio.cpp
|
||||
RSX/Overlays/overlay_compile_notification.cpp
|
||||
RSX/Overlays/overlay_controls.cpp
|
||||
RSX/Overlays/overlay_cursor.cpp
|
||||
|
||||
@ -20,19 +20,19 @@ namespace aarch64
|
||||
sp
|
||||
};
|
||||
|
||||
static const char* gpr_names[] =
|
||||
[[maybe_unused]] static const char* gpr_names[] =
|
||||
{
|
||||
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9",
|
||||
"x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19",
|
||||
"x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30"
|
||||
};
|
||||
|
||||
static const char* spr_names[] =
|
||||
[[maybe_unused]] static const char* spr_names[] =
|
||||
{
|
||||
"xzr", "pc", "sp"
|
||||
};
|
||||
|
||||
static const char* spr_asm_names[] =
|
||||
[[maybe_unused]] static const char* spr_asm_names[] =
|
||||
{
|
||||
"xzr", ".", "sp"
|
||||
};
|
||||
|
||||
@ -206,11 +206,7 @@ struct cpu_prof
|
||||
// Print only 7 hash characters out of 11 (which covers roughly 48 bits)
|
||||
if (type_id == 2)
|
||||
{
|
||||
fmt::append(results, "\n\t[%s", fmt::base57(be_t<u64>{name}));
|
||||
results.resize(results.size() - 4);
|
||||
|
||||
// Print chunk address from lowest 16 bits
|
||||
fmt::append(results, "...chunk-0x%05x]: %.4f%% (%u)", (name & 0xffff) * 4, _frac * 100., count);
|
||||
fmt::append(results, "\n\t[%s]: %.4f%% (%u)", spu_block_hash{name}, _frac * 100., count);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1377,7 +1373,7 @@ std::vector<std::pair<u32, u32>> cpu_thread::dump_callstack_list() const
|
||||
|
||||
std::string cpu_thread::dump_misc() const
|
||||
{
|
||||
return fmt::format("Type: %s; State: %s\n", get_class() == thread_class::ppu ? "PPU" : get_class() == thread_class::spu ? "SPU" : "RSX", state.load());
|
||||
return fmt::format("%s[0x%x]; State: %s\n", get_class() == thread_class::ppu ? "PPU" : get_class() == thread_class::spu ? "SPU" : "RSX", id, state.load());
|
||||
}
|
||||
|
||||
bool cpu_thread::suspend_work::push(cpu_thread* _this) noexcept
|
||||
|
||||
@ -201,6 +201,13 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
|
||||
m_use_vnni = true;
|
||||
m_use_gfni = true;
|
||||
}
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
if (utils::has_dotprod())
|
||||
{
|
||||
m_use_dotprod = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type) const
|
||||
|
||||
@ -3090,6 +3090,9 @@ protected:
|
||||
// For now, setting this flag will speed up SPU verification
|
||||
// but I will remove this later with explicit parralelism - Whatcookie
|
||||
bool m_use_avx = true;
|
||||
|
||||
// ARMv8 SDOT/UDOT
|
||||
bool m_use_dotprod = false;
|
||||
#else
|
||||
// Allow FMA
|
||||
bool m_use_fma = false;
|
||||
@ -3647,10 +3650,59 @@ public:
|
||||
const auto data0 = a.eval(m_ir);
|
||||
const auto data1 = b.eval(m_ir);
|
||||
const auto data2 = c.eval(m_ir);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 22
|
||||
// LLVM 22+ changed the intrinsic signature from v4i32 to v16i8 for operands 2 and 3
|
||||
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpdpbusd_128),
|
||||
{data0, m_ir->CreateBitCast(data1, get_type<u8[16]>()), m_ir->CreateBitCast(data2, get_type<u8[16]>())});
|
||||
#else
|
||||
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpdpbusd_128), {data0, data1, data2});
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
template <typename T1, typename T2, typename T3>
|
||||
value_t<u32[4]> udot(T1 a, T2 b, T3 c)
|
||||
{
|
||||
value_t<u32[4]> result;
|
||||
|
||||
const auto data0 = a.eval(m_ir);
|
||||
const auto data1 = b.eval(m_ir);
|
||||
const auto data2 = c.eval(m_ir);
|
||||
|
||||
result.value = m_ir->CreateCall(get_intrinsic<u32[4], u8[16]>(llvm::Intrinsic::aarch64_neon_udot), {data0, data1, data2});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
value_t<u32[4]> sdot(T1 a, T2 b, T3 c)
|
||||
{
|
||||
value_t<u32[4]> result;
|
||||
|
||||
const auto data0 = a.eval(m_ir);
|
||||
const auto data1 = b.eval(m_ir);
|
||||
const auto data2 = c.eval(m_ir);
|
||||
|
||||
result.value = m_ir->CreateCall(get_intrinsic<u32[4], u8[16]>(llvm::Intrinsic::aarch64_neon_sdot), {data0, data1, data2});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
auto addp(T1 a, T2 b)
|
||||
{
|
||||
using T_vector = typename is_llvm_expr<T1>::type;
|
||||
const auto data1 = a.eval(m_ir);
|
||||
const auto data2 = b.eval(m_ir);
|
||||
|
||||
const auto func = get_intrinsic<T_vector>(llvm::Intrinsic::aarch64_neon_addp);
|
||||
|
||||
value_t<T_vector> result;
|
||||
result.value = m_ir->CreateCall(func, {data1, data2});
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T1, typename T2>
|
||||
value_t<u8[16]> vpermb(T1 a, T2 b)
|
||||
{
|
||||
|
||||
@ -919,7 +919,7 @@ error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm
|
||||
|
||||
if (!check_dev_num(dev_num))
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "dev_num=%d", dev_num };
|
||||
}
|
||||
|
||||
if (g_cfg.io.camera == camera_handler::null)
|
||||
@ -935,7 +935,7 @@ error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm
|
||||
|
||||
if (!arg1)
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "arg1=null" };
|
||||
}
|
||||
|
||||
if (error_code error = check_resolution(dev_num))
|
||||
@ -952,7 +952,7 @@ error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm
|
||||
|
||||
if (!attr_name) // invalid attributes don't have a name
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "attrib=0x%x", attrib };
|
||||
}
|
||||
|
||||
if (arg1)
|
||||
@ -983,7 +983,7 @@ error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2)
|
||||
|
||||
if (!check_dev_num(dev_num))
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "dev_num=%d", dev_num };
|
||||
}
|
||||
|
||||
if (g_cfg.io.camera == camera_handler::null)
|
||||
@ -1004,7 +1004,7 @@ error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2)
|
||||
|
||||
if (!attr_name) // invalid attributes don't have a name
|
||||
{
|
||||
return CELL_CAMERA_ERROR_PARAM;
|
||||
return { CELL_CAMERA_ERROR_PARAM, "attrib=0x%x", attrib };
|
||||
}
|
||||
|
||||
g_camera.set_attr(attrib, arg1, arg2);
|
||||
|
||||
@ -169,18 +169,18 @@ public:
|
||||
static const u32 id_count = 1023;
|
||||
SAVESTATE_INIT_POS(34);
|
||||
|
||||
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec);
|
||||
ElementaryStream(Demuxer* dmux, vm::ptr<void> addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, vm::ptr<void> cbArg, u32 spec);
|
||||
|
||||
Demuxer* dmux;
|
||||
const u32 id = idm::last_id();
|
||||
const u32 memAddr;
|
||||
const vm::ptr<void> memAddr;
|
||||
const u32 memSize;
|
||||
const u32 fidMajor;
|
||||
const u32 fidMinor;
|
||||
const u32 sup1;
|
||||
const u32 sup2;
|
||||
const vm::ptr<CellDmuxCbEsMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
const vm::ptr<void> cbArg;
|
||||
const u32 spec; //addr
|
||||
|
||||
std::vector<u8> raw_data; // demultiplexed data stream (managed by demuxer thread)
|
||||
@ -208,13 +208,13 @@ public:
|
||||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const vm::ptr<CellDmuxCbMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
const vm::ptr<void> cbArg;
|
||||
volatile bool is_finished = false;
|
||||
volatile bool is_closed = false;
|
||||
atomic_t<bool> is_running = false;
|
||||
atomic_t<bool> is_working = false;
|
||||
|
||||
Demuxer(u32 addr, u32 size, vm::ptr<CellDmuxCbMsg> func, u32 arg)
|
||||
Demuxer(u32 addr, u32 size, vm::ptr<CellDmuxCbMsg> func, vm::ptr<void> arg)
|
||||
: ppu_thread({}, "", 0)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
@ -755,11 +755,11 @@ PesHeader::PesHeader(DemuxerStream& stream)
|
||||
is_ok = true;
|
||||
}
|
||||
|
||||
ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec)
|
||||
: put(utils::align(addr, 128))
|
||||
ElementaryStream::ElementaryStream(Demuxer* dmux, vm::ptr<void> addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, vm::ptr<void> cbArg, u32 spec)
|
||||
: put(utils::align(addr.addr(), 128))
|
||||
, dmux(dmux)
|
||||
, memAddr(utils::align(addr, 128))
|
||||
, memSize(size - (addr - memAddr))
|
||||
, memAddr(vm::ptr<void>::make(utils::align(addr.addr(), 128)))
|
||||
, memSize(size - (addr.addr() - memAddr.addr()))
|
||||
, fidMajor(fidMajor)
|
||||
, fidMinor(fidMinor)
|
||||
, sup1(sup1)
|
||||
@ -788,9 +788,9 @@ bool ElementaryStream::is_full(u32 space)
|
||||
{
|
||||
return first - put < space + 128;
|
||||
}
|
||||
else if (put + space + 128 > memAddr + memSize)
|
||||
else if (put + space + 128 > memAddr.addr() + memSize)
|
||||
{
|
||||
return first - memAddr < space + 128;
|
||||
return first - memAddr.addr() < space + 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -816,35 +816,35 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
|
||||
std::lock_guard lock(m_mutex);
|
||||
ensure(!is_full(size));
|
||||
|
||||
if (put + size + 128 > memAddr + memSize)
|
||||
if (put + size + 128 > memAddr.addr() + memSize)
|
||||
{
|
||||
put = memAddr;
|
||||
put = memAddr.addr();
|
||||
}
|
||||
|
||||
std::memcpy(vm::base(put + 128), raw_data.data(), size);
|
||||
raw_data.erase(raw_data.begin(), raw_data.begin() + size);
|
||||
|
||||
auto info = vm::ptr<CellDmuxAuInfoEx>::make(put);
|
||||
info->auAddr = put + 128;
|
||||
info->auAddr.set(put + 128);
|
||||
info->auSize = size;
|
||||
info->dts.lower = static_cast<u32>(dts);
|
||||
info->dts.upper = static_cast<u32>(dts >> 32);
|
||||
info->pts.lower = static_cast<u32>(pts);
|
||||
info->pts.upper = static_cast<u32>(pts >> 32);
|
||||
info->isRap = rap;
|
||||
info->reserved = 0;
|
||||
info->auMaxSize = 0;
|
||||
info->userData = userdata;
|
||||
|
||||
auto spec = vm::ptr<u32>::make(put + u32{sizeof(CellDmuxAuInfoEx)});
|
||||
*spec = specific;
|
||||
|
||||
auto inf = vm::ptr<CellDmuxAuInfo>::make(put + 64);
|
||||
inf->auAddr = put + 128;
|
||||
inf->auAddr.set(put + 128);
|
||||
inf->auSize = size;
|
||||
inf->dtsLower = static_cast<u32>(dts);
|
||||
inf->dtsUpper = static_cast<u32>(dts >> 32);
|
||||
inf->ptsLower = static_cast<u32>(pts);
|
||||
inf->ptsUpper = static_cast<u32>(pts >> 32);
|
||||
inf->dts.lower = static_cast<u32>(dts);
|
||||
inf->dts.upper = static_cast<u32>(dts >> 32);
|
||||
inf->pts.lower = static_cast<u32>(pts);
|
||||
inf->pts.upper = static_cast<u32>(pts >> 32);
|
||||
inf->auMaxSize = 0; // ?????
|
||||
inf->userData = userdata;
|
||||
|
||||
@ -927,7 +927,7 @@ bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool updat
|
||||
void ElementaryStream::reset()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
put = memAddr;
|
||||
put = memAddr.addr();
|
||||
entries.clear();
|
||||
put_count = 0;
|
||||
got_count = 0;
|
||||
|
||||
@ -33,118 +33,6 @@ enum CellDmuxEsMsgType : s32
|
||||
CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE = 1,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfM2vLevel : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_M2V_MP_LL = 0,
|
||||
CELL_DMUX_PAMF_M2V_MP_ML,
|
||||
CELL_DMUX_PAMF_M2V_MP_H14,
|
||||
CELL_DMUX_PAMF_M2V_MP_HL,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfAvcLevel : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_2P1 = 21,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_3P0 = 30,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_3P1 = 31,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_3P2 = 32,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_4P1 = 41,
|
||||
CELL_DMUX_PAMF_AVC_LEVEL_4P2 = 42,
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoM2v
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoAvc
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoLpcm
|
||||
{
|
||||
u8 channelAssignmentInfo;
|
||||
u8 samplingFreqInfo;
|
||||
u8 bitsPerSample;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoAc3
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoAtrac3plus
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAuSpecificInfoUserData
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoM2v
|
||||
{
|
||||
be_t<u32> profileLevel;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoAvc
|
||||
{
|
||||
be_t<u32> level;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoLpcm
|
||||
{
|
||||
be_t<u32> samplingFreq;
|
||||
be_t<u32> numOfChannels;
|
||||
be_t<u32> bitsPerSample;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoAc3
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoAtrac3plus
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsSpecificInfoUserData
|
||||
{
|
||||
be_t<u32> reserved1;
|
||||
};
|
||||
|
||||
enum CellDmuxPamfSamplingFrequency : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_FS_48K = 48000,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfBitsPerSample : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_BITS_PER_SAMPLE_16 = 16,
|
||||
CELL_DMUX_PAMF_BITS_PER_SAMPLE_24 = 24,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfLpcmChannelAssignmentInfo : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_LPCM_CH_M1 = 1,
|
||||
CELL_DMUX_PAMF_LPCM_CH_LR = 3,
|
||||
CELL_DMUX_PAMF_LPCM_CH_LRCLSRSLFE = 9,
|
||||
CELL_DMUX_PAMF_LPCM_CH_LRCLSCS1CS2RSLFE = 11,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfLpcmFs : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_LPCM_FS_48K = 1,
|
||||
};
|
||||
|
||||
enum CellDmuxPamfLpcmBitsPerSamples : s32
|
||||
{
|
||||
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_16 = 1,
|
||||
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_24 = 3,
|
||||
};
|
||||
|
||||
struct CellDmuxMsg
|
||||
{
|
||||
be_t<s32> msgType; // CellDmuxMsgType
|
||||
@ -163,12 +51,6 @@ struct CellDmuxType
|
||||
be_t<u32> reserved[2];
|
||||
};
|
||||
|
||||
struct CellDmuxPamfSpecificInfo
|
||||
{
|
||||
be_t<u32> thisSize;
|
||||
b8 programEndCodeCb;
|
||||
};
|
||||
|
||||
struct CellDmuxType2
|
||||
{
|
||||
be_t<s32> streamType; // CellDmuxStreamType
|
||||
@ -177,7 +59,7 @@ struct CellDmuxType2
|
||||
|
||||
struct CellDmuxResource
|
||||
{
|
||||
be_t<u32> memAddr;
|
||||
vm::bptr<void> memAddr;
|
||||
be_t<u32> memSize;
|
||||
be_t<u32> ppuThreadPriority;
|
||||
be_t<u32> ppuThreadStackSize;
|
||||
@ -187,7 +69,7 @@ struct CellDmuxResource
|
||||
|
||||
struct CellDmuxResourceEx
|
||||
{
|
||||
be_t<u32> memAddr;
|
||||
vm::bptr<void> memAddr;
|
||||
be_t<u32> memSize;
|
||||
be_t<u32> ppuThreadPriority;
|
||||
be_t<u32> ppuThreadStackSize;
|
||||
@ -227,16 +109,16 @@ struct CellDmuxResource2
|
||||
be_t<u32> shit[4];
|
||||
};
|
||||
|
||||
using CellDmuxCbMsg = u32(u32 demuxerHandle, vm::ptr<CellDmuxMsg> demuxerMsg, u32 cbArg);
|
||||
using CellDmuxCbMsg = u32(u32 demuxerHandle, vm::cptr<CellDmuxMsg> demuxerMsg, vm::ptr<void> cbArg);
|
||||
|
||||
using CellDmuxCbEsMsg = u32(u32 demuxerHandle, u32 esHandle, vm::ptr<CellDmuxEsMsg> esMsg, u32 cbArg);
|
||||
using CellDmuxCbEsMsg = u32(u32 demuxerHandle, u32 esHandle, vm::cptr<CellDmuxEsMsg> esMsg, vm::ptr<void> cbArg);
|
||||
|
||||
// Used for internal callbacks as well
|
||||
template <typename F>
|
||||
struct DmuxCb
|
||||
{
|
||||
vm::bptr<F> cbFunc;
|
||||
be_t<u32> cbArg;
|
||||
vm::bptr<void> cbArg;
|
||||
};
|
||||
|
||||
using CellDmuxCb = DmuxCb<CellDmuxCbMsg>;
|
||||
@ -250,42 +132,50 @@ struct CellDmuxAttr
|
||||
be_t<u32> demuxerVerLower;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAttr
|
||||
{
|
||||
be_t<u32> maxEnabledEsNum;
|
||||
be_t<u32> version;
|
||||
be_t<u32> memSize;
|
||||
};
|
||||
|
||||
struct CellDmuxEsAttr
|
||||
{
|
||||
be_t<u32> memSize;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfEsAttr
|
||||
{
|
||||
be_t<u32> auQueueMaxSize;
|
||||
be_t<u32> memSize;
|
||||
be_t<u32> specificInfoSize;
|
||||
};
|
||||
|
||||
struct CellDmuxEsResource
|
||||
{
|
||||
be_t<u32> memAddr;
|
||||
vm::bptr<void> memAddr;
|
||||
be_t<u32> memSize;
|
||||
};
|
||||
|
||||
struct CellDmuxAuInfo
|
||||
{
|
||||
be_t<u32> auAddr;
|
||||
vm::bptr<void> auAddr;
|
||||
be_t<u32> auSize;
|
||||
be_t<u32> auMaxSize;
|
||||
be_t<u64> userData;
|
||||
be_t<u32> ptsUpper;
|
||||
be_t<u32> ptsLower;
|
||||
be_t<u32> dtsUpper;
|
||||
be_t<u32> dtsLower;
|
||||
};
|
||||
|
||||
struct CellDmuxAuInfoEx
|
||||
{
|
||||
be_t<u32> auAddr;
|
||||
be_t<u32> auSize;
|
||||
be_t<u32> reserved;
|
||||
b8 isRap;
|
||||
be_t<u64> userData;
|
||||
CellCodecTimeStamp pts;
|
||||
CellCodecTimeStamp dts;
|
||||
};
|
||||
|
||||
struct CellDmuxPamfAttr;
|
||||
struct CellDmuxPamfEsAttr;
|
||||
using CellDmuxAuInfoEx = CellDmuxAuInfo;
|
||||
|
||||
struct DmuxAuInfo
|
||||
{
|
||||
CellDmuxAuInfo info;
|
||||
vm::bptr<void> specific_info;
|
||||
be_t<u32> specific_info_size;
|
||||
};
|
||||
|
||||
using DmuxNotifyDemuxDone = error_code(vm::ptr<void>, u32, vm::ptr<void>);
|
||||
using DmuxNotifyFatalErr = error_code(vm::ptr<void>, u32, vm::ptr<void>);
|
||||
@ -301,7 +191,7 @@ using CellDmuxCoreOpResetStream = error_code(vm::ptr<void>);
|
||||
using CellDmuxCoreOpCreateThread = error_code(vm::ptr<void>);
|
||||
using CellDmuxCoreOpJoinThread = error_code(vm::ptr<void>);
|
||||
using CellDmuxCoreOpSetStream = error_code(vm::ptr<void>, vm::cptr<void>, u32, b8, u64);
|
||||
using CellDmuxCoreOpFreeMemory = error_code(vm::ptr<void>, vm::ptr<void>, u32);
|
||||
using CellDmuxCoreOpReleaseAu = error_code(vm::ptr<void>, vm::ptr<void>, u32);
|
||||
using CellDmuxCoreOpQueryEsAttr = error_code(vm::cptr<void>, vm::cptr<void>, vm::ptr<CellDmuxPamfEsAttr>);
|
||||
using CellDmuxCoreOpEnableEs = error_code(vm::ptr<void>, vm::cptr<void>, vm::cptr<CellDmuxEsResource>, vm::cptr<DmuxCb<DmuxEsNotifyAuFound>>, vm::cptr<DmuxCb<DmuxEsNotifyFlushDone>>, vm::cptr<void>, vm::pptr<void>);
|
||||
using CellDmuxCoreOpDisableEs = u32(vm::ptr<void>);
|
||||
@ -318,7 +208,7 @@ struct CellDmuxCoreOps
|
||||
vm::bptr<CellDmuxCoreOpCreateThread> createThread;
|
||||
vm::bptr<CellDmuxCoreOpJoinThread> joinThread;
|
||||
vm::bptr<CellDmuxCoreOpSetStream> setStream;
|
||||
vm::bptr<CellDmuxCoreOpFreeMemory> freeMemory;
|
||||
vm::bptr<CellDmuxCoreOpReleaseAu> releaseAu;
|
||||
vm::bptr<CellDmuxCoreOpQueryEsAttr> queryEsAttr;
|
||||
vm::bptr<CellDmuxCoreOpEnableEs> enableEs;
|
||||
vm::bptr<CellDmuxCoreOpDisableEs> disableEs;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -492,8 +492,8 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
||||
strcpy_trunc(get->getParam.titleLang[i], psf::get_string(psf, fmt::format("TITLE_%02d", i)));
|
||||
}
|
||||
|
||||
cellGame.warning("cellHddGameCheck(): Data exists:\nATTRIBUTE: 0x%x, RESOLUTION: 0x%x, RESOLUTION: 0x%x, SOUND_FORMAT: 0x%x, dataVersion: %s"
|
||||
, get->getParam.attribute, get->getParam.resolution, get->getParam.soundFormat, get->getParam.soundFormat, std::span<const u8>(reinterpret_cast<const u8*>(get->getParam.dataVersion), 6));
|
||||
cellGame.warning("cellHddGameCheck(): Data exists:\nATTRIBUTE: 0x%x, RESOLUTION: 0x%x, SOUND_FORMAT: 0x%x, dataVersion: %s"
|
||||
, get->getParam.attribute, get->getParam.resolution, get->getParam.soundFormat, std::span<const u8>(reinterpret_cast<const u8*>(get->getParam.dataVersion), 6));
|
||||
}
|
||||
|
||||
// TODO ?
|
||||
@ -580,7 +580,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
||||
break;
|
||||
|
||||
default:
|
||||
cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->invalidMsg);
|
||||
cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->result, result->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, "%s", result->invalidMsg);
|
||||
break;
|
||||
}
|
||||
@ -1199,7 +1199,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
|
||||
break;
|
||||
|
||||
default:
|
||||
cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x). Error message: %s", cbResult->invalidMsg);
|
||||
cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x). Error message: %s", cbResult->result, cbResult->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, "%s", cbResult->invalidMsg);
|
||||
break;
|
||||
}
|
||||
@ -1747,7 +1747,7 @@ error_code cellGameThemeInstall(vm::cptr<char> usrdirPath, vm::cptr<char> fileNa
|
||||
{
|
||||
u32 magic{};
|
||||
|
||||
if (src_path.ends_with(".p3t") || !theme.read(magic) || magic != "P3TF"_u32)
|
||||
if (!fmt::to_lower(src_path).ends_with(".p3t") || !theme.read(magic) || magic != "P3TF"_u32)
|
||||
{
|
||||
return CELL_GAME_ERROR_INVALID_THEME_FILE;
|
||||
}
|
||||
@ -1819,7 +1819,7 @@ error_code cellGameThemeInstallFromBuffer(ppu_thread& ppu, u32 fileSize, u32 buf
|
||||
const u32 read_size = std::min(bufSize, fileSize - file_offset);
|
||||
cellGame.notice("cellGameThemeInstallFromBuffer: writing %d bytes at pos %d", read_size, file_offset);
|
||||
|
||||
if (theme.write(reinterpret_cast<u8*>(buf.get_ptr()) + file_offset, read_size) != read_size)
|
||||
if (theme.write(reinterpret_cast<u8*>(buf.get_ptr()), read_size) != read_size)
|
||||
{
|
||||
cellGame.error("cellGameThemeInstallFromBuffer: failed to write to destination file '%s' (error=%s)", dst_path, fs::g_tls_error);
|
||||
|
||||
|
||||
@ -770,8 +770,8 @@ namespace gem
|
||||
if constexpr (use_gain)
|
||||
{
|
||||
dst0[0] = static_cast<u8>(std::clamp(r * gain_r, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -822,8 +822,8 @@ namespace gem
|
||||
if constexpr (use_gain)
|
||||
{
|
||||
dst0[0] = static_cast<u8>(std::clamp(r * gain_r, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -845,6 +845,53 @@ namespace gem
|
||||
debayer_raw8_impl<false>(src, dst, alpha, gain_r, gain_g, gain_b);
|
||||
}
|
||||
|
||||
template <bool use_gain>
|
||||
static inline void debayer_raw8_downscale_impl(const u8* src, u8* dst, u8 alpha, f32 gain_r, f32 gain_g, f32 gain_b)
|
||||
{
|
||||
constexpr u32 in_pitch = 640;
|
||||
constexpr u32 out_pitch = 320 * 4;
|
||||
|
||||
// Simple debayer
|
||||
for (s32 y = 0; y < 240; y++)
|
||||
{
|
||||
const u8* src0 = src + y * 2 * in_pitch;
|
||||
const u8* src1 = src0 + in_pitch;
|
||||
|
||||
u8* dst0 = dst + y * out_pitch;
|
||||
|
||||
for (s32 x = 0; x < 320; x++, dst0 += 4, src0 += 2, src1 += 2)
|
||||
{
|
||||
const u8 b = src0[0];
|
||||
const u8 g0 = src0[1];
|
||||
const u8 g1 = src1[0];
|
||||
const u8 r = src1[1];
|
||||
const u8 g = (g0 + g1) >> 1;
|
||||
|
||||
if constexpr (use_gain)
|
||||
{
|
||||
dst0[0] = static_cast<u8>(std::clamp(r * gain_r, 0.0f, 255.0f));
|
||||
dst0[1] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
|
||||
dst0[2] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
dst0[0] = r;
|
||||
dst0[1] = g;
|
||||
dst0[2] = b;
|
||||
}
|
||||
dst0[3] = alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void debayer_raw8_downscale(const u8* src, u8* dst, u8 alpha, f32 gain_r, f32 gain_g, f32 gain_b)
|
||||
{
|
||||
if (gain_r != 1.0f || gain_g != 1.0f || gain_b != 1.0f)
|
||||
debayer_raw8_downscale_impl<true>(src, dst, alpha, gain_r, gain_g, gain_b);
|
||||
else
|
||||
debayer_raw8_downscale_impl<false>(src, dst, alpha, gain_r, gain_g, gain_b);
|
||||
}
|
||||
|
||||
bool convert_image_format(CellCameraFormat input_format, const CellGemVideoConvertAttribute& vc,
|
||||
const std::vector<u8>& video_data_in, u32 width, u32 height,
|
||||
u8* video_data_out, u32 video_data_out_size, u8* buffer_memory,
|
||||
@ -881,9 +928,9 @@ namespace gem
|
||||
|
||||
const u8* src_data = video_data_in.data();
|
||||
const u8 alpha = vc.alpha;
|
||||
const f32 gain_r = vc.gain * vc.blue_gain;
|
||||
const f32 gain_r = vc.gain * vc.red_gain;
|
||||
const f32 gain_g = vc.gain * vc.green_gain;
|
||||
const f32 gain_b = vc.gain * vc.red_gain;
|
||||
const f32 gain_b = vc.gain * vc.blue_gain;
|
||||
|
||||
// Only RAW8 should be relevant for cellGem unless I'm mistaken
|
||||
if (input_format == CELL_CAMERA_RAW8)
|
||||
@ -1183,34 +1230,7 @@ namespace gem
|
||||
{
|
||||
case CELL_CAMERA_RAW8:
|
||||
{
|
||||
const u32 in_pitch = width;
|
||||
const u32 out_pitch = width * 4 / 2;
|
||||
|
||||
for (u32 y = 0; y < height - 1; y += 2)
|
||||
{
|
||||
const u8* src0 = src_data + y * in_pitch;
|
||||
const u8* src1 = src0 + in_pitch;
|
||||
|
||||
u8* dst0 = video_data_out + (y / 2) * out_pitch;
|
||||
u8* dst1 = dst0 + out_pitch;
|
||||
|
||||
for (u32 x = 0; x < width - 1; x += 2, src0 += 2, src1 += 2, dst0 += 4, dst1 += 4)
|
||||
{
|
||||
const u8 b = src0[0];
|
||||
const u8 g0 = src0[1];
|
||||
const u8 g1 = src1[0];
|
||||
const u8 r = src1[1];
|
||||
|
||||
const u8 top[4] = { r, g0, b, alpha };
|
||||
const u8 bottom[4] = { r, g1, b, alpha };
|
||||
|
||||
// Top-Left
|
||||
std::memcpy(dst0, top, 4);
|
||||
|
||||
// Bottom-Left Pixel
|
||||
std::memcpy(dst1, bottom, 4);
|
||||
}
|
||||
}
|
||||
debayer_raw8_downscale(src_data, video_data_out, alpha, gain_r, gain_g, gain_b);
|
||||
break;
|
||||
}
|
||||
case CELL_CAMERA_RGBA:
|
||||
@ -1609,13 +1629,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_camera_info.bytesize)
|
||||
{
|
||||
cellGem.error("gem_tracker: unexpected image size: %d", m_camera_info.bytesize);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_tracker.set_image_data(m_camera_info.buffer.get_ptr(), m_camera_info.bytesize, m_camera_info.width, m_camera_info.height, m_camera_info.format);
|
||||
m_framenumber++; // using framenumber instead of timestamp since the timestamp could be identical
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1648,6 +1663,7 @@ public:
|
||||
}
|
||||
|
||||
auto& gem = g_fxo->get<gem_config>();
|
||||
u64 last_framenumber = 0;
|
||||
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
@ -1663,6 +1679,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (std::exchange(last_framenumber, m_framenumber.load()) == last_framenumber)
|
||||
{
|
||||
cellGem.warning("Tracker woke up without new frame. Skipping processing (framenumber=%d)", last_framenumber);
|
||||
tracker_done();
|
||||
continue;
|
||||
}
|
||||
|
||||
m_busy.release(true);
|
||||
|
||||
// Update PS Move LED colors
|
||||
@ -1754,6 +1777,7 @@ public:
|
||||
private:
|
||||
atomic_t<u32> m_wake_up_tracker = 0;
|
||||
atomic_t<u32> m_tracker_done = 0;
|
||||
atomic_t<u64> m_framenumber = 0;
|
||||
atomic_t<bool> m_busy = false;
|
||||
ps_move_tracker<false> m_tracker{};
|
||||
CellCameraInfoEx m_camera_info{};
|
||||
@ -1873,21 +1897,10 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
|
||||
gem_state->pos[2] = controller.distance_mm;
|
||||
gem_state->pos[3] = 0.f;
|
||||
|
||||
// TODO: calculate handle position based on our world coordinate and the angles
|
||||
gem_state->handle_pos[0] = camera_x;
|
||||
gem_state->handle_pos[1] = camera_y;
|
||||
gem_state->handle_pos[2] = controller.distance_mm + 10.0f;
|
||||
gem_state->handle_pos[3] = 0.f;
|
||||
|
||||
// Calculate orientation
|
||||
if (g_cfg.io.move == move_handler::real || (g_cfg.io.move == move_handler::fake && move_data.orientation_enabled))
|
||||
{
|
||||
gem_state->quat[0] = move_data.quaternion.x();
|
||||
gem_state->quat[1] = move_data.quaternion.y();
|
||||
gem_state->quat[2] = move_data.quaternion.z();
|
||||
gem_state->quat[3] = move_data.quaternion.w();
|
||||
}
|
||||
else
|
||||
ps_move_data::vect<4> quat = move_data.quaternion;
|
||||
|
||||
if (g_cfg.io.move != move_handler::real && !(g_cfg.io.move == move_handler::fake && move_data.orientation_enabled))
|
||||
{
|
||||
const f32 max_angle_per_side_h = g_cfg.io.fake_move_rotation_cone_h / 2.0f;
|
||||
const f32 max_angle_per_side_v = g_cfg.io.fake_move_rotation_cone_v / 2.0f;
|
||||
@ -1901,17 +1914,27 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
|
||||
const f32 cy = std::cos(yaw * 0.5f);
|
||||
const f32 sy = std::sin(yaw * 0.5f);
|
||||
|
||||
const f32 q_x = sr * cp * cy - cr * sp * sy;
|
||||
const f32 q_y = cr * sp * cy + sr * cp * sy;
|
||||
const f32 q_z = cr * cp * sy - sr * sp * cy;
|
||||
const f32 q_w = cr * cp * cy + sr * sp * sy;
|
||||
|
||||
gem_state->quat[0] = q_x;
|
||||
gem_state->quat[1] = q_y;
|
||||
gem_state->quat[2] = q_z;
|
||||
gem_state->quat[3] = q_w;
|
||||
quat.x() = sr * cp * cy - cr * sp * sy;
|
||||
quat.y() = cr * sp * cy + sr * cp * sy;
|
||||
quat.z() = cr * cp * sy - sr * sp * cy;
|
||||
quat.w() = cr * cp * cy + sr * sp * sy;
|
||||
}
|
||||
|
||||
gem_state->quat[0] = quat.x();
|
||||
gem_state->quat[1] = quat.y();
|
||||
gem_state->quat[2] = quat.z();
|
||||
gem_state->quat[3] = quat.w();
|
||||
|
||||
// Calculate handle position based on our world coordinate and the current orientation
|
||||
constexpr ps_move_data::vect<3> offset_local_mm({0.f, 0.f, -45.f}); // handle is ~45 mm below sphere
|
||||
const ps_move_data::vect<3> offset_world = ps_move_data::rotate_vector(quat, offset_local_mm);
|
||||
|
||||
gem_state->handle_pos[0] = gem_state->pos[0] - offset_world.x(); // Flip x offset
|
||||
gem_state->handle_pos[1] = gem_state->pos[1] - offset_world.y(); // Flip y offset
|
||||
gem_state->handle_pos[2] = gem_state->pos[2] + offset_world.z();
|
||||
gem_state->handle_pos[3] = 0.f;
|
||||
|
||||
// Calculate velocity
|
||||
if constexpr (!ps_move_data::use_imu_for_velocity)
|
||||
{
|
||||
move_data.update_velocity(shared_data.frame_timestamp_us, gem_state->pos);
|
||||
@ -1920,6 +1943,10 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
|
||||
{
|
||||
gem_state->vel[i] = move_data.vel_world[i];
|
||||
gem_state->accel[i] = move_data.accel_world[i];
|
||||
|
||||
// TODO: maybe this also needs to be adjusted depending on the orientation
|
||||
gem_state->handle_vel[i] = gem_state->vel[i];
|
||||
gem_state->handle_accel[i] = gem_state->accel[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -3612,7 +3639,7 @@ error_code cellGemReadExternalPortDeviceInfo(u32 gem_num, vm::ptr<u32> ext_id, v
|
||||
if (!pad->move_data.external_device_read_requested)
|
||||
{
|
||||
*ext_id = controller.ext_id = pad->move_data.external_device_id;
|
||||
std::memcpy(pad->move_data.external_device_read.data(), ext_info.get_ptr(), CELL_GEM_EXTERNAL_PORT_OUTPUT_SIZE);
|
||||
std::memcpy(ext_info.get_ptr(), pad->move_data.external_device_read.data(), CELL_GEM_EXTERNAL_PORT_DEVICE_INFO_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3876,13 +3903,15 @@ error_code cellGemUpdateStart(vm::cptr<void> camera_frame, u64 timestamp)
|
||||
|
||||
gem.camera_frame = camera_frame.addr();
|
||||
|
||||
if (!tracker.set_image(gem.camera_frame))
|
||||
const bool image_set = tracker.set_image(gem.camera_frame);
|
||||
|
||||
tracker.wake_up_tracker();
|
||||
|
||||
if (!image_set)
|
||||
{
|
||||
return not_an_error(CELL_GEM_NO_VIDEO);
|
||||
}
|
||||
|
||||
tracker.wake_up_tracker();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Memory/vm_ptr.h"
|
||||
|
||||
// Error Codes
|
||||
|
||||
@ -876,39 +876,42 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
|
||||
// Sort the entries
|
||||
{
|
||||
const u32 order = setList->sortOrder;
|
||||
const u32 type = setList->sortType;
|
||||
|
||||
std::sort(save_entries.begin(), save_entries.end(), [order, type](const SaveDataEntry& entry1, const SaveDataEntry& entry2) -> bool
|
||||
auto comp = [type](const SaveDataEntry& entry1, const SaveDataEntry& entry2) -> bool
|
||||
{
|
||||
const bool mtime_lower = entry1.mtime < entry2.mtime;
|
||||
const bool mtime_equal = entry1.mtime == entry2.mtime;
|
||||
const bool subtitle_lower = entry1.subtitle < entry2.subtitle;
|
||||
const bool subtitle_equal = entry1.subtitle == entry2.subtitle;
|
||||
const bool revert_order = order == CELL_SAVEDATA_SORTORDER_DESCENT;
|
||||
|
||||
if (type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME)
|
||||
{
|
||||
if (mtime_equal)
|
||||
{
|
||||
return subtitle_lower != revert_order;
|
||||
return subtitle_lower;
|
||||
}
|
||||
|
||||
return mtime_lower != revert_order;
|
||||
return mtime_lower;
|
||||
}
|
||||
else if (type == CELL_SAVEDATA_SORTTYPE_SUBTITLE)
|
||||
{
|
||||
if (subtitle_equal)
|
||||
{
|
||||
return mtime_lower != revert_order;
|
||||
return mtime_lower;
|
||||
}
|
||||
|
||||
return subtitle_lower != revert_order;
|
||||
return subtitle_lower;
|
||||
}
|
||||
|
||||
ensure(false);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
if (setList->sortOrder == CELL_SAVEDATA_SORTORDER_ASCENT)
|
||||
std::sort(save_entries.begin(), save_entries.end(), comp);
|
||||
else
|
||||
std::sort(save_entries.rbegin(), save_entries.rend(), comp);
|
||||
}
|
||||
|
||||
// Fill the listGet->dirList array
|
||||
|
||||
@ -1462,7 +1462,12 @@ error_code cellVdecGetPicItem(ppu_thread& ppu, u32 handle, vm::pptr<CellVdecPicI
|
||||
struct all_info_t
|
||||
{
|
||||
CellVdecPicItem picItem;
|
||||
std::aligned_union_t<0, CellVdecAvcInfo, CellVdecDivxInfo, CellVdecMpeg2Info> picInfo;
|
||||
union
|
||||
{
|
||||
CellVdecAvcInfo avcInfo;
|
||||
CellVdecDivxInfo divxInfo;
|
||||
CellVdecMpeg2Info mpeg2Info;
|
||||
} picInfo;
|
||||
};
|
||||
|
||||
AVFrame* frame{};
|
||||
|
||||
@ -871,7 +871,7 @@ error_code sceNpDrmGetTimelimit(vm::cptr<char> path, vm::ptr<u64> time_remain)
|
||||
}
|
||||
|
||||
// Convert time to milliseconds
|
||||
s64 msec = *sec * 1000ll + *nsec / 1000ll;
|
||||
s64 msec = *sec * 1000ll + *nsec / 1'000'000ll;
|
||||
|
||||
// Return the remaining time in microseconds
|
||||
if (npd.activate_time != 0 && msec < npd.activate_time)
|
||||
@ -1199,7 +1199,7 @@ error_code _sceNpBasicSendMessage(vm::cptr<SceNpId> to, vm::cptr<void> data, u32
|
||||
.msgFeatures = {},
|
||||
.data = std::vector<u8>(static_cast<const u8*>(data.get_ptr()), static_cast<const u8*>(data.get_ptr()) + size)};
|
||||
std::set<std::string> npids;
|
||||
npids.insert(std::string(to->handle.data));
|
||||
npids.insert(np::npid_to_string(*to));
|
||||
|
||||
nph.send_message(msg_data, npids);
|
||||
|
||||
@ -1228,7 +1228,7 @@ error_code sceNpBasicSendMessageGui(ppu_thread& ppu, vm::cptr<SceNpBasicMessageD
|
||||
sceNp.notice("sceNpBasicSendMessageGui: msgId: %d, mainType: %d, subType: %d, msgFeatures: %d, count: %d, npids: *0x%x", msg->msgId, msg->mainType, msg->subType, msg->msgFeatures, msg->count, msg->npids);
|
||||
for (u32 i = 0; i < msg->count && msg->npids; i++)
|
||||
{
|
||||
sceNp.trace("sceNpBasicSendMessageGui: NpId[%d] = %s", i, static_cast<char*>(&msg->npids[i].handle.data[0]));
|
||||
sceNp.trace("sceNpBasicSendMessageGui: NpId[%d] = %s", i, np::npid_to_string(msg->npids[i]));
|
||||
}
|
||||
sceNp.notice("sceNpBasicSendMessageGui: subject: %s", msg->subject);
|
||||
sceNp.notice("sceNpBasicSendMessageGui: body: %s", msg->body);
|
||||
@ -1398,7 +1398,7 @@ error_code sceNpBasicSendMessageGui(ppu_thread& ppu, vm::cptr<SceNpBasicMessageD
|
||||
{
|
||||
for (u32 i = 0; i < msg->count; i++)
|
||||
{
|
||||
npids.insert(std::string(msg->npids[i].handle.data));
|
||||
npids.insert(np::npid_to_string(msg->npids[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4242,19 +4242,16 @@ error_code sceNpManagerGetTicket(vm::ptr<void> buffer, vm::ptr<u32> bufferSize)
|
||||
}
|
||||
|
||||
const auto& ticket = nph.get_ticket();
|
||||
*bufferSize = static_cast<u32>(ticket.size());
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
*bufferSize = static_cast<u32>(ticket.size());
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (*bufferSize < ticket.size())
|
||||
{
|
||||
return SCE_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
memcpy(buffer.get_ptr(), ticket.data(), ticket.size());
|
||||
const u32 size_read = std::min(::size32(ticket), static_cast<u32>(*bufferSize));
|
||||
std::memcpy(buffer.get_ptr(), ticket.data(), size_read);
|
||||
*bufferSize = size_read;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -5676,7 +5673,7 @@ error_code scenp_score_record_score(s32 transId, SceNpScoreBoardId boardId, SceN
|
||||
else
|
||||
{
|
||||
data = &gameInfo->nativeData[0];
|
||||
data_size = 64;
|
||||
data_size = sizeof(gameInfo->nativeData);
|
||||
}
|
||||
|
||||
nph.record_score(trans_ctx, boardId, score, scoreComment, data, data_size, tmpRank, async);
|
||||
@ -7144,7 +7141,7 @@ error_code sceNpUtilCanonicalizeNpIdForPsp(vm::ptr<SceNpId> npId)
|
||||
|
||||
error_code sceNpUtilCmpNpId(vm::ptr<SceNpId> id1, vm::ptr<SceNpId> id2)
|
||||
{
|
||||
sceNp.trace("sceNpUtilCmpNpId(id1=*0x%x(%s), id2=*0x%x(%s))", id1, id1 ? id1->handle.data : "", id2, id2 ? id2->handle.data : "");
|
||||
sceNp.trace("sceNpUtilCmpNpId(id1=*0x%x(%s), id2=*0x%x(%s))", id1, id1 ? np::npid_to_string(*id1) : std::string(), id2, id2 ? np::npid_to_string(*id2) : std::string());
|
||||
|
||||
if (!id1 || !id2)
|
||||
{
|
||||
|
||||
@ -1397,9 +1397,9 @@ struct SceNpBasicMessageDetails
|
||||
// Presence details of an user
|
||||
struct SceNpBasicPresenceDetails
|
||||
{
|
||||
s8 title[SCE_NP_BASIC_PRESENCE_TITLE_SIZE_MAX];
|
||||
s8 status[SCE_NP_BASIC_PRESENCE_STATUS_SIZE_MAX];
|
||||
s8 comment[SCE_NP_BASIC_PRESENCE_COMMENT_SIZE_MAX];
|
||||
char title[SCE_NP_BASIC_PRESENCE_TITLE_SIZE_MAX];
|
||||
char status[SCE_NP_BASIC_PRESENCE_STATUS_SIZE_MAX];
|
||||
char comment[SCE_NP_BASIC_PRESENCE_COMMENT_SIZE_MAX];
|
||||
u8 data[SCE_NP_BASIC_MAX_PRESENCE_SIZE];
|
||||
be_t<u32> size;
|
||||
be_t<s32> state;
|
||||
@ -1410,9 +1410,9 @@ struct SceNpBasicPresenceDetails2
|
||||
{
|
||||
be_t<u32> struct_size;
|
||||
be_t<s32> state;
|
||||
s8 title[SCE_NP_BASIC_PRESENCE_TITLE_SIZE_MAX];
|
||||
s8 status[SCE_NP_BASIC_PRESENCE_EXTENDED_STATUS_SIZE_MAX];
|
||||
s8 comment[SCE_NP_BASIC_PRESENCE_COMMENT_SIZE_MAX];
|
||||
char title[SCE_NP_BASIC_PRESENCE_TITLE_SIZE_MAX];
|
||||
char status[SCE_NP_BASIC_PRESENCE_EXTENDED_STATUS_SIZE_MAX];
|
||||
char comment[SCE_NP_BASIC_PRESENCE_COMMENT_SIZE_MAX];
|
||||
u8 data[SCE_NP_BASIC_MAX_PRESENCE_SIZE];
|
||||
be_t<u32> size;
|
||||
};
|
||||
@ -1420,9 +1420,9 @@ struct SceNpBasicPresenceDetails2
|
||||
// Country/region code
|
||||
struct SceNpCountryCode
|
||||
{
|
||||
s8 data[2];
|
||||
s8 term;
|
||||
s8 padding[1];
|
||||
char data[2];
|
||||
char term;
|
||||
char padding[1];
|
||||
};
|
||||
|
||||
// Date information
|
||||
@ -1451,8 +1451,8 @@ struct SceNpScoreGameInfo
|
||||
// Ranking comment structure
|
||||
struct SceNpScoreComment
|
||||
{
|
||||
s8 data[SCE_NP_SCORE_COMMENT_MAXLEN];
|
||||
s8 term[1];
|
||||
char data[SCE_NP_SCORE_COMMENT_MAXLEN];
|
||||
char term[1];
|
||||
};
|
||||
|
||||
// Ranking information structure
|
||||
@ -1524,15 +1524,15 @@ struct SceNpScoreNpIdPcId
|
||||
// Basic clan information to be used in raking
|
||||
struct SceNpScoreClanBasicInfo
|
||||
{
|
||||
s8 clanName[SCE_NP_CLANS_CLAN_NAME_MAX_LENGTH + 1];
|
||||
s8 clanTag[SCE_NP_CLANS_CLAN_TAG_MAX_LENGTH + 1];
|
||||
char clanName[SCE_NP_CLANS_CLAN_NAME_MAX_LENGTH + 1];
|
||||
char clanTag[SCE_NP_CLANS_CLAN_TAG_MAX_LENGTH + 1];
|
||||
u8 reserved[10];
|
||||
};
|
||||
|
||||
// Clan member information handled in ranking
|
||||
struct SceNpScoreClansMemberDescription
|
||||
{
|
||||
s8 description[SCE_NP_CLANS_CLAN_DESCRIPTION_MAX_LENGTH + 1];
|
||||
char description[SCE_NP_CLANS_CLAN_DESCRIPTION_MAX_LENGTH + 1];
|
||||
};
|
||||
|
||||
// Clan ranking information
|
||||
|
||||
@ -1135,7 +1135,7 @@ error_code sceNpMatching2ContextStartAsync(SceNpMatching2ContextId ctxId, u32 ti
|
||||
{
|
||||
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
|
||||
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, context_callback_param);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
@ -1760,7 +1760,7 @@ error_code sceNpMatching2ContextStop(SceNpMatching2ContextId ctxId)
|
||||
const auto ctx = get_match2_context(ctxId);
|
||||
|
||||
if (!ctx)
|
||||
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
|
||||
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
|
||||
|
||||
if (!ctx->started.compare_and_swap_test(1, 0))
|
||||
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED;
|
||||
|
||||
@ -1026,14 +1026,14 @@ error_code sceNpTrophyUnlockTrophy(ppu_thread& ppu, u32 context, u32 handle, s32
|
||||
|
||||
auto& trophy_manager = g_fxo->get<sce_np_trophy_manager>();
|
||||
|
||||
reader_lock lock(trophy_manager.mtx);
|
||||
std::scoped_lock lock(trophy_manager.mtx);
|
||||
|
||||
if (!trophy_manager.is_initialized)
|
||||
{
|
||||
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
const auto [ctxt, error] = trophy_manager.get_context_ex(context, handle);
|
||||
const auto [ctxt, error] = trophy_manager.get_context_ex(context, handle, true);
|
||||
|
||||
if (error)
|
||||
{
|
||||
@ -1184,9 +1184,9 @@ error_code sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, vm::ptr<SceN
|
||||
for (u32 id = 0; id < count_; id++)
|
||||
{
|
||||
if (tropusr->GetTrophyUnlockState(id))
|
||||
flags->flag_bits[id / 32] |= 1 << (id % 32);
|
||||
flags->flag_bits[id / 32] |= 1u << (id % 32);
|
||||
else
|
||||
flags->flag_bits[id / 32] &= ~(1 << (id % 32));
|
||||
flags->flag_bits[id / 32] &= ~(1u << (id % 32));
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
|
||||
@ -2535,7 +2535,7 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
|
||||
// SLDI mnemonic
|
||||
reg_state_t rs = get_reg(op.rs);
|
||||
|
||||
if (!rs.shift_left(op.sh32, reg_tag_allocator))
|
||||
if (!rs.shift_left(sh, reg_tag_allocator))
|
||||
{
|
||||
unmap_reg(op.ra);
|
||||
}
|
||||
|
||||
@ -330,7 +330,7 @@ void comment_constant(std::string& last_opcode, u64 value, bool print_float = fa
|
||||
// Comment constant formation
|
||||
fmt::append(last_opcode, " #0x%xh", value);
|
||||
|
||||
if (print_float && ((value >> 31) <= 1u || (value >> 31) == 0x1'ffff'ffffu))
|
||||
if (print_float && ((value >> 31) <= 1u || (value >> 31) == 0x1'ffff'ffffu) && (value > 0x3fffff && (value << 32 >> 32) < 0xffc00000))
|
||||
{
|
||||
const f32 float_val = std::bit_cast<f32>(static_cast<u32>(value));
|
||||
|
||||
|
||||
@ -1004,7 +1004,7 @@ static import_result_t ppu_load_imports(const ppu_module<lv2_obj>& _module, std:
|
||||
|
||||
// Check address
|
||||
// TODO: The address of use should be extracted from analyser instead
|
||||
if (fstub && fstub >= _module.segs[0].addr && fstub <= _module.segs[0].addr + _module.segs[0].size)
|
||||
if (fstub && fstub >= _module.segs[0].addr && fstub < _module.segs[0].addr + _module.segs[0].size)
|
||||
{
|
||||
nid_to_use_addr.emplace(fnid, fstub);
|
||||
}
|
||||
@ -1895,7 +1895,7 @@ shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, bool virtual_load, c
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu_loader.error("Library %s: PRX library info not found");
|
||||
ppu_loader.error("Library: PRX library info not found");
|
||||
}
|
||||
|
||||
prx->start.set(prx->specials[0xbc9a0086]);
|
||||
@ -3192,7 +3192,7 @@ bool ppu_load_rel_exec(const ppu_rel_object& elf)
|
||||
|
||||
for (const auto& s : elf.shdrs)
|
||||
{
|
||||
if (s.sh_type != sec_type::sht_progbits)
|
||||
if (s.sh_type == sec_type::sht_progbits)
|
||||
{
|
||||
memsize = utils::align<u32>(memsize + vm::cast(s.sh_size), 128);
|
||||
}
|
||||
|
||||
@ -3867,12 +3867,12 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
||||
|
||||
if (mself.read(hdr) && hdr.get_count(mself.size()))
|
||||
{
|
||||
std::set<u64> offs;
|
||||
|
||||
for (u32 j = 0; j < hdr.count; j++)
|
||||
{
|
||||
mself_record rec{};
|
||||
|
||||
std::set<u64> offs;
|
||||
|
||||
if (mself.read(rec) && rec.get_pos(mself.size()))
|
||||
{
|
||||
if (rec.size <= 0x20)
|
||||
|
||||
@ -550,11 +550,12 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
|
||||
else if (_target >= caddr && _target <= cend)
|
||||
{
|
||||
u32 target_last = static_cast<u32>(_target);
|
||||
|
||||
std::unordered_set<u32> passed_targets{target_last};
|
||||
|
||||
// Try to follow unconditional branches as long as there is no infinite loop
|
||||
while (target_last != _target)
|
||||
// !! Triggers compilation issues in Asura's Wrath in other parts of the code
|
||||
// !! See https://github.com/RPCS3/rpcs3/issues/18287
|
||||
while (false)
|
||||
{
|
||||
const ppu_opcode_t op{*ensure(m_info.get_ptr<u32>(target_last))};
|
||||
const ppu_itype::type itype = g_ppu_itype.decode(op.opcode);
|
||||
@ -1304,7 +1305,7 @@ void PPUTranslator::VMADDFP(ppu_opcode_t op)
|
||||
if (!m_use_fma && data == v128{})
|
||||
{
|
||||
set_vr(op.vd, vec_handle_result(a * c + fsplat<f32[4]>(0.f)));
|
||||
ppu_log.notice("LLVM: VMADDFP with -0 addend at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
|
||||
ppu_log.notice("LLVM: VMADDFP with +0 addend at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -3680,9 +3681,7 @@ void PPUTranslator::STVLX(ppu_opcode_t op)
|
||||
const auto addr = op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb);
|
||||
const auto data = pshufb(get_vr<u8[16]>(op.vs), build<u8[16]>(127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112) + vsplat<u8[16]>(trunc<u8>(value<u64>(addr) & 0xf)));
|
||||
const auto mask = bitcast<bool[16]>(splat<u16>(0xffff) << trunc<u16>(value<u64>(addr) & 0xf));
|
||||
const auto ptr = value<u8(*)[16]>(GetMemory(m_ir->CreateAnd(addr, ~0xfull)));
|
||||
const auto align = splat<u32>(16);
|
||||
eval(llvm_calli<void, decltype(data), decltype(ptr), decltype(align), decltype(mask)>{"llvm.masked.store.v16i8.p0", {data, ptr, align, mask}});
|
||||
m_ir->CreateMaskedStore(data.eval(m_ir), GetMemory(m_ir->CreateAnd(addr, ~0xfull)), llvm::Align(16), mask.eval(m_ir));
|
||||
}
|
||||
|
||||
void PPUTranslator::STDBRX(ppu_opcode_t op)
|
||||
@ -3710,9 +3709,7 @@ void PPUTranslator::STVRX(ppu_opcode_t op)
|
||||
const auto addr = op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb);
|
||||
const auto data = pshufb(get_vr<u8[16]>(op.vs), build<u8[16]>(255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240) + vsplat<u8[16]>(trunc<u8>(value<u64>(addr) & 0xf)));
|
||||
const auto mask = bitcast<bool[16]>(trunc<u16>(splat<u64>(0xffff) << (value<u64>(addr) & 0xf) >> 16));
|
||||
const auto ptr = value<u8(*)[16]>(GetMemory(m_ir->CreateAnd(addr, ~0xfull)));
|
||||
const auto align = splat<u32>(16);
|
||||
eval(llvm_calli<void, decltype(data), decltype(ptr), decltype(align), decltype(mask)>{"llvm.masked.store.v16i8.p0", {data, ptr, align, mask}});
|
||||
m_ir->CreateMaskedStore(data.eval(m_ir), GetMemory(m_ir->CreateAnd(addr, ~0xfull)), llvm::Align(16), mask.eval(m_ir));
|
||||
}
|
||||
|
||||
void PPUTranslator::STFSUX(ppu_opcode_t op)
|
||||
|
||||
@ -51,22 +51,22 @@ struct spu_itype
|
||||
RDCH,
|
||||
RCHCNT,
|
||||
|
||||
BR, // branch_tag first
|
||||
BR, // branch_tag first, zregmod_tag (2) first
|
||||
BRA,
|
||||
BRNZ,
|
||||
BRZ,
|
||||
BRHNZ,
|
||||
BRHZ,
|
||||
BRSL,
|
||||
BRASL,
|
||||
IRET,
|
||||
BI,
|
||||
BISLED,
|
||||
BISL,
|
||||
BIZ,
|
||||
BINZ,
|
||||
BIHZ,
|
||||
BIHNZ, // branch_tag last
|
||||
BIHNZ, // zregmod_tag (2) last
|
||||
BRSL,
|
||||
BRASL,
|
||||
BISL, // branch_tag last
|
||||
|
||||
ILH, // constant_tag_first
|
||||
ILHU,
|
||||
@ -245,7 +245,7 @@ struct spu_itype
|
||||
// Test for branch instruction
|
||||
friend constexpr bool operator &(type value, branch_tag)
|
||||
{
|
||||
return value >= BR && value <= BIHNZ;
|
||||
return value >= BR && value <= BISL;
|
||||
}
|
||||
|
||||
// Test for floating point instruction
|
||||
@ -299,7 +299,7 @@ struct spu_itype
|
||||
// Test for non register-modifying instruction
|
||||
friend constexpr bool operator &(type value, zregmod_tag)
|
||||
{
|
||||
return value >= HEQ && value <= STQR;
|
||||
return (value >= HEQ && value <= STQR) || (value >= BR && value <= BIHNZ);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1176,108 +1176,6 @@ void spu_cache::initialize(bool build_existing_cache)
|
||||
if ((g_cfg.core.spu_decoder == spu_decoder_type::asmjit || g_cfg.core.spu_decoder == spu_decoder_type::llvm) && !func_list.empty())
|
||||
{
|
||||
spu_log.success("SPU Runtime: Built %u functions.", func_list.size());
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
std::string dump;
|
||||
dump.reserve(10'000'000);
|
||||
|
||||
std::map<std::span<u8>, spu_program*, span_less<u8>> sorted;
|
||||
|
||||
for (auto&& f : func_list)
|
||||
{
|
||||
// Interpret as a byte string
|
||||
std::span<u8> data = {reinterpret_cast<u8*>(f.data.data()), f.data.size() * sizeof(u32)};
|
||||
|
||||
sorted[data] = &f;
|
||||
}
|
||||
|
||||
std::unordered_set<u32> depth_n;
|
||||
|
||||
u32 n_max = 0;
|
||||
|
||||
for (auto&& [bytes, f] : sorted)
|
||||
{
|
||||
{
|
||||
sha1_context ctx;
|
||||
u8 output[20];
|
||||
|
||||
sha1_starts(&ctx);
|
||||
sha1_update(&ctx, bytes.data(), bytes.size());
|
||||
sha1_finish(&ctx, output);
|
||||
fmt::append(dump, "\n\t[%s] ", fmt::base57(output));
|
||||
}
|
||||
|
||||
u32 depth_m = 0;
|
||||
|
||||
for (auto&& [data, f2] : sorted)
|
||||
{
|
||||
u32 depth = 0;
|
||||
|
||||
if (f2 == f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < bytes.size(); i++)
|
||||
{
|
||||
if (i < data.size() && data[i] == bytes[i])
|
||||
{
|
||||
depth++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
depth_n.emplace(depth);
|
||||
depth_m = std::max(depth, depth_m);
|
||||
}
|
||||
|
||||
fmt::append(dump, "c=%06d,d=%06d ", depth_n.size(), depth_m);
|
||||
|
||||
bool sk = false;
|
||||
|
||||
for (u32 i = 0; i < std::min<usz>(bytes.size(), std::max<usz>(256, depth_m)); i++)
|
||||
{
|
||||
if (depth_m == i)
|
||||
{
|
||||
dump += '|';
|
||||
sk = true;
|
||||
}
|
||||
|
||||
fmt::append(dump, "%02x", bytes[i]);
|
||||
|
||||
if (i % 4 == 3)
|
||||
{
|
||||
if (sk)
|
||||
{
|
||||
sk = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
dump += ' ';
|
||||
}
|
||||
|
||||
dump += ' ';
|
||||
}
|
||||
}
|
||||
|
||||
fmt::append(dump, "\n\t%49s", "");
|
||||
|
||||
for (u32 i = 0; i < std::min<usz>(f->data.size(), std::max<usz>(64, utils::aligned_div<u32>(depth_m, 4))); i++)
|
||||
{
|
||||
fmt::append(dump, "%-10s", g_spu_iname.decode(std::bit_cast<be_t<u32>>(f->data[i])));
|
||||
}
|
||||
|
||||
n_max = std::max(n_max, ::size32(depth_n));
|
||||
|
||||
depth_n.clear();
|
||||
}
|
||||
|
||||
spu_log.notice("SPU Cache Dump (max_c=%d): %s", n_max, dump);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize global cache instance
|
||||
@ -3705,6 +3603,11 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
default:
|
||||
{
|
||||
if (type & spu_itype::zregmod)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Unconst
|
||||
const u32 op_rt = type & spu_itype::_quadrop ? +op.rt4 : +op.rt;
|
||||
m_regmod[pos / 4] = op_rt;
|
||||
@ -7488,6 +7391,7 @@ void spu_recompiler_base::dump(const spu_program& result, std::string& out)
|
||||
SPUDisAsm dis_asm(cpu_disasm_mode::dump, reinterpret_cast<const u8*>(result.data.data()), result.lower_bound);
|
||||
|
||||
std::string hash;
|
||||
be_t<u64> hash_start{};
|
||||
|
||||
if (!result.data.empty())
|
||||
{
|
||||
@ -7498,6 +7402,7 @@ void spu_recompiler_base::dump(const spu_program& result, std::string& out)
|
||||
sha1_update(&ctx, reinterpret_cast<const u8*>(result.data.data()), result.data.size() * 4);
|
||||
sha1_finish(&ctx, output);
|
||||
fmt::append(hash, "%s", fmt::base57(output));
|
||||
std::memcpy(&hash_start, output, sizeof(hash_start));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -7510,7 +7415,7 @@ void spu_recompiler_base::dump(const spu_program& result, std::string& out)
|
||||
{
|
||||
if (m_block_info[bb.first / 4])
|
||||
{
|
||||
fmt::append(out, "A: [0x%05x] %s\n", bb.first, m_entry_info[bb.first / 4] ? (m_ret_info[bb.first / 4] ? "Chunk" : "Entry") : "Block");
|
||||
fmt::append(out, "A: [0x%05x] %s [%s]\n", bb.first, m_entry_info[bb.first / 4] ? (m_ret_info[bb.first / 4] ? "Chunk" : "Entry") : "Block", spu_block_hash{(hash_start & -65536) + bb.first / 4});
|
||||
|
||||
fmt::append(out, "\t F: 0x%05x\n", bb.second.func);
|
||||
|
||||
|
||||
@ -903,8 +903,14 @@ public:
|
||||
|
||||
if (auto [is_const, value] = try_get_const_equal_value_array<u32>(+op.ra); is_const)
|
||||
{
|
||||
if (value % 0x200 != 0)
|
||||
{
|
||||
// si10 is overwritten - likely an analysis mistake
|
||||
return;
|
||||
}
|
||||
|
||||
// Comment constant formation
|
||||
comment_constant(last_opcode, value | static_cast<u32>(op.si10));
|
||||
comment_constant(last_opcode, value | static_cast<u32>(op.si10), false);
|
||||
}
|
||||
}
|
||||
void ORHI(spu_opcode_t op)
|
||||
@ -941,8 +947,14 @@ public:
|
||||
|
||||
if (auto [is_const, value] = try_get_const_equal_value_array<u32>(op.ra); is_const)
|
||||
{
|
||||
if (value % 0x200 != 0)
|
||||
{
|
||||
// si10 is overwritten - likely an analysis mistake
|
||||
return;
|
||||
}
|
||||
|
||||
// Comment constant formation
|
||||
comment_constant(last_opcode, value + static_cast<u32>(op.si10));
|
||||
comment_constant(last_opcode, value + static_cast<u32>(op.si10), false);
|
||||
}
|
||||
}
|
||||
void AHI(spu_opcode_t op)
|
||||
@ -963,8 +975,14 @@ public:
|
||||
|
||||
if (auto [is_const, value] = try_get_const_equal_value_array<u32>(op.ra); is_const)
|
||||
{
|
||||
if (value % 0x200 != 0)
|
||||
{
|
||||
// si10 is overwritten - likely an analysis mistake
|
||||
return;
|
||||
}
|
||||
|
||||
// Comment constant formation
|
||||
comment_constant(last_opcode, value ^ static_cast<u32>(op.si10));
|
||||
comment_constant(last_opcode, value ^ static_cast<u32>(op.si10), false);
|
||||
}
|
||||
}
|
||||
void XORHI(spu_opcode_t op)
|
||||
|
||||
@ -2160,6 +2160,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (bb.preds.size() >= 2)
|
||||
{
|
||||
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
|
||||
{
|
||||
m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536) | (baddr >> 2)), spu_ptr(&spu_thread::block_hash));
|
||||
}
|
||||
}
|
||||
|
||||
// State check at the beginning of the chunk
|
||||
if (need_check || (bi == 0 && g_cfg.core.spu_block_size != spu_block_size_type::safe))
|
||||
{
|
||||
@ -2802,12 +2810,9 @@ public:
|
||||
std::string& llvm_log = function_log;
|
||||
raw_string_ostream out(llvm_log);
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
fmt::append(llvm_log, "LLVM IR at 0x%x:\n", func.entry_point);
|
||||
out << *_module; // print IR
|
||||
out << "\n\n";
|
||||
}
|
||||
fmt::append(llvm_log, "LLVM IR at 0x%x:\n", func.entry_point);
|
||||
out << *_module; // print IR
|
||||
out << "\n\n";
|
||||
|
||||
if (verifyModule(*_module, &out))
|
||||
{
|
||||
@ -3274,12 +3279,9 @@ public:
|
||||
std::string llvm_log;
|
||||
raw_string_ostream out(llvm_log);
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
fmt::append(llvm_log, "LLVM IR (interpreter):\n");
|
||||
out << *_module; // print IR
|
||||
out << "\n\n";
|
||||
}
|
||||
fmt::append(llvm_log, "LLVM IR (interpreter):\n");
|
||||
out << *_module; // print IR
|
||||
out << "\n\n";
|
||||
|
||||
if (verifyModule(*_module, &out))
|
||||
{
|
||||
@ -4757,6 +4759,50 @@ public:
|
||||
}
|
||||
|
||||
const auto a = get_vr<s32[4]>(op.ra);
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
// Use dot product instructions with special values to shift then sum results into the preferred slot
|
||||
if (m_use_dotprod)
|
||||
{
|
||||
if (match_vr<s32[4], s64[2]>(op.ra, [&](auto c, auto MP)
|
||||
{
|
||||
using VT = typename decltype(MP)::type;
|
||||
|
||||
if (auto [ok, x] = match_expr(c, sext<VT>(match<bool[std::extent_v<VT>]>())); ok)
|
||||
{
|
||||
const auto zeroes = splat<u32[4]>(0);
|
||||
|
||||
const auto es = zshuffle(bitcast<u8[16]>(a), 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 4, 8, 12);
|
||||
|
||||
set_vr(op.rt, sdot(zeroes, es, build<u8[16]>(
|
||||
-0x01, -0x02, -0x04, -0x08,
|
||||
-0x01, -0x02, -0x04, -0x08,
|
||||
-0x01, -0x02, -0x04, -0x08,
|
||||
-0x01, -0x02, -0x04, -0x08
|
||||
)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto zeroes = splat<u32[4]>(0);
|
||||
const auto masked = a & 0x01;
|
||||
|
||||
const auto es = zshuffle(bitcast<u8[16]>(masked), 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 4, 8, 12);
|
||||
|
||||
set_vr(op.rt, udot(zeroes, es, build<u8[16]>(
|
||||
0x01, 0x02, 0x04, 0x08,
|
||||
0x01, 0x02, 0x04, 0x08,
|
||||
0x01, 0x02, 0x04, 0x08,
|
||||
0x01, 0x02, 0x04, 0x08
|
||||
)));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto m = zext<u32>(bitcast<i4>(trunc<bool[4]>(a)));
|
||||
set_vr(op.rt, insert(splat<u32[4]>(0), 3, eval(m)));
|
||||
}
|
||||
@ -4772,6 +4818,54 @@ public:
|
||||
}
|
||||
|
||||
const auto a = get_vr<s16[8]>(op.ra);
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
// Use dot product instructions with special values to shift then sum results into the preferred slot
|
||||
if (m_use_dotprod)
|
||||
{
|
||||
if (match_vr<s16[8], s32[4], s64[2]>(op.ra, [&](auto c, auto MP)
|
||||
{
|
||||
using VT = typename decltype(MP)::type;
|
||||
|
||||
if (auto [ok, x] = match_expr(c, sext<VT>(match<bool[std::extent_v<VT>]>())); ok)
|
||||
{
|
||||
const auto zeroes = splat<u32[4]>(0);
|
||||
|
||||
const auto es = zshuffle(bitcast<u8[16]>(a), 16, 16, 16, 16, 16, 16, 16, 16, 0, 2, 4, 6, 8, 10, 12, 14);
|
||||
|
||||
const auto extracted = sdot(zeroes, es, build<u8[16]>(
|
||||
-0x01, -0x02, -0x04, -0x08,
|
||||
-0x10, -0x20, -0x40, -0x80,
|
||||
-0x01, -0x02, -0x04, -0x08,
|
||||
-0x10, -0x20, -0x40, -0x80
|
||||
));
|
||||
|
||||
set_vr(op.rt, addp(zeroes, bitcast<u32[4]>(extracted)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto zeroes = splat<u32[4]>(0);
|
||||
const auto masked = a & 0x01;
|
||||
|
||||
const auto es = zshuffle(bitcast<u8[16]>(masked), 16, 16, 16, 16, 16, 16, 16, 16, 0, 2, 4, 6, 8, 10, 12, 14);
|
||||
|
||||
const auto extracted = udot(zeroes, es, build<u8[16]>(
|
||||
0x01, 0x02, 0x04, 0x08,
|
||||
0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x04, 0x08,
|
||||
0x10, 0x20, 0x40, 0x80
|
||||
));
|
||||
|
||||
set_vr(op.rt, addp(zeroes, bitcast<u32[4]>(extracted)));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto m = zext<u32>(bitcast<u8>(trunc<bool[8]>(a)));
|
||||
set_vr(op.rt, insert(splat<u32[4]>(0), 3, eval(m)));
|
||||
}
|
||||
@ -4780,6 +4874,53 @@ public:
|
||||
{
|
||||
const auto a = get_vr<u8[16]>(op.ra);
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
// Use dot product instructions with special values to shift then sum results into the preferred slot
|
||||
if (m_use_dotprod)
|
||||
{
|
||||
if (match_vr<s8[16], s16[8], s32[4], s64[2]>(op.ra, [&](auto c, auto MP)
|
||||
{
|
||||
using VT = typename decltype(MP)::type;
|
||||
|
||||
if (auto [ok, x] = match_expr(c, sext<VT>(match<bool[std::extent_v<VT>]>())); ok)
|
||||
{
|
||||
const auto zeroes = splat<u32[4]>(0);
|
||||
|
||||
const auto extracted = sdot(zeroes, a, build<u8[16]>(
|
||||
-0x01, -0x02, -0x04, -0x08,
|
||||
-0x10, -0x20, -0x40, -0x80,
|
||||
-0x01, -0x02, -0x04, -0x08,
|
||||
-0x10, -0x20, -0x40, -0x80
|
||||
));
|
||||
|
||||
const auto es = zshuffle(bitcast<u8[16]>(extracted), 16, 16, 16, 16, 16, 16, 16, 16, 0, 8, 4, 12, 16, 16, 16, 16);
|
||||
const auto zeroes16 = splat<u16[8]>(0);
|
||||
set_vr(op.rt, addp(zeroes16, bitcast<u16[8]>(es)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto zeroes = splat<u32[4]>(0);
|
||||
const auto masked = a & 0x01;
|
||||
|
||||
const auto extracted = udot(zeroes, masked, build<u8[16]>(
|
||||
0x01, 0x02, 0x04, 0x08,
|
||||
0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x04, 0x08,
|
||||
0x10, 0x20, 0x40, 0x80
|
||||
));
|
||||
|
||||
const auto es = zshuffle(bitcast<u8[16]>(extracted), 16, 16, 16, 16, 16, 16, 16, 16, 0, 8, 4, 12, 16, 16, 16, 16);
|
||||
const auto zeroes16 = splat<u16[8]>(0);
|
||||
set_vr(op.rt, addp(zeroes16, bitcast<u16[8]>(es)));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_use_gfni)
|
||||
{
|
||||
const auto as = zshuffle(a, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8);
|
||||
@ -5311,13 +5452,24 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
if (m_use_dotprod)
|
||||
#else
|
||||
if (m_use_vnni)
|
||||
#endif
|
||||
{
|
||||
const auto [a, b] = get_vrs<u32[4]>(op.ra, op.rb);
|
||||
const auto zeroes = splat<u32[4]>(0);
|
||||
#ifdef ARCH_ARM64
|
||||
const auto [a, b] = get_vrs<u8[16]>(op.ra, op.rb);
|
||||
const auto ones = splat<u8[16]>(0x01);
|
||||
const auto ax = bitcast<u16[8]>(udot(zeroes, a, ones));
|
||||
const auto bx = bitcast<u16[8]>(udot(zeroes, b, ones));
|
||||
#else
|
||||
const auto [a, b] = get_vrs<u32[4]>(op.ra, op.rb);
|
||||
const auto ones = splat<u32[4]>(0x01010101);
|
||||
const auto ax = bitcast<u16[8]>(vpdpbusd(zeroes, a, ones));
|
||||
const auto bx = bitcast<u16[8]>(vpdpbusd(zeroes, b, ones));
|
||||
#endif
|
||||
set_vr(op.rt, shuffle2(ax, bx, 0, 8, 2, 10, 4, 12, 6, 14));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ void fmt_class_string<spu_block_hash>::format(std::string& out, u64 arg)
|
||||
out.resize(out.size() - 4);
|
||||
|
||||
// Print chunk address from lowest 16 bits
|
||||
fmt::append(out, "...chunk-0x%05x", (arg & 0xffff) * 4);
|
||||
fmt::append(out, "-0x%05x", (arg & 0xffff) * 4);
|
||||
}
|
||||
|
||||
enum class spu_block_hash_short : u64{};
|
||||
|
||||
@ -2219,6 +2219,28 @@ void lv2_obj::prepare_for_sleep(cpu_thread& cpu)
|
||||
cpu_counter::remove(&cpu);
|
||||
}
|
||||
|
||||
ppu_thread* lv2_obj::get_running_ppu(u32 index)
|
||||
{
|
||||
usz thread_count = g_cfg.core.ppu_threads;
|
||||
|
||||
if (index >= thread_count)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto target = atomic_storage<ppu_thread*>::load(g_ppu);
|
||||
|
||||
for (usz cur = 0; target; target = atomic_storage<ppu_thread*>::load(target->next_ppu), cur++)
|
||||
{
|
||||
if (cur == index)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void lv2_obj::notify_all() noexcept
|
||||
{
|
||||
for (auto cpu : g_to_notify)
|
||||
|
||||
@ -59,6 +59,7 @@ CellError lv2_cond::on_id_create()
|
||||
if (!mutex)
|
||||
{
|
||||
_mutex = static_cast<shared_ptr<lv2_obj>>(ensure(idm::get_unlocked<lv2_obj, lv2_mutex>(mtx_id)));
|
||||
mutex = static_cast<lv2_mutex*>(_mutex.get());
|
||||
}
|
||||
|
||||
// Defer function
|
||||
|
||||
@ -174,20 +174,28 @@ bool lv2_config_service_listener::check_service(const lv2_config_service& servic
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lv2_config_service_listener::notify(const shared_ptr<lv2_config_service_event>& event)
|
||||
{
|
||||
service_events.emplace_back(event);
|
||||
return event->notify();
|
||||
}
|
||||
|
||||
bool lv2_config_service_listener::notify(const shared_ptr<lv2_config_service>& service)
|
||||
{
|
||||
if (!check_service(*service))
|
||||
return false;
|
||||
{
|
||||
std::lock_guard lock(mutex_service_events);
|
||||
|
||||
// Create service event and notify queue!
|
||||
const auto event = lv2_config_service_event::create(handle, service, *this);
|
||||
return notify(event);
|
||||
if (!check_service(*service))
|
||||
return false;
|
||||
|
||||
// Create service event and notify queue!
|
||||
const auto event = lv2_config_service_event::create(handle, service, *this);
|
||||
service_events.emplace_back(event);
|
||||
|
||||
if (!event->notify())
|
||||
{
|
||||
// If we fail to deliver the event to the queue just clean the event up or it'll hold the listener alive forever
|
||||
g_fxo->get<lv2_config>().remove_service_event(event->id);
|
||||
service_events.pop_back();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void lv2_config_service_listener::notify_all()
|
||||
@ -267,7 +275,7 @@ void lv2_config_service_event::write(sys_config_service_event_t *dst) const
|
||||
{
|
||||
const auto registered = service->is_registered();
|
||||
|
||||
dst->service_listener_handle = listener.get_id();
|
||||
dst->service_listener_handle = listener_id;
|
||||
dst->registered = registered;
|
||||
dst->service_id = service->id;
|
||||
dst->user_id = service->user_id;
|
||||
@ -346,7 +354,7 @@ error_code sys_config_get_service_event(u32 config_hdl, u32 event_id, vm::ptr<sy
|
||||
|
||||
// Find service_event object
|
||||
const auto event = g_fxo->get<lv2_config>().find_event(event_id);
|
||||
if (!event)
|
||||
if (!event || event->handle != cfg)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
@ -296,11 +296,10 @@ private:
|
||||
|
||||
// The service listener owns the service events - service events will not be freed as long as their corresponding listener exists
|
||||
// This has been confirmed to be the case in realhw
|
||||
shared_mutex mutex_service_events;
|
||||
std::vector<shared_ptr<lv2_config_service_event>> service_events;
|
||||
shared_ptr<lv2_config_handle> handle;
|
||||
|
||||
bool notify(const shared_ptr<lv2_config_service_event>& event);
|
||||
|
||||
public:
|
||||
const sys_config_service_id service_id;
|
||||
const u64 min_verbosity;
|
||||
@ -370,14 +369,14 @@ public:
|
||||
// This has been confirmed to be the case in realhw
|
||||
const shared_ptr<lv2_config_handle> handle;
|
||||
const shared_ptr<lv2_config_service> service;
|
||||
const lv2_config_service_listener& listener;
|
||||
const u32 listener_id;
|
||||
|
||||
// Constructors (should not be used directly)
|
||||
lv2_config_service_event(shared_ptr<lv2_config_handle> _handle, shared_ptr<lv2_config_service> _service, const lv2_config_service_listener& _listener) noexcept
|
||||
: id(get_next_id())
|
||||
, handle(std::move(_handle))
|
||||
, service(std::move(_service))
|
||||
, listener(_listener)
|
||||
, listener_id(_listener.get_id())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ error_code sys_dbg_write_process_memory(s32 pid, u32 address, u32 size, vm::cptr
|
||||
i += op_size;
|
||||
}
|
||||
|
||||
if (!is_exec || i >= end)
|
||||
if ((!is_exec || i >= end) && exec_update_size > 0)
|
||||
{
|
||||
// Commit executable data update
|
||||
// The read memory is also super ptr so memmove can work correctly on all implementations
|
||||
|
||||
@ -170,8 +170,7 @@ CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_even
|
||||
{
|
||||
if (auto cpu = get_current_cpu_thread())
|
||||
{
|
||||
cpu->state += cpu_flag::again;
|
||||
cpu->state += cpu_flag::exit;
|
||||
cpu->state += cpu_flag::again + cpu_flag::exit;
|
||||
}
|
||||
|
||||
sys_event.warning("Ignored event!");
|
||||
@ -309,6 +308,15 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
for (auto cpu = head; cpu; cpu = cpu->get_next_cpu())
|
||||
{
|
||||
if (cpu->state & cpu_flag::again)
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
if (!queue.events.empty())
|
||||
{
|
||||
// Copy events for logging, does not empty
|
||||
@ -321,17 +329,6 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
|
||||
{
|
||||
qlock.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto cpu = head; cpu; cpu = cpu->get_next_cpu())
|
||||
{
|
||||
if (cpu->state & cpu_flag::again)
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
@ -621,7 +618,7 @@ error_code sys_event_port_create(cpu_thread& cpu, vm::ptr<u32> eport_id, s32 por
|
||||
|
||||
sys_event.warning("sys_event_port_create(eport_id=*0x%x, port_type=%d, name=0x%llx)", eport_id, port_type, name);
|
||||
|
||||
if (port_type != SYS_EVENT_PORT_LOCAL && port_type != 3)
|
||||
if (port_type != SYS_EVENT_PORT_LOCAL && port_type != SYS_EVENT_PORT_IPC)
|
||||
{
|
||||
sys_event.error("sys_event_port_create(): unknown port type (%d)", port_type);
|
||||
return CELL_EINVAL;
|
||||
@ -675,8 +672,9 @@ error_code sys_event_port_connect_local(cpu_thread& cpu, u32 eport_id, u32 equeu
|
||||
std::lock_guard lock(id_manager::g_mutex);
|
||||
|
||||
const auto port = idm::check_unlocked<lv2_obj, lv2_event_port>(eport_id);
|
||||
auto queue = idm::get_unlocked<lv2_obj, lv2_event_queue>(equeue_id);
|
||||
|
||||
if (!port || !idm::check_unlocked<lv2_obj, lv2_event_queue>(equeue_id))
|
||||
if (!port || !queue)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
@ -691,7 +689,7 @@ error_code sys_event_port_connect_local(cpu_thread& cpu, u32 eport_id, u32 equeu
|
||||
return CELL_EISCONN;
|
||||
}
|
||||
|
||||
port->queue = idm::get_unlocked<lv2_obj, lv2_event_queue>(equeue_id);
|
||||
port->queue = std::move(queue);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
#include <deque>
|
||||
|
||||
class cpu_thread;
|
||||
class spu_thrread;
|
||||
|
||||
// Event Queue Type
|
||||
enum : u32
|
||||
|
||||
@ -19,6 +19,22 @@ lv2_event_flag::lv2_event_flag(utils::serial& ar)
|
||||
ar(pattern);
|
||||
}
|
||||
|
||||
// Always set result
|
||||
struct sys_event_store_result
|
||||
{
|
||||
vm::ptr<u64> ptr;
|
||||
u64 val = 0;
|
||||
|
||||
~sys_event_store_result() noexcept
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
cpu_thread::get_current()->check_state();
|
||||
*ptr = val;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::function<void(void*)> lv2_event_flag::load(utils::serial& ar)
|
||||
{
|
||||
return load_func(make_shared<lv2_event_flag>(stx::exact_t<utils::serial&>(ar)));
|
||||
@ -120,21 +136,7 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
|
||||
ppu.gpr[5] = mode;
|
||||
ppu.gpr[6] = 0;
|
||||
|
||||
// Always set result
|
||||
struct store_result
|
||||
{
|
||||
vm::ptr<u64> ptr;
|
||||
u64 val = 0;
|
||||
|
||||
~store_result() noexcept
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
cpu_thread::get_current()->check_state();
|
||||
*ptr = val;
|
||||
}
|
||||
}
|
||||
} store{result};
|
||||
sys_event_store_result store{result};
|
||||
|
||||
if (!lv2_event_flag::check_mode(mode))
|
||||
{
|
||||
@ -273,21 +275,7 @@ error_code sys_event_flag_trywait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode,
|
||||
|
||||
sys_event_flag.trace("sys_event_flag_trywait(id=0x%x, bitptn=0x%llx, mode=0x%x, result=*0x%x)", id, bitptn, mode, result);
|
||||
|
||||
// Always set result
|
||||
struct store_result
|
||||
{
|
||||
vm::ptr<u64> ptr;
|
||||
u64 val = 0;
|
||||
|
||||
~store_result() noexcept
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
cpu_thread::get_current()->check_state();
|
||||
*ptr = val;
|
||||
}
|
||||
}
|
||||
} store{result};
|
||||
sys_event_store_result store{result};
|
||||
|
||||
if (!lv2_event_flag::check_mode(mode))
|
||||
{
|
||||
@ -556,8 +544,6 @@ error_code sys_event_flag_get(ppu_thread& ppu, u32 id, vm::ptr<u64> flags)
|
||||
return +flag.pattern;
|
||||
});
|
||||
|
||||
ppu.check_state();
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
if (flags) *flags = 0;
|
||||
@ -569,6 +555,8 @@ error_code sys_event_flag_get(ppu_thread& ppu, u32 id, vm::ptr<u64> flags)
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
ppu.check_state();
|
||||
|
||||
*flags = flag.ret;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -382,10 +382,12 @@ lv2_fs_object::lv2_fs_object(utils::serial& ar, bool)
|
||||
|
||||
u64 lv2_file::op_read(const fs::file& file, vm::ptr<void> buf, u64 size, u64 opt_pos)
|
||||
{
|
||||
if (u64 region = buf.addr() >> 28, region_end = (buf.addr() & 0xfff'ffff) + (size & 0xfff'ffff); region == region_end && ((region >> 28) == 0 || region >= 0xC))
|
||||
if (u64 region = buf.addr() >> 28, region_end = (buf.addr() + size) >> 28;
|
||||
size < u32{umax} && region == region_end && (region == 0 || region == 0xD) && vm::check_addr(buf.addr(), vm::page_writable, static_cast<u32>(size)))
|
||||
{
|
||||
// Optimize reads from safe memory
|
||||
return (opt_pos == umax ? file.read(buf.get_ptr(), size) : file.read_at(opt_pos, buf.get_ptr(), size));
|
||||
const auto buf_ptr = vm::get_super_ptr(buf.addr());
|
||||
return (opt_pos == umax ? file.read(buf_ptr, size) : file.read_at(opt_pos, buf_ptr, size));
|
||||
}
|
||||
|
||||
// Copy data from intermediate buffer (avoid passing vm pointer to a native API)
|
||||
@ -412,6 +414,14 @@ u64 lv2_file::op_read(const fs::file& file, vm::ptr<void> buf, u64 size, u64 opt
|
||||
|
||||
u64 lv2_file::op_write(const fs::file& file, vm::cptr<void> buf, u64 size)
|
||||
{
|
||||
if (u64 region = buf.addr() >> 28, region_end = (buf.addr() + size) >> 28;
|
||||
size < u32{umax} && region == region_end && (region == 0 || region == 0xD) && vm::check_addr(buf.addr(), vm::page_readable, static_cast<u32>(size)))
|
||||
{
|
||||
// Optimize writes from safe memory
|
||||
const auto buf_ptr = vm::get_super_ptr(buf.addr());
|
||||
return file.write(buf_ptr, size);
|
||||
}
|
||||
|
||||
// Copy data to intermediate buffer (avoid passing vm pointer to a native API)
|
||||
std::vector<uchar> local_buf(std::min<u64>(size, 65536));
|
||||
|
||||
@ -890,7 +900,7 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return {CELL_ENOENT};
|
||||
default: sys_fs.error("lv2_file::open(): unknown error %s", error);
|
||||
default: sys_fs.error("lv2_file::open(): unknown error %s", error); break;
|
||||
}
|
||||
|
||||
return {CELL_EIO};
|
||||
@ -1391,7 +1401,8 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
|
||||
// Add additional entries for split file candidates (while ends with .66600)
|
||||
while (mp.mp != &g_mp_sys_dev_hdd1 && data.back().name.ends_with(".66600"))
|
||||
{
|
||||
data.emplace_back(data.back()).name.resize(data.back().name.size() - 6);
|
||||
fs::dir_entry copy = data.back();
|
||||
data.emplace_back(copy).name.resize(copy.name.size() - 6);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2147,6 +2158,7 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
|
||||
sys_fs.notice("sys_fs_fcntl(0xc0000006): %s", vpath);
|
||||
|
||||
// Check only mountpoint
|
||||
vpath = vpath.substr(0, vpath.find_first_of('\0'));
|
||||
vpath = vpath.substr(0, vpath.find_first_of("/", 1));
|
||||
|
||||
// Some mountpoints seem to be handled specially
|
||||
@ -2635,8 +2647,6 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr
|
||||
|
||||
error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd)
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.trace("sys_fs_fdadasync(fd=%d)", fd);
|
||||
|
||||
const auto file = idm::get_unlocked<lv2_fs_object, lv2_file>(fd);
|
||||
@ -2661,8 +2671,6 @@ error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd)
|
||||
|
||||
error_code sys_fs_fsync(ppu_thread& ppu, u32 fd)
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.trace("sys_fs_fsync(fd=%d)", fd);
|
||||
|
||||
const auto file = idm::get_unlocked<lv2_fs_object, lv2_file>(fd);
|
||||
@ -2903,14 +2911,6 @@ error_code sys_fs_chmod(ppu_thread&, vm::cptr<char> path, s32 mode)
|
||||
{
|
||||
// Try to locate split files
|
||||
|
||||
for (u32 i = 66601; i <= 66699; i++)
|
||||
{
|
||||
if (mp != &g_mp_sys_dev_hdd1 && !fs::get_stat(fmt::format("%s.%u", local_path, i), info) && !info.is_directory)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fs::get_stat(local_path + ".66600", info) && !info.is_directory)
|
||||
{
|
||||
break;
|
||||
|
||||
@ -67,7 +67,6 @@ u32 sys_gamepad_ycon_is_gem(vm::ptr<u8> in, vm::ptr<u8> out)
|
||||
// syscall(621,packet_id,u8 *in,u8 *out) Talk:LV2_Functions_and_Syscalls#Syscall_621_.280x26D.29 gamepad_if usage
|
||||
u32 sys_gamepad_ycon_if(u8 packet_id, vm::ptr<u8> in, vm::ptr<u8> out)
|
||||
{
|
||||
|
||||
switch (packet_id)
|
||||
{
|
||||
case 0:
|
||||
|
||||
@ -487,6 +487,8 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
||||
{
|
||||
ensure(cond.unqueue(cond.sq, &ppu));
|
||||
ppu.state += cpu_flag::again;
|
||||
cond.lwmutex_waiters--;
|
||||
mutex->lwcond_waiters--;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,18 @@ LOG_CHANNEL(sys_memory);
|
||||
//
|
||||
static shared_mutex s_memstats_mtx;
|
||||
|
||||
// This struct is for reduced logging repetition
|
||||
struct last_reported_memory_stats
|
||||
{
|
||||
struct inner_body
|
||||
{
|
||||
u32 prev_total = umax;
|
||||
u32 prev_avail = umax;
|
||||
};
|
||||
|
||||
atomic_t<inner_body> body{};
|
||||
};
|
||||
|
||||
lv2_memory_container::lv2_memory_container(u32 size, bool from_idm) noexcept
|
||||
: size(size)
|
||||
, id{from_idm ? idm::last_id() : SYS_MEMORY_CONTAINER_ID_INVALID}
|
||||
@ -313,8 +325,6 @@ error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_i
|
||||
{
|
||||
cpu.state += cpu_flag::wait;
|
||||
|
||||
sys_memory.warning("sys_memory_get_user_memory_size(mem_info=*0x%x)", mem_info);
|
||||
|
||||
// Get "default" memory container
|
||||
auto& dct = g_fxo->get<lv2_memory_container>();
|
||||
|
||||
@ -332,6 +342,22 @@ error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_i
|
||||
});
|
||||
}
|
||||
|
||||
typename last_reported_memory_stats::inner_body now;
|
||||
now.prev_total = out.total_user_memory;
|
||||
now.prev_avail = out.available_user_memory;
|
||||
|
||||
now = g_fxo->get<last_reported_memory_stats>().body.exchange(now);
|
||||
|
||||
if (now.prev_total != out.total_user_memory || now.prev_avail != out.available_user_memory)
|
||||
{
|
||||
// Log on change
|
||||
sys_memory.warning("sys_memory_get_user_memory_size(mem_info=*0x%x): Avail=0x%x, Total=0x%x", mem_info, out.available_user_memory, out.total_user_memory);
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_memory.trace("sys_memory_get_user_memory_size(mem_info=*0x%x): Avail=0x%x, Total=0x%x", mem_info, out.available_user_memory, out.total_user_memory);
|
||||
}
|
||||
|
||||
cpu.check_state();
|
||||
*mem_info = out;
|
||||
return CELL_OK;
|
||||
|
||||
@ -333,7 +333,7 @@ error_code sys_mmapper_allocate_shared_memory_ext(ppu_thread& ppu, u64 ipc_key,
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & ~SYS_MEMORY_PAGE_SIZE_MASK)
|
||||
if (flags & ~SYS_MEMORY_GRANULARITY_MASK)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
@ -401,6 +401,11 @@ error_code sys_mmapper_allocate_shared_memory_from_container_ext(ppu_thread& ppu
|
||||
sys_mmapper.todo("sys_mmapper_allocate_shared_memory_from_container_ext(ipc_key=0x%x, size=0x%x, flags=0x%x, cid=0x%x, entries=*0x%x, entry_count=0x%x, mem_id=*0x%x)", ipc_key, size, flags, cid, entries,
|
||||
entry_count, mem_id);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
return CELL_EALIGN;
|
||||
}
|
||||
|
||||
switch (flags & SYS_MEMORY_PAGE_SIZE_MASK)
|
||||
{
|
||||
case SYS_MEMORY_PAGE_SIZE_1M:
|
||||
@ -546,8 +551,7 @@ error_code sys_mmapper_free_address(ppu_thread& ppu, u32 addr)
|
||||
|
||||
// If a memory block is freed, remove it from page notification table.
|
||||
auto& pf_entries = g_fxo->get<page_fault_notification_entries>();
|
||||
std::lock_guard lock(pf_entries.mutex);
|
||||
|
||||
std::unique_lock lock(pf_entries.mutex);
|
||||
auto ind_to_remove = pf_entries.entries.begin();
|
||||
for (; ind_to_remove != pf_entries.entries.end(); ++ind_to_remove)
|
||||
{
|
||||
@ -558,7 +562,11 @@ error_code sys_mmapper_free_address(ppu_thread& ppu, u32 addr)
|
||||
}
|
||||
if (ind_to_remove != pf_entries.entries.end())
|
||||
{
|
||||
u32 port_id = ind_to_remove->port_id;
|
||||
pf_entries.entries.erase(ind_to_remove);
|
||||
lock.unlock();
|
||||
sys_event_port_disconnect(ppu, port_id);
|
||||
sys_event_port_destroy(ppu, port_id);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -826,7 +834,6 @@ error_code sys_mmapper_enable_page_fault_notification(ppu_thread& ppu, u32 start
|
||||
|
||||
vm::var<u32> port_id(0);
|
||||
error_code res = sys_event_port_create(ppu, port_id, SYS_EVENT_PORT_LOCAL, SYS_MEMORY_PAGE_FAULT_EVENT_KEY);
|
||||
sys_event_port_connect_local(ppu, *port_id, event_queue_id);
|
||||
|
||||
if (res + 0u == CELL_EAGAIN)
|
||||
{
|
||||
@ -834,6 +841,8 @@ error_code sys_mmapper_enable_page_fault_notification(ppu_thread& ppu, u32 start
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
sys_event_port_connect_local(ppu, *port_id, event_queue_id);
|
||||
|
||||
auto& pf_entries = g_fxo->get<page_fault_notification_entries>();
|
||||
std::unique_lock lock(pf_entries.mutex);
|
||||
|
||||
|
||||
@ -85,7 +85,7 @@ error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_
|
||||
sys_mutex.todo("sys_mutex_create(): unexpected adaptive (0x%x)", _attr.adaptive);
|
||||
}
|
||||
|
||||
if (auto error = lv2_obj::create<lv2_mutex>(_attr.pshared, _attr.ipc_key, _attr.flags, [&]()
|
||||
if (auto error = lv2_obj::create<lv2_mutex>(_attr.pshared, ipc_key, _attr.flags, [&]()
|
||||
{
|
||||
return make_shared<lv2_mutex>(
|
||||
_attr.protocol,
|
||||
|
||||
@ -173,7 +173,11 @@ struct lv2_mutex final : lv2_obj
|
||||
|
||||
if (sq == data.sq)
|
||||
{
|
||||
atomic_storage<u32>::release(control.raw().owner, res->id);
|
||||
if (cpu_flag::again - res->state)
|
||||
{
|
||||
atomic_storage<u32>::release(control.raw().owner, res->id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -563,37 +563,34 @@ error_code sys_net_bnet_connect(ppu_thread& ppu, s32 s, vm::ptr<sys_net_sockaddr
|
||||
return not_an_error(result);
|
||||
}
|
||||
|
||||
if (!sock.ret)
|
||||
while (auto state = ppu.state.fetch_sub(cpu_flag::signal))
|
||||
{
|
||||
while (auto state = ppu.state.fetch_sub(cpu_flag::signal))
|
||||
if (is_stopped(state))
|
||||
{
|
||||
if (is_stopped(state))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (state & cpu_flag::signal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ppu.state.wait(state);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (ppu.gpr[3] == static_cast<u64>(-SYS_NET_EINTR))
|
||||
if (state & cpu_flag::signal)
|
||||
{
|
||||
return -SYS_NET_EINTR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (result < 0)
|
||||
{
|
||||
return sys_net_error{result};
|
||||
}
|
||||
ppu.state.wait(state);
|
||||
}
|
||||
|
||||
return not_an_error(result);
|
||||
if (ppu.gpr[3] == static_cast<u64>(-SYS_NET_EINTR))
|
||||
{
|
||||
return -SYS_NET_EINTR;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (result < 0)
|
||||
{
|
||||
return sys_net_error{result};
|
||||
}
|
||||
|
||||
return not_an_error(result);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -992,7 +989,7 @@ error_code sys_net_bnet_sendto(ppu_thread& ppu, s32 s, vm::cptr<void> buf, u32 l
|
||||
fmt::throw_exception("sys_net_bnet_sendto(s=%d): unknown flags (0x%x)", flags);
|
||||
}
|
||||
|
||||
if (addr && addrlen < 8)
|
||||
if (addr && addrlen < sizeof(sys_net_sockaddr))
|
||||
{
|
||||
sys_net.error("sys_net_bnet_sendto(s=%d): bad addrlen (%u)", s, addrlen);
|
||||
return -SYS_NET_EINVAL;
|
||||
@ -1295,7 +1292,7 @@ error_code sys_net_bnet_poll(ppu_thread& ppu, vm::ptr<sys_net_pollfd> fds, s32 n
|
||||
|
||||
if (auto sock = idm::check_unlocked<lv2_socket>(fds_buf[i].fd))
|
||||
{
|
||||
signaled += sock->poll(fds_buf[i], _fds[i]);
|
||||
sock->poll(fds_buf[i], _fds[i]);
|
||||
#ifdef _WIN32
|
||||
connecting[i] = sock->is_connecting();
|
||||
#endif
|
||||
@ -1303,7 +1300,6 @@ error_code sys_net_bnet_poll(ppu_thread& ppu, vm::ptr<sys_net_pollfd> fds, s32 n
|
||||
else
|
||||
{
|
||||
fds_buf[i].revents |= SYS_NET_POLLNVAL;
|
||||
signaled++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1536,9 +1532,9 @@ error_code sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptr<sys_net_fd_set
|
||||
for (s32 i = 0; i < nfds; i++)
|
||||
{
|
||||
bool sig = false;
|
||||
if (_fds[i].revents & (POLLIN | POLLHUP | POLLERR))
|
||||
if ((_fds[i].revents & (POLLIN | POLLHUP | POLLERR)) && _readfds.bit(i))
|
||||
sig = true, rread.set(i);
|
||||
if (_fds[i].revents & (POLLOUT | POLLERR))
|
||||
if ((_fds[i].revents & (POLLOUT | POLLERR)) && _writefds.bit(i))
|
||||
sig = true, rwrite.set(i);
|
||||
|
||||
if (sig)
|
||||
|
||||
@ -107,7 +107,7 @@ enum lv2_ip_option : s32
|
||||
SYS_NET_IP_MULTICAST_LOOP = 11,
|
||||
SYS_NET_IP_ADD_MEMBERSHIP = 12,
|
||||
SYS_NET_IP_DROP_MEMBERSHIP = 13,
|
||||
SYS_NET_IP_TTLCHK = 23,
|
||||
SYS_NET_IP_TTLCHK = 23, // This is probably the equivalent of IP_MINTTL on FreeBSD
|
||||
SYS_NET_IP_MAXTTL = 24,
|
||||
SYS_NET_IP_DONTFRAG = 26
|
||||
};
|
||||
|
||||
@ -104,7 +104,7 @@ public:
|
||||
virtual void close() = 0;
|
||||
virtual s32 shutdown(s32 how) = 0;
|
||||
|
||||
virtual s32 poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) = 0;
|
||||
virtual void poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) = 0;
|
||||
virtual std::tuple<bool, bool, bool> select(bs_t<poll_t> selected, pollfd& native_pfd) = 0;
|
||||
|
||||
error_code abort_socket(s32 flags);
|
||||
|
||||
@ -551,12 +551,14 @@ std::tuple<s32, lv2_socket::sockopt_data, u32> lv2_socket_native::getsockopt(s32
|
||||
}
|
||||
case SYS_NET_IP_TTLCHK:
|
||||
{
|
||||
sys_net.error("sys_net_bnet_getsockopt(IPPROTO_IP, SYS_NET_IP_TTLCHK): stubbed option");
|
||||
out_val._int = min_ttl;
|
||||
out_len = sizeof(s32);
|
||||
return {CELL_OK, out_val, out_len};
|
||||
}
|
||||
case SYS_NET_IP_MAXTTL:
|
||||
{
|
||||
sys_net.error("sys_net_bnet_getsockopt(IPPROTO_IP, SYS_NET_IP_MAXTTL): stubbed option");
|
||||
out_val._int = max_ttl;
|
||||
out_len = sizeof(s32);
|
||||
return {CELL_OK, out_val, out_len};
|
||||
}
|
||||
case SYS_NET_IP_DONTFRAG:
|
||||
@ -834,13 +836,13 @@ s32 lv2_socket_native::setsockopt(s32 level, s32 optname, const std::vector<u8>&
|
||||
}
|
||||
case SYS_NET_IP_TTLCHK:
|
||||
{
|
||||
sys_net.error("sys_net_bnet_setsockopt(s=%d, IPPROTO_IP): Stubbed option (0x%x) (SYS_NET_IP_TTLCHK)", lv2_id, optname);
|
||||
break;
|
||||
min_ttl = native_int;
|
||||
return {};
|
||||
}
|
||||
case SYS_NET_IP_MAXTTL:
|
||||
{
|
||||
sys_net.error("sys_net_bnet_setsockopt(s=%d, IPPROTO_IP): Stubbed option (0x%x) (SYS_NET_IP_MAXTTL)", lv2_id, optname);
|
||||
break;
|
||||
max_ttl = native_int;
|
||||
return {};
|
||||
}
|
||||
case SYS_NET_IP_DONTFRAG:
|
||||
{
|
||||
@ -910,7 +912,7 @@ std::optional<std::tuple<s32, std::vector<u8>, sys_net_sockaddr>> lv2_socket_nat
|
||||
{
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
const auto packet = dnshook.get_dns_packet(lv2_id);
|
||||
ensure(packet.size() < len);
|
||||
ensure(packet.size() <= len);
|
||||
memcpy(res_buf.data(), packet.data(), packet.size());
|
||||
native_addr.ss_family = AF_INET;
|
||||
(reinterpret_cast<::sockaddr_in*>(&native_addr))->sin_port = std::bit_cast<u16, be_t<u16>>(53); // htons(53)
|
||||
@ -1069,18 +1071,20 @@ std::optional<s32> lv2_socket_native::sendmsg(s32 flags, const sys_net_msghdr& m
|
||||
return {-SYS_NET_ECONNRESET};
|
||||
}
|
||||
|
||||
std::vector<u8> buf_copy;
|
||||
for (int i = 0; i < msg.msg_iovlen; i++)
|
||||
{
|
||||
auto iov_base = msg.msg_iov[i].iov_base;
|
||||
const u32 len = msg.msg_iov[i].iov_len;
|
||||
const std::vector<u8> buf_copy(vm::_ptr<const char>(iov_base.addr()), vm::_ptr<const char>(iov_base.addr()) + len);
|
||||
const auto* src = vm::_ptr<const char>(iov_base.addr());
|
||||
buf_copy.insert(buf_copy.end(), src, src + len);
|
||||
}
|
||||
|
||||
native_result = ::send(native_socket, reinterpret_cast<const char*>(buf_copy.data()), ::narrow<int>(buf_copy.size()), native_flags);
|
||||
native_result = ::send(native_socket, reinterpret_cast<const char*>(buf_copy.data()), ::narrow<int>(buf_copy.size()), native_flags);
|
||||
|
||||
if (native_result >= 0)
|
||||
{
|
||||
return {native_result};
|
||||
}
|
||||
if (native_result >= 0)
|
||||
{
|
||||
return {native_result};
|
||||
}
|
||||
|
||||
result = get_last_error(!so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0);
|
||||
@ -1143,14 +1147,14 @@ s32 lv2_socket_native::shutdown(s32 how)
|
||||
return -get_last_error(false);
|
||||
}
|
||||
|
||||
s32 lv2_socket_native::poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd)
|
||||
void lv2_socket_native::poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd)
|
||||
{
|
||||
// Check for fake packet for dns interceptions
|
||||
auto& dnshook = g_fxo->get<np::dnshook>();
|
||||
if (sn_pfd.events & SYS_NET_POLLIN && dnshook.is_dns(sn_pfd.fd) && dnshook.is_dns_queue(sn_pfd.fd))
|
||||
{
|
||||
sn_pfd.revents |= SYS_NET_POLLIN;
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
if (sn_pfd.events & ~(SYS_NET_POLLIN | SYS_NET_POLLOUT | SYS_NET_POLLERR))
|
||||
{
|
||||
@ -1167,8 +1171,6 @@ s32 lv2_socket_native::poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd)
|
||||
{
|
||||
native_pfd.events |= POLLOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, bool> lv2_socket_native::select(bs_t<lv2_socket::poll_t> selected, pollfd& native_pfd)
|
||||
@ -1232,16 +1234,16 @@ bool lv2_socket_native::is_socket_connected()
|
||||
return false;
|
||||
}
|
||||
|
||||
fd_set readfds, writefds;
|
||||
struct timeval timeout{0, 0}; // Zero timeout
|
||||
pollfd pfd{};
|
||||
pfd.fd = native_socket;
|
||||
pfd.events = POLLIN | POLLOUT;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(native_socket, &readfds);
|
||||
FD_SET(native_socket, &writefds);
|
||||
|
||||
// Use select to check for readability and writability
|
||||
const int result = ::select(1, &readfds, &writefds, NULL, &timeout);
|
||||
// Use poll to check for readability and writability
|
||||
#ifdef _WIN32
|
||||
const int result = WSAPoll(&pfd, 1, 0);
|
||||
#else
|
||||
const int result = ::poll(&pfd, 1, 0);
|
||||
#endif
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
@ -1250,5 +1252,5 @@ bool lv2_socket_native::is_socket_connected()
|
||||
}
|
||||
|
||||
// Socket is connected if it's readable or writable
|
||||
return FD_ISSET(native_socket, &readfds) || FD_ISSET(native_socket, &writefds);
|
||||
return (pfd.revents & (POLLIN | POLLOUT)) != 0;
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ public:
|
||||
std::optional<s32> sendto(s32 flags, const std::vector<u8>& buf, std::optional<sys_net_sockaddr> opt_sn_addr, bool is_lock = true) override;
|
||||
std::optional<s32> sendmsg(s32 flags, const sys_net_msghdr& msg, bool is_lock = true) override;
|
||||
|
||||
s32 poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) override;
|
||||
void poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) override;
|
||||
std::tuple<bool, bool, bool> select(bs_t<poll_t> selected, pollfd& native_pfd) override;
|
||||
|
||||
bool is_socket_connected();
|
||||
@ -70,6 +70,10 @@ private:
|
||||
s32 so_reuseaddr = 0;
|
||||
s32 so_reuseport = 0;
|
||||
#endif
|
||||
// Those values come from FreeBSD
|
||||
s32 min_ttl = 1;
|
||||
s32 max_ttl = 64;
|
||||
|
||||
u16 bound_port = 0;
|
||||
bool feign_tcp_conn_failure = false; // Savestate load related
|
||||
};
|
||||
|
||||
@ -364,7 +364,7 @@ s32 lv2_socket_p2p::shutdown([[maybe_unused]] s32 how)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 lv2_socket_p2p::poll(sys_net_pollfd& sn_pfd, [[maybe_unused]] pollfd& native_pfd)
|
||||
void lv2_socket_p2p::poll(sys_net_pollfd& sn_pfd, [[maybe_unused]] pollfd& native_pfd)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
ensure(vport);
|
||||
@ -381,8 +381,6 @@ s32 lv2_socket_p2p::poll(sys_net_pollfd& sn_pfd, [[maybe_unused]] pollfd& native
|
||||
{
|
||||
sn_pfd.revents |= SYS_NET_POLLOUT;
|
||||
}
|
||||
|
||||
return sn_pfd.revents ? 1 : 0;
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, bool> lv2_socket_p2p::select(bs_t<lv2_socket::poll_t> selected, [[maybe_unused]] pollfd& native_pfd)
|
||||
|
||||
@ -30,7 +30,7 @@ public:
|
||||
void close() override;
|
||||
s32 shutdown(s32 how) override;
|
||||
|
||||
s32 poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) override;
|
||||
void poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) override;
|
||||
std::tuple<bool, bool, bool> select(bs_t<poll_t> selected, pollfd& native_pfd) override;
|
||||
|
||||
void handle_new_data(sys_net_sockaddr_in_p2p p2p_addr, std::vector<u8> p2p_data);
|
||||
|
||||
@ -112,7 +112,6 @@ public:
|
||||
|
||||
// reply is late, increases rtt
|
||||
auto& msg = it->second;
|
||||
const auto addr = msg.dst_addr.sin_addr.s_addr;
|
||||
rtt_info rtt = rtts[msg.sock_id];
|
||||
// Only increases rtt once per loop(in case a big number of packets are sent at once)
|
||||
if (!rtt_increased.count(msg.sock_id))
|
||||
@ -120,7 +119,7 @@ public:
|
||||
rtt.num_retries += 1;
|
||||
// Increases current rtt by 10%
|
||||
rtt.rtt_time += (rtt.rtt_time / 10);
|
||||
rtts[addr] = rtt;
|
||||
rtts[msg.sock_id] = rtt;
|
||||
|
||||
rtt_increased.emplace(msg.sock_id);
|
||||
}
|
||||
@ -625,7 +624,7 @@ std::tuple<bool, s32, shared_ptr<lv2_socket>, sys_net_sockaddr> lv2_socket_p2ps:
|
||||
sys_net_sockaddr ps3_addr{};
|
||||
auto* paddr = reinterpret_cast<sys_net_sockaddr_in_p2p*>(&ps3_addr);
|
||||
|
||||
lv2_socket_p2ps* sock_client = reinterpret_cast<lv2_socket_p2ps*>(idm::check_unlocked<lv2_socket>(p2ps_client));
|
||||
auto sock_client = static_cast<shared_ptr<lv2_socket_p2ps>>(idm::get_unlocked<lv2_socket>(p2ps_client));
|
||||
{
|
||||
std::lock_guard lock(sock_client->mutex);
|
||||
paddr->sin_family = SYS_NET_AF_INET;
|
||||
@ -986,7 +985,7 @@ s32 lv2_socket_p2ps::shutdown([[maybe_unused]] s32 how)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 lv2_socket_p2ps::poll(sys_net_pollfd& sn_pfd, [[maybe_unused]] pollfd& native_pfd)
|
||||
void lv2_socket_p2ps::poll(sys_net_pollfd& sn_pfd, [[maybe_unused]] pollfd& native_pfd)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
sys_net.trace("[P2PS] poll checking for 0x%X", sn_pfd.events);
|
||||
@ -1003,14 +1002,7 @@ s32 lv2_socket_p2ps::poll(sys_net_pollfd& sn_pfd, [[maybe_unused]] pollfd& nativ
|
||||
{
|
||||
sn_pfd.revents |= SYS_NET_POLLOUT;
|
||||
}
|
||||
|
||||
if (sn_pfd.revents)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, bool> lv2_socket_p2ps::select(bs_t<lv2_socket::poll_t> selected, [[maybe_unused]] pollfd& native_pfd)
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
void close() override;
|
||||
s32 shutdown(s32 how) override;
|
||||
|
||||
s32 poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) override;
|
||||
void poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) override;
|
||||
std::tuple<bool, bool, bool> select(bs_t<poll_t> selected, pollfd& native_pfd) override;
|
||||
|
||||
private:
|
||||
|
||||
@ -134,10 +134,9 @@ s32 lv2_socket_raw::shutdown([[maybe_unused]] s32 how)
|
||||
return {};
|
||||
}
|
||||
|
||||
s32 lv2_socket_raw::poll([[maybe_unused]] sys_net_pollfd& sn_pfd, [[maybe_unused]] pollfd& native_pfd)
|
||||
void lv2_socket_raw::poll([[maybe_unused]] sys_net_pollfd& sn_pfd, [[maybe_unused]] pollfd& native_pfd)
|
||||
{
|
||||
LOG_ONCE(raw_poll, "lv2_socket_raw::poll");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, bool> lv2_socket_raw::select([[maybe_unused]] bs_t<lv2_socket::poll_t> selected, [[maybe_unused]] pollfd& native_pfd)
|
||||
|
||||
@ -32,6 +32,6 @@ public:
|
||||
void close() override;
|
||||
s32 shutdown(s32 how) override;
|
||||
|
||||
s32 poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) override;
|
||||
void poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) override;
|
||||
std::tuple<bool, bool, bool> select(bs_t<poll_t> selected, pollfd& native_pfd) override;
|
||||
};
|
||||
|
||||
@ -249,8 +249,9 @@ bool nt_p2p_port::recv_data()
|
||||
|
||||
auto& bound_sockets = ::at32(bound_p2p_vports, dst_vport);
|
||||
|
||||
for (const auto sock_id : bound_sockets)
|
||||
for (auto it = bound_sockets.begin(); it != bound_sockets.end();)
|
||||
{
|
||||
s32 sock_id = *it;
|
||||
const auto sock = idm::check<lv2_socket>(sock_id, [&](lv2_socket& sock)
|
||||
{
|
||||
ensure(sock.get_type() == SYS_NET_SOCK_DGRAM_P2P);
|
||||
@ -262,12 +263,17 @@ bool nt_p2p_port::recv_data()
|
||||
if (!sock)
|
||||
{
|
||||
sys_net.error("Socket %d found in bound_p2p_vports didn't exist!", sock_id);
|
||||
bound_sockets.erase(sock_id);
|
||||
it = bound_sockets.erase(it);
|
||||
if (bound_sockets.empty())
|
||||
{
|
||||
bound_p2p_vports.erase(dst_vport);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -305,6 +305,7 @@ error_code sys_ppu_thread_detach(ppu_thread& ppu, u32 thread_id)
|
||||
{
|
||||
// Join and notify thread (it is detached from IDM now so it must be done explicitly now)
|
||||
*ptr = thread_state::finished;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@ -64,7 +64,7 @@ extern const std::map<std::string_view, int> g_prx_list
|
||||
{ "libddpdec.sprx", 0 },
|
||||
{ "libdivxdec.sprx", 0 },
|
||||
{ "libdmux.sprx", 0 },
|
||||
{ "libdmuxpamf.sprx", 0 },
|
||||
{ "libdmuxpamf.sprx", 1 },
|
||||
{ "libdtslbrdec.sprx", 0 },
|
||||
{ "libfiber.sprx", 0 },
|
||||
{ "libfont.sprx", 0 },
|
||||
@ -899,7 +899,7 @@ error_code _sys_prx_register_library(ppu_thread& ppu, vm::ptr<void> library)
|
||||
{
|
||||
for (u32 lib_addr = prx.exports_start, index = 0; lib_addr < prx.exports_end; index++, lib_addr += vm::read8(lib_addr) ? vm::read8(lib_addr) : sizeof_lib)
|
||||
{
|
||||
if (std::memcpy(vm::base(lib_addr), mem_copy.data(), sizeof_lib) == 0)
|
||||
if (std::memcmp(vm::base(lib_addr), mem_copy.data(), sizeof_lib) == 0)
|
||||
{
|
||||
atomic_storage<char>::release(prx.m_external_loaded_flags[index], true);
|
||||
return true;
|
||||
|
||||
@ -46,14 +46,14 @@ namespace rsxaudio_ringbuf_reader
|
||||
static void set_timestamp(rsxaudio_shmem::ringbuf_t& ring_buf, u64 timestamp)
|
||||
{
|
||||
const s32 entry_idx_raw = (ring_buf.read_idx + ring_buf.rw_max_idx - (ring_buf.rw_max_idx > 2) - 1) % ring_buf.rw_max_idx;
|
||||
const s32 entry_idx = std::clamp<s32>(entry_idx_raw, 0, SYS_RSXAUDIO_RINGBUF_SZ);
|
||||
const s32 entry_idx = std::clamp<s32>(entry_idx_raw, 0, SYS_RSXAUDIO_RINGBUF_SZ - 1);
|
||||
|
||||
ring_buf.entries[entry_idx].timestamp = convert_to_timebased_time(timestamp);
|
||||
}
|
||||
|
||||
static std::tuple<bool /*notify*/, u64 /*blk_idx*/, u64 /*timestamp*/> update_status(rsxaudio_shmem::ringbuf_t& ring_buf)
|
||||
{
|
||||
const s32 read_idx = std::clamp<s32>(ring_buf.read_idx, 0, SYS_RSXAUDIO_RINGBUF_SZ);
|
||||
const s32 read_idx = std::clamp<s32>(ring_buf.read_idx, 0, SYS_RSXAUDIO_RINGBUF_SZ - 1);
|
||||
|
||||
if ((ring_buf.entries[read_idx].valid & 1) == 0U)
|
||||
{
|
||||
@ -61,7 +61,7 @@ namespace rsxaudio_ringbuf_reader
|
||||
}
|
||||
|
||||
const s32 entry_idx_raw = (ring_buf.read_idx + ring_buf.rw_max_idx - (ring_buf.rw_max_idx > 2)) % ring_buf.rw_max_idx;
|
||||
const s32 entry_idx = std::clamp<s32>(entry_idx_raw, 0, SYS_RSXAUDIO_RINGBUF_SZ);
|
||||
const s32 entry_idx = std::clamp<s32>(entry_idx_raw, 0, SYS_RSXAUDIO_RINGBUF_SZ - 1);
|
||||
|
||||
ring_buf.entries[read_idx].valid = 0;
|
||||
ring_buf.queue_notify_idx = (ring_buf.queue_notify_idx + 1) % ring_buf.queue_notify_step;
|
||||
@ -72,7 +72,7 @@ namespace rsxaudio_ringbuf_reader
|
||||
|
||||
static std::pair<bool /*entry_valid*/, u32 /*addr*/> get_addr(const rsxaudio_shmem::ringbuf_t& ring_buf)
|
||||
{
|
||||
const s32 read_idx = std::clamp<s32>(ring_buf.read_idx, 0, SYS_RSXAUDIO_RINGBUF_SZ);
|
||||
const s32 read_idx = std::clamp<s32>(ring_buf.read_idx, 0, SYS_RSXAUDIO_RINGBUF_SZ - 1);
|
||||
|
||||
if (ring_buf.entries[read_idx].valid & 1)
|
||||
{
|
||||
@ -1392,9 +1392,9 @@ void rsxaudio_backend_thread::operator()()
|
||||
return;
|
||||
}
|
||||
|
||||
static rsxaudio_state ra_state{};
|
||||
static emu_audio_cfg emu_cfg{};
|
||||
static bool backend_failed = false;
|
||||
rsxaudio_state ra_state{};
|
||||
emu_audio_cfg emu_cfg{};
|
||||
bool backend_failed = false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@ -2018,7 +2018,7 @@ void rsxaudio_periodic_tmr::cancel_timer_unlocked()
|
||||
{
|
||||
const u64 flag = 1;
|
||||
const auto wr_res = write(cancel_event, &flag, sizeof(flag));
|
||||
ensure(wr_res == sizeof(flag) || wr_res == -EAGAIN);
|
||||
ensure(wr_res == sizeof(flag) || errno == EAGAIN);
|
||||
}
|
||||
#elif defined(BSD) || defined(__APPLE__)
|
||||
handle[TIMER_ID].flags = (handle[TIMER_ID].flags & ~EV_ENABLE) | EV_DISABLE;
|
||||
|
||||
@ -441,6 +441,8 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
continue;
|
||||
}
|
||||
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
std::lock_guard lock(rwlock->mutex);
|
||||
|
||||
if (!rwlock->unqueue(rwlock->wq, &ppu))
|
||||
|
||||
@ -72,7 +72,7 @@ error_code sys_semaphore_create(ppu_thread& ppu, vm::ptr<u32> sem_id, vm::ptr<sy
|
||||
return error;
|
||||
}
|
||||
|
||||
static_cast<void>(ppu.test_stopped());
|
||||
ppu.check_state();
|
||||
|
||||
*sem_id = idm::last_id();
|
||||
return CELL_OK;
|
||||
@ -358,7 +358,7 @@ error_code sys_semaphore_get_value(ppu_thread& ppu, u32 sem_id, vm::ptr<s32> cou
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
static_cast<void>(ppu.test_stopped());
|
||||
ppu.check_state();
|
||||
|
||||
*count = sema.ret;
|
||||
return CELL_OK;
|
||||
|
||||
@ -437,7 +437,7 @@ struct spu_limits_t
|
||||
raw_spu_count += spu_thread::g_raw_spu_ctr;
|
||||
|
||||
// physical_spus_count >= spu_limit returns EBUSY, not EINVAL!
|
||||
if (spu_limit + raw_limit > 6 || raw_spu_count > raw_limit || physical_spus_count >= spu_limit || physical_spus_count > spu_limit || controllable_spu_count > spu_limit)
|
||||
if (spu_limit + raw_limit > 6 || raw_spu_count > raw_limit || physical_spus_count >= spu_limit || controllable_spu_count > spu_limit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ struct lv2_update_manager
|
||||
|
||||
// For example, 4.90 should be converted to 0x4900000000000
|
||||
std::erase(version_str, '.');
|
||||
if (std::from_chars(version_str.data(), version_str.data() + version_str.size(), system_sw_version, 16).ec != std::errc{})
|
||||
if (std::from_chars(version_str.data(), version_str.data() + version_str.size(), system_sw_version, 16).ec == std::errc{})
|
||||
system_sw_version <<= 40;
|
||||
else
|
||||
system_sw_version = 0;
|
||||
@ -79,6 +79,7 @@ struct lv2_update_manager
|
||||
|
||||
if (malloc_set.count(addr))
|
||||
{
|
||||
malloc_set.erase(addr);
|
||||
return vm::dealloc(addr, vm::main);
|
||||
}
|
||||
|
||||
|
||||
@ -453,6 +453,7 @@ public:
|
||||
|
||||
// Can be called before the actual sleep call in order to move it out of mutex scope
|
||||
static void prepare_for_sleep(cpu_thread& cpu);
|
||||
static ppu_thread* get_running_ppu(u32 index);
|
||||
|
||||
struct notify_all_t
|
||||
{
|
||||
|
||||
@ -118,6 +118,7 @@ static int clock_gettime(int clk_id, struct timespec* tp)
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <exception>
|
||||
#include <sys/time.h>
|
||||
|
||||
static struct timespec start_time = []()
|
||||
|
||||
@ -1531,9 +1531,11 @@ private:
|
||||
}
|
||||
}();
|
||||
|
||||
if (sce_idx == umax)
|
||||
return PS3AV_STATUS_INVALID_VIDEO_PARAM;
|
||||
|
||||
const video_sce_param &sce_param = sce_param_arr[sce_idx];
|
||||
if (sce_idx == umax ||
|
||||
video_head_cfg.video_head > PS3AV_HEAD_B_ANALOG ||
|
||||
if (video_head_cfg.video_head > PS3AV_HEAD_B_ANALOG ||
|
||||
video_head_cfg.video_order > 1 ||
|
||||
video_head_cfg.video_format > 16 ||
|
||||
video_head_cfg.video_out_format > 16 ||
|
||||
|
||||
@ -1173,11 +1173,15 @@ error_code sys_usbd_get_device_list(ppu_thread& ppu, u32 handle, vm::ptr<UsbInte
|
||||
return CELL_EINVAL;
|
||||
|
||||
// TODO: was std::min<s32>
|
||||
u32 i_tocopy = std::min<u32>(max_devices, ::size32(usbh.handled_devices));
|
||||
const u32 i_tocopy = std::min<u32>(max_devices, ::size32(usbh.handled_devices));
|
||||
u32 index = 0;
|
||||
|
||||
for (u32 index = 0; index < i_tocopy; index++)
|
||||
for (const auto& [_, device] : usbh.handled_devices)
|
||||
{
|
||||
device_list[index] = usbh.handled_devices[index].first;
|
||||
if (index == i_tocopy)
|
||||
break;
|
||||
|
||||
device_list[index++] = device.first;
|
||||
}
|
||||
|
||||
return not_an_error(i_tocopy);
|
||||
@ -1409,7 +1413,7 @@ error_code sys_usbd_receive_event(ppu_thread& ppu, u32 handle, vm::ptr<u64> arg1
|
||||
|
||||
if (is_stopped(state))
|
||||
{
|
||||
std::lock_guard lock(usbh.mutex);
|
||||
std::lock_guard lock(usbh.mutex_sq);
|
||||
|
||||
for (auto cpu = +usbh.sq; cpu; cpu = cpu->next_cpu)
|
||||
{
|
||||
@ -1587,7 +1591,7 @@ error_code sys_usbd_get_transfer_status(ppu_thread& ppu, u32 handle, u32 id_tran
|
||||
|
||||
std::lock_guard lock(usbh.mutex);
|
||||
|
||||
if (!usbh.is_init)
|
||||
if (!usbh.is_init || id_transfer >= MAX_SYS_USBD_TRANSFERS)
|
||||
return CELL_EINVAL;
|
||||
|
||||
const auto status = usbh.get_transfer_status(id_transfer);
|
||||
@ -1607,7 +1611,7 @@ error_code sys_usbd_get_isochronous_transfer_status(ppu_thread& ppu, u32 handle,
|
||||
|
||||
std::lock_guard lock(usbh.mutex);
|
||||
|
||||
if (!usbh.is_init)
|
||||
if (!usbh.is_init || id_transfer >= MAX_SYS_USBD_TRANSFERS)
|
||||
return CELL_EINVAL;
|
||||
|
||||
const auto status = usbh.get_isochronous_transfer_status(id_transfer);
|
||||
|
||||
@ -97,7 +97,7 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64
|
||||
// Look for unmapped space
|
||||
if (const auto area = vm::find_map(0x10000000, 0x10000000, 2 | (flag & SYS_MEMORY_PAGE_SIZE_MASK)))
|
||||
{
|
||||
sys_vm.warning("sys_vm_memory_map(): Found VM 0x%x area (vsize=0x%x)", addr, vsize);
|
||||
sys_vm.warning("sys_vm_memory_map(): Found VM 0x%x area (vsize=0x%x)", area->addr, vsize);
|
||||
|
||||
// Alloc all memory (shall not fail)
|
||||
ensure(area->alloc(static_cast<u32>(vsize)));
|
||||
|
||||
@ -8,6 +8,7 @@ struct GameInfo
|
||||
std::string path;
|
||||
std::string icon_path;
|
||||
std::string movie_path;
|
||||
std::string audio_path;
|
||||
|
||||
std::string name;
|
||||
std::string serial;
|
||||
|
||||
@ -945,17 +945,6 @@ static u8 sdl_to_logitech_g27_pedal(std::map<u64, std::vector<SDL_Joystick*>>& j
|
||||
return unsigned_avg * 0xFF / 0xFFFF;
|
||||
}
|
||||
|
||||
static inline void set_bit(u8* buf, int bit_num, bool set)
|
||||
{
|
||||
const int byte_num = bit_num / 8;
|
||||
bit_num %= 8;
|
||||
const u8 mask = 1 << bit_num;
|
||||
if (set)
|
||||
buf[byte_num] = buf[byte_num] | mask;
|
||||
else
|
||||
buf[byte_num] = buf[byte_num] & (~mask);
|
||||
}
|
||||
|
||||
void usb_device_logitech_g27::transfer_dfex(u32 buf_size, u8* buf, UsbTransfer* transfer)
|
||||
{
|
||||
DFEX_data data{};
|
||||
|
||||
@ -38,10 +38,7 @@ struct logitech_g27_ffb_slot
|
||||
logitech_g27_ffb_state state = logitech_g27_ffb_state::inactive;
|
||||
u64 last_update = 0;
|
||||
SDL_HapticEffect last_effect {};
|
||||
|
||||
// TODO switch to SDL_HapticEffectID when it becomes available in a future SDL release
|
||||
// Match the return of SDL_CreateHapticEffect for now
|
||||
int effect_id = -1;
|
||||
SDL_HapticEffectID effect_id = -1;
|
||||
};
|
||||
|
||||
struct sdl_mapping
|
||||
|
||||
@ -24,13 +24,11 @@ std::set<u32> PadHandlerBase::narrow_set(const std::set<u64>& src)
|
||||
return dst;
|
||||
}
|
||||
|
||||
// Get new multiplied value based on the multiplier
|
||||
s32 PadHandlerBase::MultipliedInput(s32 raw_value, s32 multiplier)
|
||||
{
|
||||
return (multiplier * raw_value) / 100;
|
||||
}
|
||||
|
||||
// Get new scaled value between 0 and range based on its minimum and maximum
|
||||
f32 PadHandlerBase::ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range)
|
||||
{
|
||||
if (deadzone > 0 && deadzone > minimum)
|
||||
@ -46,7 +44,6 @@ f32 PadHandlerBase::ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 dea
|
||||
return range * val;
|
||||
}
|
||||
|
||||
// Get new scaled value between -range and range based on its minimum and maximum
|
||||
f32 PadHandlerBase::ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range)
|
||||
{
|
||||
// convert [min, max] to [0, 1]
|
||||
@ -79,7 +76,6 @@ f32 PadHandlerBase::ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32
|
||||
return (2.0f * range * val) - range;
|
||||
}
|
||||
|
||||
// Get normalized trigger value based on the range defined by a threshold
|
||||
u16 PadHandlerBase::NormalizeTriggerInput(u16 value, u32 threshold) const
|
||||
{
|
||||
if (value <= threshold || threshold >= trigger_max)
|
||||
@ -90,8 +86,6 @@ u16 PadHandlerBase::NormalizeTriggerInput(u16 value, u32 threshold) const
|
||||
return static_cast<u16>(ScaledInput(static_cast<f32>(value), static_cast<f32>(trigger_min), static_cast<f32>(trigger_max), static_cast<f32>(threshold)));
|
||||
}
|
||||
|
||||
// normalizes a directed input, meaning it will correspond to a single "button" and not an axis with two directions
|
||||
// the input values must lie in 0+
|
||||
u16 PadHandlerBase::NormalizeDirectedInput(s32 raw_value, s32 threshold, s32 maximum) const
|
||||
{
|
||||
if (threshold >= maximum || maximum <= 0 || raw_value < 0)
|
||||
@ -114,9 +108,6 @@ u16 PadHandlerBase::NormalizeStickInput(u16 raw_value, s32 threshold, s32 multip
|
||||
return static_cast<u16>(ScaledInput(static_cast<f32>(scaled_value), 0.0f, static_cast<f32>(thumb_max), static_cast<f32>(threshold)));
|
||||
}
|
||||
|
||||
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13% (default of anti deadzone)
|
||||
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
|
||||
// return is new x and y values in 0-255 range
|
||||
std::tuple<u16, u16> PadHandlerBase::NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone, u32 anti_deadzone) const
|
||||
{
|
||||
f32 X = inX / 255.0f;
|
||||
@ -150,28 +141,21 @@ std::tuple<u16, u16> PadHandlerBase::NormalizeStickDeadzone(s32 inX, s32 inY, u3
|
||||
return std::tuple<u16, u16>(ConvertAxis(X), ConvertAxis(Y));
|
||||
}
|
||||
|
||||
// get clamped value between 0 and 255
|
||||
u16 PadHandlerBase::Clamp0To255(f32 input)
|
||||
{
|
||||
return static_cast<u16>(std::clamp(input, 0.0f, 255.0f));
|
||||
}
|
||||
|
||||
// get clamped value between 0 and 1023
|
||||
u16 PadHandlerBase::Clamp0To1023(f32 input)
|
||||
{
|
||||
return static_cast<u16>(std::clamp(input, 0.0f, 1023.0f));
|
||||
}
|
||||
|
||||
// input has to be [-1,1]. result will be [0,255]
|
||||
u16 PadHandlerBase::ConvertAxis(f32 value)
|
||||
{
|
||||
return static_cast<u16>((value + 1.0) * (255.0 / 2.0));
|
||||
}
|
||||
|
||||
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
|
||||
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
|
||||
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of ~4000
|
||||
// This function assumes inX and inY is already in 0-255
|
||||
void PadHandlerBase::ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor)
|
||||
{
|
||||
if (!squircle_factor)
|
||||
|
||||
@ -274,7 +274,7 @@ protected:
|
||||
// the input values must lie in 0+
|
||||
u16 NormalizeDirectedInput(s32 raw_value, s32 threshold, s32 maximum) const;
|
||||
|
||||
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13%
|
||||
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13% (default of anti deadzone)
|
||||
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
|
||||
// return is new x and y values in 0-255 range
|
||||
std::tuple<u16, u16> NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone, u32 anti_deadzone) const;
|
||||
@ -284,10 +284,10 @@ public:
|
||||
// Get new multiplied value based on the multiplier
|
||||
static s32 MultipliedInput(s32 raw_value, s32 multiplier);
|
||||
|
||||
// Get new scaled value between 0 and 255 based on its minimum and maximum
|
||||
// Get new scaled value between 0 and range based on its minimum and maximum
|
||||
static f32 ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f);
|
||||
|
||||
// Get new scaled value between -255 and 255 based on its minimum and maximum
|
||||
// Get new scaled value between -range and range based on its minimum and maximum
|
||||
static f32 ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f);
|
||||
|
||||
// get clamped value between 0 and 255
|
||||
@ -301,7 +301,7 @@ public:
|
||||
|
||||
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
|
||||
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
|
||||
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
|
||||
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of ~4000
|
||||
// This function assumes inX and inY is already in 0-255
|
||||
static void ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor);
|
||||
|
||||
|
||||
@ -24,34 +24,34 @@ void ps_move_data::reset_sensors()
|
||||
angaccel_world = {};
|
||||
}
|
||||
|
||||
ps_move_data::vect<3> ps_move_data::rotate_vector(const vect<4>& q, const vect<3>& v)
|
||||
{
|
||||
const auto cross = [](const vect<3>& a, const vect<3>& b)
|
||||
{
|
||||
return vect<3>({
|
||||
a.y() * b.z() - a.z() * b.y(),
|
||||
a.z() * b.x() - a.x() * b.z(),
|
||||
a.x() * b.y() - a.y() * b.x()
|
||||
});
|
||||
};
|
||||
|
||||
// q = (x, y, z, w)
|
||||
const vect<3> q_vec({q.x(), q.y(), q.z()});
|
||||
|
||||
// t = 2 * cross(q_vec, v)
|
||||
const vect<3> t = cross(q_vec, v) * 2.0f;
|
||||
|
||||
// v' = v + w * t + cross(q_vec, t)
|
||||
const vect<3> v_prime = v + t * q.w() + cross(q_vec, t);
|
||||
|
||||
return v_prime;
|
||||
}
|
||||
|
||||
void ps_move_data::update_orientation(f32 delta_time)
|
||||
{
|
||||
if (!delta_time)
|
||||
return;
|
||||
|
||||
// Rotate vector v by quaternion q
|
||||
const auto rotate_vector = [](const vect<4>& q, const vect<3>& v)
|
||||
{
|
||||
const vect<4> qv({0.0f, v.x(), v.y(), v.z()});
|
||||
const vect<4> q_inv({q.w(), -q.x(), -q.y(), -q.z()});
|
||||
|
||||
// t = q * v
|
||||
vect<4> t;
|
||||
t.w() = -q.x() * qv.x() - q.y() * qv.y() - q.z() * qv.z();
|
||||
t.x() = q.w() * qv.x() + q.y() * qv.z() - q.z() * qv.y();
|
||||
t.y() = q.w() * qv.y() - q.x() * qv.z() + q.z() * qv.x();
|
||||
t.z() = q.w() * qv.z() + q.x() * qv.y() - q.y() * qv.x();
|
||||
|
||||
// r = t * q_inv
|
||||
vect<4> r;
|
||||
r.w() = -t.x() * q_inv.x() - t.y() * q_inv.y() - t.z() * q_inv.z();
|
||||
r.x() = t.w() * q_inv.x() + t.y() * q_inv.z() - t.z() * q_inv.y();
|
||||
r.y() = t.w() * q_inv.y() - t.x() * q_inv.z() + t.z() * q_inv.x();
|
||||
r.z() = t.w() * q_inv.z() + t.x() * q_inv.y() - t.y() * q_inv.x();
|
||||
|
||||
return vect<3>({r.x(), r.y(), r.z()});
|
||||
};
|
||||
|
||||
if constexpr (use_imu_for_velocity)
|
||||
{
|
||||
// Gravity in world frame
|
||||
|
||||
@ -15,6 +15,26 @@ struct ps_move_data
|
||||
template <typename I>
|
||||
const T& operator[](I i) const { return data[i]; }
|
||||
|
||||
vect<Size, T> operator*(f32 s) const
|
||||
{
|
||||
vect<Size, T> result = *this;
|
||||
for (int i = 0; i < Size; ++i)
|
||||
{
|
||||
result[i] *= s;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vect<Size, T> operator+(const vect<Size, T>& other) const
|
||||
{
|
||||
vect<Size, T> result = *this;
|
||||
for (int i = 0; i < Size; ++i)
|
||||
{
|
||||
result[i] += other[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
T x() const requires (Size >= 1) { return data[0]; }
|
||||
T y() const requires (Size >= 2) { return data[1]; }
|
||||
T z() const requires (Size >= 3) { return data[2]; }
|
||||
@ -72,4 +92,7 @@ struct ps_move_data
|
||||
void reset_sensors();
|
||||
void update_orientation(f32 delta_time);
|
||||
void update_velocity(u64 timestamp, be_t<f32> pos_world[4]);
|
||||
|
||||
// Rotate vector v by quaternion q
|
||||
static vect<3> rotate_vector(const vect<4>& q, const vect<3>& v);
|
||||
};
|
||||
|
||||
@ -128,12 +128,6 @@ void fmt_class_string<clan::ClanRequestAction>::format(std::string& out, u64 arg
|
||||
|
||||
namespace clan
|
||||
{
|
||||
struct curl_memory
|
||||
{
|
||||
char* response;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
size_t clans_client::curl_write_callback(void* data, size_t size, size_t nmemb, void* clientp)
|
||||
{
|
||||
const size_t realsize = size * nmemb;
|
||||
@ -464,7 +458,7 @@ namespace clan
|
||||
clan.append_child("ticket").text().set(ticket.c_str());
|
||||
clan.append_child("id").text().set(clan_id);
|
||||
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np_id.handle.data);
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np::npid_to_string(np_id));
|
||||
clan.append_child("jid").text().set(jid_str.c_str());
|
||||
|
||||
pugi::xml_document response = pugi::xml_document();
|
||||
@ -656,7 +650,7 @@ namespace clan
|
||||
clan.append_child("ticket").text().set(ticket.c_str());
|
||||
clan.append_child("id").text().set(clan_id);
|
||||
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np_id.handle.data);
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np::npid_to_string(np_id));
|
||||
clan.append_child("jid").text().set(jid_str.c_str());
|
||||
|
||||
pugi::xml_document response = pugi::xml_document();
|
||||
@ -674,7 +668,7 @@ namespace clan
|
||||
clan.append_child("ticket").text().set(ticket.c_str());
|
||||
clan.append_child("id").text().set(clan_id);
|
||||
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np_id.handle.data);
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np::npid_to_string(np_id));
|
||||
clan.append_child("jid").text().set(jid_str.c_str());
|
||||
|
||||
pugi::xml_document response = pugi::xml_document();
|
||||
@ -832,7 +826,7 @@ namespace clan
|
||||
clan.append_child("ticket").text().set(ticket.c_str());
|
||||
clan.append_child("id").text().set(clan_id);
|
||||
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np_id.handle.data);
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np::npid_to_string(np_id));
|
||||
clan.append_child("jid").text().set(jid_str.c_str());
|
||||
|
||||
pugi::xml_document response = pugi::xml_document();
|
||||
@ -850,7 +844,7 @@ namespace clan
|
||||
clan.append_child("ticket").text().set(ticket.c_str());
|
||||
clan.append_child("id").text().set(clan_id);
|
||||
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np_id.handle.data);
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np::npid_to_string(np_id));
|
||||
clan.append_child("jid").text().set(jid_str.c_str());
|
||||
|
||||
pugi::xml_document response = pugi::xml_document();
|
||||
@ -868,7 +862,7 @@ namespace clan
|
||||
clan.append_child("ticket").text().set(ticket.c_str());
|
||||
clan.append_child("id").text().set(clan_id);
|
||||
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np_id.handle.data);
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np::npid_to_string(np_id));
|
||||
clan.append_child("jid").text().set(jid_str.c_str());
|
||||
|
||||
pugi::xml_document response = pugi::xml_document();
|
||||
@ -902,7 +896,7 @@ namespace clan
|
||||
clan.append_child("id").text().set(clan_id);
|
||||
|
||||
pugi::xml_node role = clan.append_child("onlinename");
|
||||
role.text().set(nph.get_npid().handle.data);
|
||||
role.text().set(np::npid_to_string(nph.get_npid()).c_str());
|
||||
|
||||
pugi::xml_node description = clan.append_child("description");
|
||||
description.text().set(info.description);
|
||||
@ -990,7 +984,7 @@ namespace clan
|
||||
clan.append_child("ticket").text().set(ticket.c_str());
|
||||
clan.append_child("id").text().set(clan_id);
|
||||
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np_id.handle.data);
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np::npid_to_string(np_id));
|
||||
clan.append_child("jid").text().set(jid_str.c_str());
|
||||
|
||||
pugi::xml_document response = pugi::xml_document();
|
||||
@ -1008,7 +1002,7 @@ namespace clan
|
||||
clan.append_child("ticket").text().set(ticket.c_str());
|
||||
clan.append_child("id").text().set(clan_id);
|
||||
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np_id.handle.data);
|
||||
const std::string jid_str = fmt::format(JID_FORMAT, np::npid_to_string(np_id));
|
||||
clan.append_child("jid").text().set(jid_str.c_str());
|
||||
|
||||
pugi::xml_node role_node = clan.append_child("role");
|
||||
|
||||
@ -377,7 +377,7 @@ namespace np
|
||||
|
||||
if (!rooms.contains(room_id))
|
||||
{
|
||||
np_cache.error("np_cache::get_memberid cache miss room_id: room_id(%d)/npid(%s)", room_id, static_cast<const char*>(npid.handle.data));
|
||||
np_cache.error("np_cache::get_memberid cache miss room_id: room_id(%d)/npid(%s)", room_id, np::npid_to_string(npid));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@ -389,7 +389,7 @@ namespace np
|
||||
return id;
|
||||
}
|
||||
|
||||
np_cache.error("np_cache::get_memberid cache miss member_id: room_id(%d)/npid(%s)", room_id, static_cast<const char*>(npid.handle.data));
|
||||
np_cache.error("np_cache::get_memberid cache miss member_id: room_id(%d)/npid(%s)", room_id, np::npid_to_string(npid));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user