mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 03:25:16 +00:00
Compare commits
85 commits
Author | SHA1 | Date | |
---|---|---|---|
|
8437a5f5ac | ||
|
564c903fbd | ||
|
268de3cd24 | ||
|
d20f48f876 | ||
|
88e2a3761c | ||
|
e136c2eadf | ||
|
b2b50f5e82 | ||
|
26a7e9653f | ||
|
76948b6364 | ||
|
0f57624a61 | ||
|
8aaf2f8577 | ||
|
8ce8410a5b | ||
|
a0ce9e52fa | ||
|
53288309a5 | ||
|
275f7e15c0 | ||
|
7de2869a53 | ||
|
ab7a1a6ec4 | ||
|
b8d1d7cdf1 | ||
|
8b2b74c34b | ||
|
a004ebfffb | ||
|
b51d6e9d92 | ||
|
b96e41285c | ||
|
9295e6f5c8 | ||
|
e80809f629 | ||
|
5ac4db752d | ||
|
746b438500 | ||
|
0964c0356b | ||
|
7500d16524 | ||
|
b3bdff741c | ||
|
fcb6bc70f8 | ||
|
9c5b3a2300 | ||
|
2d7ffaf07f | ||
|
9b7d5cd1a9 | ||
|
bcb5041df2 | ||
|
235707278f | ||
|
db85595124 | ||
|
15758171f0 | ||
|
d08610882a | ||
|
21434c471b | ||
|
87d8bebd0d | ||
|
e4d84e2c1c | ||
|
16036e0419 | ||
|
58714d8c68 | ||
|
ddf684c4d2 | ||
|
daa76be77e | ||
|
600e460416 | ||
|
e095904e1b | ||
|
599d5c17a0 | ||
|
6f98b8c5ae | ||
|
eb2eb9ccf5 | ||
|
19d01835d3 | ||
|
f38a61bdb3 | ||
|
ed280cdbfe | ||
|
66909168ac | ||
|
38a1c8becb | ||
|
1816a1eb34 | ||
|
dad9a2b916 | ||
|
b3bbd939e3 | ||
|
cc84ebf8c2 | ||
|
2438e975e7 | ||
|
04d833d3e6 | ||
|
2f872b3755 | ||
|
bd1f5ff194 | ||
|
613212f9e1 | ||
|
4aff4a9c82 | ||
|
264af550d5 | ||
|
822546bf7d | ||
|
2ac2439c33 | ||
|
37dbd77628 | ||
|
733ceada5e | ||
|
847f92956f | ||
|
73f2aaf9d8 | ||
|
c86a250795 | ||
|
c6170aa4c7 | ||
|
89ae495c36 | ||
|
5526c33d69 | ||
|
e816636676 | ||
|
40e8bc530c | ||
|
9684467dc0 | ||
|
8e83fd7d50 | ||
|
fac1cc57d7 | ||
|
6511e0f3e6 | ||
|
9c1c932e68 | ||
|
82c85c1a9c | ||
|
7cec2d0e18 |
174 changed files with 4401 additions and 18125 deletions
|
@ -72,13 +72,13 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
|
|||
git clone https://github.com/engnr/qt-downloader.git
|
||||
cd qt-downloader
|
||||
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
|
||||
# nested Qt 6.8.3 URL workaround
|
||||
# nested Qt 6.9.0 URL workaround
|
||||
# sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
|
||||
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
|
||||
cd "/tmp/Qt"
|
||||
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
|
||||
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
|
||||
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.3 workaround
|
||||
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.9.0 workaround
|
||||
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
|
||||
fi
|
||||
|
||||
|
@ -145,6 +145,8 @@ export MACOSX_DEPLOYMENT_TARGET=14.0
|
|||
-DCMAKE_SYSTEM_PROCESSOR=arm64 \
|
||||
-DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \
|
||||
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" \
|
||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||
-DCMAKE_OSX_SYSROOT="$(xcrun --sdk macosx --show-sdk-path)" \
|
||||
-G Ninja
|
||||
|
||||
"$BREW_PATH/bin/ninja"; build_status=$?;
|
||||
|
|
|
@ -39,13 +39,13 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
|
|||
git clone https://github.com/engnr/qt-downloader.git
|
||||
cd qt-downloader
|
||||
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
|
||||
# nested Qt 6.8.3 URL workaround
|
||||
# nested Qt 6.9.0 URL workaround
|
||||
# sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
|
||||
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
|
||||
cd "/tmp/Qt"
|
||||
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
|
||||
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
|
||||
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.3 workaround
|
||||
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.9.0 workaround
|
||||
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
|
||||
fi
|
||||
|
||||
|
@ -108,6 +108,8 @@ export MACOSX_DEPLOYMENT_TARGET=14.0
|
|||
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
|
||||
-DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
|
||||
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" \
|
||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||
-DCMAKE_OSX_SYSROOT="$(xcrun --sdk macosx --show-sdk-path)" \
|
||||
-G Ninja
|
||||
|
||||
"$BREW_PATH/bin/ninja"; build_status=$?;
|
||||
|
|
|
@ -25,11 +25,20 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
|||
# Remove libvulkan because it causes issues with gamescope
|
||||
rm -f ./AppDir/usr/lib/libvulkan.so*
|
||||
|
||||
# Remove unused Qt6 libraries
|
||||
rm -f ./AppDir/usr/lib/libQt6OpenGL.so*
|
||||
rm -f ./AppDir/usr/lib/libQt6Qml*.so*
|
||||
rm -f ./AppDir/usr/lib/libQt6Quick.so*
|
||||
rm -f ./AppDir/usr/lib/libQt6VirtualKeyboard.so*
|
||||
rm -f ./AppDir/usr/plugins/platforminputcontexts/libqtvirtualkeyboardplugin.so*
|
||||
|
||||
# Remove git directory containing local commit history file
|
||||
rm -rf ./AppDir/usr/share/rpcs3/git
|
||||
|
||||
linuxdeploy --appimage-extract
|
||||
./squashfs-root/plugins/linuxdeploy-plugin-appimage/usr/bin/appimagetool AppDir -g
|
||||
curl -fsSLo /uruntime "https://github.com/VHSgunzo/uruntime/releases/download/v0.3.4/uruntime-appimage-dwarfs-$CPU_ARCH"
|
||||
chmod +x /uruntime
|
||||
/uruntime --appimage-mkdwarfs -f --set-owner 0 --set-group 0 --no-history --no-create-timestamp \
|
||||
--compression zstd:level=22 -S26 -B32 --header /uruntime -i AppDir -o RPCS3.AppImage
|
||||
|
||||
APPIMAGE_SUFFIX="linux_${CPU_ARCH}"
|
||||
if [ "$CPU_ARCH" = "x86_64" ]; then
|
||||
|
|
|
@ -8,7 +8,6 @@ ARTIFACT_DIR="$BUILD_ARTIFACTSTAGINGDIRECTORY"
|
|||
|
||||
# Remove unecessary files
|
||||
rm -f ./bin/rpcs3.exp ./bin/rpcs3.lib ./bin/rpcs3.pdb ./bin/vc_redist.x64.exe
|
||||
rm -rf ./bin/git
|
||||
|
||||
# Prepare compatibility and SDL database for packaging
|
||||
mkdir ./bin/config
|
||||
|
|
|
@ -22,7 +22,7 @@ QT_SVG_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtsvg${QT_SUFFIX}"
|
|||
LLVMLIBS_URL="https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-${LLVM_VER}/llvmlibs_mt.7z"
|
||||
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z'
|
||||
VULKAN_SDK_URL="https://www.dropbox.com/scl/fi/sjjh0fc4ld281pjbl2xzu/VulkanSDK-${VULKAN_VER}-Installer.exe?rlkey=f6wzc0lvms5vwkt2z3qabfv9d&dl=1"
|
||||
CCACHE_URL="https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-windows-x86_64.zip"
|
||||
CCACHE_URL="https://github.com/ccache/ccache/releases/download/v4.11.2/ccache-4.11.2-windows-x86_64.zip"
|
||||
|
||||
DEP_URLS=" \
|
||||
$QT_BASE_URL \
|
||||
|
|
|
@ -7,7 +7,7 @@ env:
|
|||
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
|
||||
RPCS3_TOKEN: ENCRYPTED[100ebb8e3552bf2021d0ef55dccda3e58d27be5b6cab0b0b92843ef490195d3c4edaefa087e4a3b425caa6392300b9b1]
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.8.3'
|
||||
QT_VER: '6.9.0'
|
||||
LLVM_COMPILER_VER: '19'
|
||||
LLVM_VER: '19.1.7'
|
||||
|
||||
|
@ -23,7 +23,7 @@ env:
|
|||
# COMPILER: msvc
|
||||
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
|
||||
# QT_VER_MSVC: 'msvc2022'
|
||||
# QT_DATE: '202503201308'
|
||||
# QT_DATE: '202503301022'
|
||||
# QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
|
||||
# VULKAN_VER: '1.3.268.0'
|
||||
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
||||
|
@ -58,7 +58,7 @@ env:
|
|||
|
||||
# linux_task:
|
||||
# container:
|
||||
# image: rpcs3/rpcs3-ci-jammy:1.2
|
||||
# image: rpcs3/rpcs3-ci-jammy:1.5
|
||||
# cpu: 4
|
||||
# memory: 16G
|
||||
# env:
|
||||
|
@ -134,7 +134,7 @@ freebsd_task:
|
|||
# matrix:
|
||||
# - name: Cirrus Linux AArch64 Clang
|
||||
# arm_container:
|
||||
# image: 'docker.io/rpcs3/rpcs3-ci-jammy-aarch64:1.2'
|
||||
# image: 'docker.io/rpcs3/rpcs3-ci-jammy-aarch64:1.5'
|
||||
# cpu: 8
|
||||
# memory: 8G
|
||||
# clang_script:
|
||||
|
|
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
|
@ -16,4 +16,4 @@ Submitting your test results for Commercial Games must be done on our forums. Pl
|
|||
|
||||
# Contributing
|
||||
|
||||
Check the [Coding Style Guidelines](https://github.com/RPCS3/rpcs3/wiki/Coding-Style) and [Developer Information](https://github.com/RPCS3/rpcs3/wiki/Developer-Information). If you have any questions, hit us up on our [Discord Server](https://discord.me/RPCS3) in the **#development** channel.
|
||||
Check the [Coding Style Guidelines](https://github.com/RPCS3/rpcs3/wiki/Coding-Style) and [Developer Information](https://github.com/RPCS3/rpcs3/wiki/Developer-Information). If you have any questions, hit us up on our [Discord Server](https://discord.gg/rpcs3) in the **#development** channel.
|
||||
|
|
|
@ -7,7 +7,7 @@ body:
|
|||
attributes:
|
||||
value: |
|
||||
# Summary
|
||||
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
|
||||
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.gg/rpcs3) or [forums](https://forums.rpcs3.net/) instead.
|
||||
- type: textarea
|
||||
id: quick-summary
|
||||
attributes:
|
||||
|
@ -50,7 +50,7 @@ body:
|
|||
* Completely close RPCS3 and locate the log file.
|
||||
|
||||
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
|
||||
* On Windows it will be in the RPCS3 directory near the executable
|
||||
* On Windows it will be in the ```log``` folder inside your RPCS3 folder.
|
||||
* On Linux it will be in ```~/.cache/rpcs3/```
|
||||
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
|
||||
- type: textarea
|
||||
|
|
4
.github/ISSUE_TEMPLATE/2-bug-report.yml
vendored
4
.github/ISSUE_TEMPLATE/2-bug-report.yml
vendored
|
@ -7,7 +7,7 @@ body:
|
|||
attributes:
|
||||
value: |
|
||||
# Summary
|
||||
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
|
||||
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.gg/rpcs3) or [forums](https://forums.rpcs3.net/) instead.
|
||||
- type: textarea
|
||||
id: quick-summary
|
||||
attributes:
|
||||
|
@ -36,7 +36,7 @@ body:
|
|||
* Completely close RPCS3 and locate the log file.
|
||||
|
||||
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
|
||||
* On Windows it will be in the RPCS3 directory near the executable
|
||||
* On Windows it will be in the ```log``` folder inside your RPCS3 folder.
|
||||
* On Linux it will be in ```~/.cache/rpcs3/```
|
||||
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
|
||||
- type: textarea
|
||||
|
|
4
.github/ISSUE_TEMPLATE/3-feature-request.yml
vendored
4
.github/ISSUE_TEMPLATE/3-feature-request.yml
vendored
|
@ -6,7 +6,7 @@ body:
|
|||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
|
||||
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.gg/rpcs3) or [forums](https://forums.rpcs3.net/) instead.
|
||||
- type: textarea
|
||||
id: quick-summary
|
||||
attributes:
|
||||
|
@ -31,6 +31,6 @@ body:
|
|||
* If this feature is something that a game is trying to use, upload a log file for it.
|
||||
|
||||
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
|
||||
* On Windows it will be in the RPCS3 directory near the executable
|
||||
* On Windows it will be in the ```log``` folder inside your RPCS3 folder.
|
||||
* On Linux it will be in ```~/.cache/rpcs3/```
|
||||
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
|
||||
|
|
2
.github/ISSUE_TEMPLATE/4-advanced.md
vendored
2
.github/ISSUE_TEMPLATE/4-advanced.md
vendored
|
@ -7,7 +7,7 @@ assignees: ''
|
|||
|
||||
---
|
||||
|
||||
## Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
|
||||
## Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.gg/rpcs3) or [forums](https://forums.rpcs3.net/) instead.
|
||||
|
||||
You're using the advanced template. You're expected to know what to write in order to fill in all the required information for proper report.
|
||||
|
||||
|
|
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -4,7 +4,7 @@ contact_links:
|
|||
url: https://rpcs3.net/quickstart
|
||||
about: Everything you need to know to install and configure emulator, and add games
|
||||
- name: Ask for help
|
||||
url: https://discord.me/RPCS3
|
||||
url: https://discord.gg/rpcs3
|
||||
about: If you have some questions or need help, please use our Discord server instead of GitHub
|
||||
- name: Report game compatibility
|
||||
url: https://forums.rpcs3.net/thread-196671.html
|
||||
|
|
18
.github/PR-BUILD.md
vendored
18
.github/PR-BUILD.md
vendored
|
@ -1,18 +0,0 @@
|
|||
## How to test a PR build
|
||||
|
||||
Please take into account, that RPCS3 build usually takes some time (about 15 mins), so you can't access a build if a PR was just submitted.
|
||||
|
||||
- Open a PR you want to test
|
||||
- Scroll to the very bottom and locate the **Checks** section
|
||||
- Click on **Show all checks**
|
||||
You are supposed to see something like this
|
||||

|
||||
- Click on __Details__ on either **Cirrus Linux GCC** or **Cirrus Windows**
|
||||
- Click **View more details on Cirrus CI** at the very bottom
|
||||

|
||||
- Click on the download button for **Artifact** on the **Artifacts** block
|
||||

|
||||
|
||||
- Congratulations! You are now downloading an RPCS3 build for that specific PR.
|
||||
|
||||
__Please note that PR builds are not supposed to be stable because they contain new changesets.__
|
3
.github/PULL_REQUEST_TEMPLATE/1-default.md
vendored
3
.github/PULL_REQUEST_TEMPLATE/1-default.md
vendored
|
@ -1,3 +0,0 @@
|
|||
<!-- Please include a summary of the change and which issue is fixed. -->
|
||||
|
||||
[How to test this PR](.github/PR-BUILD.md)
|
12
.github/workflows/rpcs3.yml
vendored
12
.github/workflows/rpcs3.yml
vendored
|
@ -25,17 +25,17 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- os: ubuntu-24.04
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.3"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.5"
|
||||
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.3"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.5"
|
||||
build_sh: "/rpcs3/.ci/build-linux.sh"
|
||||
compiler: gcc
|
||||
- os: ubuntu-24.04-arm
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.3"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.5"
|
||||
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
|
||||
compiler: clang
|
||||
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
|
||||
|
@ -105,13 +105,13 @@ jobs:
|
|||
env:
|
||||
COMPILER: msvc
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.8.3'
|
||||
QT_VER: '6.9.0'
|
||||
QT_VER_MSVC: 'msvc2022'
|
||||
QT_DATE: '202503201308'
|
||||
QT_DATE: '202503301022'
|
||||
LLVM_VER: '19.1.7'
|
||||
VULKAN_VER: '1.3.268.0'
|
||||
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
||||
CCACHE_SHA: '6252f081876a9a9f700fae13a5aec5d0d486b28261d7f1f72ac11c7ad9df4da9'
|
||||
CCACHE_SHA: '1f39f3ad5aae3fe915e99ad1302633bc8f6718e58fa7c0de2b0ba7e080f0f08c'
|
||||
CCACHE_BIN_DIR: 'C:\ccache_bin'
|
||||
CCACHE_DIR: 'C:\ccache'
|
||||
CCACHE_INODECACHE: 'true'
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -55,9 +55,6 @@
|
|||
/bin/GuiConfigs/*.dat
|
||||
/bin/GuiConfigs/*.dat.*
|
||||
|
||||
# Some data from git
|
||||
!/bin/git/
|
||||
|
||||
# Visual Studio Files
|
||||
.vs/*
|
||||
.vscode/*
|
||||
|
|
2
3rdparty/FAudio
vendored
2
3rdparty/FAudio
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 486e33eef3f282e4ce3d29f32ded3e67bacdbe5c
|
||||
Subproject commit 091c6b4693ce507ac48037836a5a884e35cd2860
|
51
3rdparty/GL/glext.h
vendored
51
3rdparty/GL/glext.h
vendored
|
@ -32,7 +32,7 @@ extern "C" {
|
|||
#define GLAPI extern
|
||||
#endif
|
||||
|
||||
#define GL_GLEXT_VERSION 20220530
|
||||
#define GL_GLEXT_VERSION 20250203
|
||||
|
||||
#include <KHR/khrplatform.h>
|
||||
|
||||
|
@ -5397,12 +5397,12 @@ typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severi
|
|||
typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
|
||||
typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);
|
||||
typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam);
|
||||
typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufSize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
|
||||
typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufSize, GLenum *categories, GLenum *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
|
||||
GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);
|
||||
GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam);
|
||||
GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufSize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
|
||||
GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufSize, GLenum *categories, GLenum *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
|
||||
#endif
|
||||
#endif /* GL_AMD_debug_output */
|
||||
|
||||
|
@ -7370,6 +7370,16 @@ GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1,
|
|||
#endif
|
||||
#endif /* GL_EXT_framebuffer_blit */
|
||||
|
||||
#ifndef GL_EXT_framebuffer_blit_layers
|
||||
#define GL_EXT_framebuffer_blit_layers 1
|
||||
typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERLAYERSEXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERLAYEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint srcLayer, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLint dstLayer, GLbitfield mask, GLenum filter);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBlitFramebufferLayersEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
GLAPI void APIENTRY glBlitFramebufferLayerEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint srcLayer, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLint dstLayer, GLbitfield mask, GLenum filter);
|
||||
#endif
|
||||
#endif /* GL_EXT_framebuffer_blit_layers */
|
||||
|
||||
#ifndef GL_EXT_framebuffer_multisample
|
||||
#define GL_EXT_framebuffer_multisample 1
|
||||
#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
|
||||
|
@ -9394,6 +9404,11 @@ GLAPI void APIENTRY glResizeBuffersMESA (void);
|
|||
#define GL_MESA_shader_integer_functions 1
|
||||
#endif /* GL_MESA_shader_integer_functions */
|
||||
|
||||
#ifndef GL_MESA_texture_const_bandwidth
|
||||
#define GL_MESA_texture_const_bandwidth 1
|
||||
#define GL_CONST_BW_TILING_MESA 0x8BBE
|
||||
#endif /* GL_MESA_texture_const_bandwidth */
|
||||
|
||||
#ifndef GL_MESA_tile_raster_order
|
||||
#define GL_MESA_tile_raster_order 1
|
||||
#define GL_TILE_RASTER_ORDER_FIXED_MESA 0x8BB8
|
||||
|
@ -10248,12 +10263,6 @@ typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s,
|
|||
typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
|
||||
typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
|
||||
typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
|
||||
typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
|
||||
typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
|
||||
typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);
|
||||
|
@ -10266,6 +10275,12 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, c
|
|||
typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
|
||||
typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
|
||||
typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
|
||||
typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
|
||||
typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y);
|
||||
GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v);
|
||||
|
@ -10295,12 +10310,6 @@ GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t,
|
|||
GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
|
||||
GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog);
|
||||
GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog);
|
||||
GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
|
||||
GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight);
|
||||
GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight);
|
||||
GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x);
|
||||
GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y);
|
||||
|
@ -10313,6 +10322,12 @@ GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfN
|
|||
GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog);
|
||||
GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog);
|
||||
GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
|
||||
GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight);
|
||||
GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight);
|
||||
#endif
|
||||
#endif /* GL_NV_half_float */
|
||||
|
||||
|
@ -11449,6 +11464,10 @@ GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id);
|
|||
#endif
|
||||
#endif /* GL_NV_transform_feedback2 */
|
||||
|
||||
#ifndef GL_NV_uniform_buffer_std430_layout
|
||||
#define GL_NV_uniform_buffer_std430_layout 1
|
||||
#endif /* GL_NV_uniform_buffer_std430_layout */
|
||||
|
||||
#ifndef GL_NV_uniform_buffer_unified_memory
|
||||
#define GL_NV_uniform_buffer_unified_memory 1
|
||||
#define GL_UNIFORM_BUFFER_UNIFIED_NV 0x936E
|
||||
|
@ -11964,8 +11983,10 @@ GLAPI void APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum s
|
|||
#define GL_MAX_VIEWS_OVR 0x9631
|
||||
#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
|
||||
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
GLAPI void APIENTRY glNamedFramebufferTextureMultiviewOVR (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
#endif
|
||||
#endif /* GL_OVR_multiview */
|
||||
|
||||
|
|
1
3rdparty/MoltenVK/CMakeLists.txt
vendored
1
3rdparty/MoltenVK/CMakeLists.txt
vendored
|
@ -1,4 +1,3 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(moltenvk NONE)
|
||||
include(ExternalProject)
|
||||
|
||||
|
|
2
3rdparty/OpenAL/openal-soft
vendored
2
3rdparty/OpenAL/openal-soft
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 90191edd20bb877c5cbddfdac7ec0fe49ad93727
|
||||
Subproject commit dc7d7054a5b4f3bec1dc23a42fd616a0847af948
|
2
3rdparty/SoundTouch/soundtouch
vendored
2
3rdparty/SoundTouch/soundtouch
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 394e1f58b23dc80599214d2e9b6a5e0dfd0bbe07
|
||||
Subproject commit 3982730833b6daefe77dcfb32b5c282851640c17
|
2
3rdparty/curl/curl
vendored
2
3rdparty/curl/curl
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 57495c64871d18905a0941db9196ef90bafe9a29
|
||||
Subproject commit 1c3149881769e7bd79b072e48374e4c2b3678b2f
|
14
3rdparty/curl/libcurl.vcxproj
vendored
14
3rdparty/curl/libcurl.vcxproj
vendored
|
@ -76,6 +76,7 @@
|
|||
<ClCompile Include="curl\lib\connect.c" />
|
||||
<ClCompile Include="curl\lib\content_encoding.c" />
|
||||
<ClCompile Include="curl\lib\cookie.c" />
|
||||
<ClCompile Include="curl\lib\cshutdn.c" />
|
||||
<ClCompile Include="curl\lib\curl_addrinfo.c" />
|
||||
<ClCompile Include="curl\lib\curl_des.c" />
|
||||
<ClCompile Include="curl\lib\curl_endian.c" />
|
||||
|
@ -94,7 +95,9 @@
|
|||
<ClCompile Include="curl\lib\curl_threads.c" />
|
||||
<ClCompile Include="curl\lib\curl_trc.c" />
|
||||
<ClCompile Include="curl\lib\cw-out.c" />
|
||||
<ClCompile Include="curl\lib\cw-pause.c" />
|
||||
<ClCompile Include="curl\lib\dict.c" />
|
||||
<ClCompile Include="curl\lib\dllmain.c" />
|
||||
<ClCompile Include="curl\lib\doh.c" />
|
||||
<ClCompile Include="curl\lib\dynbuf.c" />
|
||||
<ClCompile Include="curl\lib\dynhds.c" />
|
||||
|
@ -112,6 +115,7 @@
|
|||
<ClCompile Include="curl\lib\getinfo.c" />
|
||||
<ClCompile Include="curl\lib\gopher.c" />
|
||||
<ClCompile Include="curl\lib\hash.c" />
|
||||
<ClCompile Include="curl\lib\hash_offt.c" />
|
||||
<ClCompile Include="curl\lib\headers.c" />
|
||||
<ClCompile Include="curl\lib\hmac.c" />
|
||||
<ClCompile Include="curl\lib\hostasyn.c" />
|
||||
|
@ -138,6 +142,7 @@
|
|||
<ClCompile Include="curl\lib\krb5.c" />
|
||||
<ClCompile Include="curl\lib\ldap.c" />
|
||||
<ClCompile Include="curl\lib\llist.c" />
|
||||
<ClCompile Include="curl\lib\macos.c" />
|
||||
<ClCompile Include="curl\lib\md4.c" />
|
||||
<ClCompile Include="curl\lib\md5.c" />
|
||||
<ClCompile Include="curl\lib\memdebug.c" />
|
||||
|
@ -145,6 +150,7 @@
|
|||
<ClCompile Include="curl\lib\mprintf.c" />
|
||||
<ClCompile Include="curl\lib\mqtt.c" />
|
||||
<ClCompile Include="curl\lib\multi.c" />
|
||||
<ClCompile Include="curl\lib\multi_ev.c" />
|
||||
<ClCompile Include="curl\lib\netrc.c" />
|
||||
<ClCompile Include="curl\lib\nonblock.c" />
|
||||
<ClCompile Include="curl\lib\noproxy.c" />
|
||||
|
@ -174,10 +180,9 @@
|
|||
<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\strparse.c" />
|
||||
<ClCompile Include="curl\lib\strtok.c" />
|
||||
<ClCompile Include="curl\lib\strtoofft.c" />
|
||||
<ClCompile Include="curl\lib\system_win32.c" />
|
||||
<ClCompile Include="curl\lib\telnet.c" />
|
||||
<ClCompile Include="curl\lib\tftp.c" />
|
||||
|
@ -260,6 +265,7 @@
|
|||
<ClInclude Include="curl\lib\connect.h" />
|
||||
<ClInclude Include="curl\lib\content_encoding.h" />
|
||||
<ClInclude Include="curl\lib\cookie.h" />
|
||||
<ClInclude Include="curl\lib\cshutdn.h" />
|
||||
<ClInclude Include="curl\lib\curlx.h" />
|
||||
<ClInclude Include="curl\lib\curl_addrinfo.h" />
|
||||
<ClInclude Include="curl\lib\curl_base64.h" />
|
||||
|
@ -291,6 +297,7 @@
|
|||
<ClInclude Include="curl\lib\curl_threads.h" />
|
||||
<ClInclude Include="curl\lib\curl_trc.h" />
|
||||
<ClInclude Include="curl\lib\cw-out.h" />
|
||||
<ClInclude Include="curl\lib\cw-pause.h" />
|
||||
<ClInclude Include="curl\lib\dict.h" />
|
||||
<ClInclude Include="curl\lib\doh.h" />
|
||||
<ClInclude Include="curl\lib\dynbuf.h" />
|
||||
|
@ -309,6 +316,7 @@
|
|||
<ClInclude Include="curl\lib\getinfo.h" />
|
||||
<ClInclude Include="curl\lib\gopher.h" />
|
||||
<ClInclude Include="curl\lib\hash.h" />
|
||||
<ClInclude Include="curl\lib\hash_offt.h" />
|
||||
<ClInclude Include="curl\lib\headers.h" />
|
||||
<ClInclude Include="curl\lib\hostip.h" />
|
||||
<ClInclude Include="curl\lib\hsts.h" />
|
||||
|
@ -328,11 +336,13 @@
|
|||
<ClInclude Include="curl\lib\inet_ntop.h" />
|
||||
<ClInclude Include="curl\lib\inet_pton.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" />
|
||||
<ClInclude Include="curl\lib\multiif.h" />
|
||||
<ClInclude Include="curl\lib\multi_ev.h" />
|
||||
<ClInclude Include="curl\lib\netrc.h" />
|
||||
<ClInclude Include="curl\lib\nonblock.h" />
|
||||
<ClInclude Include="curl\lib\noproxy.h" />
|
||||
|
|
42
3rdparty/curl/libcurl.vcxproj.filters
vendored
42
3rdparty/curl/libcurl.vcxproj.filters
vendored
|
@ -291,12 +291,6 @@
|
|||
<ClCompile Include="curl\lib\strerror.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\strtok.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\strtoofft.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\system_win32.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -522,6 +516,27 @@
|
|||
<ClCompile Include="curl\lib\vtls\vtls_spack.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\cshutdn.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\cw-pause.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\dllmain.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\hash_offt.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\macos.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\multi_ev.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\strequal.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="curl\include\curl\curl.h">
|
||||
|
@ -1055,6 +1070,21 @@
|
|||
<ClInclude Include="curl\lib\vtls\vtls_spack.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\cshutdn.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\cw-pause.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\hash_offt.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\macos.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\multi_ev.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="curl\lib\libcurl.rc">
|
||||
|
|
2
3rdparty/discord-rpc/discord-rpc
vendored
2
3rdparty/discord-rpc/discord-rpc
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 171b2142ac8acdf016c231e36dc7a8d48daff19c
|
||||
Subproject commit 3dc2c326cb4dc5815c6069970c13154898f58d48
|
2
3rdparty/libsdl-org/SDL
vendored
2
3rdparty/libsdl-org/SDL
vendored
|
@ -1 +1 @@
|
|||
Subproject commit f6864924f76e1a0b4abaefc76ae2ed22b1a8916e
|
||||
Subproject commit 877399b2b2cf21e67554ed9046410f268ce1d1b2
|
2
3rdparty/libusb/CMakeLists.txt
vendored
2
3rdparty/libusb/CMakeLists.txt
vendored
|
@ -1,5 +1,3 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(libusb)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
|
||||
|
|
2551
3rdparty/robin_hood/include/robin_hood.h
vendored
2551
3rdparty/robin_hood/include/robin_hood.h
vendored
File diff suppressed because it is too large
Load diff
2101
3rdparty/unordered_dense/include/unordered_dense.h
vendored
Normal file
2101
3rdparty/unordered_dense/include/unordered_dense.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
10
BUILDING.md
10
BUILDING.md
|
@ -19,26 +19,26 @@ The following tools are required to build RPCS3 on Windows 10 or later:
|
|||
with standalone **CMake** tool.
|
||||
|
||||
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
|
||||
- [Qt 6.8.3](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
|
||||
- [Qt 6.9.0](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
|
||||
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
|
||||
The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode.
|
||||
|
||||
In order to build **RPCS3** with the `sln` solution (with **Visual Studio**), **Qt** libs need to be detected. To detect the libs:
|
||||
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.8.3\msvc2022_64\`
|
||||
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.9.0\msvc2022_64\`
|
||||
- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022)
|
||||
|
||||
**NOTE:** If you have issues with the **Visual Studio Qt Plugin**, you may want to uninstall it and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2022) instead.
|
||||
|
||||
In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool):
|
||||
- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.8.3\msvc2022_64\`
|
||||
- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.9.0\msvc2022_64\`
|
||||
|
||||
### Linux
|
||||
|
||||
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager:
|
||||
- Clang 17+ or GCC 13+
|
||||
- [CMake 3.28.0+](https://www.cmake.org/download/)
|
||||
- [Qt 6.8.3](https://www.qt.io/download-qt-installer)
|
||||
- [Qt 6.9.0](https://www.qt.io/download-qt-installer)
|
||||
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
- [SDL3](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
|
||||
|
||||
|
@ -121,7 +121,7 @@ Start **Visual Studio**, click on `Open a project or solution` and select the `r
|
|||
##### Configuring the Qt Plugin (if used)
|
||||
|
||||
1) go to `Extensions->Qt VS Tools->Qt Versions`
|
||||
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.8.3\msvc2022_64`, version will fill in automatically
|
||||
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.9.0\msvc2022_64`, version will fill in automatically
|
||||
3) go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the **Legacy Qt Plugin**)
|
||||
4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
cmake_minimum_required(VERSION 3.16.9)
|
||||
cmake_minimum_required(VERSION 3.28)
|
||||
|
||||
project(rpcs3 LANGUAGES C CXX)
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ RPCS3
|
|||
[](https://dev.azure.com/nekotekina/nekotekina/_build?definitionId=8&_a=summary&repositoryFilter=4)
|
||||
[](https://cirrus-ci.com/github/RPCS3/rpcs3)
|
||||
[](https://github.com/RPCS3/rpcs3/actions/workflows/rpcs3.yml)
|
||||
[](https://discord.me/rpcs3)
|
||||
[](https://discord.gg/rpcs3)
|
||||
|
||||
The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows, Linux, macOS and FreeBSD.
|
||||
|
||||
|
@ -34,7 +34,7 @@ See [BUILDING.md](BUILDING.md) for more information about how to setup an enviro
|
|||
|
||||
Check our friendly [quickstart](https://rpcs3.net/quickstart) guide to make sure your computer meets the minimum system requirements to run RPCS3.
|
||||
|
||||
Don't forget to have your graphics driver up to date and to install the [Visual C++ Redistributable Packages for Visual Studio 2019](https://aka.ms/vs/16/release/VC_redist.x64.exe) if you are a Windows user.
|
||||
Don't forget to have your graphics driver up to date and to install the [Visual C++ Redistributable Packages for Visual Studio 2022](https://aka.ms/vs/17/release/VC_redist.x64.exe) if you are a Windows user.
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -40,13 +40,13 @@ jobs:
|
|||
# displayName: ccache
|
||||
|
||||
# - bash: |
|
||||
# docker pull --quiet rpcs3/rpcs3-ci-jammy:1.3
|
||||
# docker pull --quiet rpcs3/rpcs3-ci-jammy:1.5
|
||||
# docker run \
|
||||
# -v $(pwd):/rpcs3 \
|
||||
# --env-file .ci/docker.env \
|
||||
# -v $CCACHE_DIR:/root/.ccache \
|
||||
# -v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
|
||||
# rpcs3/rpcs3-ci-jammy:1.3 \
|
||||
# rpcs3/rpcs3-ci-jammy:1.5 \
|
||||
# /rpcs3/.ci/build-linux.sh
|
||||
# displayName: Docker setup and build
|
||||
|
||||
|
@ -71,9 +71,9 @@ jobs:
|
|||
# variables:
|
||||
# COMPILER: msvc
|
||||
# QT_VER_MAIN: '6'
|
||||
# QT_VER: '6.8.3'
|
||||
# QT_VER: '6.9.0'
|
||||
# QT_VER_MSVC: 'msvc2022'
|
||||
# QT_DATE: '202503201308'
|
||||
# QT_DATE: '202503301022'
|
||||
# QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
|
||||
# LLVM_VER: '19.1.7'
|
||||
# VULKAN_VER: '1.3.268.0'
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Cached data from GitHub API.
|
13533
bin/git/commits.lst
13533
bin/git/commits.lst
File diff suppressed because one or more lines are too long
|
@ -158,19 +158,16 @@ if (NOT ANDROID)
|
|||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/../Resources/git
|
||||
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}")
|
||||
elseif(UNIX)
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs)
|
||||
elseif(WIN32)
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:OpenAL::OpenAL> $<TARGET_FILE_DIR:rpcs3>
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git
|
||||
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt
|
||||
--no-translations --no-system-d3d-compiler --no-system-dxc-compiler --no-ffmpeg --no-quick-import
|
||||
--plugindir "$<IF:$<CXX_COMPILER_ID:MSVC>,$<TARGET_FILE_DIR:rpcs3>/plugins,$<TARGET_FILE_DIR:rpcs3>/share/qt6/plugins>"
|
||||
|
@ -195,8 +192,6 @@ if (NOT ANDROID)
|
|||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||
install(DIRECTORY ../bin/GuiConfigs
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||
install(DIRECTORY ../bin/git
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||
install(DIRECTORY ../bin/test
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||
endif()
|
||||
|
|
|
@ -1343,10 +1343,13 @@ static fs::file CheckDebugSelf(const fs::file& s)
|
|||
fs::file e = fs::make_stream<std::vector<u8>>();
|
||||
|
||||
// Copy the data.
|
||||
char buf[2048];
|
||||
while (const u64 size = s.read(buf, 2048))
|
||||
std::vector<u8> buf(std::min<usz>(s.size(), 4096));
|
||||
|
||||
usz read_pos = 0;
|
||||
while (const u64 size = s.read_at(read_pos, buf.data(), buf.size()))
|
||||
{
|
||||
e.write(buf, size);
|
||||
e.write(buf.data(), size);
|
||||
read_pos += size;
|
||||
}
|
||||
|
||||
return e;
|
||||
|
@ -1371,7 +1374,10 @@ fs::file decrypt_self(const fs::file& elf_or_self, const u8* klic_key, SelfAddit
|
|||
elf_or_self.seek(0);
|
||||
|
||||
// Check SELF header first. Check for a debug SELF.
|
||||
if (elf_or_self.size() >= 4 && elf_or_self.read<u32>() == "SCE\0"_u32)
|
||||
u32 file_type = umax;
|
||||
elf_or_self.read_at(0, &file_type, sizeof(file_type));
|
||||
|
||||
if (file_type == "SCE\0"_u32)
|
||||
{
|
||||
if (fs::file res = CheckDebugSelf(elf_or_self))
|
||||
{
|
||||
|
@ -1409,6 +1415,23 @@ fs::file decrypt_self(const fs::file& elf_or_self, const u8* klic_key, SelfAddit
|
|||
// Make a new ELF file from this SELF.
|
||||
return self_dec.MakeElf(isElf32);
|
||||
}
|
||||
else if (Emu.GetBoot().ends_with(".elf") || Emu.GetBoot().ends_with(".ELF"))
|
||||
{
|
||||
// Write the file back if the main executable is not signed
|
||||
fs::file e = fs::make_stream<std::vector<u8>>();
|
||||
|
||||
// Copy the data.
|
||||
std::vector<u8> buf(std::min<usz>(elf_or_self.size(), 4096));
|
||||
|
||||
usz read_pos = 0;
|
||||
while (const u64 size = elf_or_self.read_at(read_pos, buf.data(), buf.size()))
|
||||
{
|
||||
e.write(buf.data(), size);
|
||||
read_pos += size;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -546,6 +546,7 @@ target_sources(rpcs3_emu PRIVATE
|
|||
RSX/Overlays/overlay_trophy_notification.cpp
|
||||
RSX/Overlays/overlay_user_list_dialog.cpp
|
||||
RSX/Overlays/overlay_utils.cpp
|
||||
RSX/Overlays/overlay_video.cpp
|
||||
RSX/Overlays/Shaders/shader_loading_dialog.cpp
|
||||
RSX/Overlays/Shaders/shader_loading_dialog_native.cpp
|
||||
RSX/Program/CgBinaryFragmentProgram.cpp
|
||||
|
@ -626,6 +627,7 @@ if(TARGET 3rdparty_vulkan)
|
|||
RSX/VK/VKCommonDecompiler.cpp
|
||||
RSX/VK/VKCommonPipelineLayout.cpp
|
||||
RSX/VK/VKCompute.cpp
|
||||
RSX/VK/VKDataHeapManager.cpp
|
||||
RSX/VK/VKDMA.cpp
|
||||
RSX/VK/VKDraw.cpp
|
||||
RSX/VK/VKFormats.cpp
|
||||
|
@ -648,6 +650,7 @@ if(TARGET 3rdparty_vulkan)
|
|||
RSX/VK/VKVertexBuffers.cpp
|
||||
RSX/VK/VKVertexProgram.cpp
|
||||
RSX/VK/VKTextureCache.cpp
|
||||
RSX/VK/VulkanAPI.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ struct audio_port
|
|||
// Handle copy ctor of atomic var
|
||||
audio_port(const audio_port& r)
|
||||
{
|
||||
std::memcpy(this, &r, sizeof(r));
|
||||
std::memcpy(static_cast<void*>(this), &r, sizeof(r));
|
||||
}
|
||||
|
||||
ENABLE_BITWISE_SERIALIZATION;
|
||||
|
|
|
@ -75,7 +75,7 @@ struct CellAudioInDeviceInfo
|
|||
u8 reserved[12];
|
||||
be_t<u64> deviceId;
|
||||
be_t<u64> type;
|
||||
char name[64];
|
||||
char name[64]; // Not necessarily null terminated!
|
||||
CellAudioInSoundMode availableModes[16];
|
||||
};
|
||||
|
||||
|
|
|
@ -38,11 +38,17 @@ void fmt_class_string<CellAudioInError>::format(std::string& out, u64 arg)
|
|||
struct avconf_manager
|
||||
{
|
||||
shared_mutex mutex;
|
||||
std::vector<CellAudioInDeviceInfo> devices;
|
||||
|
||||
struct device_info
|
||||
{
|
||||
CellAudioInDeviceInfo info {};
|
||||
std::string full_device_name; // The device name may be too long for CellAudioInDeviceInfo, so we additionally save the full name.
|
||||
};
|
||||
std::vector<device_info> devices;
|
||||
CellAudioInDeviceMode inDeviceMode = CELL_AUDIO_IN_SINGLE_DEVICE_MODE; // TODO: use somewhere
|
||||
|
||||
void copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> info) const;
|
||||
std::optional<CellAudioInDeviceInfo> get_device_info(vm::cptr<char> name) const;
|
||||
std::optional<device_info> get_device_info(vm::cptr<char> name) const;
|
||||
|
||||
avconf_manager();
|
||||
|
||||
|
@ -62,78 +68,89 @@ avconf_manager::avconf_manager()
|
|||
switch (g_cfg.audio.microphone_type)
|
||||
{
|
||||
case microphone_handler::standard:
|
||||
{
|
||||
for (u32 index = 0; index < mic_list.size(); index++)
|
||||
{
|
||||
devices.emplace_back();
|
||||
|
||||
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
|
||||
devices[curindex].availableModeCount = 1;
|
||||
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
devices[curindex].deviceId = 0xE11CC0DE + curindex;
|
||||
devices[curindex].type = 0xC0DEE11C;
|
||||
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
|
||||
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
devices[curindex].deviceNumber = curindex;
|
||||
strcpy_trunc(devices[curindex].name, mic_list[index]);
|
||||
device_info device {};
|
||||
device.info.portType = CELL_AUDIO_IN_PORT_USB;
|
||||
device.info.availableModeCount = 1;
|
||||
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
device.info.deviceId = 0xE11CC0DE + curindex;
|
||||
device.info.type = 0xC0DEE11C;
|
||||
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
|
||||
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
device.info.deviceNumber = curindex;
|
||||
device.full_device_name = mic_list[index];
|
||||
strcpy_trunc(device.info.name, device.full_device_name);
|
||||
|
||||
devices.push_back(std::move(device));
|
||||
curindex++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case microphone_handler::real_singstar:
|
||||
case microphone_handler::singstar:
|
||||
{
|
||||
// Only one device for singstar device
|
||||
devices.emplace_back();
|
||||
|
||||
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
|
||||
devices[curindex].availableModeCount = 1;
|
||||
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
devices[curindex].deviceId = 0x00000001;
|
||||
devices[curindex].type = 0x14150000;
|
||||
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
|
||||
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
devices[curindex].deviceNumber = curindex;
|
||||
strcpy_trunc(devices[curindex].name, mic_list[0]);
|
||||
device_info device {};
|
||||
device.info.portType = CELL_AUDIO_IN_PORT_USB;
|
||||
device.info.availableModeCount = 1;
|
||||
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
device.info.deviceId = 0x00000001;
|
||||
device.info.type = 0x14150000;
|
||||
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
|
||||
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
device.info.deviceNumber = curindex;
|
||||
device.full_device_name = mic_list[0];
|
||||
strcpy_trunc(device.info.name, device.full_device_name);
|
||||
|
||||
devices.push_back(std::move(device));
|
||||
curindex++;
|
||||
break;
|
||||
}
|
||||
case microphone_handler::rocksmith:
|
||||
devices.emplace_back();
|
||||
|
||||
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
|
||||
devices[curindex].availableModeCount = 1;
|
||||
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
devices[curindex].deviceId = 0x12BA00FF; // Specific to rocksmith usb input
|
||||
devices[curindex].type = 0xC0DE73C4;
|
||||
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_1;
|
||||
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
devices[curindex].deviceNumber = curindex;
|
||||
strcpy_trunc(devices[curindex].name, mic_list[0]);
|
||||
{
|
||||
device_info device {};
|
||||
device.info.portType = CELL_AUDIO_IN_PORT_USB;
|
||||
device.info.availableModeCount = 1;
|
||||
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
device.info.deviceId = 0x12BA00FF; // Specific to rocksmith usb input
|
||||
device.info.type = 0xC0DE73C4;
|
||||
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_1;
|
||||
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
device.info.deviceNumber = curindex;
|
||||
device.full_device_name = mic_list[0];
|
||||
strcpy_trunc(device.info.name, device.full_device_name);
|
||||
|
||||
devices.push_back(std::move(device));
|
||||
curindex++;
|
||||
break;
|
||||
}
|
||||
case microphone_handler::null:
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_cfg.io.camera != camera_handler::null)
|
||||
{
|
||||
devices.emplace_back();
|
||||
|
||||
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
|
||||
devices[curindex].availableModeCount = 1;
|
||||
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
devices[curindex].deviceId = 0xDEADBEEF;
|
||||
devices[curindex].type = 0xBEEFDEAD;
|
||||
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE;
|
||||
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
devices[curindex].deviceNumber = curindex;
|
||||
strcpy_trunc(devices[curindex].name, "USB Camera");
|
||||
device_info device {};
|
||||
device.info.portType = CELL_AUDIO_IN_PORT_USB;
|
||||
device.info.availableModeCount = 1;
|
||||
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
device.info.deviceId = 0xDEADBEEF;
|
||||
device.info.type = 0xBEEFDEAD;
|
||||
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE;
|
||||
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
device.info.deviceNumber = curindex;
|
||||
device.full_device_name = "USB Camera";
|
||||
strcpy_trunc(device.info.name, device.full_device_name);
|
||||
|
||||
devices.push_back(std::move(device));
|
||||
curindex++;
|
||||
}
|
||||
}
|
||||
|
@ -142,14 +159,14 @@ void avconf_manager::copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> in
|
|||
{
|
||||
memset(info.get_ptr(), 0, sizeof(CellAudioInDeviceInfo));
|
||||
ensure(num < devices.size());
|
||||
*info = devices[num];
|
||||
*info = devices[num].info;
|
||||
}
|
||||
|
||||
std::optional<CellAudioInDeviceInfo> avconf_manager::get_device_info(vm::cptr<char> name) const
|
||||
std::optional<avconf_manager::device_info> avconf_manager::get_device_info(vm::cptr<char> name) const
|
||||
{
|
||||
for (const CellAudioInDeviceInfo& device : devices)
|
||||
for (const device_info& device : devices)
|
||||
{
|
||||
if (strncmp(device.name, name.get_ptr(), sizeof(device.name)) == 0)
|
||||
if (strncmp(device.info.name, name.get_ptr(), sizeof(device.info.name)) == 0)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
|
@ -398,8 +415,8 @@ error_code cellAudioInRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::pt
|
|||
auto& av_manager = g_fxo->get<avconf_manager>();
|
||||
const std::lock_guard lock(av_manager.mutex);
|
||||
|
||||
std::optional<CellAudioInDeviceInfo> info = av_manager.get_device_info(name);
|
||||
if (!info || !memchr(info->name, '\0', sizeof(info->name)))
|
||||
std::optional<avconf_manager::device_info> device = av_manager.get_device_info(name);
|
||||
if (!device)
|
||||
{
|
||||
// TODO
|
||||
return CELL_AUDIO_IN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
@ -407,7 +424,7 @@ error_code cellAudioInRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::pt
|
|||
|
||||
auto& mic_thr = g_fxo->get<mic_thread>();
|
||||
const std::lock_guard mic_lock(mic_thr.mutex);
|
||||
const u32 device_number = mic_thr.register_device(info->name);
|
||||
const u32 device_number = mic_thr.register_device(device->full_device_name);
|
||||
|
||||
return not_an_error(device_number);
|
||||
}
|
||||
|
|
|
@ -446,7 +446,7 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> contex
|
|||
gcm_cfg.zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
|
||||
gcm_cfg.tiles_addr = vm::alloc(sizeof(CellGcmTileInfo) * 15, vm::main);
|
||||
|
||||
vm::_ref<CellGcmContextData>(gcm_cfg.gcm_info.context_addr) = gcm_cfg.current_context;
|
||||
vm::write<CellGcmContextData>(gcm_cfg.gcm_info.context_addr, gcm_cfg.current_context);
|
||||
context->set(gcm_cfg.gcm_info.context_addr);
|
||||
|
||||
// 0x40 is to offset CellGcmControl from RsxDmaControl
|
||||
|
@ -590,7 +590,7 @@ ret_type gcmSetPrepareFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt, u3
|
|||
|
||||
if (!old_api && ctxt.addr() == gcm_cfg.gcm_info.context_addr)
|
||||
{
|
||||
vm::_ref<CellGcmControl>(gcm_cfg.gcm_info.control_addr).put += cmd_size;
|
||||
vm::_ptr<CellGcmControl>(gcm_cfg.gcm_info.control_addr)->put += cmd_size;
|
||||
}
|
||||
|
||||
return static_cast<ret_type>(not_an_error(id));
|
||||
|
@ -1463,7 +1463,7 @@ s32 cellGcmCallback(ppu_thread& ppu, vm::ptr<CellGcmContextData> context, u32 co
|
|||
|
||||
auto& gcm_cfg = g_fxo->get<gcm_config>();
|
||||
|
||||
auto& ctrl = vm::_ref<CellGcmControl>(gcm_cfg.gcm_info.control_addr);
|
||||
auto& ctrl = *vm::_ptr<CellGcmControl>(gcm_cfg.gcm_info.control_addr);
|
||||
|
||||
// Flush command buffer (ie allow RSX to read up to context->current)
|
||||
ctrl.put.exchange(getOffsetFromAddress(context->current.addr()));
|
||||
|
|
|
@ -322,6 +322,8 @@ error_code microphone_device::open_microphone(const u8 type, const u32 dsp_r, co
|
|||
num_channels = channels;
|
||||
|
||||
#ifndef WITHOUT_OPENAL
|
||||
enumerate_devices();
|
||||
|
||||
// Adjust number of channels depending on microphone type
|
||||
switch (device_type)
|
||||
{
|
||||
|
@ -423,36 +425,40 @@ error_code microphone_device::open_microphone(const u8 type, const u32 dsp_r, co
|
|||
break;
|
||||
}
|
||||
|
||||
ALCdevice* device = nullptr;
|
||||
|
||||
// Make sure we use a proper sampling rate
|
||||
const auto fixup_samplingrate = [this](u32& rate) -> bool
|
||||
// TODO: The used sample rate may vary for Sony's camera devices
|
||||
const std::array<u32, 7> samplingrates = { raw_samplingrate, 48000u, 32000u, 24000u, 16000u, 12000u, 8000u };
|
||||
|
||||
for (u32 samplingrate : samplingrates)
|
||||
{
|
||||
// TODO: The used sample rate may vary for Sony's camera devices
|
||||
const std::array<u32, 7> samplingrates = { rate, 48000u, 32000u, 24000u, 16000u, 12000u, 8000u };
|
||||
|
||||
const auto test_samplingrate = [&samplingrates](const u32& rate)
|
||||
if (!std::any_of(samplingrates.cbegin() + 1, samplingrates.cend(), [samplingrate](u32 r){ return r == samplingrate; }))
|
||||
{
|
||||
// TODO: actually check if device supports sampling rates
|
||||
return std::any_of(samplingrates.cbegin() + 1, samplingrates.cend(), [&rate](const u32& r){ return r == rate; });
|
||||
};
|
||||
|
||||
for (u32 samplingrate : samplingrates)
|
||||
{
|
||||
if (test_samplingrate(samplingrate))
|
||||
{
|
||||
// Use this sampling rate
|
||||
raw_samplingrate = samplingrate;
|
||||
cellMic.notice("Using sampling rate %d.", samplingrate);
|
||||
return true;
|
||||
}
|
||||
|
||||
cellMic.warning("Requested sampling rate %d, but we do not support it. Trying next sampling rate...", samplingrate);
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
cellMic.notice("Trying sampling rate %d with %d channel(s)", samplingrate, num_channels);
|
||||
|
||||
if (!fixup_samplingrate(raw_samplingrate))
|
||||
device = open_device(devices[0].name, samplingrate, num_al_channels, inbuf_size);
|
||||
if (!device)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use this sampling rate
|
||||
raw_samplingrate = samplingrate;
|
||||
cellMic.notice("Using sampling rate %d and %d channel(s)", raw_samplingrate, num_channels);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!device)
|
||||
{
|
||||
cellMic.error("Failed to open capture device '%s' (raw_samplingrate=%d, num_al_channels=0x%x, inbuf_size=%d)", devices[0].name, raw_samplingrate, num_al_channels, inbuf_size);
|
||||
#ifdef _WIN32
|
||||
cellMic.error("Make sure microphone use is authorized under \"Microphone privacy settings\" in windows configuration");
|
||||
#endif
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_SUPPORT;
|
||||
}
|
||||
|
||||
|
@ -460,29 +466,19 @@ error_code microphone_device::open_microphone(const u8 type, const u32 dsp_r, co
|
|||
|
||||
ensure(!devices.empty());
|
||||
|
||||
ALCdevice* device = alcCaptureOpenDevice(devices[0].name.c_str(), raw_samplingrate, num_al_channels, inbuf_size);
|
||||
|
||||
if (ALCenum err = alcGetError(device); err != ALC_NO_ERROR || !device)
|
||||
{
|
||||
cellMic.error("Error opening capture device %s (error=%s, device=*0x%x)", devices[0].name, fmt::alc_error{device, err}, device);
|
||||
#ifdef _WIN32
|
||||
cellMic.error("Make sure microphone use is authorized under \"Microphone privacy settings\" in windows configuration");
|
||||
#endif
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_SUPPORT;
|
||||
}
|
||||
|
||||
devices[0].device = device;
|
||||
devices[0].buf.resize(inbuf_size, 0);
|
||||
|
||||
if (device_type == microphone_handler::singstar && devices.size() >= 2)
|
||||
{
|
||||
// Open a 2nd microphone into the same device
|
||||
device = alcCaptureOpenDevice(devices[1].name.c_str(), raw_samplingrate, AL_FORMAT_MONO16, inbuf_size);
|
||||
num_al_channels = AL_FORMAT_MONO16;
|
||||
device = open_device(devices[1].name, raw_samplingrate, num_al_channels, inbuf_size);
|
||||
|
||||
if (ALCenum err = alcGetError(device); err != ALC_NO_ERROR || !device)
|
||||
if (!device)
|
||||
{
|
||||
// Ignore it and move on
|
||||
cellMic.error("Error opening 2nd SingStar capture device %s (error=%s, device=*0x%x)", devices[1].name, fmt::alc_error{device, err}, device);
|
||||
cellMic.error("Failed to open 2nd SingStar capture device '%s' (raw_samplingrate=%d, num_al_channels=0x%x, inbuf_size=%d)", devices[1].name, raw_samplingrate, num_al_channels, inbuf_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -517,7 +513,7 @@ error_code microphone_device::close_microphone()
|
|||
{
|
||||
if (alcCaptureCloseDevice(micdevice.device) != ALC_TRUE)
|
||||
{
|
||||
cellMic.error("Error closing capture device %s", micdevice.name);
|
||||
cellMic.error("Error closing capture device '%s'", micdevice.name);
|
||||
}
|
||||
|
||||
micdevice.device = nullptr;
|
||||
|
@ -539,7 +535,7 @@ error_code microphone_device::start_microphone()
|
|||
alcCaptureStart(micdevice.device);
|
||||
if (ALCenum err = alcGetError(micdevice.device); err != ALC_NO_ERROR)
|
||||
{
|
||||
cellMic.error("Error starting capture of device %s (error=%s)", micdevice.name, fmt::alc_error{micdevice.device, err});
|
||||
cellMic.error("Error starting capture of device '%s' (error=%s)", micdevice.name, fmt::alc_error{micdevice.device, err});
|
||||
stop_microphone();
|
||||
return CELL_MICIN_ERROR_FATAL;
|
||||
}
|
||||
|
@ -558,7 +554,7 @@ error_code microphone_device::stop_microphone()
|
|||
alcCaptureStop(micdevice.device);
|
||||
if (ALCenum err = alcGetError(micdevice.device); err != ALC_NO_ERROR)
|
||||
{
|
||||
cellMic.error("Error stopping capture of device %s (error=%s)", micdevice.name, fmt::alc_error{micdevice.device, err});
|
||||
cellMic.error("Error stopping capture of device '%s' (error=%s)", micdevice.name, fmt::alc_error{micdevice.device, err});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -637,7 +633,7 @@ u32 microphone_device::capture_audio()
|
|||
|
||||
if (ALCenum err = alcGetError(micdevice.device); err != ALC_NO_ERROR)
|
||||
{
|
||||
cellMic.error("Error getting number of captured samples of device %s (error=%s)", micdevice.name, fmt::alc_error{micdevice.device, err});
|
||||
cellMic.error("Error getting number of captured samples of device '%s' (error=%s)", micdevice.name, fmt::alc_error{micdevice.device, err});
|
||||
return CELL_MICIN_ERROR_FATAL;
|
||||
}
|
||||
|
||||
|
@ -655,7 +651,7 @@ u32 microphone_device::capture_audio()
|
|||
|
||||
if (ALCenum err = alcGetError(micdevice.device); err != ALC_NO_ERROR)
|
||||
{
|
||||
cellMic.error("Error capturing samples of device %s (error=%s)", micdevice.name, fmt::alc_error{micdevice.device, err});
|
||||
cellMic.error("Error capturing samples of device '%s' (error=%s)", micdevice.name, fmt::alc_error{micdevice.device, err});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -667,6 +663,56 @@ u32 microphone_device::capture_audio()
|
|||
|
||||
// Private functions
|
||||
|
||||
#ifndef WITHOUT_OPENAL
|
||||
void microphone_device::enumerate_devices()
|
||||
{
|
||||
cellMic.notice("Enumerating capture devices...");
|
||||
enumerated_devices.clear();
|
||||
|
||||
if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") == AL_TRUE)
|
||||
{
|
||||
if (const char* alc_devices = alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER))
|
||||
{
|
||||
while (alc_devices && *alc_devices != 0)
|
||||
{
|
||||
cellMic.notice("Found capture device: '%s'", alc_devices);
|
||||
enumerated_devices.push_back(alc_devices);
|
||||
alc_devices += strlen(alc_devices) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Without enumeration we can only use one device
|
||||
cellMic.error("OpenAl extension ALC_ENUMERATION_EXT not supported. The enumerated capture devices will only contain the default capture device.");
|
||||
|
||||
if (const char* alc_device = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER))
|
||||
{
|
||||
cellMic.notice("Found default capture device: '%s'", alc_device);
|
||||
enumerated_devices.push_back(alc_device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ALCdevice* microphone_device::open_device(const std::string& name, u32 samplingrate, ALCenum num_al_channels, u32 buf_size)
|
||||
{
|
||||
if (std::none_of(enumerated_devices.cbegin(), enumerated_devices.cend(), [&name](const std::string& dev){ return dev == name; }))
|
||||
{
|
||||
cellMic.error("Capture device '%s' not in enumerated devices", name);
|
||||
}
|
||||
|
||||
ALCdevice* device = alcCaptureOpenDevice(name.c_str(), samplingrate, num_al_channels, buf_size);
|
||||
|
||||
if (ALCenum err = alcGetError(device); err != ALC_NO_ERROR || !device)
|
||||
{
|
||||
cellMic.warning("Failed to open capture device '%s' (error=%s, device=*0x%x, samplingrate=%d, num_al_channels=0x%x, buf_size=%d)", name, fmt::alc_error{device, err}, device, samplingrate, num_al_channels, buf_size);
|
||||
device = nullptr;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
#endif
|
||||
|
||||
void microphone_device::get_data(const u32 num_samples)
|
||||
{
|
||||
if (num_samples == 0)
|
||||
|
|
|
@ -326,6 +326,11 @@ private:
|
|||
static inline void variable_byteswap(const void* src, void* dst);
|
||||
inline u32 convert_16_bit_pcm_to_float(const std::vector<u8>& buffer, u32 num_bytes);
|
||||
|
||||
#ifndef WITHOUT_OPENAL
|
||||
void enumerate_devices();
|
||||
ALCdevice* open_device(const std::string& name, u32 samplingrate, ALCenum num_al_channels, u32 buf_size);
|
||||
#endif
|
||||
|
||||
u32 capture_audio();
|
||||
|
||||
void get_data(const u32 num_samples);
|
||||
|
@ -345,6 +350,7 @@ private:
|
|||
std::vector<u8> buf;
|
||||
};
|
||||
|
||||
std::vector<std::string> enumerated_devices;
|
||||
std::vector<mic_device> devices;
|
||||
std::vector<u8> temp_buf;
|
||||
std::vector<u8> float_buf;
|
||||
|
@ -376,7 +382,7 @@ public:
|
|||
void wake_up();
|
||||
|
||||
// Returns index of registered device
|
||||
u32 register_device(const std::string& name);
|
||||
u32 register_device(const std::string& device_name);
|
||||
void unregister_device(u32 dev_num);
|
||||
bool check_device(u32 dev_num);
|
||||
|
||||
|
|
|
@ -244,7 +244,7 @@ static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir,
|
|||
continue;
|
||||
}
|
||||
|
||||
SaveDataEntry save_entry;
|
||||
SaveDataEntry save_entry {};
|
||||
save_entry.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
|
||||
save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
|
||||
save_entry.title = psf::get_string(psf, "TITLE");
|
||||
|
@ -307,7 +307,7 @@ static error_code select_and_delete(ppu_thread& ppu)
|
|||
// Display a blocking Save Data List asynchronously in the GUI thread.
|
||||
if (auto save_dialog = Emu.GetCallbacks().get_save_dialog())
|
||||
{
|
||||
selected = save_dialog->ShowSaveDataList(save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get<savedata_manager>().enable_overlay);
|
||||
selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get<savedata_manager>().enable_overlay);
|
||||
}
|
||||
|
||||
// Reschedule after a blocking dialog returns
|
||||
|
@ -326,7 +326,7 @@ static error_code select_and_delete(ppu_thread& ppu)
|
|||
focused = save_entries.empty() ? -1 : selected;
|
||||
|
||||
// Get information from the selected entry
|
||||
SaveDataEntry entry = save_entries[selected];
|
||||
const SaveDataEntry& entry = ::at32(save_entries, selected);
|
||||
const std::string info = entry.title + "\n" + entry.subtitle + "\n" + entry.details;
|
||||
|
||||
// Reusable display message string
|
||||
|
@ -760,7 +760,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||
|
||||
result->userdata = userdata; // probably should be assigned only once (allows the callback to change it)
|
||||
|
||||
SaveDataEntry save_entry;
|
||||
SaveDataEntry save_entry {};
|
||||
|
||||
if (setList)
|
||||
{
|
||||
|
@ -820,7 +820,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||
break;
|
||||
}
|
||||
|
||||
SaveDataEntry save_entry2;
|
||||
SaveDataEntry save_entry2 {};
|
||||
save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
|
||||
save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
|
||||
save_entry2.title = psf::get_string(psf, "TITLE");
|
||||
|
@ -1183,7 +1183,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||
// Display a blocking Save Data List asynchronously in the GUI thread.
|
||||
if (auto save_dialog = Emu.GetCallbacks().get_save_dialog())
|
||||
{
|
||||
selected = save_dialog->ShowSaveDataList(save_entries, focused, operation, listSet, g_fxo->get<savedata_manager>().enable_overlay);
|
||||
selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, operation, listSet, g_fxo->get<savedata_manager>().enable_overlay);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1214,8 +1214,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||
else
|
||||
{
|
||||
// Get information from the selected entry
|
||||
SaveDataEntry entry = save_entries[selected];
|
||||
message = get_confirmation_message(operation, entry);
|
||||
message = get_confirmation_message(operation, ::at32(save_entries, selected));
|
||||
}
|
||||
|
||||
// Yield before a blocking dialog is being spawned
|
||||
|
@ -1345,14 +1344,14 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||
else
|
||||
{
|
||||
// Get information from the selected entry
|
||||
SaveDataEntry entry = save_entries[selected];
|
||||
message = get_confirmation_message(operation, entry);
|
||||
message = get_confirmation_message(operation, ::at32(save_entries, selected));
|
||||
}
|
||||
|
||||
// Yield before a blocking dialog is being spawned
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
// Get user confirmation by opening a blocking dialog
|
||||
// TODO: show fixedSet->newIcon
|
||||
s32 return_code = CELL_MSGDIALOG_BUTTON_NONE;
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code);
|
||||
|
||||
|
|
|
@ -361,5 +361,5 @@ class SaveDialogBase
|
|||
public:
|
||||
virtual ~SaveDialogBase();
|
||||
|
||||
virtual s32 ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) = 0;
|
||||
virtual s32 ShowSaveDataList(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) = 0;
|
||||
};
|
||||
|
|
|
@ -4134,7 +4134,7 @@ s32 _spurs::create_task(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id,
|
|||
|
||||
u32 tmp_task_id;
|
||||
|
||||
vm::light_op(vm::_ref<atomic_be_t<v128>>(taskset.ptr(&CellSpursTaskset::enabled).addr()), [&](atomic_be_t<v128>& ptr)
|
||||
vm::light_op(*vm::_ptr<atomic_be_t<v128>>(taskset.ptr(&CellSpursTaskset::enabled).addr()), [&](atomic_be_t<v128>& ptr)
|
||||
{
|
||||
// NOTE: Realfw processes this using 4 32-bits atomic loops
|
||||
// But here its processed within a single 128-bit atomic op
|
||||
|
|
|
@ -1594,12 +1594,12 @@ s32 spursTasksetProcessRequest(spu_thread& spu, s32 request, u32* taskId, u32* i
|
|||
spursHalt(spu);
|
||||
}
|
||||
|
||||
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::waiting)) = waiting;
|
||||
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::running)) = running;
|
||||
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::ready)) = ready;
|
||||
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::pending_ready)) = v128{};
|
||||
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::enabled)) = enabled;
|
||||
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::signalled)) = signalled;
|
||||
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::waiting)) = waiting;
|
||||
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::running)) = running;
|
||||
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::ready)) = ready;
|
||||
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::pending_ready)) = v128{};
|
||||
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::enabled)) = enabled;
|
||||
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::signalled)) = signalled;
|
||||
|
||||
std::memcpy(spu._ptr<void>(0x2700), spu._ptr<void>(0x100), 128); // Copy data
|
||||
}//);
|
||||
|
|
|
@ -546,6 +546,11 @@ error_code sceNpTrophyDestroyContext(u32 context)
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
struct register_context_thread_name
|
||||
{
|
||||
static constexpr std::string_view thread_name = "Trophy Register Thread";
|
||||
};
|
||||
|
||||
error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, vm::ptr<SceNpTrophyStatusCallback> statusCb, vm::ptr<void> arg, u64 options)
|
||||
{
|
||||
sceNpTrophy.warning("sceNpTrophyRegisterContext(context=0x%x, handle=0x%x, statusCb=*0x%x, arg=*0x%x, options=0x%llx)", context, handle, statusCb, arg, options);
|
||||
|
@ -709,57 +714,77 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
|
|||
|
||||
ensure(tropusr->Load(trophyUsrPath, trophyConfPath).success);
|
||||
|
||||
// This emulates vsh sending the events and ensures that not 2 events are processed at once
|
||||
const std::pair<u32, s32> statuses[] =
|
||||
{
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_SETUP, 3 },
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS, ::narrow<s32>(tropusr->GetTrophiesCount()) - 1 },
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_FINALIZE, 4 },
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE, 0 }
|
||||
};
|
||||
|
||||
lock2.unlock();
|
||||
|
||||
struct register_context_thread : register_context_thread_name
|
||||
{
|
||||
void operator()(s32 progress_cb_count, u32 context, vm::ptr<SceNpTrophyStatusCallback> statusCb, vm::ptr<void> arg) const
|
||||
{
|
||||
// This emulates vsh sending the events and ensures that not 2 events are processed at once
|
||||
const std::pair<SceNpTrophyStatus, s32> statuses[] =
|
||||
{
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_SETUP, 3 },
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS, progress_cb_count },
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_FINALIZE, std::max<s32>(progress_cb_count, 9) - 5 }, // Seems varying, little bit less than progress_cb_count
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE, 0 }
|
||||
};
|
||||
|
||||
// Create a counter which is destroyed after the function ends
|
||||
const auto queued = std::make_shared<atomic_t<u32>>(0);
|
||||
|
||||
for (auto status : statuses)
|
||||
{
|
||||
for (s32 completed = 0; completed <= status.second; completed++)
|
||||
{
|
||||
// One status max per cellSysutilCheckCallback call
|
||||
*queued += 1;
|
||||
|
||||
sysutil_register_cb([statusCb, status, context, completed, arg, queued](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
// TODO: it is possible that we need to check the return value here as well.
|
||||
statusCb(cb_ppu, context, status.first, completed, status.second, arg);
|
||||
|
||||
if (queued && (*queued)-- == 1)
|
||||
{
|
||||
queued->notify_one();
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
u64 current = get_system_time();
|
||||
|
||||
const u64 until_max = current + 300'000;
|
||||
const u64 until_min = current + 100'000;
|
||||
|
||||
// If too much time passes just send the rest of the events anyway
|
||||
for (u32 old_value = *queued; current < (old_value ? until_max : until_min);
|
||||
current = get_system_time(), old_value = *queued)
|
||||
{
|
||||
if (!old_value)
|
||||
{
|
||||
thread_ctrl::wait_for(until_min - current);
|
||||
}
|
||||
else
|
||||
{
|
||||
thread_ctrl::wait_on(*queued, old_value, until_max - current);
|
||||
}
|
||||
|
||||
if (thread_ctrl::state() == thread_state::aborting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
// Create a counter which is destroyed after the function ends
|
||||
const auto queued = std::make_shared<atomic_t<u32>>(0);
|
||||
g_fxo->get<named_thread<register_context_thread>>()(::narrow<s32>(tropusr->GetTrophiesCount()) - 1, context, statusCb, arg);
|
||||
|
||||
for (auto status : statuses)
|
||||
{
|
||||
// One status max per cellSysutilCheckCallback call
|
||||
*queued += status.second;
|
||||
for (s32 completed = 0; completed <= status.second; completed++)
|
||||
{
|
||||
sysutil_register_cb([statusCb, status, context, completed, arg, queued](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
// TODO: it is possible that we need to check the return value here as well.
|
||||
statusCb(cb_ppu, context, status.first, completed, status.second, arg);
|
||||
|
||||
if (queued && (*queued)-- == 1)
|
||||
{
|
||||
queued->notify_one();
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
u64 current = get_system_time();
|
||||
const u64 until = current + 300'000;
|
||||
|
||||
// If too much time passes just send the rest of the events anyway
|
||||
for (u32 old_value; current < until && (old_value = *queued);
|
||||
current = get_system_time())
|
||||
{
|
||||
thread_ctrl::wait_on(*queued, old_value, until - current);
|
||||
|
||||
if (ppu.is_stopped())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
thread_ctrl::wait_for(200'000);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ struct SceNpTrophyFlagArray
|
|||
be_t<u32> flag_bits[SCE_NP_TROPHY_FLAG_SETSIZE >> SCE_NP_TROPHY_FLAG_BITS_SHIFT];
|
||||
};
|
||||
|
||||
enum
|
||||
enum SceNpTrophyStatus : u32
|
||||
{
|
||||
SCE_NP_TROPHY_STATUS_UNKNOWN = 0,
|
||||
SCE_NP_TROPHY_STATUS_NOT_INSTALLED = 1,
|
||||
|
|
|
@ -38,11 +38,13 @@ void ppubreak(ppu_thread& ppu)
|
|||
}
|
||||
}
|
||||
|
||||
#define PPU_WRITE(type, addr, value) vm::write<type>(addr, value, &ppu);
|
||||
#define PPU_WRITE_8(addr, value) vm::write8(addr, value, &ppu);
|
||||
#define PPU_WRITE_16(addr, value) vm::write16(addr, value, &ppu);
|
||||
#define PPU_WRITE_32(addr, value) vm::write32(addr, value, &ppu);
|
||||
#define PPU_WRITE_64(addr, value) vm::write64(addr, value, &ppu);
|
||||
#else
|
||||
#define PPU_WRITE(type, addr, value) vm::write<type>(addr, value);
|
||||
#define PPU_WRITE_8(addr, value) vm::write8(addr, value);
|
||||
#define PPU_WRITE_16(addr, value) vm::write16(addr, value);
|
||||
#define PPU_WRITE_32(addr, value) vm::write32(addr, value);
|
||||
|
@ -4573,7 +4575,7 @@ auto STVX()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull;
|
||||
vm::_ref<v128>(vm::cast(addr)) = ppu.vr[op.vs];
|
||||
PPU_WRITE(v128, vm::cast(addr), ppu.vr[op.vs]);
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -5074,7 +5076,7 @@ auto STVXL()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull;
|
||||
vm::_ref<v128>(vm::cast(addr)) = ppu.vr[op.vs];
|
||||
PPU_WRITE(v128, vm::cast(addr), ppu.vr[op.vs]);
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -5363,7 +5365,7 @@ auto STDBRX()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||
vm::_ref<le_t<u64>>(vm::cast(addr)) = ppu.gpr[op.rs];
|
||||
PPU_WRITE(le_t<u64>, vm::cast(addr), ppu.gpr[op.rs]);
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -5402,7 +5404,7 @@ auto STWBRX()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||
vm::_ref<le_t<u32>>(vm::cast(addr)) = static_cast<u32>(ppu.gpr[op.rs]);
|
||||
PPU_WRITE(le_t<u32>, vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -5415,7 +5417,7 @@ auto STFSX()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||
vm::_ref<f32>(vm::cast(addr)) = static_cast<float>(ppu.fpr[op.frs]);
|
||||
PPU_WRITE(f32, vm::cast(addr), static_cast<float>(ppu.fpr[op.frs]));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -5446,7 +5448,7 @@ auto STFSUX()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
||||
vm::_ref<f32>(vm::cast(addr)) = static_cast<float>(ppu.fpr[op.frs]);
|
||||
PPU_WRITE(f32, vm::cast(addr), static_cast<float>(ppu.fpr[op.frs]));
|
||||
ppu.gpr[op.ra] = addr;
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
|
@ -5496,7 +5498,7 @@ auto STFDX()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||
vm::_ref<f64>(vm::cast(addr)) = ppu.fpr[op.frs];
|
||||
PPU_WRITE(f64, vm::cast(addr), ppu.fpr[op.frs]);
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -5509,7 +5511,7 @@ auto STFDUX()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
||||
vm::_ref<f64>(vm::cast(addr)) = ppu.fpr[op.frs];
|
||||
PPU_WRITE(f64, vm::cast(addr), ppu.fpr[op.frs]);
|
||||
ppu.gpr[op.ra] = addr;
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
|
@ -5664,7 +5666,7 @@ auto STHBRX()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||
vm::_ref<le_t<u16>>(vm::cast(addr)) = static_cast<u16>(ppu.gpr[op.rs]);
|
||||
PPU_WRITE(le_t<u16>, vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -6054,7 +6056,7 @@ auto STFS()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
||||
vm::_ref<f32>(vm::cast(addr)) = static_cast<float>(ppu.fpr[op.frs]);
|
||||
PPU_WRITE(f32, vm::cast(addr), static_cast<float>(ppu.fpr[op.frs]));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -6067,7 +6069,7 @@ auto STFSU()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
||||
vm::_ref<f32>(vm::cast(addr)) = static_cast<float>(ppu.fpr[op.frs]);
|
||||
PPU_WRITE(f32, vm::cast(addr), static_cast<float>(ppu.fpr[op.frs]));
|
||||
ppu.gpr[op.ra] = addr;
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
|
@ -6081,7 +6083,7 @@ auto STFD()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
||||
vm::_ref<f64>(vm::cast(addr)) = ppu.fpr[op.frs];
|
||||
PPU_WRITE(f64, vm::cast(addr), ppu.fpr[op.frs]);
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -6094,7 +6096,7 @@ auto STFDU()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
||||
vm::_ref<f64>(vm::cast(addr)) = ppu.fpr[op.frs];
|
||||
PPU_WRITE(f64, vm::cast(addr), ppu.fpr[op.frs]);
|
||||
ppu.gpr[op.ra] = addr;
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
|
|
|
@ -3367,7 +3367,10 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||
fmt::throw_exception("PPU %s: Unaligned address: 0x%08x", sizeof(T) == 4 ? "STWCX" : "STDCX", addr);
|
||||
}
|
||||
|
||||
auto& data = vm::_ref<atomic_be_t<u64>>(addr & -8);
|
||||
// Notify breakpoint handler
|
||||
vm::write<void>(addr, T{0}, &ppu);
|
||||
|
||||
auto& data = const_cast<atomic_be_t<u64>&>(vm::_ref<atomic_be_t<u64>>(addr & -8));
|
||||
auto& res = vm::reservation_acquire(addr);
|
||||
const u64 rtime = ppu.rtime;
|
||||
|
||||
|
@ -4956,9 +4959,9 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
|
|||
return +code_ptr;
|
||||
}
|
||||
|
||||
constexpr auto abs_diff = [](u64 a, u64 b) { return a <= b ? b - a : a - b; };
|
||||
[[maybe_unused]] constexpr auto abs_diff = [](u64 a, u64 b) { return a <= b ? b - a : a - b; };
|
||||
|
||||
auto write_le = [](u8*& code, auto value)
|
||||
[[maybe_unused]] auto write_le = [](u8*& code, auto value)
|
||||
{
|
||||
write_to_ptr<le_t<std::remove_cvref_t<decltype(value)>>>(code, value);
|
||||
code += sizeof(value);
|
||||
|
@ -5823,7 +5826,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module<lv2_obj>& module
|
|||
min_addr = std::min<u32>(min_addr, mod_func.addr);
|
||||
|
||||
// Translate
|
||||
if (const auto func = translator.Translate(mod_func))
|
||||
if ([[maybe_unused]] const auto func = translator.Translate(mod_func))
|
||||
{
|
||||
#ifdef ARCH_X64 // TODO
|
||||
// Run optimization passes
|
||||
|
@ -5841,7 +5844,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module<lv2_obj>& module
|
|||
// Run this only in one module for all functions compiled
|
||||
if (module_part.jit_bounds)
|
||||
{
|
||||
if (const auto func = translator.GetSymbolResolver(module_part))
|
||||
if ([[maybe_unused]] const auto func = translator.GetSymbolResolver(module_part))
|
||||
{
|
||||
#ifdef ARCH_X64 // TODO
|
||||
// Run optimization passes
|
||||
|
|
|
@ -1290,7 +1290,7 @@ void PPUTranslator::VMADDFP(ppu_opcode_t op)
|
|||
void PPUTranslator::VMAXFP(ppu_opcode_t op)
|
||||
{
|
||||
const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb);
|
||||
set_vr(op.vd, vec_handle_result(bitcast<f32[4]>(bitcast<u32[4]>(fmax(a, b)) & bitcast<u32[4]>(fmax(b, a)))));
|
||||
set_vr(op.vd, vec_handle_result(select(fcmp_ord(a < b) | fcmp_uno(b != b), b, a)));
|
||||
}
|
||||
|
||||
void PPUTranslator::VMAXSB(ppu_opcode_t op)
|
||||
|
@ -1352,7 +1352,7 @@ void PPUTranslator::VMHRADDSHS(ppu_opcode_t op)
|
|||
void PPUTranslator::VMINFP(ppu_opcode_t op)
|
||||
{
|
||||
const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb);
|
||||
set_vr(op.vd, vec_handle_result(bitcast<f32[4]>(bitcast<u32[4]>(fmin(a, b)) | bitcast<u32[4]>(fmin(b, a)))));
|
||||
set_vr(op.vd, vec_handle_result(select(fcmp_ord(a > b) | fcmp_uno(b != b), b, a)));
|
||||
}
|
||||
|
||||
void PPUTranslator::VMINSB(ppu_opcode_t op)
|
||||
|
@ -4653,7 +4653,7 @@ void PPUTranslator::MTFSF(ppu_opcode_t op)
|
|||
|
||||
for (u32 i = 16; i < 20; i++)
|
||||
{
|
||||
if (i != 1 && i != 2 && (op.flm & (128 >> (i / 4))) != 0)
|
||||
if ((op.flm & (128 >> (i / 4))) != 0)
|
||||
{
|
||||
SetFPSCRBit(i, Trunc(m_ir->CreateLShr(value, i ^ 31), GetType<bool>()), false);
|
||||
}
|
||||
|
|
|
@ -1237,7 +1237,7 @@ void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const
|
|||
|
||||
if (const_value != r)
|
||||
{
|
||||
// Expectation of pretictable code path has not been met (such as a branch directly to the instruction)
|
||||
// Expectation of predictable code path has not been met (such as a branch directly to the instruction)
|
||||
is_const = false;
|
||||
}
|
||||
|
||||
|
@ -1447,7 +1447,7 @@ std::vector<std::pair<u32, u32>> spu_thread::dump_callstack_list() const
|
|||
if (v != v128::from32r(addr))
|
||||
{
|
||||
// 1) Non-zero lower words are invalid (because BRSL-like instructions generate only zeroes)
|
||||
// 2) Bits normally masked out by indirect braches are considered invalid
|
||||
// 2) Bits normally masked out by indirect branches are considered invalid
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3833,14 +3833,14 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args)
|
|||
{
|
||||
if (addr - spurs_addr <= 0x80)
|
||||
{
|
||||
mov_rdata(vm::_ref<spu_rdata_t>(addr), to_write);
|
||||
mov_rdata(*vm::_ptr<spu_rdata_t>(addr), to_write);
|
||||
res += 64;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (!g_use_rtm)
|
||||
{
|
||||
vm::_ref<atomic_t<u32>>(addr) += 0;
|
||||
*vm::_ptr<atomic_t<u32>>(addr) += 0;
|
||||
}
|
||||
|
||||
if (g_use_rtm) [[likely]]
|
||||
|
|
|
@ -373,7 +373,7 @@ const std::array<std::pair<ppu_intrp_func_t, std::string_view>, 1024> g_ppu_sysc
|
|||
|
||||
uns_func, uns_func, uns_func, uns_func, uns_func, //255-259 UNS
|
||||
|
||||
NULL_FUNC(sys_spu_image_open_by_fd), //260 (0x104)
|
||||
BIND_SYSC(sys_spu_image_open_by_fd), //260 (0x104)
|
||||
|
||||
uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, //261-269 UNS
|
||||
uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, //270-279 UNS
|
||||
|
|
|
@ -502,7 +502,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
|||
|
||||
if (!cond || !mutex)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
return { CELL_ESRCH, fmt::format("lwmutex_id: 0x%x, lwcond_id: 0x%x", lwmutex_id, lwcond_id) };
|
||||
}
|
||||
|
||||
if (ppu.state & cpu_flag::again)
|
||||
|
|
|
@ -183,7 +183,12 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
|
|||
|
||||
if (!mutex)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
if (lwmutex_id >> 24 == lv2_lwmutex::id_base >> 24)
|
||||
{
|
||||
return { CELL_ESRCH, lwmutex_id };
|
||||
}
|
||||
|
||||
return { CELL_ESRCH, "Invalid ID" };
|
||||
}
|
||||
|
||||
if (mutex.ret)
|
||||
|
@ -313,7 +318,12 @@ error_code _sys_lwmutex_trylock(ppu_thread& ppu, u32 lwmutex_id)
|
|||
|
||||
if (!mutex)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
if (lwmutex_id >> 24 == lv2_lwmutex::id_base >> 24)
|
||||
{
|
||||
return { CELL_ESRCH, lwmutex_id };
|
||||
}
|
||||
|
||||
return { CELL_ESRCH, "Invalid ID" };
|
||||
}
|
||||
|
||||
if (!mutex.ret)
|
||||
|
|
|
@ -181,7 +181,7 @@ error_code sys_rsx_memory_allocate(cpu_thread& cpu, vm::ptr<u32> mem_handle, vm:
|
|||
|
||||
if (u32 addr = rsx::get_current_renderer()->driver_info)
|
||||
{
|
||||
vm::_ref<RsxDriverInfo>(addr).memory_size = size;
|
||||
vm::_ptr<RsxDriverInfo>(addr)->memory_size = size;
|
||||
}
|
||||
|
||||
*mem_addr = rsx::constants::local_mem_base;
|
||||
|
@ -265,7 +265,7 @@ error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr<u32> context_id, vm
|
|||
*lpar_driver_info = dma_address + 0x100000;
|
||||
*lpar_reports = dma_address + 0x200000;
|
||||
|
||||
auto &reports = vm::_ref<RsxReports>(vm::cast(*lpar_reports));
|
||||
auto &reports = *vm::_ptr<RsxReports>(vm::cast(*lpar_reports));
|
||||
std::memset(&reports, 0, sizeof(RsxReports));
|
||||
|
||||
for (usz i = 0; i < std::size(reports.notify); ++i)
|
||||
|
@ -273,10 +273,10 @@ error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr<u32> context_id, vm
|
|||
|
||||
for (usz i = 0; i < std::size(reports.semaphore); i += 4)
|
||||
{
|
||||
reports.semaphore[i + 0].val.raw() = 0x1337C0D3;
|
||||
reports.semaphore[i + 1].val.raw() = 0x1337BABE;
|
||||
reports.semaphore[i + 2].val.raw() = 0x1337BEEF;
|
||||
reports.semaphore[i + 3].val.raw() = 0x1337F001;
|
||||
reports.semaphore[i + 0] = 0x1337C0D3;
|
||||
reports.semaphore[i + 1] = 0x1337BABE;
|
||||
reports.semaphore[i + 2] = 0x1337BEEF;
|
||||
reports.semaphore[i + 3] = 0x1337F001;
|
||||
}
|
||||
|
||||
for (usz i = 0; i < std::size(reports.report); ++i)
|
||||
|
@ -286,7 +286,7 @@ error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr<u32> context_id, vm
|
|||
reports.report[i].pad = -1;
|
||||
}
|
||||
|
||||
auto &driverInfo = vm::_ref<RsxDriverInfo>(vm::cast(*lpar_driver_info));
|
||||
auto &driverInfo = *vm::_ptr<RsxDriverInfo>(vm::cast(*lpar_driver_info));
|
||||
|
||||
std::memset(&driverInfo, 0, sizeof(RsxDriverInfo));
|
||||
|
||||
|
@ -303,7 +303,7 @@ error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr<u32> context_id, vm
|
|||
|
||||
render->driver_info = vm::cast(*lpar_driver_info);
|
||||
|
||||
auto &dmaControl = vm::_ref<RsxDmaControl>(vm::cast(*lpar_dma_control));
|
||||
auto &dmaControl = *vm::_ptr<RsxDmaControl>(vm::cast(*lpar_dma_control));
|
||||
dmaControl.get = 0;
|
||||
dmaControl.put = 0;
|
||||
dmaControl.ref = 0; // Set later to -1 by cellGcmSys
|
||||
|
@ -527,7 +527,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
|
|||
return { CELL_EINVAL, "context_id is 0x%x", context_id };
|
||||
}
|
||||
|
||||
auto &driverInfo = vm::_ref<RsxDriverInfo>(render->driver_info);
|
||||
auto &driverInfo = *vm::_ptr<RsxDriverInfo>(render->driver_info);
|
||||
switch (package_id)
|
||||
{
|
||||
case 0x001: // FIFO
|
||||
|
@ -862,7 +862,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
|
|||
|
||||
// seems gcmSysWaitLabel uses this offset, so lets set it to 0 every flip
|
||||
// NOTE: Realhw resets 16 bytes of this semaphore for some reason
|
||||
vm::_ref<atomic_t<u128>>(render->label_addr + 0x10).store(u128{});
|
||||
vm::_ptr<atomic_t<u128>>(render->label_addr + 0x10)->store(u128{});
|
||||
|
||||
render->send_event(0, SYS_RSX_EVENT_FLIP_BASE << 1, 0);
|
||||
break;
|
||||
|
|
|
@ -87,10 +87,7 @@ struct RsxDmaControl
|
|||
be_t<u32> unk1;
|
||||
};
|
||||
|
||||
struct RsxSemaphore
|
||||
{
|
||||
atomic_be_t<u32> val;
|
||||
};
|
||||
using RsxSemaphore = be_t<u32>;
|
||||
|
||||
struct alignas(16) RsxNotify
|
||||
{
|
||||
|
|
|
@ -66,13 +66,14 @@ void fmt_class_string<spu_stop_syscall>::format(std::string& out, u64 arg)
|
|||
});
|
||||
}
|
||||
|
||||
void sys_spu_image::load(const fs::file& stream)
|
||||
bool sys_spu_image::load(const fs::file& stream)
|
||||
{
|
||||
const spu_exec_object obj{stream, 0, elf_opt::no_sections + elf_opt::no_data};
|
||||
|
||||
if (obj != elf_error::ok)
|
||||
{
|
||||
fmt::throw_exception("Failed to load SPU image: %s", obj.get_error());
|
||||
sys_spu.error("Failed to load SPU image: %s", obj.get_error());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& shdr : obj.shdrs)
|
||||
|
@ -94,7 +95,7 @@ void sys_spu_image::load(const fs::file& stream)
|
|||
const s32 nsegs = sys_spu_image::get_nsegs(obj.progs);
|
||||
|
||||
const u32 mem_size = nsegs * sizeof(sys_spu_segment) + ::size32(stream);
|
||||
const vm::ptr<sys_spu_segment> segs = vm::cast(vm::alloc(mem_size, vm::main));
|
||||
const vm::ptr<sys_spu_segment> segs = vm::cast(vm::reserve_map(vm::user64k, 0, 0x10000000)->alloc(mem_size));
|
||||
|
||||
//const u32 entry = obj.header.e_entry;
|
||||
|
||||
|
@ -116,6 +117,7 @@ void sys_spu_image::load(const fs::file& stream)
|
|||
this->segs = vm::null;
|
||||
|
||||
vm::page_protect(segs.addr(), utils::align(mem_size, 4096), 0, 0, vm::page_writable);
|
||||
return true;
|
||||
}
|
||||
|
||||
void sys_spu_image::free() const
|
||||
|
@ -388,19 +390,43 @@ struct spu_limits_t
|
|||
|
||||
SAVESTATE_INIT_POS(47);
|
||||
|
||||
bool check(const limits_data& init) const
|
||||
bool check_valid(const limits_data& init) const
|
||||
{
|
||||
const u32 physical_spus_count = init.physical;
|
||||
const u32 controllable_spu_count = init.controllable;
|
||||
|
||||
const u32 spu_limit = init.spu_limit != umax ? init.spu_limit : max_spu;
|
||||
const u32 raw_limit = init.raw_limit != umax ? init.raw_limit : max_raw;
|
||||
|
||||
if (spu_limit + raw_limit > 6 || physical_spus_count > spu_limit || controllable_spu_count > spu_limit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check_busy(const limits_data& init) const
|
||||
{
|
||||
u32 physical_spus_count = init.physical;
|
||||
u32 raw_spu_count = init.raw_spu;
|
||||
u32 controllable_spu_count = init.controllable;
|
||||
u32 system_coop = init.controllable != 0 && init.physical != 0 ? 1 : 0;
|
||||
|
||||
const u32 spu_limit = init.spu_limit != umax ? init.spu_limit : max_spu;
|
||||
const u32 raw_limit = init.raw_limit != umax ? init.raw_limit : max_raw;
|
||||
|
||||
idm::select<lv2_spu_group>([&](u32, lv2_spu_group& group)
|
||||
{
|
||||
if (group.has_scheduler_context)
|
||||
if (group.type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
|
||||
{
|
||||
controllable_spu_count = std::max(controllable_spu_count, group.max_num);
|
||||
system_coop++;
|
||||
controllable_spu_count = std::max<u32>(controllable_spu_count, 1);
|
||||
physical_spus_count += group.max_num - 1;
|
||||
}
|
||||
else if (group.has_scheduler_context)
|
||||
{
|
||||
controllable_spu_count = std::max<u32>(controllable_spu_count, group.max_num);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -410,11 +436,18 @@ struct spu_limits_t
|
|||
|
||||
raw_spu_count += spu_thread::g_raw_spu_ctr;
|
||||
|
||||
if (spu_limit + raw_limit > 6 || raw_spu_count > raw_limit || physical_spus_count >= spu_limit || physical_spus_count + controllable_spu_count > spu_limit)
|
||||
// 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)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (system_coop > 1)
|
||||
{
|
||||
// Cannot have more than one SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM group at a time
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -437,7 +470,7 @@ error_code sys_spu_initialize(ppu_thread& ppu, u32 max_usable_spu, u32 max_raw_s
|
|||
|
||||
std::lock_guard lock(limits.mutex);
|
||||
|
||||
if (!limits.check(limits_data{.spu_limit = max_usable_spu - max_raw_spu, .raw_limit = max_raw_spu}))
|
||||
if (!limits.check_busy(limits_data{.spu_limit = max_usable_spu - max_raw_spu, .raw_limit = max_raw_spu}))
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
@ -486,15 +519,52 @@ error_code sys_spu_image_open(ppu_thread& ppu, vm::ptr<sys_spu_image> img, vm::c
|
|||
|
||||
u128 klic = g_fxo->get<loaded_npdrm_keys>().last_key();
|
||||
|
||||
const fs::file elf_file = decrypt_self(std::move(file), reinterpret_cast<u8*>(&klic));
|
||||
const fs::file elf_file = decrypt_self(file, reinterpret_cast<const u8*>(&klic));
|
||||
|
||||
if (!elf_file)
|
||||
if (!elf_file || !img->load(elf_file))
|
||||
{
|
||||
sys_spu.error("sys_spu_image_open(): file %s is illegal for SPU image!", path);
|
||||
return {CELL_ENOEXEC, path};
|
||||
}
|
||||
|
||||
img->load(elf_file);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_spu_image_open_by_fd(ppu_thread& ppu, vm::ptr<sys_spu_image> img, s32 fd, s64 offset)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
sys_spu.warning("sys_spu_image_open_by_fd(img=*0x%x, fd=%d, offset=0x%x)", img, fd, offset);
|
||||
|
||||
const auto file = idm::get_unlocked<lv2_fs_object, lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
std::lock_guard lock(file->mp->mutex);
|
||||
|
||||
if (!file->file)
|
||||
{
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
u128 klic = g_fxo->get<loaded_npdrm_keys>().last_key();
|
||||
|
||||
const fs::file elf_file = decrypt_self(lv2_file::make_view(file, offset), reinterpret_cast<const u8*>(&klic));
|
||||
|
||||
if (!img->load(elf_file))
|
||||
{
|
||||
sys_spu.error("sys_spu_image_open(): file %s is illegal for SPU image!", file->name.data());
|
||||
return {CELL_ENOEXEC, file->name.data()};
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -526,7 +596,7 @@ error_code _sys_spu_image_close(ppu_thread& ppu, vm::ptr<sys_spu_image> img)
|
|||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
ensure(vm::dealloc(handle->segs.addr(), vm::main));
|
||||
ensure(vm::dealloc(handle->segs.addr(), vm::user64k));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -845,23 +915,24 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
|
|||
switch (type)
|
||||
{
|
||||
case 0x0:
|
||||
case 0x4:
|
||||
case 0x18:
|
||||
case SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER:
|
||||
case SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x20:
|
||||
case 0x22:
|
||||
case 0x24:
|
||||
case 0x26:
|
||||
case SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM:
|
||||
case (SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM | 0x2):
|
||||
case (SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM | 0x4):
|
||||
case (SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM | 0x6):
|
||||
{
|
||||
if (type == 0x22 || type == 0x26)
|
||||
{
|
||||
needs_root = true;
|
||||
}
|
||||
|
||||
min_threads = 2; // That's what appears from reversing
|
||||
// For a single thread that is being shared with system (the cooperative victim)
|
||||
min_threads = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -901,7 +972,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
|
|||
|
||||
if (is_system_coop)
|
||||
{
|
||||
// Constant size, unknown what it means
|
||||
// For a single thread that is being shared with system (the cooperative victim)
|
||||
mem_size = SPU_LS_SIZE;
|
||||
}
|
||||
else if (type & SYS_SPU_THREAD_GROUP_TYPE_NON_CONTEXT)
|
||||
|
@ -952,7 +1023,29 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
|
|||
|
||||
std::unique_lock lock(limits.mutex);
|
||||
|
||||
if (!limits.check(use_scheduler ? limits_data{.controllable = num} : limits_data{.physical = num}))
|
||||
limits_data group_limits{};
|
||||
|
||||
if (is_system_coop)
|
||||
{
|
||||
group_limits.controllable = 1;
|
||||
group_limits.physical = num - 1;
|
||||
}
|
||||
else if (use_scheduler)
|
||||
{
|
||||
group_limits.controllable = num;
|
||||
}
|
||||
else
|
||||
{
|
||||
group_limits.physical = num;
|
||||
}
|
||||
|
||||
if (!limits.check_valid(group_limits))
|
||||
{
|
||||
ct->free(mem_size);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (!limits.check_busy(group_limits))
|
||||
{
|
||||
ct->free(mem_size);
|
||||
return CELL_EBUSY;
|
||||
|
@ -1135,6 +1228,11 @@ error_code sys_spu_thread_group_suspend(ppu_thread& ppu, u32 id)
|
|||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (group->type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
std::lock_guard lock(group->mutex);
|
||||
|
||||
CellError error;
|
||||
|
@ -1218,6 +1316,11 @@ error_code sys_spu_thread_group_resume(ppu_thread& ppu, u32 id)
|
|||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (group->type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
struct notify_on_exit
|
||||
{
|
||||
usz index = umax;
|
||||
|
@ -1565,6 +1668,11 @@ error_code sys_spu_thread_group_set_priority(ppu_thread& ppu, u32 id, s32 priori
|
|||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (group->type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
group->prio.atomic_op([&](std::common_type_t<decltype(lv2_spu_group::prio)>& prio)
|
||||
{
|
||||
prio.prio = priority;
|
||||
|
@ -1592,6 +1700,11 @@ error_code sys_spu_thread_group_get_priority(ppu_thread& ppu, u32 id, vm::ptr<s3
|
|||
{
|
||||
*priority = 0;
|
||||
}
|
||||
else if (group->type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM)
|
||||
{
|
||||
// Regardless of the value being set in group creation
|
||||
*priority = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
*priority = group->prio.load().prio;
|
||||
|
@ -1751,7 +1864,7 @@ error_code sys_spu_thread_write_spu_mb(ppu_thread& ppu, u32 id, u32 value)
|
|||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
sys_spu.warning("sys_spu_thread_write_spu_mb(id=0x%x, value=0x%x)", id, value);
|
||||
sys_spu.trace("sys_spu_thread_write_spu_mb(id=0x%x, value=0x%x)", id, value);
|
||||
|
||||
const auto [thread, group] = lv2_spu_group::get_thread(id);
|
||||
|
||||
|
@ -2275,7 +2388,7 @@ error_code sys_raw_spu_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<void> at
|
|||
|
||||
std::lock_guard lock(limits.mutex);
|
||||
|
||||
if (!limits.check(limits_data{.raw_spu = 1}))
|
||||
if (!limits.check_busy(limits_data{.raw_spu = 1}))
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
@ -2331,7 +2444,7 @@ error_code sys_isolated_spu_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<voi
|
|||
|
||||
std::lock_guard lock(limits.mutex);
|
||||
|
||||
if (!limits.check(limits_data{.raw_spu = 1}))
|
||||
if (!limits.check_busy(limits_data{.raw_spu = 1}))
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ struct sys_spu_image
|
|||
return num_segs;
|
||||
}
|
||||
|
||||
void load(const fs::file& stream);
|
||||
bool load(const fs::file& stream);
|
||||
void free() const;
|
||||
static void deploy(u8* loc, std::span<const sys_spu_segment> segs, bool is_verbose = true);
|
||||
};
|
||||
|
@ -354,6 +354,7 @@ class ppu_thread;
|
|||
error_code sys_spu_initialize(ppu_thread&, u32 max_usable_spu, u32 max_raw_spu);
|
||||
error_code _sys_spu_image_get_information(ppu_thread&, vm::ptr<sys_spu_image> img, vm::ptr<u32> entry_point, vm::ptr<s32> nsegs);
|
||||
error_code sys_spu_image_open(ppu_thread&, vm::ptr<sys_spu_image> img, vm::cptr<char> path);
|
||||
error_code sys_spu_image_open_by_fd(ppu_thread&, vm::ptr<sys_spu_image> img, s32 fd, s64 offset);
|
||||
error_code _sys_spu_image_import(ppu_thread&, vm::ptr<sys_spu_image> img, u32 src, u32 size, u32 arg4);
|
||||
error_code _sys_spu_image_close(ppu_thread&, vm::ptr<sys_spu_image> img);
|
||||
error_code _sys_spu_image_get_segments(ppu_thread&, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_segment> segments, s32 nseg);
|
||||
|
|
|
@ -553,7 +553,7 @@ error_code sys_ss_individual_info_manager(u64 pkg_id, u64 a2, vm::ptr<u64> out_s
|
|||
case 0x17002:
|
||||
{
|
||||
// TODO
|
||||
vm::_ref<u64>(a5) = a4; // Write back size of buffer
|
||||
vm::write<u64>(a5, a4); // Write back size of buffer
|
||||
break;
|
||||
}
|
||||
// Get EID size
|
||||
|
|
|
@ -483,8 +483,6 @@ namespace vm
|
|||
}
|
||||
}
|
||||
|
||||
bool to_prepare_memory = true;
|
||||
|
||||
for (u64 i = 0;; i++)
|
||||
{
|
||||
auto& bits = get_range_lock_bits(true);
|
||||
|
@ -512,22 +510,11 @@ namespace vm
|
|||
|
||||
if (i < 100)
|
||||
{
|
||||
if (to_prepare_memory)
|
||||
{
|
||||
// We have some spare time, prepare cache lines (todo: reservation tests here)
|
||||
utils::prefetch_write(vm::get_super_ptr(addr));
|
||||
utils::prefetch_write(vm::get_super_ptr(addr) + 64);
|
||||
to_prepare_memory = false;
|
||||
}
|
||||
|
||||
busy_wait(200);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::this_thread::yield();
|
||||
|
||||
// Thread may have been switched or the cache clue has been undermined, cache needs to be prapred again
|
||||
to_prepare_memory = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,13 +578,6 @@ namespace vm
|
|||
break;
|
||||
}
|
||||
|
||||
if (to_prepare_memory)
|
||||
{
|
||||
utils::prefetch_write(vm::get_super_ptr(addr));
|
||||
utils::prefetch_write(vm::get_super_ptr(addr) + 64);
|
||||
to_prepare_memory = false;
|
||||
}
|
||||
|
||||
utils::pause();
|
||||
}
|
||||
|
||||
|
@ -607,13 +587,6 @@ namespace vm
|
|||
{
|
||||
while (!(ptr->state & cpu_flag::wait))
|
||||
{
|
||||
if (to_prepare_memory)
|
||||
{
|
||||
utils::prefetch_write(vm::get_super_ptr(addr));
|
||||
utils::prefetch_write(vm::get_super_ptr(addr) + 64);
|
||||
to_prepare_memory = false;
|
||||
}
|
||||
|
||||
utils::pause();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
#include "util/to_endian.hpp"
|
||||
|
||||
class ppu_thread;
|
||||
|
||||
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||
#include "rpcs3qt/breakpoint_handler.h"
|
||||
#include "util/logs.hpp"
|
||||
|
||||
LOG_CHANNEL(debugbp_log, "DebugBP");
|
||||
|
||||
class ppu_thread;
|
||||
|
||||
void ppubreak(ppu_thread& ppu);
|
||||
#endif
|
||||
|
||||
|
@ -282,9 +282,10 @@ namespace vm
|
|||
}
|
||||
|
||||
// Convert specified PS3 address to a reference of specified (possibly converted to BE) type
|
||||
template <typename T, typename U> inline to_be_t<T>& _ref(const U& addr)
|
||||
// Const lvalue: prevent abused writes
|
||||
template <typename T, typename U> inline const to_be_t<T>& _ref(const U& addr)
|
||||
{
|
||||
return *static_cast<to_be_t<T>*>(base(addr));
|
||||
return *static_cast<const to_be_t<T>*>(base(addr));
|
||||
}
|
||||
|
||||
// Access memory bypassing memory protection
|
||||
|
@ -300,42 +301,43 @@ namespace vm
|
|||
}
|
||||
|
||||
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||
inline void write16(u32 addr, be_t<u16> value, ppu_thread* ppu = nullptr)
|
||||
template <typename T, typename U = T>
|
||||
inline void write(u32 addr, U value, ppu_thread* ppu = nullptr)
|
||||
#else
|
||||
inline void write16(u32 addr, be_t<u16> value)
|
||||
template <typename T, typename U = T>
|
||||
inline void write(u32 addr, U value, ppu_thread* = nullptr)
|
||||
#endif
|
||||
{
|
||||
_ref<u16>(addr) = value;
|
||||
using dest_t = std::conditional_t<std::is_void_v<T>, U, T>;
|
||||
|
||||
if constexpr (!std::is_void_v<T>)
|
||||
{
|
||||
*_ptr<dest_t>(addr) = value;
|
||||
}
|
||||
|
||||
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
|
||||
{
|
||||
debugbp_log.success("BPMW: breakpoint writing(16) 0x%x at 0x%x", value, addr);
|
||||
debugbp_log.success("BPMW: breakpoint writing(%d) 0x%x at 0x%x",
|
||||
sizeof(dest_t) * CHAR_BIT, value, addr);
|
||||
ppubreak(*ppu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void write16(u32 addr, be_t<u16> value, ppu_thread* ppu = nullptr)
|
||||
{
|
||||
write<be_t<u16>>(addr, value, ppu);
|
||||
}
|
||||
|
||||
inline const be_t<u32>& read32(u32 addr)
|
||||
{
|
||||
return _ref<u32>(addr);
|
||||
}
|
||||
|
||||
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||
inline void write32(u32 addr, be_t<u32> value, ppu_thread* ppu = nullptr)
|
||||
#else
|
||||
inline void write32(u32 addr, be_t<u32> value)
|
||||
#endif
|
||||
{
|
||||
_ref<u32>(addr) = value;
|
||||
|
||||
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
|
||||
{
|
||||
debugbp_log.success("BPMW: breakpoint writing(32) 0x%x at 0x%x", value, addr);
|
||||
ppubreak(*ppu);
|
||||
}
|
||||
#endif
|
||||
write<be_t<u32>>(addr, value, ppu);
|
||||
}
|
||||
|
||||
inline const be_t<u64>& read64(u32 addr)
|
||||
|
@ -343,21 +345,9 @@ namespace vm
|
|||
return _ref<u64>(addr);
|
||||
}
|
||||
|
||||
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||
inline void write64(u32 addr, be_t<u64> value, ppu_thread* ppu = nullptr)
|
||||
#else
|
||||
inline void write64(u32 addr, be_t<u64> value)
|
||||
#endif
|
||||
{
|
||||
_ref<u64>(addr) = value;
|
||||
|
||||
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
|
||||
{
|
||||
debugbp_log.success("BPMW: breakpoint writing(64) 0x%x at 0x%x", value, addr);
|
||||
ppubreak(*ppu);
|
||||
}
|
||||
#endif
|
||||
write<be_t<u64>>(addr, value, ppu);
|
||||
}
|
||||
|
||||
void init();
|
||||
|
|
|
@ -6,6 +6,14 @@
|
|||
#include "util/v128.hpp"
|
||||
#include "util/simd.hpp"
|
||||
|
||||
#if defined(ARCH_ARM64)
|
||||
#if !defined(_MSC_VER)
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#endif
|
||||
#undef FORCE_INLINE
|
||||
#include "Emu/CPU/sse2neon.h"
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
|
@ -404,57 +412,76 @@ namespace
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
NEVER_INLINE std::tuple<T, T, u32> upload_untouched_skip_restart(std::span<to_be_t<const T>> src, std::span<T> dst, T restart_index)
|
||||
{
|
||||
T min_index = index_limit<T>();
|
||||
T max_index = 0;
|
||||
u32 written = 0;
|
||||
u32 length = ::size32(src);
|
||||
|
||||
for (u32 i = written; i < length; ++i)
|
||||
template <typename T>
|
||||
NEVER_INLINE std::tuple<T, T, u32> upload_untouched_skip_restart(std::span<to_be_t<const T>> src, std::span<T> dst, T restart_index)
|
||||
{
|
||||
T index = src[i];
|
||||
if (index != restart_index)
|
||||
T min_index = index_limit<T>();
|
||||
T max_index = 0;
|
||||
u32 written = 0;
|
||||
u32 length = ::size32(src);
|
||||
|
||||
for (u32 i = written; i < length; ++i)
|
||||
{
|
||||
dst[written++] = min_max(min_index, max_index, index);
|
||||
T index = src[i];
|
||||
if (index != restart_index)
|
||||
{
|
||||
dst[written++] = min_max(min_index, max_index, index);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_tuple(min_index, max_index, written);
|
||||
}
|
||||
|
||||
return std::make_tuple(min_index, max_index, written);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::tuple<T, T, u32> upload_untouched(std::span<to_be_t<const T>> src, std::span<T> dst, rsx::primitive_type draw_mode, bool is_primitive_restart_enabled, u32 primitive_restart_index)
|
||||
{
|
||||
if (!is_primitive_restart_enabled)
|
||||
template<typename T>
|
||||
std::tuple<T, T, u32> upload_untouched(std::span<to_be_t<const T>> src, std::span<T> dst, rsx::primitive_type draw_mode, bool is_primitive_restart_enabled, u32 primitive_restart_index)
|
||||
{
|
||||
return untouched_impl::upload_untouched(src, dst);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, u16>)
|
||||
{
|
||||
if (primitive_restart_index > 0xffff)
|
||||
if (!is_primitive_restart_enabled)
|
||||
{
|
||||
return untouched_impl::upload_untouched(src, dst);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, u16>)
|
||||
{
|
||||
if (primitive_restart_index > 0xffff)
|
||||
{
|
||||
return untouched_impl::upload_untouched(src, dst);
|
||||
}
|
||||
else if (is_primitive_disjointed(draw_mode))
|
||||
{
|
||||
return upload_untouched_skip_restart(src, dst, static_cast<u16>(primitive_restart_index));
|
||||
}
|
||||
else
|
||||
{
|
||||
return primitive_restart_impl::upload_untouched(src, dst, static_cast<u16>(primitive_restart_index));
|
||||
}
|
||||
}
|
||||
else if (is_primitive_disjointed(draw_mode))
|
||||
{
|
||||
return upload_untouched_skip_restart(src, dst, static_cast<u16>(primitive_restart_index));
|
||||
return upload_untouched_skip_restart(src, dst, primitive_restart_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
return primitive_restart_impl::upload_untouched(src, dst, static_cast<u16>(primitive_restart_index));
|
||||
return primitive_restart_impl::upload_untouched(src, dst, primitive_restart_index);
|
||||
}
|
||||
}
|
||||
else if (is_primitive_disjointed(draw_mode))
|
||||
|
||||
void iota16(u16* dst, u32 count)
|
||||
{
|
||||
return upload_untouched_skip_restart(src, dst, primitive_restart_index);
|
||||
unsigned i = 0;
|
||||
#if defined(ARCH_X64) || defined(ARCH_ARM64)
|
||||
const unsigned step = 8; // We do 8 entries per step
|
||||
const __m128i vec_step = _mm_set1_epi16(8); // Constant to increment the raw values
|
||||
__m128i values = _mm_set_epi16(7, 6, 5, 4, 3, 2, 1, 0);
|
||||
__m128i* vec_ptr = reinterpret_cast<__m128i*>(dst);
|
||||
|
||||
for (; (i + step) <= count; i += step, vec_ptr++)
|
||||
{
|
||||
_mm_stream_si128(vec_ptr, values);
|
||||
_mm_add_epi16(values, vec_step);
|
||||
}
|
||||
#endif
|
||||
for (; i < count; ++i)
|
||||
dst[i] = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
return primitive_restart_impl::upload_untouched(src, dst, primitive_restart_index);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::tuple<T, T, u32> expand_indexed_triangle_fan(std::span<to_be_t<const T>> src, std::span<T> dst, bool is_primitive_restart_enabled, u32 primitive_restart_index)
|
||||
|
@ -624,8 +651,7 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst,
|
|||
switch (draw_mode)
|
||||
{
|
||||
case rsx::primitive_type::line_loop:
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
typedDst[i] = i;
|
||||
iota16(typedDst, count);
|
||||
typedDst[count] = 0;
|
||||
return;
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
|
|
|
@ -20,29 +20,33 @@ protected:
|
|||
template<int Alignment>
|
||||
bool can_alloc(usz size) const
|
||||
{
|
||||
usz alloc_size = utils::align(size, Alignment);
|
||||
usz aligned_put_pos = utils::align(m_put_pos, Alignment);
|
||||
if (aligned_put_pos + alloc_size < m_size)
|
||||
const usz alloc_size = utils::align(size, Alignment);
|
||||
const usz aligned_put_pos = utils::align(m_put_pos, Alignment);
|
||||
const usz alloc_end = aligned_put_pos + alloc_size;
|
||||
|
||||
if (alloc_end < m_size) [[ likely ]]
|
||||
{
|
||||
// range before get
|
||||
if (aligned_put_pos + alloc_size < m_get_pos)
|
||||
// Range before get
|
||||
if (alloc_end < m_get_pos)
|
||||
return true;
|
||||
// range after get
|
||||
|
||||
// Range after get
|
||||
if (aligned_put_pos > m_get_pos)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ..]....[..get..
|
||||
if (aligned_put_pos < m_get_pos)
|
||||
return false;
|
||||
// ..get..]...[...
|
||||
// Actually all resources extending beyond heap space starts at 0
|
||||
if (alloc_size > m_get_pos)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ..]....[..get..
|
||||
if (aligned_put_pos < m_get_pos)
|
||||
return false;
|
||||
|
||||
// ..get..]...[...
|
||||
// Actually all resources extending beyond heap space starts at 0
|
||||
if (alloc_size > m_get_pos)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Grow the buffer to hold at least size bytes
|
||||
|
@ -53,10 +57,9 @@ protected:
|
|||
}
|
||||
|
||||
usz m_size;
|
||||
usz m_put_pos; // Start of free space
|
||||
usz m_min_guard_size; //If an allocation touches the guard region, reset the heap to avoid going over budget
|
||||
usz m_current_allocated_size;
|
||||
usz m_largest_allocated_pool;
|
||||
usz m_put_pos; // Start of free space
|
||||
usz m_get_pos; // End of free space
|
||||
usz m_min_guard_size; // If an allocation touches the guard region, reset the heap to avoid going over budget
|
||||
|
||||
char* m_name;
|
||||
public:
|
||||
|
@ -65,8 +68,6 @@ public:
|
|||
data_heap(const data_heap&) = delete;
|
||||
data_heap(data_heap&&) = delete;
|
||||
|
||||
usz m_get_pos; // End of free space
|
||||
|
||||
void init(usz heap_size, const char* buffer_name = "unnamed", usz min_guard_size=0x10000)
|
||||
{
|
||||
m_name = const_cast<char*>(buffer_name);
|
||||
|
@ -75,10 +76,8 @@ public:
|
|||
m_put_pos = 0;
|
||||
m_get_pos = heap_size - 1;
|
||||
|
||||
//allocation stats
|
||||
// Allocation stats
|
||||
m_min_guard_size = min_guard_size;
|
||||
m_current_allocated_size = 0;
|
||||
m_largest_allocated_pool = 0;
|
||||
}
|
||||
|
||||
template<int Alignment>
|
||||
|
@ -89,24 +88,45 @@ public:
|
|||
|
||||
if (!can_alloc<Alignment>(size) && !grow(alloc_size))
|
||||
{
|
||||
fmt::throw_exception("[%s] Working buffer not big enough, buffer_length=%d allocated=%d requested=%d guard=%d largest_pool=%d",
|
||||
m_name, m_size, m_current_allocated_size, size, m_min_guard_size, m_largest_allocated_pool);
|
||||
fmt::throw_exception("[%s] Working buffer not big enough, buffer_length=%d requested=%d guard=%d",
|
||||
m_name, m_size, size, m_min_guard_size);
|
||||
}
|
||||
|
||||
const usz block_length = (aligned_put_pos - m_put_pos) + alloc_size;
|
||||
m_current_allocated_size += block_length;
|
||||
m_largest_allocated_pool = std::max(m_largest_allocated_pool, block_length);
|
||||
|
||||
if (aligned_put_pos + alloc_size < m_size)
|
||||
const usz alloc_end = aligned_put_pos + alloc_size;
|
||||
if (alloc_end < m_size)
|
||||
{
|
||||
m_put_pos = aligned_put_pos + alloc_size;
|
||||
m_put_pos = alloc_end;
|
||||
return aligned_put_pos;
|
||||
}
|
||||
else
|
||||
|
||||
m_put_pos = alloc_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For use in cases where we take a fixed amount each time
|
||||
*/
|
||||
template<int Alignment, usz Size = Alignment>
|
||||
usz static_alloc()
|
||||
{
|
||||
static_assert((Size & (Alignment - 1)) == 0);
|
||||
ensure((m_put_pos & (Alignment - 1)) == 0);
|
||||
|
||||
if (!can_alloc<Alignment>(Size) && !grow(Size))
|
||||
{
|
||||
m_put_pos = alloc_size;
|
||||
return 0;
|
||||
fmt::throw_exception("[%s] Working buffer not big enough, buffer_length=%d requested=%d guard=%d",
|
||||
m_name, m_size, Size, m_min_guard_size);
|
||||
}
|
||||
|
||||
const usz alloc_end = m_put_pos + Size;
|
||||
if (m_put_pos + Size < m_size)
|
||||
{
|
||||
m_put_pos = alloc_end;
|
||||
return m_put_pos;
|
||||
}
|
||||
|
||||
m_put_pos = Size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,30 +137,20 @@ public:
|
|||
return (m_put_pos > 0) ? m_put_pos - 1 : m_size - 1;
|
||||
}
|
||||
|
||||
virtual bool is_critical() const
|
||||
inline void set_get_pos(usz value)
|
||||
{
|
||||
const usz guard_length = std::max(m_min_guard_size, m_largest_allocated_pool);
|
||||
return (m_current_allocated_size + guard_length) >= m_size;
|
||||
m_get_pos = value;
|
||||
}
|
||||
|
||||
void reset_allocation_stats()
|
||||
{
|
||||
m_current_allocated_size = 0;
|
||||
m_largest_allocated_pool = 0;
|
||||
m_get_pos = get_current_put_pos_minus_one();
|
||||
}
|
||||
|
||||
// Updates the current_allocated_size metrics
|
||||
void notify()
|
||||
inline void notify()
|
||||
{
|
||||
if (m_get_pos == umax)
|
||||
m_current_allocated_size = 0;
|
||||
else if (m_get_pos < m_put_pos)
|
||||
m_current_allocated_size = (m_put_pos - m_get_pos - 1);
|
||||
else if (m_get_pos > m_put_pos)
|
||||
m_current_allocated_size = (m_put_pos + (m_size - m_get_pos - 1));
|
||||
else
|
||||
fmt::throw_exception("m_put_pos == m_get_pos!");
|
||||
// @unused
|
||||
}
|
||||
|
||||
usz size() const
|
||||
|
|
|
@ -390,14 +390,22 @@ namespace rsx
|
|||
}
|
||||
|
||||
bool ret = false;
|
||||
for (auto ptr = _data, last = _data + _size - 1; ptr < last; ptr++)
|
||||
for (auto ptr = _data, last = _data + _size - 1; ptr <= last; ptr++)
|
||||
{
|
||||
if (predicate(*ptr))
|
||||
{
|
||||
ret = true;
|
||||
|
||||
if (ptr == last)
|
||||
{
|
||||
// Popping the last entry from list. Just set the new size and exit
|
||||
_size--;
|
||||
break;
|
||||
}
|
||||
|
||||
// Move item to the end of the list and shrink by 1
|
||||
std::memcpy(ptr, last, sizeof(Ty));
|
||||
last = _data + (--_size);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@ namespace rsx
|
|||
using unordered_map = std::unordered_map<T, U>;
|
||||
}
|
||||
#else
|
||||
#include "3rdparty/robin_hood/include/robin_hood.h"
|
||||
#include "3rdparty/unordered_dense/include/unordered_dense.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
template<typename T, typename U>
|
||||
using unordered_map = ::robin_hood::unordered_map<T, U>;
|
||||
using unordered_map = ankerl::unordered_dense::map<T, U>;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "Emu/RSX/Common/BufferUtils.h"
|
||||
#include "Emu/RSX/Common/buffer_stream.hpp"
|
||||
#include "Emu/RSX/Common/io_buffer.h"
|
||||
#include "Emu/RSX/Common/simple_array.hpp"
|
||||
#include "Emu/RSX/NV47/HW/context_accessors.define.h"
|
||||
#include "Emu/RSX/Program/GLSLCommon.h"
|
||||
#include "Emu/RSX/rsx_methods.h"
|
||||
|
@ -759,7 +758,8 @@ namespace rsx
|
|||
ensure(draw_call.is_trivial_instanced_draw);
|
||||
|
||||
// Temp indirection table. Used to track "running" updates.
|
||||
rsx::simple_array<u32> instancing_indirection_table;
|
||||
auto& instancing_indirection_table = m_scratch_buffers.u32buf;
|
||||
|
||||
// indirection table size
|
||||
const auto full_reupload = !prog || prog->has_indexed_constants;
|
||||
const auto reloc_table = full_reupload ? decltype(prog->constant_ids){} : prog->constant_ids;
|
||||
|
@ -767,7 +767,8 @@ namespace rsx
|
|||
instancing_indirection_table.resize(redirection_table_size);
|
||||
|
||||
// Temp constants data
|
||||
rsx::simple_array<u128> constants_data;
|
||||
auto& constants_data = m_scratch_buffers.u128buf;
|
||||
constants_data.clear();
|
||||
constants_data.reserve(redirection_table_size * draw_call.pass_count());
|
||||
|
||||
// Allocate indirection buffer on GPU stream
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <util/types.hpp>
|
||||
|
||||
#include "Emu/RSX/Common/simple_array.hpp"
|
||||
#include "Emu/RSX/Core/RSXVertexTypes.h"
|
||||
#include "Emu/RSX/NV47/FW/draw_call.hpp"
|
||||
#include "Emu/RSX/Program/ProgramStateCache.h"
|
||||
|
@ -28,6 +29,12 @@ namespace rsx
|
|||
std::array<push_buffer_vertex_info, 16> m_vertex_push_buffers;
|
||||
rsx::simple_array<u32> m_element_push_buffer;
|
||||
|
||||
struct
|
||||
{
|
||||
rsx::simple_array<u32> u32buf;
|
||||
rsx::simple_array<u128> u128buf;
|
||||
} mutable m_scratch_buffers;
|
||||
|
||||
public:
|
||||
draw_command_processor() = default;
|
||||
|
||||
|
|
|
@ -218,12 +218,12 @@ namespace gl
|
|||
m_input_filter = gl::filter::linear;
|
||||
}
|
||||
|
||||
gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid)
|
||||
gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info_base* desc, bool temp_resource, u32 owner_uid)
|
||||
{
|
||||
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D, desc->w, desc->h, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
|
||||
const GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
|
||||
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
|
||||
|
||||
auto result = view.get();
|
||||
|
@ -234,7 +234,7 @@ namespace gl
|
|||
}
|
||||
else
|
||||
{
|
||||
u64 key = reinterpret_cast<u64>(desc);
|
||||
const u64 key = reinterpret_cast<u64>(desc);
|
||||
temp_image_cache[key] = std::make_pair(owner_uid, std::move(tex));
|
||||
temp_view_cache[key] = std::move(view);
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ namespace gl
|
|||
rsx::overlays::resource_config configuration;
|
||||
configuration.load_files();
|
||||
|
||||
for (const auto &res : configuration.texture_raw_data)
|
||||
for (const auto& res : configuration.texture_raw_data)
|
||||
{
|
||||
load_simple_image(res.get(), false, -1);
|
||||
}
|
||||
|
@ -318,13 +318,22 @@ namespace gl
|
|||
return result;
|
||||
}
|
||||
|
||||
gl::texture_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info* desc, u32 owner_uid)
|
||||
gl::texture_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info_base* desc, u32 owner_uid)
|
||||
{
|
||||
auto key = reinterpret_cast<u64>(desc);
|
||||
const bool dirty = std::exchange(desc->dirty, false);
|
||||
const u64 key = reinterpret_cast<u64>(desc);
|
||||
|
||||
auto cached = temp_view_cache.find(key);
|
||||
if (cached != temp_view_cache.end())
|
||||
{
|
||||
return cached->second.get();
|
||||
gl::texture_view* view = cached->second.get();
|
||||
|
||||
if (dirty)
|
||||
{
|
||||
view->image()->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
return load_simple_image(desc, true, owner_uid);
|
||||
|
@ -420,7 +429,7 @@ namespace gl
|
|||
}
|
||||
case rsx::overlays::image_resource_id::raw_image:
|
||||
{
|
||||
cmd_->bind_texture(31, GL_TEXTURE_2D, find_temp_image(static_cast<rsx::overlays::image_info*>(cmd.config.external_data_ref), ui.uid)->id());
|
||||
cmd_->bind_texture(31, GL_TEXTURE_2D, find_temp_image(static_cast<rsx::overlays::image_info_base*>(cmd.config.external_data_ref), ui.uid)->id());
|
||||
break;
|
||||
}
|
||||
case rsx::overlays::image_resource_id::font_file:
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace gl
|
|||
|
||||
ui_overlay_renderer();
|
||||
|
||||
gl::texture_view* load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid);
|
||||
gl::texture_view* load_simple_image(rsx::overlays::image_info_base* desc, bool temp_resource, u32 owner_uid);
|
||||
|
||||
void create();
|
||||
void destroy();
|
||||
|
@ -84,7 +84,7 @@ namespace gl
|
|||
|
||||
gl::texture_view* find_font(rsx::overlays::font* font);
|
||||
|
||||
gl::texture_view* find_temp_image(rsx::overlays::image_info* desc, u32 owner_uid);
|
||||
gl::texture_view* find_temp_image(rsx::overlays::image_info_base* desc, u32 owner_uid);
|
||||
|
||||
void set_primitive_type(rsx::overlays::primitive_type type);
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ namespace rsx
|
|||
}
|
||||
};
|
||||
|
||||
draw_command_barrier_mask |= (1u << type);
|
||||
|
||||
if (type == primitive_restart_barrier)
|
||||
{
|
||||
// Rasterization flow barrier
|
||||
|
@ -97,48 +99,32 @@ namespace rsx
|
|||
return false;
|
||||
}
|
||||
|
||||
// For instancing all draw calls must be identical
|
||||
const auto& ref = draw_command_ranges.front();
|
||||
for (const auto& range : draw_command_ranges)
|
||||
{
|
||||
if (range.first != ref.first || range.count != ref.count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_command_barriers.empty())
|
||||
{
|
||||
// Raise alarm here for investigation, we may be missing a corner case.
|
||||
rsx_log.error("Instanced draw detected, but no command barriers found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Barriers must exist, but can only involve updating transform constants (for now)
|
||||
for (const auto& barrier : draw_command_barriers)
|
||||
{
|
||||
if (barrier.type != rsx::transform_constant_load_modifier_barrier &&
|
||||
barrier.type != rsx::transform_constant_update_barrier)
|
||||
{
|
||||
ensure(barrier.draw_id < ::size32(draw_command_ranges));
|
||||
if (draw_command_ranges[barrier.draw_id].count == 0)
|
||||
{
|
||||
// Dangling command barriers are ignored. We're also at the end of the command, so abort.
|
||||
break;
|
||||
}
|
||||
const u32 compatible_barrier_mask =
|
||||
(1u << rsx::transform_constant_load_modifier_barrier) |
|
||||
(1u << rsx::transform_constant_update_barrier);
|
||||
|
||||
// Fail. Only transform constant instancing is supported at the moment.
|
||||
return false;
|
||||
}
|
||||
if (draw_command_barrier_mask & ~compatible_barrier_mask)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// For instancing all draw calls must be identical
|
||||
// FIXME: This requirement can be easily lifted by chunking contiguous chunks.
|
||||
const auto& ref = draw_command_ranges.front();
|
||||
return !draw_command_ranges.any(FN(x.first != ref.first || x.count != ref.count));
|
||||
}
|
||||
|
||||
void draw_clause::reset(primitive_type type)
|
||||
{
|
||||
current_range_index = ~0u;
|
||||
last_execution_barrier_index = 0;
|
||||
draw_command_barrier_mask = 0;
|
||||
|
||||
command = draw_command::none;
|
||||
primitive = type;
|
||||
|
@ -152,6 +138,47 @@ namespace rsx
|
|||
is_disjoint_primitive = is_primitive_disjointed(primitive);
|
||||
}
|
||||
|
||||
simple_array<draw_range_t> draw_clause::get_subranges() const
|
||||
{
|
||||
ensure(!is_single_draw());
|
||||
|
||||
const auto range = get_range();
|
||||
const auto limit = range.first + range.count;
|
||||
const auto _pass_count = pass_count();
|
||||
|
||||
simple_array<draw_range_t> ret;
|
||||
ret.reserve(_pass_count);
|
||||
|
||||
u32 previous_barrier = range.first;
|
||||
u32 vertex_counter = 0;
|
||||
|
||||
for (auto it = current_barrier_it;
|
||||
it != draw_command_barriers.end() && it->draw_id == current_range_index;
|
||||
it++)
|
||||
{
|
||||
const auto& barrier = *it;
|
||||
if (barrier.type != primitive_restart_barrier)
|
||||
continue;
|
||||
|
||||
if (barrier.address <= range.first)
|
||||
continue;
|
||||
|
||||
if (barrier.address >= limit)
|
||||
break;
|
||||
|
||||
const u32 count = barrier.address - previous_barrier;
|
||||
ret.push_back({ 0, vertex_counter, count });
|
||||
previous_barrier = barrier.address;
|
||||
vertex_counter += count;
|
||||
}
|
||||
|
||||
ensure(!ret.empty());
|
||||
ensure(previous_barrier < limit);
|
||||
ret.push_back({ 0, vertex_counter, limit - previous_barrier });
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 draw_clause::execute_pipeline_dependencies(context* ctx, instanced_draw_config_t* instance_config) const
|
||||
{
|
||||
u32 result = 0u;
|
||||
|
|
|
@ -29,6 +29,9 @@ namespace rsx
|
|||
// Location of last execution barrier
|
||||
u32 last_execution_barrier_index{};
|
||||
|
||||
// Mask of all active barriers
|
||||
u32 draw_command_barrier_mask = 0;
|
||||
|
||||
// Draw-time iterator to the draw_command_barriers struct
|
||||
mutable simple_array<barrier_t>::iterator current_barrier_it;
|
||||
|
||||
|
@ -282,48 +285,19 @@ namespace rsx
|
|||
*/
|
||||
u32 execute_pipeline_dependencies(struct context* ctx, instanced_draw_config_t* instance_config = nullptr) const;
|
||||
|
||||
/**
|
||||
* Returns the first-count data for the current subdraw
|
||||
*/
|
||||
const draw_range_t& get_range() const
|
||||
{
|
||||
ensure(current_range_index < draw_command_ranges.size());
|
||||
return draw_command_ranges[current_range_index];
|
||||
}
|
||||
|
||||
simple_array<draw_range_t> get_subranges() const
|
||||
{
|
||||
ensure(!is_single_draw());
|
||||
|
||||
const auto range = get_range();
|
||||
const auto limit = range.first + range.count;
|
||||
|
||||
simple_array<draw_range_t> ret;
|
||||
u32 previous_barrier = range.first;
|
||||
u32 vertex_counter = 0;
|
||||
|
||||
for (const auto& barrier : draw_command_barriers)
|
||||
{
|
||||
if (barrier.draw_id != current_range_index)
|
||||
continue;
|
||||
|
||||
if (barrier.type != primitive_restart_barrier)
|
||||
continue;
|
||||
|
||||
if (barrier.address <= range.first)
|
||||
continue;
|
||||
|
||||
if (barrier.address >= limit)
|
||||
break;
|
||||
|
||||
const u32 count = barrier.address - previous_barrier;
|
||||
ret.push_back({ 0, vertex_counter, count });
|
||||
previous_barrier = barrier.address;
|
||||
vertex_counter += count;
|
||||
}
|
||||
|
||||
ensure(!ret.empty());
|
||||
ensure(previous_barrier < limit);
|
||||
ret.push_back({ 0, vertex_counter, limit - previous_barrier });
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Returns a compiled list of all subdraws.
|
||||
* NOTE: This is a non-trivial operation as it takes disjoint primitive boundaries into account.
|
||||
*/
|
||||
simple_array<draw_range_t> get_subranges() const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace rsx
|
|||
RSX(ctx)->sync();
|
||||
|
||||
// Write ref+get (get will be written again with the same value at command end)
|
||||
auto& dma = vm::_ref<RsxDmaControl>(RSX(ctx)->dma_address);
|
||||
auto& dma = *vm::_ptr<RsxDmaControl>(RSX(ctx)->dma_address);
|
||||
dma.get.release(RSX(ctx)->fifo_ctrl->get_pos());
|
||||
dma.ref.store(arg);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ namespace rsx
|
|||
// Syncronization point, may be associated with memory changes without actually changing addresses
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::fragment_program_needs_rehash;
|
||||
|
||||
const auto& sema = vm::_ref<RsxSemaphore>(addr).val;
|
||||
const auto& sema = vm::_ref<RsxSemaphore>(addr);
|
||||
|
||||
if (sema == arg)
|
||||
{
|
||||
|
|
|
@ -566,7 +566,7 @@ namespace rsx
|
|||
default:
|
||||
rsx_log.error("NV4097_GET_REPORT: Bad type %d", type);
|
||||
|
||||
vm::_ref<atomic_t<CellGcmReportData>>(address_ptr).atomic_op([&](CellGcmReportData& data)
|
||||
vm::_ptr<atomic_t<CellGcmReportData>>(address_ptr)->atomic_op([&](CellGcmReportData& data)
|
||||
{
|
||||
data.timer = RSX(ctx)->timestamp();
|
||||
data.padding = 0;
|
||||
|
@ -651,7 +651,7 @@ namespace rsx
|
|||
|
||||
ensure(addr != umax);
|
||||
|
||||
vm::_ref<atomic_t<RsxNotify>>(addr).store(
|
||||
vm::_ptr<atomic_t<RsxNotify>>(addr)->store(
|
||||
{
|
||||
RSX(ctx)->timestamp(),
|
||||
0
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace rsx
|
|||
// First, queue the GPU work. If it flushes the queue for us, the following routines will be faster.
|
||||
const bool handled = RSX(ctx)->get_backend_config().supports_host_gpu_labels && RSX(ctx)->release_GCM_label(address, data);
|
||||
|
||||
if (vm::_ref<RsxSemaphore>(address).val == data)
|
||||
if (vm::_ref<RsxSemaphore>(address) == data)
|
||||
{
|
||||
// It's a no-op to write the same value (although there is a delay in real-hw so it's more accurate to allow GPU label in this case)
|
||||
return;
|
||||
|
@ -57,7 +57,7 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
vm::_ref<RsxSemaphore>(address).val = data;
|
||||
vm::write<atomic_t<RsxSemaphore>>(address, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace rsx
|
|||
{
|
||||
update_value();
|
||||
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
const f32 col = m_last_value ? 1.0f : 0.3f;
|
||||
const f32 bkg = m_last_value ? 0.3f : 1.0f;
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace rsx
|
|||
if (const T new_value = m_setting->get(); new_value != m_last_value || initializing)
|
||||
{
|
||||
m_last_value = new_value;
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ namespace rsx
|
|||
{
|
||||
this->update_value();
|
||||
|
||||
if (!this->is_compiled)
|
||||
if (!this->is_compiled())
|
||||
{
|
||||
const std::string value_text = Emu.GetCallbacks().get_localized_setting(home_menu_setting<T, cfg::_enum<T>>::m_setting, static_cast<u32>(this->m_last_value));
|
||||
m_dropdown.set_text(value_text);
|
||||
|
@ -145,7 +145,7 @@ namespace rsx
|
|||
{
|
||||
this->update_value();
|
||||
|
||||
if (!this->is_compiled)
|
||||
if (!this->is_compiled())
|
||||
{
|
||||
const f64 percentage = std::clamp((this->m_last_value - static_cast<T>(m_minimum)) / std::fabs(m_maximum - m_minimum), 0.0, 1.0);
|
||||
m_slider.set_pos(m_slider.x, this->y + (this->h - m_slider.h) / 2);
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace rsx
|
|||
|
||||
compiled_resource& home_menu_message_box::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
compiled_resource& compiled = overlay_element::get_compiled();
|
||||
compiled.add(m_label.get_compiled());
|
||||
|
|
|
@ -258,9 +258,9 @@ namespace rsx
|
|||
|
||||
compiled_resource& home_menu_page::get_compiled()
|
||||
{
|
||||
if (!is_compiled || (m_message_box && !m_message_box->is_compiled))
|
||||
if (!is_compiled() || (m_message_box && !m_message_box->is_compiled()))
|
||||
{
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
|
||||
if (home_menu_page* page = get_current_page(false))
|
||||
{
|
||||
|
@ -281,7 +281,7 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
is_compiled = true;
|
||||
m_is_compiled = true;
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace rsx
|
|||
|
||||
compiled_resource& animated_icon::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
compiled_resources = image_view::get_compiled();
|
||||
}
|
||||
|
|
|
@ -302,7 +302,7 @@ namespace rsx
|
|||
void overlay_element::refresh()
|
||||
{
|
||||
// Just invalidate for draw when get_compiled() is called
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::translate(s16 _x, s16 _y)
|
||||
|
@ -310,7 +310,7 @@ namespace rsx
|
|||
x += _x;
|
||||
y += _y;
|
||||
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::scale(f32 _x, f32 _y, bool origin_scaling)
|
||||
|
@ -324,7 +324,7 @@ namespace rsx
|
|||
w = static_cast<u16>(_x * w);
|
||||
h = static_cast<u16>(_y * h);
|
||||
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::set_pos(s16 _x, s16 _y)
|
||||
|
@ -332,7 +332,7 @@ namespace rsx
|
|||
x = _x;
|
||||
y = _y;
|
||||
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::set_size(u16 _w, u16 _h)
|
||||
|
@ -340,7 +340,7 @@ namespace rsx
|
|||
w = _w;
|
||||
h = _h;
|
||||
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::set_padding(u16 left, u16 right, u16 top, u16 bottom)
|
||||
|
@ -350,13 +350,13 @@ namespace rsx
|
|||
padding_top = top;
|
||||
padding_bottom = bottom;
|
||||
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::set_padding(u16 padding)
|
||||
{
|
||||
padding_left = padding_right = padding_top = padding_bottom = padding;
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
// NOTE: Functions as a simple position offset. Top left corner is the anchor.
|
||||
|
@ -365,25 +365,36 @@ namespace rsx
|
|||
margin_left = left;
|
||||
margin_top = top;
|
||||
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::set_margin(u16 margin)
|
||||
{
|
||||
margin_left = margin_top = margin;
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::set_text(const std::string& text)
|
||||
{
|
||||
this->text = utf8_to_u32string(text);
|
||||
is_compiled = false;
|
||||
std::u32string new_text = utf8_to_u32string(text);
|
||||
const bool is_dirty = this->text != new_text;
|
||||
this->text = std::move(new_text);
|
||||
|
||||
if (is_dirty)
|
||||
{
|
||||
m_is_compiled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void overlay_element::set_unicode_text(const std::u32string& text)
|
||||
{
|
||||
const bool is_dirty = this->text != text;
|
||||
this->text = text;
|
||||
is_compiled = false;
|
||||
|
||||
if (is_dirty)
|
||||
{
|
||||
m_is_compiled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void overlay_element::set_text(localized_string_id id)
|
||||
|
@ -394,19 +405,19 @@ namespace rsx
|
|||
void overlay_element::set_font(const char* font_name, u16 font_size)
|
||||
{
|
||||
font_ref = fontmgr::get(font_name, font_size);
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::align_text(text_align align)
|
||||
{
|
||||
alignment = align;
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void overlay_element::set_wrap_text(bool state)
|
||||
{
|
||||
wrap_text = state;
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
font* overlay_element::get_font() const
|
||||
|
@ -563,7 +574,7 @@ namespace rsx
|
|||
|
||||
compiled_resource& overlay_element::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
compiled_resources.clear();
|
||||
|
||||
|
@ -599,7 +610,7 @@ namespace rsx
|
|||
compiled_resources.add(std::move(compiled_resources_temp), margin_left - horizontal_scroll_offset, margin_top - vertical_scroll_offset);
|
||||
}
|
||||
|
||||
is_compiled = true;
|
||||
m_is_compiled = true;
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
|
@ -664,7 +675,7 @@ namespace rsx
|
|||
{
|
||||
overlay_element::translate(_x, _y);
|
||||
|
||||
for (auto &itm : m_items)
|
||||
for (auto& itm : m_items)
|
||||
itm->translate(_x, _y);
|
||||
}
|
||||
|
||||
|
@ -675,13 +686,23 @@ namespace rsx
|
|||
translate(dx, dy);
|
||||
}
|
||||
|
||||
bool layout_container::is_compiled()
|
||||
{
|
||||
if (m_is_compiled && std::any_of(m_items.cbegin(), m_items.cend(), [](const auto& item){ return item && !item->is_compiled(); }))
|
||||
{
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
return m_is_compiled;
|
||||
}
|
||||
|
||||
compiled_resource& layout_container::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
compiled_resource result = overlay_element::get_compiled();
|
||||
|
||||
for (auto &itm : m_items)
|
||||
for (auto& itm : m_items)
|
||||
result.add(itm->get_compiled());
|
||||
|
||||
compiled_resources = result;
|
||||
|
@ -716,7 +737,7 @@ namespace rsx
|
|||
return m_items.back().get();
|
||||
}
|
||||
|
||||
auto result = item.get();
|
||||
overlay_element* result = item.get();
|
||||
m_items.insert(m_items.begin() + offset, std::move(item));
|
||||
return result;
|
||||
}
|
||||
|
@ -726,12 +747,12 @@ namespace rsx
|
|||
if (scroll_offset_value == 0 && auto_resize)
|
||||
return layout_container::get_compiled();
|
||||
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
compiled_resource result = overlay_element::get_compiled();
|
||||
const f32 global_y_offset = static_cast<f32>(-scroll_offset_value);
|
||||
|
||||
for (auto &item : m_items)
|
||||
for (auto& item : m_items)
|
||||
{
|
||||
if (!item)
|
||||
{
|
||||
|
@ -808,7 +829,7 @@ namespace rsx
|
|||
if (scroll_offset_value == 0 && auto_resize)
|
||||
return layout_container::get_compiled();
|
||||
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
compiled_resource result = overlay_element::get_compiled();
|
||||
const f32 global_x_offset = static_cast<f32>(-scroll_offset_value);
|
||||
|
@ -862,7 +883,7 @@ namespace rsx
|
|||
|
||||
compiled_resource& image_view::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
auto& result = overlay_element::get_compiled();
|
||||
auto& cmd_img = result.draw_commands.front();
|
||||
|
@ -880,7 +901,7 @@ namespace rsx
|
|||
verts[2] += vertex(padding_left, -padding_top, 0, 0);
|
||||
verts[3] += vertex(-padding_right, -padding_top, 0, 0);
|
||||
|
||||
is_compiled = true;
|
||||
m_is_compiled = true;
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
|
@ -892,7 +913,7 @@ namespace rsx
|
|||
external_ref = nullptr;
|
||||
}
|
||||
|
||||
void image_view::set_raw_image(image_info* raw_image)
|
||||
void image_view::set_raw_image(image_info_base* raw_image)
|
||||
{
|
||||
image_resource_ref = image_resource_id::raw_image;
|
||||
external_ref = raw_image;
|
||||
|
@ -935,7 +956,7 @@ namespace rsx
|
|||
|
||||
compiled_resource& image_button::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
auto& compiled = image_view::get_compiled();
|
||||
for (auto& cmd : compiled.draw_commands)
|
||||
|
@ -987,7 +1008,7 @@ namespace rsx
|
|||
|
||||
compiled_resource& rounded_rect::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
compiled_resources.clear();
|
||||
|
||||
|
@ -1068,7 +1089,7 @@ namespace rsx
|
|||
compiled_resources.add(std::move(compiled_resources_temp), margin_left, margin_top);
|
||||
}
|
||||
|
||||
is_compiled = true;
|
||||
m_is_compiled = true;
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
|
|
|
@ -30,23 +30,32 @@ namespace rsx
|
|||
triangle_fan = 4
|
||||
};
|
||||
|
||||
struct image_info
|
||||
struct image_info_base
|
||||
{
|
||||
int w = 0, h = 0, channels = 0;
|
||||
int bpp = 0;
|
||||
bool dirty = false;
|
||||
|
||||
image_info_base() {}
|
||||
virtual ~image_info_base() {}
|
||||
virtual const u8* get_data() const = 0;
|
||||
};
|
||||
|
||||
struct image_info : public image_info_base
|
||||
{
|
||||
private:
|
||||
u8* data = nullptr;
|
||||
std::vector<u8> data_grey;
|
||||
|
||||
public:
|
||||
int w = 0, h = 0, channels = 0;
|
||||
int bpp = 0;
|
||||
|
||||
using image_info_base::image_info_base;
|
||||
image_info(image_info&) = delete;
|
||||
image_info(const std::string& filename, bool grayscaled = false);
|
||||
image_info(const std::vector<u8>& bytes, bool grayscaled = false);
|
||||
~image_info();
|
||||
virtual ~image_info();
|
||||
|
||||
void load_data(const std::vector<u8>& bytes, bool grayscaled = false);
|
||||
const u8* get_data() const { return channels == 4 ? data : data_grey.empty() ? nullptr : data_grey.data(); }
|
||||
const u8* get_data() const override { return channels == 4 ? data : data_grey.empty() ? nullptr : data_grey.data(); }
|
||||
};
|
||||
|
||||
struct resource_config
|
||||
|
@ -165,7 +174,6 @@ namespace rsx
|
|||
void set_sinus_offset(f32 sinus_modifier);
|
||||
|
||||
compiled_resource compiled_resources;
|
||||
bool is_compiled = false;
|
||||
|
||||
bool visible = true;
|
||||
|
||||
|
@ -185,6 +193,7 @@ namespace rsx
|
|||
virtual ~overlay_element() = default;
|
||||
|
||||
virtual void refresh();
|
||||
virtual bool is_compiled() { return m_is_compiled; }
|
||||
virtual void translate(s16 _x, s16 _y);
|
||||
virtual void scale(f32 _x, f32 _y, bool origin_scaling);
|
||||
virtual void set_pos(s16 _x, s16 _y);
|
||||
|
@ -204,6 +213,10 @@ namespace rsx
|
|||
virtual std::vector<vertex> render_text(const char32_t* string, f32 x, f32 y);
|
||||
virtual compiled_resource& get_compiled();
|
||||
void measure_text(u16& width, u16& height, bool ignore_word_wrap = false) const;
|
||||
virtual void set_selected(bool selected) { static_cast<void>(selected); }
|
||||
|
||||
protected:
|
||||
bool m_is_compiled = false; // Only use m_is_compiled as a getter in is_compiled() if possible
|
||||
};
|
||||
|
||||
struct layout_container : public overlay_element
|
||||
|
@ -221,6 +234,8 @@ namespace rsx
|
|||
void translate(s16 _x, s16 _y) override;
|
||||
void set_pos(s16 _x, s16 _y) override;
|
||||
|
||||
bool is_compiled() override;
|
||||
|
||||
compiled_resource& get_compiled() override;
|
||||
|
||||
virtual u16 get_scroll_offset_px() = 0;
|
||||
|
@ -248,6 +263,7 @@ namespace rsx
|
|||
compiled_resource& get_compiled() override
|
||||
{
|
||||
// No draw
|
||||
m_is_compiled = true;
|
||||
return compiled_resources;
|
||||
}
|
||||
};
|
||||
|
@ -263,7 +279,7 @@ namespace rsx
|
|||
|
||||
struct image_view : public overlay_element
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
u8 image_resource_ref = image_resource_id::none;
|
||||
void* external_ref = nullptr;
|
||||
|
||||
|
@ -276,7 +292,7 @@ namespace rsx
|
|||
compiled_resource& get_compiled() override;
|
||||
|
||||
void set_image_resource(u8 resource_id);
|
||||
void set_raw_image(image_info* raw_image);
|
||||
void set_raw_image(image_info_base* raw_image);
|
||||
void clear_image();
|
||||
void set_blur_strength(u8 strength);
|
||||
};
|
||||
|
|
|
@ -196,7 +196,7 @@ namespace rsx
|
|||
|
||||
compiled_resource& edit_text::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
auto renderer = get_font();
|
||||
const auto [caret_x, caret_y] = renderer->get_char_offset(text.c_str(), caret_position, clip_text ? w : -1, wrap_text);
|
||||
|
@ -252,7 +252,7 @@ namespace rsx
|
|||
cmd.config.clip_rect = {static_cast<f32>(x), static_cast<f32>(y), static_cast<f32>(x + w), static_cast<f32>(y + h)};
|
||||
}
|
||||
|
||||
is_compiled = true;
|
||||
m_is_compiled = true;
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
|
|
|
@ -91,6 +91,15 @@ namespace rsx
|
|||
void list_view::update_selection()
|
||||
{
|
||||
const overlay_element* current_element = get_selected_entry();
|
||||
|
||||
for (auto& item : m_items)
|
||||
{
|
||||
if (item)
|
||||
{
|
||||
item->set_selected(item.get() == current_element);
|
||||
}
|
||||
}
|
||||
|
||||
if (!current_element)
|
||||
{
|
||||
return; // Ideally unreachable but it should still be possible to recover by user interaction.
|
||||
|
@ -195,7 +204,7 @@ namespace rsx
|
|||
m_cancel_btn->set_pos(x + 180, y + h + 20);
|
||||
|
||||
m_cancel_only = cancel_only;
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
bool list_view::get_cancel_only() const
|
||||
|
@ -219,7 +228,7 @@ namespace rsx
|
|||
|
||||
compiled_resource& list_view::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
auto& compiled = vertical_layout::get_compiled();
|
||||
compiled.add(m_highlight_box->get_compiled());
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace rsx
|
|||
}
|
||||
|
||||
// Disable caching
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
|
||||
compiled_resources = rounded_rect::get_compiled();
|
||||
compiled_resources.add(m_text.get_compiled());
|
||||
|
|
|
@ -814,7 +814,7 @@ namespace rsx
|
|||
|
||||
compiled_resource& graph::get_compiled()
|
||||
{
|
||||
if (is_compiled)
|
||||
if (is_compiled())
|
||||
{
|
||||
return compiled_resources;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace rsx
|
|||
void progress_bar::set_limit(f32 limit)
|
||||
{
|
||||
m_limit = limit;
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void progress_bar::set_value(f32 value)
|
||||
|
@ -32,7 +32,7 @@ namespace rsx
|
|||
|
||||
f32 indicator_width = (w * m_value) / m_limit;
|
||||
indicator.set_size(static_cast<u16>(indicator_width), h);
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
void progress_bar::set_pos(s16 _x, s16 _y)
|
||||
|
@ -68,12 +68,12 @@ namespace rsx
|
|||
text_view.set_size(w, text_h);
|
||||
|
||||
set_pos(text_view.x, text_view.y);
|
||||
is_compiled = false;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
compiled_resource& progress_bar::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
if (!is_compiled())
|
||||
{
|
||||
auto& compiled = overlay_element::get_compiled();
|
||||
compiled.add(text_view.get_compiled());
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "overlay_save_dialog.h"
|
||||
#include "overlay_video.h"
|
||||
#include "Utilities/date_time.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
|
@ -7,26 +8,18 @@ namespace rsx
|
|||
{
|
||||
namespace overlays
|
||||
{
|
||||
save_dialog::save_dialog_entry::save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf)
|
||||
save_dialog::save_dialog_entry::save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf, const std::string& video_path)
|
||||
{
|
||||
std::unique_ptr<overlay_element> image = std::make_unique<image_view>();
|
||||
std::unique_ptr<overlay_element> image = resource_id != image_resource_id::raw_image
|
||||
? std::make_unique<video_view>(video_path, resource_id)
|
||||
: !icon_buf.empty() ? std::make_unique<video_view>(video_path, icon_buf)
|
||||
: std::make_unique<video_view>(video_path, resource_config::standard_image_resource::save); // Fallback
|
||||
image->set_size(160, 110);
|
||||
image->set_padding(36, 36, 11, 11); // Square image, 88x88
|
||||
|
||||
if (resource_id != image_resource_id::raw_image)
|
||||
{
|
||||
static_cast<image_view*>(image.get())->set_image_resource(resource_id);
|
||||
}
|
||||
else if (!icon_buf.empty())
|
||||
if (resource_id == image_resource_id::raw_image && !icon_buf.empty())
|
||||
{
|
||||
image->set_padding(0, 0, 11, 11); // Half sized icon, 320x176->160x88
|
||||
icon_data = std::make_unique<image_info>(icon_buf);
|
||||
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback
|
||||
static_cast<image_view*>(image.get())->set_image_resource(resource_config::standard_image_resource::save);
|
||||
}
|
||||
|
||||
std::unique_ptr<overlay_element> text_stack = std::make_unique<vertical_layout>();
|
||||
|
@ -74,10 +67,18 @@ namespace rsx
|
|||
|
||||
// Pack
|
||||
this->pack_padding = 15;
|
||||
add_element(image);
|
||||
m_image = add_element(image);
|
||||
add_element(text_stack);
|
||||
}
|
||||
|
||||
void save_dialog::save_dialog_entry::set_selected(bool selected)
|
||||
{
|
||||
if (m_image)
|
||||
{
|
||||
static_cast<video_view*>(m_image)->set_active(selected);
|
||||
}
|
||||
}
|
||||
|
||||
save_dialog::save_dialog()
|
||||
{
|
||||
m_dim_background = std::make_unique<overlay_element>();
|
||||
|
@ -197,7 +198,7 @@ namespace rsx
|
|||
return result;
|
||||
}
|
||||
|
||||
s32 save_dialog::show(std::vector<SaveDataEntry>& save_entries, u32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay)
|
||||
s32 save_dialog::show(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, u32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay)
|
||||
{
|
||||
rsx_log.notice("Showing native UI save_dialog (save_entries=%d, focused=%d, op=0x%x, listSet=*0x%x, enable_overlay=%d)", save_entries.size(), focused, op, listSet, enable_overlay);
|
||||
|
||||
|
@ -218,7 +219,7 @@ namespace rsx
|
|||
{
|
||||
const std::string date_and_size = fmt::format("%s %s", entry.date(), entry.data_size());
|
||||
std::unique_ptr<overlay_element> e;
|
||||
e = std::make_unique<save_dialog_entry>(entry.subtitle, date_and_size, entry.details, image_resource_id::raw_image, entry.iconBuf);
|
||||
e = std::make_unique<save_dialog_entry>(entry.subtitle, date_and_size, entry.details, image_resource_id::raw_image, entry.iconBuf, base_dir + entry.dirName + "/ICON1.PAM");
|
||||
entries.emplace_back(std::move(e));
|
||||
}
|
||||
|
||||
|
@ -270,7 +271,7 @@ namespace rsx
|
|||
id = image_resource_id::raw_image;
|
||||
}
|
||||
|
||||
std::unique_ptr<overlay_element> new_stub = std::make_unique<save_dialog_entry>(title, get_localized_string(localized_string_id::CELL_SAVEDATA_NEW_SAVED_DATA_SUB_TITLE), "", id, icon);
|
||||
std::unique_ptr<overlay_element> new_stub = std::make_unique<save_dialog_entry>(title, get_localized_string(localized_string_id::CELL_SAVEDATA_NEW_SAVED_DATA_SUB_TITLE), "", id, icon, "");
|
||||
|
||||
m_list->add_entry(new_stub);
|
||||
}
|
||||
|
|
|
@ -13,11 +13,12 @@ namespace rsx
|
|||
private:
|
||||
struct save_dialog_entry : horizontal_layout
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<image_info> icon_data;
|
||||
|
||||
public:
|
||||
save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf);
|
||||
save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf, const std::string& video_path);
|
||||
void set_selected(bool selected) override;
|
||||
|
||||
private:
|
||||
overlay_element* m_image = nullptr;
|
||||
};
|
||||
|
||||
std::unique_ptr<overlay_element> m_dim_background;
|
||||
|
@ -38,7 +39,7 @@ namespace rsx
|
|||
|
||||
compiled_resource get_compiled() override;
|
||||
|
||||
s32 show(std::vector<SaveDataEntry>& save_entries, u32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay);
|
||||
s32 show(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, u32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
116
rpcs3/Emu/RSX/Overlays/overlay_video.cpp
Normal file
116
rpcs3/Emu/RSX/Overlays/overlay_video.cpp
Normal file
|
@ -0,0 +1,116 @@
|
|||
#include "stdafx.h"
|
||||
#include "overlay_video.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
video_view::video_view(const std::string& video_path, const std::string& thumbnail_path)
|
||||
{
|
||||
init_video(video_path);
|
||||
|
||||
if (!thumbnail_path.empty())
|
||||
{
|
||||
m_thumbnail_info = std::make_unique<image_info>(thumbnail_path);
|
||||
set_raw_image(m_thumbnail_info.get());
|
||||
}
|
||||
}
|
||||
|
||||
video_view::video_view(const std::string& video_path, const std::vector<u8>& thumbnail_buf)
|
||||
{
|
||||
init_video(video_path);
|
||||
|
||||
if (!thumbnail_buf.empty())
|
||||
{
|
||||
m_thumbnail_info = std::make_unique<image_info>(thumbnail_buf);
|
||||
set_raw_image(m_thumbnail_info.get());
|
||||
}
|
||||
}
|
||||
|
||||
video_view::video_view(const std::string& video_path, u8 thumbnail_id)
|
||||
: m_thumbnail_id(thumbnail_id)
|
||||
{
|
||||
init_video(video_path);
|
||||
set_image_resource(thumbnail_id);
|
||||
}
|
||||
|
||||
video_view::~video_view()
|
||||
{
|
||||
}
|
||||
|
||||
void video_view::init_video(const std::string& video_path)
|
||||
{
|
||||
if (video_path.empty()) return;
|
||||
|
||||
m_video_source = Emu.GetCallbacks().make_video_source();
|
||||
ensure(!!m_video_source);
|
||||
|
||||
m_video_source->set_update_callback([this]()
|
||||
{
|
||||
if (m_video_active)
|
||||
{
|
||||
m_is_compiled = false;
|
||||
}
|
||||
});
|
||||
m_video_source->set_video_path(video_path);
|
||||
}
|
||||
|
||||
void video_view::set_active(bool active)
|
||||
{
|
||||
if (m_video_source)
|
||||
{
|
||||
m_video_source->set_active(active);
|
||||
m_video_active = active;
|
||||
m_is_compiled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void video_view::update()
|
||||
{
|
||||
if (m_video_active && m_video_source && m_video_source->get_active())
|
||||
{
|
||||
if (!m_video_source->has_new())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_buffer_index = (m_buffer_index + 1) % m_video_info.size();
|
||||
|
||||
auto& info = m_video_info.at(m_buffer_index);
|
||||
if (!info)
|
||||
{
|
||||
info = std::make_unique<video_info>();
|
||||
}
|
||||
|
||||
m_video_source->get_image(info->data, info->w, info->h, info->channels, info->bpp);
|
||||
info->dirty = true;
|
||||
|
||||
set_raw_image(info.get());
|
||||
m_is_compiled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_thumbnail_info && m_thumbnail_info.get() != external_ref)
|
||||
{
|
||||
set_raw_image(m_thumbnail_info.get());
|
||||
m_is_compiled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_thumbnail_id != image_resource_id::none && m_thumbnail_id != image_resource_ref)
|
||||
{
|
||||
set_image_resource(m_thumbnail_id);
|
||||
m_is_compiled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
compiled_resource& video_view::get_compiled()
|
||||
{
|
||||
update();
|
||||
|
||||
return external_ref ? image_view::get_compiled() : overlay_element::get_compiled();
|
||||
}
|
||||
}
|
||||
}
|
43
rpcs3/Emu/RSX/Overlays/overlay_video.h
Normal file
43
rpcs3/Emu/RSX/Overlays/overlay_video.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "overlay_controls.h"
|
||||
#include "util/video_source.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
struct video_info : public image_info_base
|
||||
{
|
||||
using image_info_base::image_info_base;
|
||||
virtual ~video_info() {}
|
||||
const u8* get_data() const override { return data.empty() ? nullptr : data.data(); }
|
||||
|
||||
std::vector<u8> data;
|
||||
};
|
||||
|
||||
class video_view final : public image_view
|
||||
{
|
||||
public:
|
||||
video_view(const std::string& video_path, const std::string& thumbnail_path);
|
||||
video_view(const std::string& video_path, const std::vector<u8>& thumbnail_buf);
|
||||
video_view(const std::string& video_path, u8 thumbnail_id);
|
||||
virtual ~video_view();
|
||||
|
||||
void set_active(bool active);
|
||||
|
||||
void update();
|
||||
compiled_resource& get_compiled() override;
|
||||
|
||||
private:
|
||||
void init_video(const std::string& video_path);
|
||||
|
||||
usz m_buffer_index = 0;
|
||||
std::array<std::unique_ptr<video_info>, 2> m_video_info; // double buffer
|
||||
std::unique_ptr<video_source> m_video_source;
|
||||
std::unique_ptr<image_info> m_thumbnail_info;
|
||||
u8 m_thumbnail_id = image_resource_id::none;
|
||||
bool m_video_active = false; // This is the expected state. The actual state is found in the video source.
|
||||
};
|
||||
}
|
||||
}
|
|
@ -76,6 +76,8 @@ vec4 _fetch_constant(const in uint base_offset)
|
|||
// uint override
|
||||
return _fetch_constant(int(base_offset));
|
||||
}
|
||||
#elif defined(VULKAN)
|
||||
#define _fetch_constant(x) vc[x + xform_constants_offset]
|
||||
#else
|
||||
#define _fetch_constant(x) vc[x]
|
||||
#endif
|
||||
|
|
|
@ -23,10 +23,6 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
#define AVX512_ICL_FUNC
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define AVX512_ICL_FUNC
|
||||
#else
|
||||
|
|
|
@ -1212,7 +1212,7 @@ namespace rsx
|
|||
if (const u64 get_put = new_get_put.exchange(u64{umax});
|
||||
get_put != umax)
|
||||
{
|
||||
vm::_ref<atomic_be_t<u64>>(dma_address + ::offset32(&RsxDmaControl::put)).release(get_put);
|
||||
vm::_ptr<atomic_be_t<u64>>(dma_address + ::offset32(&RsxDmaControl::put))->release(get_put);
|
||||
fifo_ctrl->set_get(static_cast<u32>(get_put));
|
||||
fifo_ctrl->abort();
|
||||
fifo_ret_addr = RSX_CALL_STACK_EMPTY;
|
||||
|
@ -2457,7 +2457,7 @@ namespace rsx
|
|||
}
|
||||
|
||||
rsx::reservation_lock<true> lock(sink, 16);
|
||||
vm::_ref<atomic_t<CellGcmReportData>>(sink).store({timestamp(), value, 0});
|
||||
vm::_ptr<atomic_t<CellGcmReportData>>(sink)->store({timestamp(), value, 0});
|
||||
}
|
||||
|
||||
u32 thread::copy_zcull_stats(u32 memory_range_start, u32 memory_range, u32 destination)
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace vk
|
|||
|
||||
idx++;
|
||||
|
||||
bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
bindings[idx].descriptorCount = 1;
|
||||
bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
bindings[idx].binding = binding_table.vertex_constant_buffers_bind_slot;
|
||||
|
@ -101,7 +101,8 @@ namespace vk
|
|||
return bindings;
|
||||
}
|
||||
|
||||
std::tuple<VkPipelineLayout, VkDescriptorSetLayout> get_common_pipeline_layout(VkDevice dev)
|
||||
std::tuple<VkPipelineLayout, VkDescriptorSetLayout, rsx::simple_array<VkDescriptorSetLayoutBinding>>
|
||||
get_common_pipeline_layout(VkDevice dev)
|
||||
{
|
||||
const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table();
|
||||
auto bindings = get_common_binding_table();
|
||||
|
@ -135,13 +136,13 @@ namespace vk
|
|||
|
||||
std::array<VkPushConstantRange, 1> push_constants;
|
||||
push_constants[0].offset = 0;
|
||||
push_constants[0].size = 16;
|
||||
push_constants[0].size = 20;
|
||||
push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
|
||||
if (vk::emulate_conditional_rendering())
|
||||
{
|
||||
// Conditional render toggle
|
||||
push_constants[0].size = 20;
|
||||
push_constants[0].size = 24;
|
||||
}
|
||||
|
||||
const auto set_layout = vk::descriptors::create_layout(bindings);
|
||||
|
@ -155,6 +156,25 @@ namespace vk
|
|||
|
||||
VkPipelineLayout result;
|
||||
CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result));
|
||||
return std::make_tuple(result, set_layout);
|
||||
return std::make_tuple(result, set_layout, bindings);
|
||||
}
|
||||
|
||||
rsx::simple_array<VkDescriptorPoolSize> get_descriptor_pool_sizes(const rsx::simple_array<VkDescriptorSetLayoutBinding>& bindings)
|
||||
{
|
||||
// Compile descriptor pool sizes
|
||||
const u32 num_ubo = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ? y.descriptorCount : 0)));
|
||||
const u32 num_texel_buffers = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ? y.descriptorCount : 0)));
|
||||
const u32 num_combined_image_sampler = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ? y.descriptorCount : 0)));
|
||||
const u32 num_ssbo = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ? y.descriptorCount : 0)));
|
||||
|
||||
ensure(num_ubo > 0 && num_texel_buffers > 0 && num_combined_image_sampler > 0 && num_ssbo > 0);
|
||||
|
||||
return
|
||||
{
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , num_ubo },
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER , num_texel_buffers },
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , num_combined_image_sampler },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, num_ssbo }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,11 @@ namespace vk
|
|||
{
|
||||
// Grab standard layout for decompiled RSX programs. Also used by the interpreter.
|
||||
// FIXME: This generates a bloated monstrosity that needs to die.
|
||||
std::tuple<VkPipelineLayout, VkDescriptorSetLayout> get_common_pipeline_layout(VkDevice dev);
|
||||
std::tuple<VkPipelineLayout, VkDescriptorSetLayout, rsx::simple_array<VkDescriptorSetLayoutBinding>> get_common_pipeline_layout(VkDevice dev);
|
||||
|
||||
// Returns the standard binding layout without texture slots. Those have special handling depending on the consumer.
|
||||
rsx::simple_array<VkDescriptorSetLayoutBinding> get_common_binding_table();
|
||||
|
||||
// Returns an array of pool sizes that can be used to generate a proper descriptor pool
|
||||
rsx::simple_array<VkDescriptorPoolSize> get_descriptor_pool_sizes(const rsx::simple_array<VkDescriptorSetLayoutBinding>& bindings);
|
||||
}
|
||||
|
|
66
rpcs3/Emu/RSX/VK/VKDataHeapManager.cpp
Normal file
66
rpcs3/Emu/RSX/VK/VKDataHeapManager.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include "stdafx.h"
|
||||
#include "VKDataHeapManager.h"
|
||||
|
||||
#include "vkutils/data_heap.h"
|
||||
#include <unordered_set>
|
||||
|
||||
namespace vk::data_heap_manager
|
||||
{
|
||||
std::unordered_set<vk::data_heap*> g_managed_heaps;
|
||||
|
||||
void register_ring_buffer(vk::data_heap& heap)
|
||||
{
|
||||
g_managed_heaps.insert(&heap);
|
||||
}
|
||||
|
||||
void register_ring_buffers(std::initializer_list<std::reference_wrapper<vk::data_heap>> heaps)
|
||||
{
|
||||
for (auto&& heap : heaps)
|
||||
{
|
||||
register_ring_buffer(heap);
|
||||
}
|
||||
}
|
||||
|
||||
managed_heap_snapshot_t get_heap_snapshot()
|
||||
{
|
||||
managed_heap_snapshot_t result{};
|
||||
for (auto& heap : g_managed_heaps)
|
||||
{
|
||||
result[heap] = heap->get_current_put_pos_minus_one();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void restore_snapshot(const managed_heap_snapshot_t& snapshot)
|
||||
{
|
||||
for (auto& heap : g_managed_heaps)
|
||||
{
|
||||
const auto found = snapshot.find(heap);
|
||||
if (found == snapshot.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
heap->set_get_pos(found->second);
|
||||
heap->notify();
|
||||
}
|
||||
}
|
||||
|
||||
void reset_heap_allocations()
|
||||
{
|
||||
for (auto& heap : g_managed_heaps)
|
||||
{
|
||||
heap->reset_allocation_stats();
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
for (auto& heap : g_managed_heaps)
|
||||
{
|
||||
heap->destroy();
|
||||
}
|
||||
|
||||
g_managed_heaps.clear();
|
||||
}
|
||||
}
|
33
rpcs3/Emu/RSX/VK/VKDataHeapManager.h
Normal file
33
rpcs3/Emu/RSX/VK/VKDataHeapManager.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include <util/types.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace vk
|
||||
{
|
||||
class data_heap;
|
||||
|
||||
namespace data_heap_manager
|
||||
{
|
||||
using managed_heap_snapshot_t = std::unordered_map<const vk::data_heap*, s64>;
|
||||
|
||||
// Submit ring buffer for management
|
||||
void register_ring_buffer(vk::data_heap& heap);
|
||||
|
||||
// Bulk registration
|
||||
void register_ring_buffers(std::initializer_list<std::reference_wrapper<vk::data_heap>> heaps);
|
||||
|
||||
// Capture managed ring buffers snapshot at current time
|
||||
managed_heap_snapshot_t get_heap_snapshot();
|
||||
|
||||
// Synchronize heap with snapshot
|
||||
void restore_snapshot(const managed_heap_snapshot_t& snapshot);
|
||||
|
||||
// Reset all managed heap allocations
|
||||
void reset_heap_allocations();
|
||||
|
||||
// Cleanup
|
||||
void reset();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue